PDO::ERRMODE_EXCEPTION]); } return $pdo; } function ensureTables() { $pdo = getDB(); // FreeDNS Accounts (multi-comptes) $pdo->exec("CREATE TABLE IF NOT EXISTS admin.freedns_accounts ( id SERIAL PRIMARY KEY, username VARCHAR(100) NOT NULL, password VARCHAR(255) NOT NULL, cookie TEXT, domains_count INTEGER DEFAULT 0, max_domains INTEGER DEFAULT 5, status VARCHAR(50) DEFAULT 'active', last_login TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )"); // FreeDNS Domains $pdo->exec("CREATE TABLE IF NOT EXISTS admin.freedns_domains ( id SERIAL PRIMARY KEY, account_id INTEGER REFERENCES admin.freedns_accounts(id), domain VARCHAR(255) NOT NULL, freedns_id VARCHAR(100), domain_type VARCHAR(50) DEFAULT 'subdomain', base_domain VARCHAR(255), status VARCHAR(50) DEFAULT 'active', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )"); // FreeDNS Records $pdo->exec("CREATE TABLE IF NOT EXISTS admin.freedns_records ( id SERIAL PRIMARY KEY, domain_id INTEGER REFERENCES admin.freedns_domains(id), record_type VARCHAR(10) NOT NULL, name VARCHAR(255), value TEXT, ttl INTEGER DEFAULT 3600, freedns_id VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )"); // Cloudflare Accounts $pdo->exec("CREATE TABLE IF NOT EXISTS admin.cloudflare_accounts ( id SERIAL PRIMARY KEY, email VARCHAR(255) NOT NULL, api_key VARCHAR(255), api_token VARCHAR(255), account_id VARCHAR(100), status VARCHAR(50) DEFAULT 'active', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )"); // Cloudflare Zones $pdo->exec("CREATE TABLE IF NOT EXISTS admin.cloudflare_zones ( id SERIAL PRIMARY KEY, account_id INTEGER REFERENCES admin.cloudflare_accounts(id), zone_id VARCHAR(100) NOT NULL, domain VARCHAR(255) NOT NULL, status VARCHAR(50), name_servers TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )"); // Cloudflare DNS Records $pdo->exec("CREATE TABLE IF NOT EXISTS admin.cloudflare_records ( id SERIAL PRIMARY KEY, zone_id INTEGER REFERENCES admin.cloudflare_zones(id), record_id VARCHAR(100), record_type VARCHAR(10), name VARCHAR(255), content TEXT, ttl INTEGER DEFAULT 1, proxied BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )"); } // FreeDNS API Class class FreeDNSAPI { private $account; private $cookie; private $baseUrl = 'https://freedns.afraid.org'; public function __construct($accountId = null) { if ($accountId) { $pdo = getDB(); $stmt = $pdo->prepare("SELECT * FROM admin.freedns_accounts WHERE id = ?"); $stmt->execute([$accountId]); $this->account = $stmt->fetch(PDO::FETCH_ASSOC); $this->cookie = $this->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', 'action' => 'auth' ]), CURLOPT_HEADER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' ]); $response = curl_exec($ch); curl_close($ch); // Extract cookie preg_match_all('/Set-Cookie:\s*([^;]+)/', $response, $matches); $cookies = implode('; ', $matches[1] ?? []); if (strpos($response, 'dns_cookie') !== false || strpos($cookies, 'dns_cookie') !== false) { $this->cookie = $cookies; return ['success' => true, 'cookie' => $cookies]; } return ['success' => false, 'error' => 'Login failed']; } public function getDomains() { $ch = curl_init($this->baseUrl . '/subdomain/'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_COOKIE => $this->cookie, CURLOPT_USERAGENT => 'Mozilla/5.0' ]); $html = curl_exec($ch); curl_close($ch); $domains = []; // Parse domains from HTML preg_match_all('/edit\.php\?data_id=(\d+).*?]*>([^<]+)<\/td>/s', $html, $matches, PREG_SET_ORDER); foreach ($matches as $m) { $domains[] = [ 'freedns_id' => $m[1], 'domain' => trim($m[2]) ]; } return $domains; } public function addSubdomain($subdomain, $baseDomain, $type = 'A', $destination) { // First get available base domains $ch = curl_init($this->baseUrl . '/subdomain/edit.php'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_COOKIE => $this->cookie, CURLOPT_USERAGENT => 'Mozilla/5.0' ]); $html = curl_exec($ch); curl_close($ch); // Find domain_id for base domain preg_match('/option value="(\d+)"[^>]*>' . preg_quote($baseDomain) . '/i', $html, $m); $domainId = $m[1] ?? null; if (!$domainId) { return ['success' => false, 'error' => 'Base domain not found']; } // Create subdomain $ch = curl_init($this->baseUrl . '/subdomain/save.php?step=2'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_COOKIE => $this->cookie, CURLOPT_POSTFIELDS => http_build_query([ 'type' => $type, 'subdomain' => $subdomain, 'domain_id' => $domainId, 'address' => $destination, 'send' => 'Save!' ]), CURLOPT_USERAGENT => 'Mozilla/5.0', CURLOPT_FOLLOWLOCATION => true ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if (strpos($response, 'ERROR') !== false) { preg_match('/ERROR[^<]*/', $response, $err); return ['success' => false, 'error' => $err[0] ?? 'Unknown error']; } return ['success' => true, 'domain' => "$subdomain.$baseDomain"]; } public function deleteSubdomain($freednsId) { $ch = curl_init($this->baseUrl . "/subdomain/delete2.php?data_id[]=$freednsId&submit=delete"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_COOKIE => $this->cookie, CURLOPT_USERAGENT => 'Mozilla/5.0', CURLOPT_FOLLOWLOCATION => true ]); $response = curl_exec($ch); curl_close($ch); return ['success' => true]; } public function getAvailableBaseDomains() { $ch = curl_init($this->baseUrl . '/domain/registry/'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_COOKIE => $this->cookie, CURLOPT_USERAGENT => 'Mozilla/5.0' ]); $html = curl_exec($ch); curl_close($ch); $domains = []; preg_match_all('/]*>([a-z0-9.-]+\.[a-z]{2,})<\/td>/i', $html, $matches); return array_unique($matches[1] ?? []); } } // Cloudflare API Class class CloudflareAPI { private $email; private $apiKey; private $apiToken; private $baseUrl = 'https://api.cloudflare.com/client/v4'; public function __construct($accountId = null) { if ($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']; } } public function setCredentials($email, $apiKey, $apiToken = null) { $this->email = $email; $this->apiKey = $apiKey; $this->apiToken = $apiToken; } 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 ]); if ($data && in_array($method, ['POST', 'PUT', 'PATCH'])) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } $response = curl_exec($ch); curl_close($ch); return json_decode($response, true); } public function verifyToken() { return $this->request('/user/tokens/verify'); } public function listZones() { return $this->request('/zones?per_page=50'); } public function getZone($zoneId) { return $this->request("/zones/$zoneId"); } public function createZone($domain, $accountId = null) { $data = ['name' => $domain, 'jump_start' => true]; if ($accountId) $data['account'] = ['id' => $accountId]; return $this->request('/zones', 'POST', $data); } public function deleteZone($zoneId) { return $this->request("/zones/$zoneId", 'DELETE'); } public function listDNSRecords($zoneId) { return $this->request("/zones/$zoneId/dns_records?per_page=100"); } public function createDNSRecord($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 updateDNSRecord($zoneId, $recordId, $type, $name, $content, $ttl = 1, $proxied = false) { return $this->request("/zones/$zoneId/dns_records/$recordId", 'PUT', [ 'type' => $type, 'name' => $name, 'content' => $content, 'ttl' => $ttl, 'proxied' => $proxied ]); } public function deleteDNSRecord($zoneId, $recordId) { return $this->request("/zones/$zoneId/dns_records/$recordId", 'DELETE'); } // Bulk operations public function bulkCreateRecords($zoneId, $records) { $results = []; foreach ($records as $record) { $results[] = $this->createDNSRecord( $zoneId, $record['type'], $record['name'], $record['content'], $record['ttl'] ?? 1, $record['proxied'] ?? false ); } return $results; } // Email routing setup public function setupEmailRouting($zoneId, $mxRecords, $spfRecord, $dkimRecord = null, $dmarcRecord = null) { $results = []; // MX Records foreach ($mxRecords as $priority => $server) { $results[] = $this->createDNSRecord($zoneId, 'MX', '@', $server, 1, false); } // SPF if ($spfRecord) { $results[] = $this->createDNSRecord($zoneId, 'TXT', '@', $spfRecord, 1, false); } // DKIM if ($dkimRecord) { $results[] = $this->createDNSRecord($zoneId, 'TXT', 'default._domainkey', $dkimRecord, 1, false); } // DMARC if ($dmarcRecord) { $results[] = $this->createDNSRecord($zoneId, 'TXT', '_dmarc', $dmarcRecord, 1, false); } return $results; } } // API Handler if (isset($_GET['action']) || isset($_POST['action'])) { header('Content-Type: application/json'); ensureTables(); $action = $_GET['action'] ?? $_POST['action']; $pdo = getDB(); try { switch ($action) { // Stats case 'stats': echo json_encode(['success' => true, 'stats' => [ 'freedns_accounts' => $pdo->query("SELECT COUNT(*) FROM admin.freedns_accounts")->fetchColumn(), 'freedns_domains' => $pdo->query("SELECT COUNT(*) FROM admin.freedns_domains")->fetchColumn(), 'cloudflare_accounts' => $pdo->query("SELECT COUNT(*) FROM admin.cloudflare_accounts")->fetchColumn(), 'cloudflare_zones' => $pdo->query("SELECT COUNT(*) FROM admin.cloudflare_zones")->fetchColumn(), ]]); break; // ============ FreeDNS ============ case 'freedns_add_account': $username = $_POST['username'] ?? ''; $password = $_POST['password'] ?? ''; $api = new FreeDNSAPI(); $login = $api->login($username, $password); if ($login['success']) { $stmt = $pdo->prepare("INSERT INTO admin.freedns_accounts (username, password, cookie, last_login) VALUES (?, ?, ?, NOW()) RETURNING id"); $stmt->execute([$username, $password, $login['cookie']]); $id = $stmt->fetchColumn(); echo json_encode(['success' => true, 'id' => $id]); } else { echo json_encode($login); } break; case 'freedns_list_accounts': $accounts = $pdo->query("SELECT id, username, domains_count, max_domains, status, last_login, created_at FROM admin.freedns_accounts ORDER BY id")->fetchAll(PDO::FETCH_ASSOC); echo json_encode(['success' => true, 'accounts' => $accounts]); break; case 'freedns_refresh_account': $accountId = $_POST['account_id'] ?? 0; $api = new FreeDNSAPI($accountId); // Re-login $stmt = $pdo->prepare("SELECT username, password FROM admin.freedns_accounts WHERE id = ?"); $stmt->execute([$accountId]); $acc = $stmt->fetch(PDO::FETCH_ASSOC); $login = $api->login($acc['username'], $acc['password']); if ($login['success']) { $pdo->exec("UPDATE admin.freedns_accounts SET cookie = " . $pdo->quote($login['cookie']) . ", last_login = NOW() WHERE id = $accountId"); // Get domains $api = new FreeDNSAPI($accountId); $domains = $api->getDomains(); $pdo->exec("UPDATE admin.freedns_accounts SET domains_count = " . count($domains) . " WHERE id = $accountId"); echo json_encode(['success' => true, 'domains_count' => count($domains)]); } else { echo json_encode($login); } break; case 'freedns_get_domains': $accountId = $_GET['account_id'] ?? 0; $api = new FreeDNSAPI($accountId); $domains = $api->getDomains(); echo json_encode(['success' => true, 'domains' => $domains]); break; case 'freedns_add_subdomain': $accountId = $_POST['account_id'] ?? 0; $subdomain = $_POST['subdomain'] ?? ''; $baseDomain = $_POST['base_domain'] ?? ''; $type = $_POST['type'] ?? 'A'; $destination = $_POST['destination'] ?? ''; // Find account with space if (!$accountId) { $stmt = $pdo->query("SELECT id FROM admin.freedns_accounts WHERE domains_count < max_domains AND status = 'active' ORDER BY domains_count ASC LIMIT 1"); $accountId = $stmt->fetchColumn(); } if (!$accountId) { echo json_encode(['success' => false, 'error' => 'No available account (all at max domains)']); break; } $api = new FreeDNSAPI($accountId); $result = $api->addSubdomain($subdomain, $baseDomain, $type, $destination); if ($result['success']) { $stmt = $pdo->prepare("INSERT INTO admin.freedns_domains (account_id, domain, base_domain, domain_type) VALUES (?, ?, ?, 'subdomain')"); $stmt->execute([$accountId, $result['domain'], $baseDomain]); $pdo->exec("UPDATE admin.freedns_accounts SET domains_count = domains_count + 1 WHERE id = $accountId"); } echo json_encode($result); break; case 'freedns_delete_subdomain': $domainId = $_POST['domain_id'] ?? 0; $freednsId = $_POST['freedns_id'] ?? ''; $stmt = $pdo->prepare("SELECT account_id FROM admin.freedns_domains WHERE id = ?"); $stmt->execute([$domainId]); $accountId = $stmt->fetchColumn(); $api = new FreeDNSAPI($accountId); $result = $api->deleteSubdomain($freednsId); if ($result['success']) { $pdo->exec("DELETE FROM admin.freedns_domains WHERE id = $domainId"); $pdo->exec("UPDATE admin.freedns_accounts SET domains_count = domains_count - 1 WHERE id = $accountId"); } echo json_encode($result); break; case 'freedns_base_domains': $accountId = $_GET['account_id'] ?? 0; $api = new FreeDNSAPI($accountId); $domains = $api->getAvailableBaseDomains(); echo json_encode(['success' => true, 'domains' => $domains]); break; case 'freedns_bulk_create': $subdomains = json_decode($_POST['subdomains'] ?? '[]', true); $baseDomain = $_POST['base_domain'] ?? ''; $type = $_POST['type'] ?? 'A'; $destination = $_POST['destination'] ?? ''; $results = ['success' => 0, 'failed' => 0, 'errors' => []]; foreach ($subdomains as $sub) { // Find account with space $stmt = $pdo->query("SELECT id FROM admin.freedns_accounts WHERE domains_count < max_domains AND status = 'active' ORDER BY domains_count ASC LIMIT 1"); $accountId = $stmt->fetchColumn(); if (!$accountId) { $results['failed']++; $results['errors'][] = "No available account for $sub"; continue; } $api = new FreeDNSAPI($accountId); $result = $api->addSubdomain($sub, $baseDomain, $type, $destination); if ($result['success']) { $stmt = $pdo->prepare("INSERT INTO admin.freedns_domains (account_id, domain, base_domain, domain_type) VALUES (?, ?, ?, 'subdomain')"); $stmt->execute([$accountId, $result['domain'], $baseDomain]); $pdo->exec("UPDATE admin.freedns_accounts SET domains_count = domains_count + 1 WHERE id = $accountId"); $results['success']++; } else { $results['failed']++; $results['errors'][] = $result['error'] ?? 'Unknown error'; } usleep(500000); // 0.5s delay } echo json_encode(['success' => true, 'results' => $results]); break; // ============ Cloudflare ============ case 'cf_add_account': $email = $_POST['email'] ?? ''; $apiKey = $_POST['api_key'] ?? ''; $apiToken = $_POST['api_token'] ?? ''; $api = new CloudflareAPI(); $api->setCredentials($email, $apiKey, $apiToken); $verify = $api->verifyToken(); if ($verify['success'] ?? false) { $stmt = $pdo->prepare("INSERT INTO admin.cloudflare_accounts (email, api_key, api_token) VALUES (?, ?, ?) RETURNING id"); $stmt->execute([$email, $apiKey, $apiToken]); $id = $stmt->fetchColumn(); echo json_encode(['success' => true, 'id' => $id]); } else { echo json_encode(['success' => false, 'error' => $verify['errors'][0]['message'] ?? 'Invalid credentials']); } break; case 'cf_list_accounts': $accounts = $pdo->query("SELECT id, email, status, created_at FROM admin.cloudflare_accounts ORDER BY id")->fetchAll(PDO::FETCH_ASSOC); echo json_encode(['success' => true, 'accounts' => $accounts]); break; case 'cf_list_zones': $accountId = $_GET['account_id'] ?? 0; $api = new CloudflareAPI($accountId); $result = $api->listZones(); if ($result['success'] ?? false) { // Sync to DB foreach ($result['result'] as $zone) { $stmt = $pdo->prepare("INSERT INTO admin.cloudflare_zones (account_id, zone_id, domain, status, name_servers) VALUES (?, ?, ?, ?, ?) ON CONFLICT (zone_id) DO UPDATE SET status = ?, name_servers = ?"); $ns = implode(',', $zone['name_servers'] ?? []); $stmt->execute([$accountId, $zone['id'], $zone['name'], $zone['status'], $ns, $zone['status'], $ns]); } } echo json_encode($result); break; case 'cf_add_zone': $accountId = $_POST['account_id'] ?? 0; $domain = $_POST['domain'] ?? ''; $api = new CloudflareAPI($accountId); $result = $api->createZone($domain); if ($result['success'] ?? false) { $zone = $result['result']; $stmt = $pdo->prepare("INSERT INTO admin.cloudflare_zones (account_id, zone_id, domain, status, name_servers) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$accountId, $zone['id'], $zone['name'], $zone['status'], implode(',', $zone['name_servers'] ?? [])]); } echo json_encode($result); break; case 'cf_delete_zone': $accountId = $_POST['account_id'] ?? 0; $zoneId = $_POST['zone_id'] ?? ''; $api = new CloudflareAPI($accountId); $result = $api->deleteZone($zoneId); if ($result['success'] ?? false) { $pdo->exec("DELETE FROM admin.cloudflare_zones WHERE zone_id = " . $pdo->quote($zoneId)); } echo json_encode($result); break; case 'cf_list_records': $accountId = $_GET['account_id'] ?? 0; $zoneId = $_GET['zone_id'] ?? ''; $api = new CloudflareAPI($accountId); echo json_encode($api->listDNSRecords($zoneId)); break; case 'cf_add_record': $accountId = $_POST['account_id'] ?? 0; $zoneId = $_POST['zone_id'] ?? ''; $type = $_POST['type'] ?? 'A'; $name = $_POST['name'] ?? '@'; $content = $_POST['content'] ?? ''; $ttl = intval($_POST['ttl'] ?? 1); $proxied = ($_POST['proxied'] ?? '0') === '1'; $api = new CloudflareAPI($accountId); echo json_encode($api->createDNSRecord($zoneId, $type, $name, $content, $ttl, $proxied)); break; case 'cf_delete_record': $accountId = $_POST['account_id'] ?? 0; $zoneId = $_POST['zone_id'] ?? ''; $recordId = $_POST['record_id'] ?? ''; $api = new CloudflareAPI($accountId); echo json_encode($api->deleteDNSRecord($zoneId, $recordId)); break; case 'cf_setup_email': $accountId = $_POST['account_id'] ?? 0; $zoneId = $_POST['zone_id'] ?? ''; $ip = $_POST['ip'] ?? ''; $domain = $_POST['domain'] ?? ''; $api = new CloudflareAPI($accountId); // Standard email records $results = []; // A record $results[] = $api->createDNSRecord($zoneId, 'A', '@', $ip, 1, false); $results[] = $api->createDNSRecord($zoneId, 'A', 'mail', $ip, 1, false); // MX $results[] = $api->createDNSRecord($zoneId, 'MX', '@', "mail.$domain", 1, false); // SPF $results[] = $api->createDNSRecord($zoneId, 'TXT', '@', "v=spf1 ip4:$ip ~all", 1, false); // DMARC $results[] = $api->createDNSRecord($zoneId, 'TXT', '_dmarc', 'v=DMARC1; p=none; rua=mailto:dmarc@'.$domain, 1, false); echo json_encode(['success' => true, 'results' => $results]); break; case 'cf_bulk_add_records': $accountId = $_POST['account_id'] ?? 0; $zoneId = $_POST['zone_id'] ?? ''; $records = json_decode($_POST['records'] ?? '[]', true); $api = new CloudflareAPI($accountId); $results = $api->bulkCreateRecords($zoneId, $records); echo json_encode(['success' => true, 'results' => $results]); break; default: echo json_encode(['success' => false, 'error' => 'Unknown action']); } } catch (Exception $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); } exit; } ensureTables(); ?> DNS Manager - FreeDNS & Cloudflare

DNS Manager

FreeDNS
Cloudflare
0
FreeDNS Accounts
0
FreeDNS Domains
0
Cloudflare Accounts
0
Cloudflare Zones

Add FreeDNS Account

FreeDNS limite à 5 domaines par compte. Créez plusieurs comptes pour plus de domaines.

FreeDNS Accounts

IDUsernameDomainsCapacityStatusLast LoginActions

Create Subdomain

My Subdomains

DomainBaseAccountStatusActions

Add Cloudflare Account

Cloudflare Accounts

IDEmailStatusCreatedActions

Zones

Select an account to view zones