From 9b1bcb9487b3443e4d2ff3cf2b6746c156e573ef Mon Sep 17 00:00:00 2001 From: Libor Peltan Date: Thu, 25 Mar 2021 13:48:36 +0100 Subject: [PATCH] catalog: enforce single label for PTR defining member --- doc/configuration.rst | 7 ++-- src/knot/catalog/interpret.c | 12 +++++-- .../tests/catalog/basic/data/catalog1.zone | 4 ++- tests-extra/tests/catalog/basic/test.py | 32 ++++++------------- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/doc/configuration.rst b/doc/configuration.rst index 48ea8ce25..b8454b03a 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -602,8 +602,8 @@ multiple catalog zones. existing zones configured on the server as it would effectively "shadow" part of your DNS subtree. -Upon catalog zone (re)load or change, all the PTR records in the zone -sub-tree *zones* (e.g. ``unique-id1.zones.catalog. 0 IN PTR member.com.``) +Upon catalog zone (re)load or change, all the PTR records in the format +``unique-id.zones.catalog. 0 IN PTR member.com.`` (but not ``too.deep.zones.catalog.``!) are processed and member zones created, with zone names taken from the PTR records' RData, and zone settings taken from the configuration template specified by :ref:`zone_catalog-template`. @@ -612,11 +612,10 @@ The owner names of the PTR records shall follow this scheme: .. code-block:: console - ..zones.. + .zones.. where the mentioned group of labels shall match: -- ** — (optional) Any additional labels with no particular meaning. - ** — Single label that is recommended to be unique among member zones. - ``zones`` — Required label. - ** — Name of the catalog zone. diff --git a/src/knot/catalog/interpret.c b/src/knot/catalog/interpret.c index fa45bbe21..f5c3b371e 100644 --- a/src/knot/catalog/interpret.c +++ b/src/knot/catalog/interpret.c @@ -22,6 +22,7 @@ typedef struct { catalog_update_t *u; const knot_dname_t *apex; + int apex_labels; bool remove; catalog_t *check; } cat_upd_ctx_t; @@ -52,6 +53,13 @@ static bool check_zone_version(const zone_contents_t *zone) static int cat_update_add_node(zone_node_t *node, void *data) { cat_upd_ctx_t *ctx = data; + int labels_diff = knot_dname_labels(node->owner, NULL) - ctx->apex_labels + - 1 /* "zones" label */ - 1 /* unique-N label */; + assert(labels_diff >= 0); + if (labels_diff > 0) { + return KNOT_EOK; + } + const knot_rdataset_t *ptr = node_rdataset(node, KNOT_RRTYPE_PTR); if (ptr == NULL || ptr->count == 0) { return KNOT_EOK; @@ -84,9 +92,9 @@ int catalog_update_from_zone(catalog_update_t *u, struct zone_contents *zone, return KNOT_EOK; } - cat_upd_ctx_t ctx = { u, zone->apex->owner, remove, check }; + cat_upd_ctx_t ctx = { u, zone->apex->owner, knot_dname_labels(zone->apex->owner, NULL), remove, check }; pthread_mutex_lock(&u->mutex); - int ret = zone_tree_sub_apply(zone->nodes, sub, false, cat_update_add_node, &ctx); + int ret = zone_tree_sub_apply(zone->nodes, sub, true, cat_update_add_node, &ctx); pthread_mutex_unlock(&u->mutex); return ret; } diff --git a/tests-extra/tests/catalog/basic/data/catalog1.zone b/tests-extra/tests/catalog/basic/data/catalog1.zone index 4883a05bb..b3f6480e9 100644 --- a/tests-extra/tests/catalog/basic/data/catalog1.zone +++ b/tests-extra/tests/catalog/basic/data/catalog1.zone @@ -5,5 +5,7 @@ $TTL 0 NS ns ns AAAA ::0 version TXT "2" -foo.bar.zones PTR cataloged1. +foo.zones PTR cataloged1. not.zones.in PTR not-cataloged1. +too.deep.zones PTR not-cataloged2. +zones PTR not-cataloged3. diff --git a/tests-extra/tests/catalog/basic/test.py b/tests-extra/tests/catalog/basic/test.py index 6528aa563..b4b1920a1 100644 --- a/tests-extra/tests/catalog/basic/test.py +++ b/tests-extra/tests/catalog/basic/test.py @@ -53,6 +53,10 @@ resp.check_count(2, "DNSKEY") resp.check_count(1, "RRSIG") resp = master.dig("not-cataloged1.", "SOA") resp.check(rcode="REFUSED") +resp = master.dig("not-cataloged2.", "SOA") +resp.check(rcode="REFUSED") +resp = master.dig("not-cataloged3.", "SOA") +resp.check(rcode="REFUSED") # Udating a cataloged zone subprocess.run(["sed", "-i", "s/10001/10002/;$s/$/\\nxyz A 1.2.3.4/", master.dir + "/master/cataloged1.zone"]) @@ -66,7 +70,7 @@ check_keys(slave, "cataloged1", 2) # Check adding cataloged zone. up = master.update(zone[1]) -up.add("junk.bar.zones.catalog1.", 0, "PTR", "cataloged2.") +up.add("bar.zones.catalog1.", 0, "PTR", "cataloged2.") up.send("NOERROR") t.sleep(6) resp = master.dig("cataloged2.", "NS") @@ -88,8 +92,8 @@ resp0 = slave.dig("cataloged2.", "DNSKEY") resp0.check_count(2, "DNSKEY") dnskey0 = resp0.resp.answer[0].to_rdataset()[0] up = master.update(zone[1]) -up.delete("junk.bar.zones.catalog1.", "PTR", "cataloged2.") -up.add("junk.bar.zones.catalog1.", 0, "PTR", "cataloged2.") +up.delete("bar.zones.catalog1.", "PTR", "cataloged2.") +up.add("bar.zones.catalog1.", 0, "PTR", "cataloged2.") up.send("NOERROR") t.sleep(4) resp1 = slave.dig("cataloged2.", "DNSKEY") @@ -107,8 +111,8 @@ else: # Check remove-adding the zone: shall effectively purge it up = master.update(zone[1]) -up.delete("junk.bar.zones.catalog1.", "PTR", "cataloged2.") -up.add("junk.bar2.zones.catalog1.", 0, "PTR", "cataloged2.") +up.delete("bar.zones.catalog1.", "PTR", "cataloged2.") +up.add("bar2.zones.catalog1.", 0, "PTR", "cataloged2.") up.send("NOERROR") t.sleep(4) shutil.copy(t.data_dir + "/cataloged2.zone", master.dir + "/master") # because the purge deletes even zonefile @@ -122,22 +126,6 @@ if resp2.count("DNSKEY") > 0: set_err("ZONE NOT PURGED") dnskey2 = resp2.resp.answer[0].to_rdataset()[0] -# Check remove-adding while keeping the 'uniq' label -up = master.update(zone[1]) -up.delete("junk.bar2.zones.catalog1.", "PTR", "cataloged2.") -up.add("jang.bar2.zones.catalog1.", 0, "PTR", "cataloged2.") -up.send("NOERROR") -t.sleep(4) -resp3 = slave.dig("cataloged2.", "DNSKEY") -resp3.check_count(2, "DNSKEY") -match = 0 -if resp3.count("DNSKEY") > 0: - for dnskey3 in resp3.resp.answer[0].to_rdataset(): - if dnskey3.to_text() == dnskey2.to_text(): - match = match + 1 -if match < 1: - set_err("ZONE PURGED2") - # Check persistence after server restart slave.stop() slave.start() @@ -171,7 +159,7 @@ check_keys(slave, "cataloged2", 2) master.ctl("zone-backup +journal +backupdir %s/backup %s" % (master.dir, zone[1].name)) # Check removing cataloged zone up = master.update(zone[1]) -up.delete("foo.bar.zones.catalog1.", "PTR") +up.delete("foo.zones.catalog1.", "PTR") up.send("NOERROR") t.sleep(6) resp = master.dig("cataloged1.", "SOA")