Open wvro-org opened 1 week ago
added bellow // DS records for the domain
logic for custom
smth like this logic not working
if (isset($c['tld_custom_records'][$dname]) && $c['tld_custom_records'][$dname]['enabled']) { $customRecords = $c['tld_custom_records'][$dname]['records']; foreach ($customRecords as $recordType => $values) { foreach ($values as $value) { $record = new ResourceRecord; $record->setName($dname_clean . '.'); $record->setClass(Classes::INTERNET); $record->setRdata(Factory::$recordType($value)); $zone->addResourceRecord($record); } } }
@getpinga @anantsparrow need help stucked here (even with phind)
class CustomRecord extends ResourceRecord { public function construct() { parent::construct(); } }
//custom tld record // Check if custom records are enabled for this TLD if (isset($c['tld_custom_records'][$tld]) && $c['tld_custom_records'][$tld]['enabled']) { $customRecords = $c['tld_custom_records'][$tld]['records'];
// Process A records
if (isset($customRecords['A'])) {
foreach ($customRecords['A'] as $value) {
$customRecord = new CustomRecord();
$customRecord->setName($dname_clean . '.');
$customRecord->setClass(Classes::INTERNET);
$customRecord->setRdata(Factory::A($value));
$zone->addResourceRecord($customRecord);
}
}
// Process AAAA records
if (isset($customRecords['AAAA'])) {
foreach ($customRecords['AAAA'] as $value) {
$customRecord = new CustomRecord();
$customRecord->setName($dname_clean . '.');
$customRecord->setClass(Classes::INTERNET);
$customRecord->setRdata(Factory::AAAA($value));
$zone->addResourceRecord($customRecord);
}
}
// Process TXT records
if (isset($customRecords['TXT'])) {
foreach ($customRecords['TXT'] as $value) {
$customRecord = new CustomRecord();
$customRecord->setName($dname_clean . '.');
$customRecord->setClass(Classes::INTERNET);
$customRecord->setRdata(Factory::Txt($value));
$zone->addResourceRecord($customRecord);
}
}
// Process MX records
if (isset($customRecords['MX'])) {
foreach ($customRecords['MX'] as $value) {
$record = new ResourceRecord();
$record->setName($dname_clean . '.');
$record->setClass(Classes::INTERNET);
$record->setRdata(Factory::Mx($value));
$zone->addResourceRecord($customrecord);
}
}
// Log custom record processing
$log->info("Processed custom records for TLD {$tld}:");
$log->info("A records: " . count($customRecords['A'] ?? []));
$log->info("TXT records: " . count($customRecords['TXT'] ?? []));
$log->info("MX records: " . count($customRecords['MX'] ?? []));
} else { $log->info("No custom records found for TLD {$tld}"); }
figured out .... will upload later in next comment
here's long awaited IPV4/6 write-zone-ipv4-ipv6.php (thanks phind ai )
<?php
require_once 'vendor/autoload.php';
use Badcow\DNS\Zone;
use Badcow\DNS\Rdata\Factory;
use Badcow\DNS\ResourceRecord;
use Badcow\DNS\Classes;
use Badcow\DNS\ZoneBuilder;
use Badcow\DNS\AlignedBuilder;
$c = require_once 'config.php';
require_once 'helpers.php';
$logFilePath = '/var/log/namingo/write_zone.log';
$log = setupLogger($logFilePath, 'Zone_Generator');
$log->info('job started.');
use Swoole\Coroutine;
// Initialize the PDO connection pool
$pool = new Swoole\Database\PDOPool(
(new Swoole\Database\PDOConfig())
->withDriver($c['db_type'])
->withHost($c['db_host'])
->withPort($c['db_port'])
->withDbName($c['db_database'])
->withUsername($c['db_username'])
->withPassword($c['db_password'])
->withCharset('utf8mb4')
);
Swoole\Runtime::enableCoroutine();
// A / A6 record for zone
function addSpecificRecords($zone, $cleanedTld, $ipv4Address, $ipv6Address) {
global $log;
// Log that the function is being called
$log->info('Zone_Generator.INFO: Adding specific records for domain: ' . $cleanedTld);
try {
// Add A record
$record = generateARecord($cleanedTld, $ipv4Address);
if ($record !== null) {
$zone->addResourceRecord($record);
$log->info('Zone_Generator.INFO: Added A record for ' . $cleanedTld . ': ' . $ipv4Address);
} else {
$log->warning('Zone_Generator.WARNING: Failed to add A record for domain: ' . $cleanedTld);
}
// Add AAAA record
$record = generateAAAARecord($cleanedTld, $ipv6Address);
if ($record !== null) {
$zone->addResourceRecord($record);
$log->info('Zone_Generator.INFO: Added AAAA record for ' . $cleanedTld . ': ' . $ipv6Address);
} else {
$log->warning('Zone_Generator.WARNING: Failed to add AAAA record for domain: ' . $cleanedTld);
}
} catch (Exception $e) {
$log->error('Zone_Generator.ERROR: Failed to add specific records for domain: ' . $cleanedTld . '. Error: ' . $e->getMessage());
}
}
function generateARecord($hostName, $ipAddress) {
$record = new ResourceRecord();
$record->setName($hostName . '.');
$record->setClass(Classes::INTERNET);
$record->setTtl(100);
$record->setRdata(Factory::A($ipAddress));
return $record;
}
function generateAAAARecord($hostName, $ipv6Address) {
$record = new ResourceRecord();
$record->setName($hostName . '.');
$record->setClass(Classes::INTERNET);
$record->setTtl(100);
$record->setRdata(Factory::AAAA($ipv6Address));
return $record;
}
// A / A6 record for zone end
// Creating first coroutine
Coroutine::create(function () use ($pool, $log, $c) {
try {
$pdo = $pool->get();
$sth = $pdo->prepare('SELECT id, tld FROM domain_tld');
$sth->execute();
$timestamp = time();
while (list($id, $tld) = $sth->fetch(PDO::FETCH_NUM)) {
$tldRE = preg_quote($tld, '/');
$cleanedTld = ltrim(strtolower($tld), '.');
$zone = new Zone($cleanedTld.'.');
$zone->setDefaultTtl(100);
//setting for // A / A6 record for zones
if ($cleanedTld === 'test') {
addSpecificRecords($zone, $cleanedTld, '0.0.0.0', '::1'); leave blank to delete A, and AAAA records
} elseif ($cleanedTld === 'com.test') {
addSpecificRecords($zone, $cleanedTld, '', '');
} else {
// Do nothing for other domains
}
//setting for // A / A6 record for zones end
$soa = new ResourceRecord;
$soa->setName('@');
$soa->setClass(Classes::INTERNET);
$soa->setRdata(Factory::Soa(
$c['ns']['ns1'] . '.',
$c['dns_soa'] . '.',
$timestamp,
900,
1800,
3600000,
3600
));
$zone->addResourceRecord($soa);
// Add A and AAAA records
foreach ($c['ns'] as $ns) {
$nsRecord = new ResourceRecord;
$nsRecord->setName($cleanedTld . '.');
$nsRecord->setClass(Classes::INTERNET);
$nsRecord->setRdata(Factory::Ns($ns . '.'));
$zone->addResourceRecord($nsRecord);
}
// Fetch domains for this TLD
$sthDomains = $pdo->prepare('SELECT DISTINCT domain.id, domain.name FROM domain WHERE tldid = :id AND (exdate > CURRENT_TIMESTAMP OR rgpstatus = \'pendingRestore\') ORDER BY domain.name');
$domainIds = [];
$sthDomains->execute([':id' => $id]);
while ($row = $sthDomains->fetch(PDO::FETCH_ASSOC)) {
$domainIds[] = $row['id'];
}
$statuses = [];
if (count($domainIds) > 0) {
$placeholders = implode(',', array_fill(0, count($domainIds), '?'));
$sthStatus = $pdo->prepare("SELECT domain_id, id FROM domain_status WHERE domain_id IN ($placeholders) AND status LIKE '%Hold'");
$sthStatus->execute($domainIds);
while ($row = $sthStatus->fetch(PDO::FETCH_ASSOC)) {
$statuses[$row['domain_id']] = $row['id'];
}
}
$sthDomains->execute([':id' => $id]);
while (list($did, $dname) = $sthDomains->fetch(PDO::FETCH_NUM)) {
if (isset($statuses[$did])) continue;
$dname_clean = $dname;
$dname_clean = ($dname_clean == "$tld.") ? '@' : $dname_clean;
// NS records for the domain
$sthNsRecords = $pdo->prepare('SELECT DISTINCT host.name FROM domain_host_map INNER JOIN host ON domain_host_map.host_id = host.id WHERE domain_host_map.domain_id = :did');
$sthNsRecords->execute([':did' => $did]);
while (list($hname) = $sthNsRecords->fetch(PDO::FETCH_NUM)) {
$nsRecord = new ResourceRecord;
$nsRecord->setName($dname_clean . '.');
$nsRecord->setClass(Classes::INTERNET);
$nsRecord->setRdata(Factory::Ns($hname . '.'));
$zone->addResourceRecord($nsRecord);
}
// A/AAAA records for the domain
$sthHostRecords = $pdo->prepare("SELECT host.name, host_addr.ip, host_addr.addr FROM host INNER JOIN host_addr ON host.id = host_addr.host_id WHERE host.domain_id = :did ORDER BY host.name");
$sthHostRecords->execute([':did' => $did]);
while (list($hname, $type, $addr) = $sthHostRecords->fetch(PDO::FETCH_NUM)) {
$hname_clean = $hname;
$hname_clean = ($hname_clean == "$tld.") ? '@' : $hname_clean;
$record = new ResourceRecord;
$record->setName($hname_clean . '.');
$record->setClass(Classes::INTERNET);
if ($type == 'v4') {
$record->setRdata(Factory::A($addr));
} else {
$record->setRdata(Factory::AAAA($addr));
}
$zone->addResourceRecord($record);
}
// DS records for the domain
$sthDS = $pdo->prepare("SELECT keytag, alg, digesttype, digest FROM secdns WHERE domain_id = :did");
$sthDS->execute([':did' => $did]);
while (list($keytag, $alg, $digesttype, $digest) = $sthDS->fetch(PDO::FETCH_NUM)) {
$dsRecord = new ResourceRecord;
$dsRecord->setName($dname_clean . '.');
$dsRecord->setClass(Classes::INTERNET);
$dsRecord->setRdata(Factory::Ds($keytag, $alg, hex2bin($digest), $digesttype));
$zone->addResourceRecord($dsRecord);
}
}
if (isset($c['zone_mode']) && $c['zone_mode'] === 'nice') {
$builder = new AlignedBuilder();
} else {
$builder = new ZoneBuilder();
}
$log->info('Building zone for TLD: ' . $cleanedTld . ', Builder type: ' . ($c['zone_mode'] === 'nice' ? 'AlignedBuilder' : 'ZoneBuilder'));
$completed_zone = $builder->build($zone);
// Log a truncated version of the completed zone content
$maxLogLength = 10000; // Maximum length for the log entry
$logContent = substr($completed_zone, 0, $maxLogLength);
$log->info("Completed zone content (truncated): " . $logContent);
if ($c['dns_server'] == 'bind') {
$basePath = '/var/lib/bind';
} elseif ($c['dns_server'] == 'nsd') {
$basePath = '/etc/nsd';
} elseif ($c['dns_server'] == 'knot') {
$basePath = '/etc/knot';
} else {
// Default path
$basePath = '/var/lib/bind';
}
file_put_contents("{$basePath}/{$cleanedTld}.zone", $completed_zone);
if ($c['dns_server'] == 'opendnssec') {
chown("{$basePath}/{$cleanedTld}.zone", 'opendnssec');
chgrp("{$basePath}/{$cleanedTld}.zone", 'opendnssec');
}
}
if ($c['dns_server'] == 'bind') {
exec("rndc reload {$cleanedTld}.", $output, $return_var);
if ($return_var != 0) {
$log->error('Failed to reload BIND. ' . $return_var);
}
exec("rndc notify {$cleanedTld}.", $output, $return_var);
if ($return_var != 0) {
$log->error('Failed to notify secondary servers. ' . $return_var);
}
} elseif ($c['dns_server'] == 'nsd') {
exec("nsd-control reload", $output, $return_var);
if ($return_var != 0) {
$log->error('Failed to reload NSD. ' . $return_var);
}
} elseif ($c['dns_server'] == 'knot') {
exec("knotc reload", $output, $return_var);
if ($return_var != 0) {
$log->error('Failed to reload Knot DNS. ' . $return_var);
}
exec("knotc zone-notify {$cleanedTld}.", $output, $return_var);
if ($return_var != 0) {
$log->error('Failed to notify secondary servers. ' . $return_var);
}
} elseif ($c['dns_server'] == 'opendnssec') {
exec("ods-signer sign {$cleanedTld}");
sleep(1);
copy("/var/lib/opendnssec/signed/{$cleanedTld}", "/var/lib/bind/{$cleanedTld}.zone.signed");
exec("rndc reload {$cleanedTld}.", $output, $return_var);
if ($return_var != 0) {
$log->error('Failed to reload BIND. ' . $return_var);
}
exec("rndc notify {$cleanedTld}.", $output, $return_var);
if ($return_var != 0) {
$log->error('Failed to notify secondary servers. ' . $return_var);
}
} else {
// Default
exec("rndc reload {$cleanedTld}.", $output, $return_var);
if ($return_var != 0) {
$log->error('Failed to reload BIND. ' . $return_var);
}
exec("rndc notify {$cleanedTld}.", $output, $return_var);
if ($return_var != 0) {
$log->error('Failed to notify secondary servers. ' . $return_var);
}
}
$log->info('job finished successfully.');
} catch (PDOException $e) {
$log->error('Database error: ' . $e->getMessage());
} catch (Throwable $e) {
$log->error('Error: ' . $e->getMessage());
} finally {
// Return the connection to the pool
$pool->put($pdo);
}
});
not closing working on other supported records... | Type | Type ID | Defining RFC | Supported? | Usage* |
---|---|---|---|---|---|
A | 1 | RFC 1035 | ✔ | In Use | |
AAAA | 28 | RFC 3596 | ✔ | In Use | |
AFSDB | 18 | RFC 1183 | ✔ | In Use | |
APL | 42 | RFC 3123 | ✔ | In Use | |
CAA | 257 | RFC 6844 | ✔ | In Use | |
CDNSKEY | 60 | RFC 7344 | ✔ | In Use | |
CDS | 59 | RFC 7344 | ✔ | In Use | |
CERT | 37 | RFC 4398 | ✔ | In Use | |
CNAME | 5 | RFC 1035 | ✔ | In Use | |
CSYNC | 62 | RFC 7477 | ✔ | In Use | |
DHCID | 49 | RFC 4701 | ✔ | In Use | |
DLV | 32769 | RFC 4431 | ✔ | In Use | |
DNAME | 39 | RFC 6672 | ✔ | In Use | |
DNSKEY | 48 | RFC 4034 | ✔ | In Use | |
DS | 43 | RFC 4034 | ✔ | In Use | |
HIP | 55 | RFC 8005 | ✔ | In Use | |
IPSECKEY | 45 | RFC 4025 | ✔ | In Use | |
KEY | 25 | RFC 2535 & RFC 2930 | ✔ | In Use | |
KX | 36 | RFC 2230 | ✔ | In Use | |
LOC | 29 | RFC 1876 | ✔ | In Use | |
MX | 15 | RFC 1035 & RFC 7505 | ✔ | In Use | |
NAPTR | 35 | RFC 3403 | ✔ | In Use | |
NSEC | 47 | RFC 4034 | ✔ | In Use | |
NSEC3 | 50 | RFC 5155 | ✔ | In Use | |
NSEC3PARAM | 51 | RFC 5155 | ✔ | In Use | |
OPENPGPKEY | 61 | RFC 7929 | ✖ | In Use | |
PTR | 12 | RFC 1035 | ✔ | In Use | |
RP | 17 | RFC 1183 | ✔ | In Use | |
RRSIG | 46 | RFC 4034 | ✔ | In Use | |
SIG | 24 | RFC 2535 | ✔ | In Use | |
SMIMEA | 53 | RFC 8162 | ✖ | In Use | |
SRV | 33 | RFC 2782 | ✔ | In Use | |
SSHFP | 44 | RFC 4255 | ✔ | In Use | |
TA | 32768 | N/A | ✔ | In Use | |
TKEY | 249 | RFC 2930 | ✔ | In Use | |
TLSA | 52 | RFC 6698 | ✔ | In Use | |
TSIG | 250 | RFC 2845 | ✔ | In Use | |
TXT | 16 | RFC 1035 | ✔ | In Use | |
URI | 256 | RFC 7553 | ✔ | In Use |
Add ability to specify other recods for "tlds" for example now it's not possible to specify for example A record for "tld" .test A record for "tld" .com.test and manually to as write-zone.php then "deletes" other records....
Smhw so smth like this setting in config.php
const RECORD_TYPES = [ 'A' => 'A', 'AAAA' => 'AAAA', 'MX' => 'MX', 'NS' => 'NS', 'PTR' => 'PTR', 'SOA' => 'SOA', 'TXT' => 'TXT', 'SRV' => 'SRV', 'CNAME' => 'CNAME', 'CAA' => 'CAA', 'DNSKEY' => 'DNSKEY', 'DS' => 'DS', 'NSEC' => 'NSEC', 'NSEC3' => 'NSEC3', 'RRSIG' => 'RRSIG', 'SPF' => 'SPF', 'SSHFP' => 'SSHFP', 'TLSA' => 'TLSA', 'URI' => 'URI', 'LOC' => 'LOC', ];
// Constants for supported record types