|
@@ -0,0 +1,42 @@
|
|
|
+<?php
|
|
|
+require 'init.php';
|
|
|
+
|
|
|
+foreach (query('select', 'ns-syncs') as $sync) {
|
|
|
+ $zone_raw = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $sync['destination'] . 'zone');
|
|
|
+ if ($zone_raw === false)
|
|
|
+ output(403, 'Unable to read zone file.');
|
|
|
+
|
|
|
+ foreach (['AAAA', 'A', 'SRV', 'CAA'] as $type) {
|
|
|
+ // Get source/distant records
|
|
|
+ try {
|
|
|
+ $results = kdig(name: $sync['source'], type: $type);
|
|
|
+ } catch (KdigException) {
|
|
|
+ error_log($sync['source'] . ' resolution failed.' . LF);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if ($results['AD'] !== 1) {
|
|
|
+ error_log($sync['source'] . ' skipped: not signed using DNSSEC.' . LF);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $source_records = array_column($results['answerRRs'] ?? [], 'rdata' . $type);
|
|
|
+
|
|
|
+ // Get destination/local records
|
|
|
+ $dest_records = array_column(parseZoneFile($zone_raw, [$type], $sync['destination'], false), 3);
|
|
|
+
|
|
|
+ // Add source records that are not yet in destination
|
|
|
+ foreach (array_diff($source_records, $dest_records) as $value_to_add)
|
|
|
+ knotcZoneExec($sync['destination'], [
|
|
|
+ $sync['destination'],
|
|
|
+ SYNC_TTL,
|
|
|
+ $type,
|
|
|
+ $value_to_add,
|
|
|
+ ], 'add');
|
|
|
+ // Delete destination records that are not part of source anymore
|
|
|
+ foreach (array_diff($dest_records, $source_records) as $value_to_delete)
|
|
|
+ knotcZoneExec($sync['destination'], [
|
|
|
+ $sync['destination'],
|
|
|
+ $type,
|
|
|
+ $value_to_delete,
|
|
|
+ ], 'delete');
|
|
|
+ }
|
|
|
+}
|