瀏覽代碼

reg: sync DS/NS using CDS/CSYNC from child zone

Miraty 1 年之前
父節點
當前提交
3ddbc7cf1a
共有 6 個文件被更改,包括 175 次插入4 次删除
  1. 57 0
      jobs/reg-cds.php
  2. 61 0
      jobs/reg-csync.php
  3. 22 2
      locales/fr/C/LC_MESSAGES/messages.po
  4. 22 2
      locales/messages.pot
  5. 1 0
      pg-act/ns/zone-add.php
  6. 12 0
      pg-view/reg/index.php

+ 57 - 0
jobs/reg-cds.php

@@ -0,0 +1,57 @@
+<?php
+/*
+	RFC 7344: Automating DNSSEC Delegation Trust Maintenance
+	RFC 8078: Managing DS Records from the Parent via CDS/CDNSKEY
+*/
+require __DIR__ . '/../init.php';
+
+foreach (query('select', 'registry') as $entry) {
+	$suffix = regParseDomain($entry['domain'])['suffix'];
+
+	// Get child/distant records
+	try {
+		$results = kdig(name: $entry['domain'], type: 'CDS');
+	} catch (KdigException) {
+		fwrite(STDERR, $entry['domain'] . ' resolution failed.' . LF);
+		continue;
+	}
+	if ($results['AD'] !== 1) // No DNSSEC
+		continue;
+	$cds_records = array_column($results['answerRRs'] ?? [], 'rdataCDS');
+
+	// Skip if no updates
+	if ($cds_records === [])
+		continue;
+
+	// Get parent/local CDS records
+	$zone_raw = file_get_contents(CONF['reg']['suffixes_path'] . '/' . $suffix . 'zone');
+	if ($zone_raw === false)
+		output(403, 'Unable to read zone file.');
+	$pds_records = array_column(parseZoneFile($zone_raw, ['DS'], $entry['domain'], false), 3);
+
+	if ($cds_records === ['0 0 0 0'])
+		// Delete every parent DS records
+		foreach ($pds_records as $value_to_delete)
+			knotcZoneExec($suffix, [
+				$entry['domain'],
+				'DS',
+				$value_to_delete,
+			], 'delete');
+	else {
+		// Add child DS records that are not yet in parent
+		foreach (array_diff($cds_records, $pds_records) as $value_to_add)
+			knotcZoneExec($suffix, [
+				$entry['domain'],
+				CONF['reg']['ttl'],
+				'DS',
+				$value_to_add,
+			], 'add');
+		// Delete parent DS records that are not part of child anymore
+		foreach (array_diff($pds_records, $cds_records) as $value_to_delete)
+			knotcZoneExec($suffix, [
+				$entry['domain'],
+				'DS',
+				$value_to_delete,
+			], 'delete');
+	}
+}

+ 61 - 0
jobs/reg-csync.php

@@ -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');
+}

+ 22 - 2
locales/fr/C/LC_MESSAGES/messages.po

@@ -1,7 +1,7 @@
 msgid ""
 msgid ""
 msgstr ""
 msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-06-26 02:14+0200\n"
+"POT-Creation-Date: 2023-07-16 20:50+0200\n"
 "Language: fr\n"
 "Language: fr\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 
 
@@ -528,7 +528,7 @@ msgstr "Serveurs de nom de la zone parente introuvables."
 msgid "NS authentication record not found."
 msgid "NS authentication record not found."
 msgstr "Enregistrement d'authentification NS introuvable."
 msgstr "Enregistrement d'authentification NS introuvable."
 
 
-#: pg-act/ns/zone-add.php:66
+#: pg-act/ns/zone-add.php:67
 msgid "Zone created."
 msgid "Zone created."
 msgstr "Zone créée."
 msgstr "Zone créée."
 
 
@@ -1230,6 +1230,26 @@ msgstr "Seuls les comptes <span aria-hidden=\"true\">👤 </span><em>approuvés<
 msgid "Nobody can register a domain under these suffixes:"
 msgid "Nobody can register a domain under these suffixes:"
 msgstr "Personne ne peut enregistrer un domain sous ces suffixes&nbsp;:"
 msgstr "Personne ne peut enregistrer un domain sous ces suffixes&nbsp;:"
 
 
+#: pg-view/reg/index.php:63
+msgid "Automatic updates from child zone"
+msgstr "Mises à jour automatiques depuis la zone enfant"
+
+#: pg-view/reg/index.php:64
+msgid "CSYNC records"
+msgstr "Enregistrements CSYNC"
+
+#: pg-view/reg/index.php:66
+msgid "The registry can synchronize NS records from the child zone if a CSYNC record is present at the apex of the child zone, has flags <code>1</code> and type bit map <code>NS</code>, and can be DNSSEC-validated. Others values are not supported."
+msgstr "Le registre peut synchroniser les enregistrements NS depuis la zone enfant si un enregistrement CSYNC est présent à l'apex de la zone enfant, a les drapeaux <code>1</code> et le type bit map <code>NS</code>, et peut être validé par DNSSEC. Les autres valeurs ne sont pas supportées."
+
+#: pg-view/reg/index.php:68
+msgid "DNSSEC and DS records"
+msgstr "DNSSEC et enregistrements DS"
+
+#: pg-view/reg/index.php:70
+msgid "Once DNSSEC has been manually enabled through the current interface, the delegated zone can publish a CDS record in order to update the DS record in the registry. A single CDS record with value <code>0 0 0 0</code> tells the registry to disable DNSSEC. Using a CDS record to enable DNSSEC is not supported."
+msgstr "Une fois que DNSSEC a été manuellement activé en utilisant l'interface actuelle, la zone déléguée peut publier un enregistrement CDS afin de mettre à jour l'enregistrement DS dans le registre. Un unique enregistrement CDS avec pour valeur <code>0 0 0 0</code> indique au registre de désactiver DNSSEC. Utiliser un enregistrement CDS pour activer DNSSEC n'est pas supporté."
+
 #: pg-view/reg/register.php:2
 #: pg-view/reg/register.php:2
 msgid "Register a new domain on your account."
 msgid "Register a new domain on your account."
 msgstr "Enregistrer un nouveau domaine sur son compte."
 msgstr "Enregistrer un nouveau domaine sur son compte."

+ 22 - 2
locales/messages.pot

@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-06-26 02:14+0200\n"
+"POT-Creation-Date: 2023-07-16 20:50+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -540,7 +540,7 @@ msgstr ""
 msgid "NS authentication record not found."
 msgid "NS authentication record not found."
 msgstr ""
 msgstr ""
 
 
-#: pg-act/ns/zone-add.php:66
+#: pg-act/ns/zone-add.php:67
 msgid "Zone created."
 msgid "Zone created."
 msgstr ""
 msgstr ""
 
 
@@ -1242,6 +1242,26 @@ msgstr ""
 msgid "Nobody can register a domain under these suffixes:"
 msgid "Nobody can register a domain under these suffixes:"
 msgstr ""
 msgstr ""
 
 
+#: pg-view/reg/index.php:63
+msgid "Automatic updates from child zone"
+msgstr ""
+
+#: pg-view/reg/index.php:64
+msgid "CSYNC records"
+msgstr ""
+
+#: pg-view/reg/index.php:66
+msgid "The registry can synchronize NS records from the child zone if a CSYNC record is present at the apex of the child zone, has flags <code>1</code> and type bit map <code>NS</code>, and can be DNSSEC-validated. Others values are not supported."
+msgstr ""
+
+#: pg-view/reg/index.php:68
+msgid "DNSSEC and DS records"
+msgstr ""
+
+#: pg-view/reg/index.php:70
+msgid "Once DNSSEC has been manually enabled through the current interface, the delegated zone can publish a CDS record in order to update the DS record in the registry. A single CDS record with value <code>0 0 0 0</code> tells the registry to disable DNSSEC. Using a CDS record to enable DNSSEC is not supported."
+msgstr ""
+
 #: pg-view/reg/register.php:2
 #: pg-view/reg/register.php:2
 msgid "Register a new domain on your account."
 msgid "Register a new domain on your account."
 msgstr ""
 msgstr ""

+ 1 - 0
pg-act/ns/zone-add.php

@@ -53,6 +53,7 @@ $knotZone = implode(' ', [
 ]) . LF;
 ]) . LF;
 foreach (CONF['ns']['servers'] as $server)
 foreach (CONF['ns']['servers'] as $server)
 	$knotZone .= $_POST['domain'] . ' 86400 NS ' . $server . LF;
 	$knotZone .= $_POST['domain'] . ' 86400 NS ' . $server . LF;
+$knotZone .= $_POST['domain'] . ' 86400 CSYNC 0 1 NS' . LF;
 if (is_int(file_put_contents($knotZonePath, $knotZone)) !== true)
 if (is_int(file_put_contents($knotZonePath, $knotZone)) !== true)
 	output(500, 'Failed to write new zone file.');
 	output(500, 'Failed to write new zone file.');
 if (chmod($knotZonePath, 0660) !== true)
 if (chmod($knotZonePath, 0660) !== true)

+ 12 - 0
pg-view/reg/index.php

@@ -58,3 +58,15 @@ foreach (CONF['reg']['suffixes'] as $suffix => $condition)
 		</dd>
 		</dd>
 	</dl>
 	</dl>
 </section>
 </section>
+
+<section>
+	<h2><?= _('Automatic updates from child zone') ?></h2>
+	<h3><?= _('CSYNC records') ?></h3>
+	<p>
+		<?= _('The registry can synchronize NS records from the child zone if a CSYNC record is present at the apex of the child zone, has flags <code>1</code> and type bit map <code>NS</code>, and can be DNSSEC-validated. Others values are not supported.') ?>
+	</p>
+	<h3><?= _('DNSSEC and DS records') ?></h3>
+	<p>
+		<?= _('Once DNSSEC has been manually enabled through the current interface, the delegated zone can publish a CDS record in order to update the DS record in the registry. A single CDS record with value <code>0 0 0 0</code> tells the registry to disable DNSSEC. Using a CDS record to enable DNSSEC is not supported.') ?>
+	</p>
+</section>