From f449f278dd3c70e479a035f50a9bb817a9b433ba Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 17:24:08 +0200 Subject: Adding upstream version 3.2.6. Signed-off-by: Daniel Baumann --- src/knot/catalog/interpret.c | 257 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 src/knot/catalog/interpret.c (limited to 'src/knot/catalog/interpret.c') diff --git a/src/knot/catalog/interpret.c b/src/knot/catalog/interpret.c new file mode 100644 index 0000000..e7a5cf0 --- /dev/null +++ b/src/knot/catalog/interpret.c @@ -0,0 +1,257 @@ +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include +#include + +#include "knot/catalog/interpret.h" +#include "knot/journal/serialization.h" + +struct cat_upd_ctx; +typedef int (*cat_interpret_cb_t)(zone_node_t *node, struct cat_upd_ctx *ctx); + +typedef struct cat_upd_ctx { + catalog_update_t *u; + const zone_contents_t *complete_conts; + int apex_labels; + bool remove; + bool zone_diff; + catalog_t *check; + cat_interpret_cb_t member_cb; + cat_interpret_cb_t property_cb; +} cat_upd_ctx_t; + +static bool label_eq(const knot_dname_t *a, const char *_b) +{ + const knot_dname_t *b = (const knot_dname_t *)_b; + return a[0] == b[0] && memcmp(a + 1, b + 1, a[0]) == 0; +} + +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 *rdata = ver_rr->rdata; + for (int i = 0; i < ver_rr->count; i++) { + if (rdata->len == 2 && rdata->data[1] == CATALOG_ZONE_VERSION[0]) { + return true; + } + rdata = knot_rdataset_next(rdata); + } + return false; +} + +static int interpret_node(zone_node_t *node, void * _ctx) +{ + cat_upd_ctx_t *ctx = _ctx; + + int labels_diff = knot_dname_labels(node->owner, NULL) - ctx->apex_labels + - 1 /* "zones" label */ - 1 /* unique-N label */; + assert(labels_diff >= 0); + + switch (labels_diff) { + case 0: + return ctx->member_cb(node, ctx); + case 1: + return ctx->property_cb(node, ctx); + default: + return KNOT_EOK; + } +} + +static int interpret_zone(zone_diff_t *zdiff, cat_upd_ctx_t *ctx) +{ + knot_dname_storage_t sub; + if (knot_dname_store(sub, (uint8_t *)CATALOG_ZONES_LABEL) == 0 || + catalog_dname_append(sub, zdiff->apex->owner) == 0) { + return KNOT_EINVAL; + } + + if (zone_tree_get(&zdiff->nodes, sub) == NULL) { + return KNOT_EOK; + } + + return zone_tree_sub_apply(&zdiff->nodes, sub, true, interpret_node, ctx); +} + +static const knot_dname_t *property_get_member(const zone_node_t *prop_node, + const zone_contents_t *complete_conts, + const knot_dname_t **owner) +{ + assert(prop_node != NULL); + knot_rdataset_t *ptr = node_rdataset(prop_node->parent, KNOT_RRTYPE_PTR); + if (ptr == NULL) { + // fallback: search in provided complete zone contents + const knot_dname_t *memb_name = knot_wire_next_label(prop_node->owner, NULL); + const zone_node_t *memb_node = zone_contents_find_node(complete_conts, memb_name); + ptr = node_rdataset(memb_node, KNOT_RRTYPE_PTR); + if (memb_node != NULL) { + *owner = memb_node->owner; + } + } else { + *owner = prop_node->parent->owner; + } + if (*owner == NULL || ptr == NULL || ptr->count != 1) { + return NULL; + } + return knot_ptr_name(ptr->rdata); +} + +static int cat_update_add_memb(zone_node_t *node, cat_upd_ctx_t *ctx) +{ + const knot_rdataset_t *ptr = node_rdataset(node, KNOT_RRTYPE_PTR); + if (ptr == NULL) { + return KNOT_EOK; + } else if (ptr->count != 1) { + return KNOT_ERROR; + } + + const knot_rdataset_t *counter_ptr = node_rdataset(binode_counterpart(node), KNOT_RRTYPE_PTR); + if (knot_rdataset_subset(ptr, counter_ptr)) { + return KNOT_EOK; + } + + knot_rdata_t *rdata = ptr->rdata; + int ret = KNOT_EOK; + for (int i = 0; ret == KNOT_EOK && i < ptr->count; i++) { + const knot_dname_t *member = knot_ptr_name(rdata); + ret = catalog_update_add(ctx->u, member, node->owner, ctx->complete_conts->apex->owner, + ctx->remove ? CAT_UPD_REM : CAT_UPD_ADD, + NULL, 0, ctx->check); + rdata = knot_rdataset_next(rdata); + } + return ret; +} + +static int cat_update_add_grp(zone_node_t *node, cat_upd_ctx_t *ctx) +{ + if (!label_eq(node->owner, CATALOG_GROUP_LABEL)) { + return KNOT_EOK; + } + + const knot_dname_t *owner = NULL; + const knot_dname_t *member = property_get_member(node, ctx->complete_conts, &owner); + if (member == NULL) { + return KNOT_EOK; // just ignore property w/o member + } + + const knot_rdataset_t *txt = node_rdataset(node, KNOT_RRTYPE_TXT); + if (txt == NULL) { + return KNOT_EOK; + } else if (txt->count != 1) { + return KNOT_ERROR; + } + + const knot_rdataset_t *counter_txt = node_rdataset(binode_counterpart(node), KNOT_RRTYPE_TXT); + if (knot_rdataset_subset(txt, counter_txt)) { + return KNOT_EOK; + } + + const char *newgr = ""; + size_t grlen = 0; + if (!ctx->remove) { + assert(txt->count == 1); + // TXT rdata consists of one or more 1-byte prefixed strings. + if (txt->rdata->len != txt->rdata->data[0] + 1) { + return KNOT_EMALF; + } + newgr = (const char *)txt->rdata->data + 1; + grlen = txt->rdata->data[0]; + assert(grlen <= CATALOG_GROUP_MAXLEN); + } + + return catalog_update_add(ctx->u, member, owner, ctx->complete_conts->apex->owner, + CAT_UPD_PROP, newgr, grlen, ctx->check); +} + +int catalog_update_from_zone(catalog_update_t *u, struct zone_contents *zone, + const zone_diff_t *zone_diff, + const struct zone_contents *complete_contents, + bool remove, catalog_t *check, ssize_t *upd_count) +{ + int ret = KNOT_EOK; + zone_diff_t zdiff; + assert(zone == NULL || zone_diff == NULL); + if (zone != NULL) { + zone_diff_from_zone(&zdiff, zone); + } else { + zdiff = *zone_diff; + } + cat_upd_ctx_t ctx = { u, complete_contents, knot_dname_labels(zdiff.apex->owner, NULL), + remove, zone_diff != NULL, check, cat_update_add_memb, cat_update_add_grp }; + + pthread_mutex_lock(&u->mutex); + *upd_count -= trie_weight(u->upd); + if (zone_diff != NULL) { + zone_diff_reverse(&zdiff); + ctx.remove = true; + ret = interpret_zone(&zdiff, &ctx); + zone_diff_reverse(&zdiff); + ctx.remove = false; + ctx.check = NULL; + } + if (ret == KNOT_EOK) { + ret = interpret_zone(&zdiff, &ctx); + } + *upd_count += trie_weight(u->upd); + pthread_mutex_unlock(&u->mutex); + return ret; +} + +static int rr_count(const zone_node_t *node, uint16_t type) +{ + const knot_rdataset_t *rd = node_rdataset(node, type); + return rd == NULL ? 0 : rd->count; +} + +static int member_verify(zone_node_t *node, cat_upd_ctx_t *ctx) +{ + return rr_count(node, KNOT_RRTYPE_PTR) > 1 ? KNOT_EISRECORD : KNOT_EOK; +} + +static int prop_verify(zone_node_t *node, cat_upd_ctx_t *ctx) +{ + if (label_eq(node->owner, CATALOG_GROUP_LABEL) && + rr_count(node, KNOT_RRTYPE_TXT) > 1) { + return KNOT_EISRECORD; + } + + return KNOT_EOK; +} + +int catalog_zone_verify(const struct zone_contents *zone) +{ + cat_upd_ctx_t ctx = { NULL, zone, knot_dname_labels(zone->apex->owner, NULL), + false, false, NULL, member_verify, prop_verify }; + + if (!check_zone_version(zone)) { + return KNOT_EZONEINVAL; + } + + zone_diff_t zdiff; + zone_diff_from_zone(&zdiff, zone); + + return interpret_zone(&zdiff, &ctx); +} -- cgit v1.2.3