: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::
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;
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)) {
#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);
}
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);
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);
@ 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.