From 9e01ffdce01bc7669c8408c18fca2abdf4698d7b Mon Sep 17 00:00:00 2001 From: Libor Peltan Date: Tue, 14 Apr 2020 18:46:28 +0200 Subject: [PATCH] catalog: check catalog zone version --- doc/configuration.rst | 3 +- src/knot/updates/zone-update.c | 22 +++++++++----- src/knot/zone/catalog.c | 30 ++++++++++++++++++- src/knot/zone/catalog.h | 2 +- .../tests/zone/catalog/data/catalog1.zone | 1 + 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/doc/configuration.rst b/doc/configuration.rst index 7fe5da592..1eed33406 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -600,7 +600,8 @@ and ACLs. Being a catalog zone is indicated by setting the option :ref:`zone_catalog-template`. The difference is that standard DNS queries to a catalog zone are answered with REFUSED as if such a zone wouldn't exist, unless querying from an address with transfers enabled -by ACL. The name of the catalog zone is arbitrary. +by ACL. The name of the catalog zone is arbitrary. It's however required to +include version record ``version 0 IN TXT "2"``. It's possible to configure more catalog zones. .. WARNING:: diff --git a/src/knot/updates/zone-update.c b/src/knot/updates/zone-update.c index 03ac4ef42..558f3cc79 100644 --- a/src/knot/updates/zone-update.c +++ b/src/knot/updates/zone-update.c @@ -717,19 +717,24 @@ static int update_catalog(conf_t *conf, zone_update_t *update) int ret = KNOT_EOK; if ((update->flags & UPDATE_INCREMENTAL)) { - ret = knot_cat_update_from_zone(update->zone->catalog_upd, update->change.remove, true, update->zone->catalog); + ret = knot_cat_update_from_zone(update->zone->catalog_upd, update->change.remove, + true, false, update->zone->catalog); if (ret == KNOT_EOK) { - ret = knot_cat_update_from_zone(update->zone->catalog_upd, update->change.add, false, NULL); + ret = knot_cat_update_from_zone(update->zone->catalog_upd, + update->change.add, false, false, NULL); } } else { ret = knot_cat_update_del_all(update->zone->catalog_upd, update->zone->catalog, update->zone->name); if (ret == KNOT_EOK) { - ret = knot_cat_update_from_zone(update->zone->catalog_upd, update->zone->contents, false, NULL); + ret = knot_cat_update_from_zone(update->zone->catalog_upd, + update->zone->contents, false, true, NULL); } } if (ret == KNOT_EOK) { - kill(getpid(), SIGUSR1); + if (kill(getpid(), SIGUSR1) != 0) { + ret = knot_map_errno(); + } } return ret; @@ -874,9 +879,12 @@ int zone_update_commit(conf_t *conf, zone_update_t *update) zone_contents_t *old_contents; old_contents = zone_switch_contents(update->zone, update->new_cont); - ret = commit_catalog(conf, update); - if (ret != KNOT_EOK) { - log_zone_warning(update->zone->name, "catalog zone not fully populated (%s)", knot_strerror(ret)); + ret = update_catalog(conf, update); + if (ret == KNOT_EZONEINVAL) { + log_zone_warning(update->zone->name, "invalid catalog zone version"); + } else if (ret != KNOT_EOK) { + log_zone_warning(update->zone->name, "catalog zone not fully populated (%s)", + knot_strerror(ret)); } if (update->flags & (UPDATE_INCREMENTAL | UPDATE_HYBRID)) { diff --git a/src/knot/zone/catalog.c b/src/knot/zone/catalog.c index 8b21a84a1..41265d954 100644 --- a/src/knot/zone/catalog.c +++ b/src/knot/zone/catalog.c @@ -26,9 +26,33 @@ #include "knot/zone/contents.h" #define CATALOG_VERSION "1.0" +#define CATALOG_ZONE_VERSION "2" // must be just one char long const MDB_val knot_catalog_iter_prefix = { 1, "" }; +static bool check_zone_version(const zone_contents_t *zone) +{ + size_t zone_size = knot_dname_size(zone->apex->owner); + knot_dname_t sub[zone_size + 8]; + memcpy(sub, "\x07""version", 8); + memcpy(sub + 8, zone->apex->owner, zone_size); + + const zone_node_t *ver_node = zone_contents_find_node(zone, sub); + knot_rdataset_t *ver_rr = node_rdataset(ver_node, KNOT_RRTYPE_TXT); + if (ver_rr == NULL) { + return false; + } + + knot_rdata_t *rd = ver_rr->rdata; + for (int i = 0; i < ver_rr->count; i++) { + if (rd->len == 2 && rd->data[1] == CATALOG_ZONE_VERSION[0]) { + return true; + } + rd = knot_rdataset_next(rd); + } + return false; +} + void knot_catalog_init(knot_catalog_t *cat, const char *path, size_t mapsize) { knot_lmdb_init(&cat->db, path, mapsize, 0, NULL); @@ -325,8 +349,12 @@ static int cat_update_add_node(zone_node_t *node, void *data) } int knot_cat_update_from_zone(knot_cat_update_t *u, struct zone_contents *zone, - bool remove, knot_catalog_t *check) + bool remove, bool check_ver, knot_catalog_t *check) { + if (check_ver && !check_zone_version(zone)) { + return KNOT_EZONEINVAL; + } + size_t zone_size = knot_dname_size(zone->apex->owner); knot_dname_t sub[zone_size + 6]; memcpy(sub, "\x05""zones", 6); diff --git a/src/knot/zone/catalog.h b/src/knot/zone/catalog.h index 54d2af63c..2e2c8967f 100644 --- a/src/knot/zone/catalog.h +++ b/src/knot/zone/catalog.h @@ -101,7 +101,7 @@ knot_cat_upd_val_t *knot_cat_update_get(knot_cat_update_t *u, const knot_dname_t struct zone_contents; int knot_cat_update_from_zone(knot_cat_update_t *u, struct zone_contents *zone, - bool remove, knot_catalog_t *check); + bool remove, bool check_ver, knot_catalog_t *check); int knot_cat_update_del_all(knot_cat_update_t *u, knot_catalog_t *cat, const knot_dname_t *zone); diff --git a/tests-extra/tests/zone/catalog/data/catalog1.zone b/tests-extra/tests/zone/catalog/data/catalog1.zone index cc802edfe..4883a05bb 100644 --- a/tests-extra/tests/zone/catalog/data/catalog1.zone +++ b/tests-extra/tests/zone/catalog/data/catalog1.zone @@ -4,5 +4,6 @@ $TTL 0 @ SOA ns admin 1 25 25 80 600 NS ns ns AAAA ::0 +version TXT "2" foo.bar.zones PTR cataloged1. not.zones.in PTR not-cataloged1.