|
@@ -0,0 +1,61 @@
|
|
|
+<?php
|
|
|
+/*
|
|
|
+ RFC 7477: Child-to-Parent Synchronization in DNS
|
|
|
+*/
|
|
|
+require __DIR__ . '/../init.php';
|
|
|
+
|
|
|
+foreach (query('select', 'registry') as $entry) {
|
|
|
+ $suffix = regParseDomain($entry['domain'])['suffix'];
|
|
|
+
|
|
|
+ // Get child/distant CSYNC records
|
|
|
+ try {
|
|
|
+ $results = kdig(name: $entry['domain'], type: 'CSYNC');
|
|
|
+ } catch (KdigException) {
|
|
|
+ fwrite(STDERR, $entry['domain'] . ' CSYNC resolution failed.' . LF);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ($results['AD'] !== 1)
|
|
|
+ continue;
|
|
|
+ if (count($results['answerRRs'] ?? []) !== 1) // Parental agents MUST ignore a child's CSYNC RDATA set if multiple CSYNC resource records are found; only a single CSYNC record should ever be present.
|
|
|
+ continue;
|
|
|
+ list($serial, $flags, $types) = explode(' ', $results['answerRRs'][0]['rdataCSYNC'], 3);
|
|
|
+ if ($flags !== '1')
|
|
|
+ continue; // Skip unsupported flags
|
|
|
+ if ($types !== 'NS')
|
|
|
+ continue; // Skip unsupported types
|
|
|
+
|
|
|
+ // Get child/distant NS records
|
|
|
+ try {
|
|
|
+ $results = kdig(name: $entry['domain'], type: 'NS');
|
|
|
+ } catch (KdigException) {
|
|
|
+ fwrite(STDERR, $entry['domain'] . ' NS resolution failed.' . LF);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ($results['AD'] !== 1)
|
|
|
+ continue;
|
|
|
+ $child_ns_records = array_column($results['answerRRs'] ?? [], 'rdataNS');
|
|
|
+ if (count($child_ns_records) === []) // Parental agents MUST NOT perform NS updates if there are no NS records returned in a query, as verified by DNSSEC denial-of-existence protection.
|
|
|
+ continue;
|
|
|
+
|
|
|
+ // Get parent/local NS records
|
|
|
+ $zone_raw = file_get_contents(CONF['reg']['suffixes_path'] . '/' . $suffix . 'zone');
|
|
|
+ if ($zone_raw === false)
|
|
|
+ output(403, 'Unable to read zone file.');
|
|
|
+ $parent_ns_records = array_column(parseZoneFile($zone_raw, ['NS'], $entry['domain'], false), 3);
|
|
|
+
|
|
|
+ // Add child NS records that are not yet in parent
|
|
|
+ foreach (array_diff($child_ns_records, $parent_ns_records) as $value_to_add)
|
|
|
+ knotcZoneExec($suffix, [
|
|
|
+ $entry['domain'],
|
|
|
+ CONF['reg']['ttl'],
|
|
|
+ 'NS',
|
|
|
+ $value_to_add,
|
|
|
+ ], 'add');
|
|
|
+ // Delete parent NS records that are not part of child anymore
|
|
|
+ foreach (array_diff($parent_ns_records, $child_ns_records) as $value_to_delete)
|
|
|
+ knotcZoneExec($suffix, [
|
|
|
+ $entry['domain'],
|
|
|
+ 'NS',
|
|
|
+ $value_to_delete,
|
|
|
+ ], 'delete');
|
|
|
+}
|