diff --git a/Knot.files b/Knot.files index f99aa1d3f572d425163b7811180e5d50b11fc480..4a28db2c2f879e382c2f90c1307171d3e85d446c 100644 --- a/Knot.files +++ b/Knot.files @@ -14,6 +14,7 @@ doc/reference.texi doc/requirements.texi doc/running.texi doc/security.texi +doc/synth_record.texi doc/troubleshooting.texi libtap/Makefile.am libtap/runtests.c @@ -208,6 +209,8 @@ src/libknot/packet/wire.h src/libknot/processing/process.c src/libknot/processing/process.h src/libknot/rdata.h +src/libknot/rr.c +src/libknot/rr.h src/libknot/rrset-dump.c src/libknot/rrset-dump.h src/libknot/rrset.c @@ -290,3 +293,5 @@ tests/slab.c tests/wire.c tests/zonedb.c tests/ztree.c +src/knot/server/serialization.c +src/knot/server/serialization.h diff --git a/src/Makefile.am b/src/Makefile.am index 1059ce8c0c738ad36a39ad29b271d2d3781a0519..cc67ce21a9516bb6c3319dac05cf4e3746611aa0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -172,6 +172,8 @@ libknot_la_SOURCES = \ libknot/rdata.h \ libknot/rrset-dump.c \ libknot/rrset-dump.h \ + libknot/rr.c \ + libknot/rr.h \ libknot/rrset.c \ libknot/rrset.h \ libknot/tsig-op.c \ @@ -254,6 +256,8 @@ libknotd_la_SOURCES = \ knot/server/zone-load.h \ knot/server/zones.c \ knot/server/zones.h \ + knot/server/serialization.c \ + knot/server/serialization.h \ knot/updates/acl.c \ knot/updates/acl.h \ knot/updates/changesets.c \ diff --git a/src/common/descriptor.c b/src/common/descriptor.c index 4a74a3d702d2f4315edf019c1ef1e73f18e601ac..ace5623c897b209dfcb39787dee32ed090e274d5 100644 --- a/src/common/descriptor.c +++ b/src/common/descriptor.c @@ -323,3 +323,11 @@ int knot_rrtype_is_ddns_forbidden(const uint16_t type) type == KNOT_RRTYPE_NSEC || type == KNOT_RRTYPE_NSEC3; } + +int knot_rrtype_additional_needed(const uint16_t rrtype) +{ + return (rrtype == KNOT_RRTYPE_NS || + rrtype == KNOT_RRTYPE_MX || + rrtype == KNOT_RRTYPE_SRV); +} + diff --git a/src/common/descriptor.h b/src/common/descriptor.h index b8d3b3d55aaf54863a9b3b53fea43543fd20e832..6e1cb999868f57cc5012cc9dd97ad3ffd4113937 100644 --- a/src/common/descriptor.h +++ b/src/common/descriptor.h @@ -287,6 +287,18 @@ int knot_rrtype_is_metatype(const uint16_t type); */ int knot_rrtype_is_ddns_forbidden(const uint16_t type); +/*! + * \brief Checks whether the given type requires additional processing. + * + * Only MX, NS and SRV types require additional processing. + * + * \param rrtype Type to check. + * + * \retval <> 0 if additional processing is needed for \a qtype. + * \retval 0 otherwise. + */ +int knot_rrtype_additional_needed(const uint16_t rrtype); + #endif // _KNOT_DESCRIPTOR_H_ /*! @} */ diff --git a/src/common/errcode.c b/src/common/errcode.c index 0c0d49a664145a00483d8986cf33e7cebafb71c4..37ab4bb3b48f53d1b411448b0f53008f3b89bd51 100644 --- a/src/common/errcode.c +++ b/src/common/errcode.c @@ -39,7 +39,7 @@ const error_table_t knot_error_msgs[] = { { KNOT_ERANGE, "Value is out of range." }, /* General errors. */ - { KNOT_ERROR, "General error." }, + { -10000 /*KNOT_ERROR*/, "General error." }, { KNOT_ENOTRUNNING, "Resource is not running." }, { KNOT_EPARSEFAIL, "Parser failed." }, { KNOT_EEXPIRED, "Resource is expired." }, diff --git a/src/common/hattrie/hat-trie.c b/src/common/hattrie/hat-trie.c index 692365ce77f324b268d3829e26be8779005fca3f..0993635026a8421f096215e65fc2401b383d8afc 100644 --- a/src/common/hattrie/hat-trie.c +++ b/src/common/hattrie/hat-trie.c @@ -317,6 +317,10 @@ hattrie_t* hattrie_dup(const hattrie_t* T, value_t (*nval)(value_t)) { hattrie_t *N = hattrie_create_n(T->bsize, &T->mm); + if (nval == NULL) { + return N; + } + /* assignment */ if (!nval) nval = hattrie_setval; diff --git a/src/common/lists.c b/src/common/lists.c index 3839f70387bac59a2ef0b1d6e40d9ff23492ed56..e59721cedca85946914c19982a39758f08d69cad 100644 --- a/src/common/lists.c +++ b/src/common/lists.c @@ -185,7 +185,7 @@ size_t list_size(const list_t *l) */ ptrnode_t *ptrlist_add(list_t *to, const void *val, mm_ctx_t *mm) { - ptrnode_t *node = mm->alloc(mm->ctx, sizeof(ptrnode_t)); + ptrnode_t *node = mm_alloc(mm , sizeof(ptrnode_t)); if (node == NULL) { return NULL; } else { @@ -204,7 +204,7 @@ void ptrlist_free(list_t *list, mm_ctx_t *mm) { node_t *n = NULL, *nxt = NULL; WALK_LIST_DELSAFE(n, nxt, *list) { - mm->free(n); + mm_free(mm, n); } init_list(list); } diff --git a/src/common/mempattern.c b/src/common/mempattern.c index 9bdfe8a5bf3ae469f1b2d8856454c1d1368d19ff..e89ebc2097d1dcbca72c360298dbf022c5297761 100644 --- a/src/common/mempattern.c +++ b/src/common/mempattern.c @@ -43,27 +43,6 @@ void *mm_alloc(mm_ctx_t *mm, size_t size) } } -void *mm_realloc(mm_ctx_t *mm, void *what, size_t size, size_t prev_size) -{ - if (mm) { - void *p = mm->alloc(mm->ctx, size); - if (knot_unlikely(p == NULL)) { - return NULL; - } else { - if (what) { - memcpy(p, what, - prev_size < size ? prev_size : size); - } - if (mm->free) { - mm->free(what); - } - return p; - } - } else { - return realloc(what, size); - } -} - void mm_free(mm_ctx_t *mm, void *what) { if (mm) { diff --git a/src/common/mempattern.h b/src/common/mempattern.h index a02726849825dd671eb9d2cfdc5b5ded10c855ab..81714071d56f96afcf496f9649163b9beca5dedc 100644 --- a/src/common/mempattern.h +++ b/src/common/mempattern.h @@ -46,8 +46,6 @@ typedef struct mm_ctx { /*! \brief Allocs using 'mm' if any, uses system malloc() otherwise. */ void *mm_alloc(mm_ctx_t *mm, size_t size); /*! \brief Reallocs using 'mm' if any, uses system realloc() otherwise. */ -void *mm_realloc(mm_ctx_t *mm, void *what, size_t size, size_t prev_size); -/*! \brief Frees using 'mm' if any, uses system free() otherwise. */ void mm_free(mm_ctx_t *mm, void *what); /*! \brief Initialize default memory allocation context. */ diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y index 29095d84f21a211c79700b0d4a9780e86fc5bc31..58e3f0aeb38c7cb8d9fb6206d570389ce5a70ccf 100644 --- a/src/knot/conf/cf-parse.y +++ b/src/knot/conf/cf-parse.y @@ -306,12 +306,12 @@ static int conf_key_exists(void *scanner, char *item) WALK_LIST (r, new_config->keys) { if (knot_dname_cmp(r->k.name, sample) == 0) { cf_error(scanner, "key '%s' is already defined", item); - knot_dname_free(&sample); + knot_dname_free(&sample, NULL); return 1; } } - knot_dname_free(&sample); + knot_dname_free(&sample, NULL); return 0; } @@ -328,13 +328,13 @@ static int conf_key_add(void *scanner, knot_tsig_key_t **key, char *item) WALK_LIST (r, new_config->keys) { if (knot_dname_cmp(r->k.name, sample) == 0) { *key = &r->k; - knot_dname_free(&sample); + knot_dname_free(&sample, NULL); return 0; } } cf_error(scanner, "key '%s' is not defined", item); - knot_dname_free(&sample); + knot_dname_free(&sample, NULL); return 1; } @@ -382,7 +382,7 @@ static void conf_zone_start(void *scanner, char *name) { knot_dname_size(dn)) != NULL) { cf_error(scanner, "zone '%s' is already present, refusing to " "duplicate", this_zone->name); - knot_dname_free(&dn); + knot_dname_free(&dn, NULL); free(this_zone->name); this_zone->name = NULL; /* Must not free, some versions of flex might continue after @@ -394,7 +394,7 @@ static void conf_zone_start(void *scanner, char *name) { *hattrie_get(new_config->zones, (const char *)dn, knot_dname_size(dn)) = this_zone; - knot_dname_free(&dn); + knot_dname_free(&dn, NULL); } } @@ -678,7 +678,7 @@ keys: k->k.algorithm = $3.alg; if (knot_binary_from_base64($4.t, &(k->k.secret)) != 0) { cf_error(scanner, "invalid key secret '%s'", $4.t); - knot_dname_free(&dname); + knot_dname_free(&dname, NULL); free(k); } else { add_tail(&new_config->keys, &k->n); diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c index b6a5fe5b5ac5cd4c7388e21607a9ed904ba8f348..185704b784c8225233aad420971392f7978a78ae 100644 --- a/src/knot/ctl/knotc_main.c +++ b/src/knot/ctl/knotc_main.c @@ -119,7 +119,7 @@ void help(void) static int cmd_remote_print_reply(const knot_rrset_t *rr) { /* Process first RRSet in data section. */ - if (knot_rrset_type(rr) != KNOT_RRTYPE_TXT) { + if (rr->type != KNOT_RRTYPE_TXT) { return KNOT_EMALF; } @@ -162,7 +162,7 @@ static int cmd_remote_reply(int c) switch(ret) { case KNOT_RCODE_NOERROR: if (authority->count > 0) { - ret = cmd_remote_print_reply(authority->rr[0]); + ret = cmd_remote_print_reply(&authority->rr[0]); } break; case KNOT_RCODE_REFUSED: @@ -199,24 +199,29 @@ static int cmd_remote(const char *cmd, uint16_t rrt, int argc, char *argv[]) /* Build query data. */ knot_pkt_begin(pkt, KNOT_AUTHORITY); - knot_rrset_t *rr = NULL; if (argc > 0) { - rr = remote_build_rr("data.", rrt); + knot_rrset_t rr; + int res = remote_build_rr(&rr, "data.", rrt); + if (res != KNOT_EOK) { + log_server_error("Couldn't create the query.\n"); + knot_pkt_free(&pkt); + return 1; + } for (int i = 0; i < argc; ++i) { switch(rrt) { case KNOT_RRTYPE_NS: - remote_create_ns(rr, argv[i]); + remote_create_ns(&rr, argv[i]); break; case KNOT_RRTYPE_TXT: default: - remote_create_txt(rr, argv[i], strlen(argv[i])); + remote_create_txt(&rr, argv[i], strlen(argv[i])); break; } } - int res = knot_pkt_put(pkt, 0, rr, KNOT_PF_FREE); + res = knot_pkt_put(pkt, 0, &rr, KNOT_PF_FREE); if (res != KNOT_EOK) { log_server_error("Couldn't create the query.\n"); - knot_rrset_free(&rr, NULL); + knot_rrset_clear(&rr, NULL); knot_pkt_free(&pkt); return 1; } diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c index 2c6d028bdeff3da1daca98c38d364a3720d6ed9d..68e5ea20cf460f7eb6b5648b5f5d12e0e2a751f3 100644 --- a/src/knot/ctl/remote.c +++ b/src/knot/ctl/remote.c @@ -39,7 +39,7 @@ /*! \brief Remote command structure. */ typedef struct remote_cmdargs_t { - const knot_rrset_t **arg; + const knot_rrset_t *arg; unsigned argc; knot_rcode_t rc; char resp[CMDARGS_BUFLEN]; @@ -93,14 +93,14 @@ static int remote_rdata_apply(server_t *s, remote_cmdargs_t* a, remote_zonef_t * for (unsigned i = 0; i < a->argc; ++i) { /* Process all zones in data section. */ - const knot_rrset_t *rr = a->arg[i]; - if (knot_rrset_type(rr) != KNOT_RRTYPE_NS) { + const knot_rrset_t *rr = &a->arg[i]; + if (rr->type != KNOT_RRTYPE_NS) { continue; } uint16_t rr_count = knot_rrset_rr_count(rr); for (uint16_t i = 0; i < rr_count; i++) { - const knot_dname_t *dn = knot_rdata_ns_name(rr, i); + const knot_dname_t *dn = knot_rrs_ns_name(&rr->rrs, i); rcu_read_lock(); zone = knot_zonedb_find(s->zone_db, dn); if (cb(s, zone) != KNOT_EOK) { @@ -235,13 +235,13 @@ static int remote_c_zonestatus(server_t *s, remote_cmdargs_t* a) const zone_t *zone = knot_zonedb_iter_val(&it); /* Fetch latest serial. */ - const knot_rrset_t *soa_rrs = 0; + const knot_rrs_t *soa_rrs = NULL; uint32_t serial = 0; if (zone->contents) { - soa_rrs = knot_node_rrset(zone->contents->apex, - KNOT_RRTYPE_SOA); + soa_rrs = knot_node_rrs(zone->contents->apex, + KNOT_RRTYPE_SOA); assert(soa_rrs != NULL); - serial = knot_rdata_soa_serial(soa_rrs); + serial = knot_rrs_soa_serial(soa_rrs); } /* Evalute zone type. */ @@ -500,18 +500,18 @@ static int remote_send_chunk(int c, knot_pkt_t *query, const char* d, uint16_t l assert(ret == KNOT_EOK); /* Create TXT RR with result. */ - knot_rrset_t *rr = remote_build_rr("result.", KNOT_RRTYPE_TXT); - if (rr == NULL) { - ret = KNOT_ENOMEM; + knot_rrset_t rr; + ret = remote_build_rr(&rr, "result.", KNOT_RRTYPE_TXT); + if (ret != KNOT_EOK) { goto failed; } - ret = remote_create_txt(rr, d, len); + ret = remote_create_txt(&rr, d, len); assert(ret == KNOT_EOK); - ret = knot_pkt_put(resp, 0, rr, KNOT_PF_FREE); + ret = knot_pkt_put(resp, 0, &rr, KNOT_PF_FREE); if (ret != KNOT_EOK) { - knot_rrset_free(&rr, NULL); + knot_rrset_clear(&rr, NULL); goto failed; } @@ -531,14 +531,14 @@ static void log_command(const char *cmd, const remote_cmdargs_t* args) size_t rest = CMDARGS_BUFLEN_LOG; for (unsigned i = 0; i < args->argc; i++) { - const knot_rrset_t *rr = args->arg[i]; - if (knot_rrset_type(rr) != KNOT_RRTYPE_NS) { + const knot_rrset_t *rr = &args->arg[i]; + if (rr->type != KNOT_RRTYPE_NS) { continue; } uint16_t rr_count = knot_rrset_rr_count(rr); for (uint16_t j = 0; j < rr_count; j++) { - const knot_dname_t *dn = knot_rdata_ns_name(rr, j); + const knot_dname_t *dn = knot_rrs_ns_name(&rr->rrs, j); char *name = knot_dname_to_str(dn); int ret = snprintf(params, rest, " %s", name); @@ -572,10 +572,10 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt) knot_dname_t *realm = knot_dname_from_str(KNOT_CTL_REALM); if (!knot_dname_is_sub(qname, realm) != 0) { dbg_server("remote: qname != *%s\n", KNOT_CTL_REALM_EXT); - knot_dname_free(&realm); + knot_dname_free(&realm, NULL); return KNOT_EMALF; } - knot_dname_free(&realm); + knot_dname_free(&realm, NULL); /* Command: * QNAME: leftmost label of QNAME @@ -742,11 +742,11 @@ knot_pkt_t* remote_query(const char *query, const knot_tsig_key_t *key) /* Cannot return != KNOT_EOK, but still. */ if (knot_pkt_put_question(pkt, dname, KNOT_CLASS_CH, KNOT_RRTYPE_ANY) != KNOT_EOK) { knot_pkt_free(&pkt); - knot_dname_free(&dname); + knot_dname_free(&dname, NULL); return NULL; } - knot_dname_free(&dname); + knot_dname_free(&dname, NULL); return pkt; } @@ -770,24 +770,22 @@ int remote_query_sign(uint8_t *wire, size_t *size, size_t maxlen, return ret; } -knot_rrset_t* remote_build_rr(const char *k, uint16_t t) +int remote_build_rr(knot_rrset_t *rr, const char *k, uint16_t t) { if (!k) { - return NULL; + return KNOT_EINVAL; } /* Assert K is FQDN. */ knot_dname_t *key = knot_dname_from_str(k); if (key == NULL) { - return NULL; + return KNOT_ENOMEM; } - /* Create RRSet. */ - knot_rrset_t *rr = knot_rrset_new(key, t, KNOT_CLASS_CH, NULL); - if (rr == NULL) - knot_dname_free(&key); + /* Init RRSet. */ + knot_rrset_init(rr, key, t, KNOT_CLASS_CH); - return rr; + return KNOT_EOK; } int remote_create_txt(knot_rrset_t *rr, const char *v, size_t v_len) @@ -799,24 +797,26 @@ int remote_create_txt(knot_rrset_t *rr, const char *v, size_t v_len) /* Number of chunks. */ const size_t K = 255; unsigned chunks = v_len / K + 1; - uint8_t *raw = knot_rrset_create_rr(rr, v_len + chunks, 0, NULL); + uint8_t raw[v_len + chunks]; + memset(raw, 0, v_len + chunks); /* Write TXT item. */ unsigned p = 0; + size_t off = 0; if (v_len > K) { for (; p + K < v_len; p += K) { - *(raw++) = (uint8_t)K; - memcpy(raw, v+p, K); - raw += K; + raw[off++] = (uint8_t)K; + memcpy(raw + off, v + p, K); + off += K; } } unsigned r = v_len - p; if (r > 0) { - *(raw++) = (uint8_t)r; - memcpy(raw, v+p, r); + raw[off++] = (uint8_t)r; + memcpy(raw + off, v + p, r); } - return KNOT_EOK; + return knot_rrset_add_rr(rr, raw, v_len + chunks, 0, NULL); } int remote_create_ns(knot_rrset_t *rr, const char *d) @@ -834,7 +834,7 @@ int remote_create_ns(knot_rrset_t *rr, const char *d) /* Build RDATA. */ int dn_size = knot_dname_size(dn); int result = knot_rrset_add_rr(rr, dn, dn_size, 0, NULL); - knot_dname_free(&dn); + knot_dname_free(&dn, NULL); return result; } diff --git a/src/knot/ctl/remote.h b/src/knot/ctl/remote.h index 6c8389aa5aa1a803f9434094769ce7bcfe645f6b..bf198e19d505d25d1b7a041d8ce181a11cd0ba32 100644 --- a/src/knot/ctl/remote.h +++ b/src/knot/ctl/remote.h @@ -161,7 +161,7 @@ int remote_query_sign(uint8_t *wire, size_t *size, size_t maxlen, * * \return created RR set or NULL. */ -knot_rrset_t* remote_build_rr(const char *k, uint16_t t); +int remote_build_rr(knot_rrset_t *rr, const char *k, uint16_t t); /*! * \brief Create a TXT rdata. @@ -171,7 +171,6 @@ knot_rrset_t* remote_build_rr(const char *k, uint16_t t); */ int remote_create_txt(knot_rrset_t *rr, const char *v, size_t v_len); - /*! * \brief Create a CNAME rdata. * \param d Domain name as a string. diff --git a/src/knot/dnssec/nsec-chain.c b/src/knot/dnssec/nsec-chain.c index d838e4de3068bce6de2d218f39d6bb62b443d98f..f2547054b0f462b06ef9856a6cfdd454f25c99a3 100644 --- a/src/knot/dnssec/nsec-chain.c +++ b/src/knot/dnssec/nsec-chain.c @@ -21,6 +21,7 @@ #include "common/debug.h" #include "knot/dnssec/nsec-chain.h" #include "knot/dnssec/zone-sign.h" +#include "libknot/dnssec/rrset-sign.h" #include "knot/dnssec/zone-nsec.h" /* - NSEC chain construction ------------------------------------------------ */ @@ -40,12 +41,8 @@ static knot_rrset_t *create_nsec_rrset(const knot_node_t *from, { assert(from); assert(to); - - // Create new RRSet - knot_dname_t *owner_cpy = knot_dname_copy(from->owner); - knot_rrset_t *rrset = knot_rrset_new(owner_cpy, - KNOT_RRTYPE_NSEC, KNOT_CLASS_IN, - NULL); + knot_rrset_t *rrset = knot_rrset_new(from->owner, KNOT_RRTYPE_NSEC, + KNOT_CLASS_IN, NULL); if (!rrset) { return NULL; } @@ -55,7 +52,7 @@ static knot_rrset_t *create_nsec_rrset(const knot_node_t *from, bitmap_add_node_rrsets(&rr_types, from); bitmap_add_type(&rr_types, KNOT_RRTYPE_NSEC); bitmap_add_type(&rr_types, KNOT_RRTYPE_RRSIG); - if (knot_node_rrset(from, KNOT_RRTYPE_SOA)) { + if (knot_node_rrtype_exists(from, KNOT_RRTYPE_SOA)) { bitmap_add_type(&rr_types, KNOT_RRTYPE_DNSKEY); } @@ -63,16 +60,18 @@ static knot_rrset_t *create_nsec_rrset(const knot_node_t *from, assert(to->owner); size_t next_owner_size = knot_dname_size(to->owner); size_t rdata_size = next_owner_size + bitmap_size(&rr_types); - uint8_t *rdata = knot_rrset_create_rr(rrset, rdata_size, ttl, NULL); - if (!rdata) { - knot_rrset_free(&rrset, NULL); - return NULL; - } + uint8_t rdata[rdata_size]; // Fill RDATA memcpy(rdata, to->owner, next_owner_size); bitmap_write(&rr_types, rdata + next_owner_size); + int ret = knot_rrset_add_rr(rrset, rdata, rdata_size, ttl, NULL); + if (ret != KNOT_EOK) { + knot_rrset_free(&rrset, NULL); + return NULL; + } + return rrset; } @@ -99,14 +98,13 @@ static int connect_nsec_nodes(knot_node_t *a, knot_node_t *b, return NSEC_NODE_SKIP; } - knot_rrset_t *old_next_nsec = knot_node_get_rrset(b, KNOT_RRTYPE_NSEC); int ret = 0; /*! * If the node has no other RRSets than NSEC (and possibly RRSIGs), * just remove the NSEC and its RRSIG, they are redundant */ - if (old_next_nsec != NULL + if (knot_node_rrtype_exists(b, KNOT_RRTYPE_NSEC) && knot_nsec_empty_nsec_and_rrsigs_in_node(b)) { ret = knot_nsec_changeset_remove(b, data->changeset); if (ret != KNOT_EOK) { @@ -123,9 +121,9 @@ static int connect_nsec_nodes(knot_node_t *a, knot_node_t *b, return KNOT_ENOMEM; } - knot_rrset_t *old_nsec = knot_node_get_rrset(a, KNOT_RRTYPE_NSEC); - if (old_nsec != NULL) { - if (knot_rrset_equal(new_nsec, old_nsec, + knot_rrset_t old_nsec = knot_node_rrset(a, KNOT_RRTYPE_NSEC); + if (!knot_rrset_empty(&old_nsec)) { + if (knot_rrset_equal(new_nsec, &old_nsec, KNOT_RRSET_COMPARE_WHOLE)) { // current NSEC is valid, do nothing dbg_dnssec_detail("NSECs equal.\n"); @@ -216,45 +214,39 @@ int knot_nsec_changeset_remove(const knot_node_t *n, int result = KNOT_EOK; - const knot_rrset_t *nsec = knot_node_rrset(n, KNOT_RRTYPE_NSEC); + knot_rrset_t *nsec = knot_node_create_rrset(n, KNOT_RRTYPE_NSEC); if (nsec == NULL) { - nsec = knot_node_rrset(n, KNOT_RRTYPE_NSEC3); + nsec = knot_node_create_rrset(n, KNOT_RRTYPE_NSEC3); } - const knot_rrset_t *rrsigs = knot_node_rrset(n, KNOT_RRTYPE_RRSIG); - - // extract copy of NSEC - knot_rrset_t *old_nsec = NULL; if (nsec) { - result = knot_rrset_copy(nsec, &old_nsec, NULL); - if (result != KNOT_EOK) { - return result; - } - // update changeset - - result = knot_changeset_add_rrset(changeset, old_nsec, + result = knot_changeset_add_rrset(changeset, nsec, KNOT_CHANGESET_REMOVE); if (result != KNOT_EOK) { - knot_rrset_free(&old_nsec, NULL); + knot_rrset_free(&nsec, NULL); return result; } } - if (rrsigs) { - // Sythesize RRSets' RRSIG - knot_rrset_t *synth_rrsigs = NULL; - result = knot_rrset_synth_rrsig(rrsigs->owner, KNOT_RRTYPE_NSEC, - rrsigs, &synth_rrsigs, NULL); - + knot_rrset_t rrsigs = knot_node_rrset(n, KNOT_RRTYPE_RRSIG); + if (!knot_rrset_empty(&rrsigs)) { + knot_rrset_t *synth_rrsigs = knot_rrset_new(n->owner, + KNOT_RRTYPE_RRSIG, + KNOT_CLASS_IN, + NULL); + if (synth_rrsigs == NULL) { + return KNOT_ENOMEM; + } + result = knot_synth_rrsig(KNOT_RRTYPE_NSEC, &rrsigs.rrs, + &synth_rrsigs->rrs, NULL); if (result == KNOT_ENOENT) { // Try removing NSEC3 RRSIGs - result = knot_rrset_synth_rrsig(rrsigs->owner, - KNOT_RRTYPE_NSEC3, - rrsigs, &synth_rrsigs, - NULL); + result = knot_synth_rrsig(KNOT_RRTYPE_NSEC3, &rrsigs.rrs, + &synth_rrsigs->rrs, NULL); } if (result != KNOT_EOK) { + knot_rrset_free(&synth_rrsigs, NULL); if (result != KNOT_ENOENT) { return result; } @@ -280,10 +272,10 @@ int knot_nsec_changeset_remove(const knot_node_t *n, bool knot_nsec_empty_nsec_and_rrsigs_in_node(const knot_node_t *n) { assert(n); - const knot_rrset_t **rrsets = knot_node_rrsets_no_copy(n); for (int i = 0; i < n->rrset_count; ++i) { - if (rrsets[i]->type != KNOT_RRTYPE_NSEC && - rrsets[i]->type != KNOT_RRTYPE_RRSIG) { + knot_rrset_t rrset = knot_node_rrset_at(n, i); + if (rrset.type != KNOT_RRTYPE_NSEC && + rrset.type != KNOT_RRTYPE_RRSIG) { return false; } } @@ -308,4 +300,3 @@ int knot_nsec_create_chain(const knot_zone_contents_t *zone, uint32_t ttl, return knot_nsec_chain_iterate_create(zone->nodes, connect_nsec_nodes, &data); } - diff --git a/src/knot/dnssec/nsec-chain.h b/src/knot/dnssec/nsec-chain.h index a21c683713d7a85d1e79fe8eceb134783aad82c7..299f793506712c9b7b32006c5da4818992ca50c9 100644 --- a/src/knot/dnssec/nsec-chain.h +++ b/src/knot/dnssec/nsec-chain.h @@ -56,19 +56,17 @@ enum { typedef int (*chain_iterate_create_cb)(knot_node_t *, knot_node_t *, nsec_chain_iterate_data_t *); - /*! * \brief Add all RR types from a node into the bitmap. */ inline static void bitmap_add_node_rrsets(bitmap_t *bitmap, const knot_node_t *node) { - const knot_rrset_t **node_rrsets = knot_node_rrsets_no_copy(node); for (int i = 0; i < node->rrset_count; i++) { - const knot_rrset_t *rr = node_rrsets[i]; - if (rr->type != KNOT_RRTYPE_NSEC && - rr->type != KNOT_RRTYPE_RRSIG) { - bitmap_add_type(bitmap, rr->type); + knot_rrset_t rr = knot_node_rrset_at(node, i); + if (rr.type != KNOT_RRTYPE_NSEC && + rr.type != KNOT_RRTYPE_RRSIG) { + bitmap_add_type(bitmap, rr.type); } } } diff --git a/src/knot/dnssec/nsec3-chain.c b/src/knot/dnssec/nsec3-chain.c index 45828aa4e75c58747b02b075d5c02fedf5e84931..23b90d70c806aac096dfdfa060c23cad37aed017 100644 --- a/src/knot/dnssec/nsec3-chain.c +++ b/src/knot/dnssec/nsec3-chain.c @@ -30,11 +30,12 @@ /* - Forward declarations --------------------------------------------------- */ -static knot_rrset_t *create_nsec3_rrset(knot_dname_t *, - const knot_nsec3_params_t *, - const bitmap_t *, - const uint8_t *, - uint32_t); +static int create_nsec3_rrset(knot_rrset_t *rrset, + knot_dname_t *dname, + const knot_nsec3_params_t *, + const bitmap_t *, + const uint8_t *, + uint32_t); /* - Helper functions ------------------------------------------------------- */ @@ -51,12 +52,12 @@ inline static bool valid_nsec3_node(const knot_node_t *node) return false; } - const knot_rrset_t *nsec3 = knot_node_rrset(node, KNOT_RRTYPE_NSEC3); + const knot_rrs_t *nsec3 = knot_node_rrs(node, KNOT_RRTYPE_NSEC3); if (nsec3 == NULL) { return false; } - if (knot_rrset_rr_count(nsec3) != 1) { + if (nsec3->rr_count != 1) { return false; } @@ -72,10 +73,9 @@ static bool are_nsec3_nodes_equal(const knot_node_t *a, const knot_node_t *b) return false; } - const knot_rrset_t *a_rrset = knot_node_rrset(a, KNOT_RRTYPE_NSEC3); - const knot_rrset_t *b_rrset = knot_node_rrset(b, KNOT_RRTYPE_NSEC3); - - return knot_rrset_equal(a_rrset, b_rrset, KNOT_RRSET_COMPARE_WHOLE); + knot_rrset_t a_rrset = knot_node_rrset(a, KNOT_RRTYPE_NSEC3); + knot_rrset_t b_rrset = knot_node_rrset(b, KNOT_RRTYPE_NSEC3); + return knot_rrset_equal(&a_rrset, &b_rrset, KNOT_RRSET_COMPARE_WHOLE); } /*! @@ -88,14 +88,14 @@ static bool are_nsec3_nodes_equal(const knot_node_t *a, const knot_node_t *b) */ static bool node_should_be_signed_nsec3(const knot_node_t *n) { - knot_rrset_t **node_rrsets = knot_node_get_rrsets_no_copy(n); for (int i = 0; i < n->rrset_count; i++) { - if (node_rrsets[i]->type == KNOT_RRTYPE_NSEC || - node_rrsets[i]->type == KNOT_RRTYPE_RRSIG) { + knot_rrset_t rrset = knot_node_rrset_at(n, i); + if (rrset.type == KNOT_RRTYPE_NSEC || + rrset.type == KNOT_RRTYPE_RRSIG) { continue; } bool should_sign = false; - int ret = knot_zone_sign_rr_should_be_signed(n, node_rrsets[i], + int ret = knot_zone_sign_rr_should_be_signed(n, &rrset, &should_sign); assert(ret == KNOT_EOK); // No tree inside the function, no fail if (should_sign) { @@ -117,11 +117,11 @@ static int shallow_copy_signature(const knot_node_t *from, knot_node_t *to) assert(valid_nsec3_node(from)); assert(valid_nsec3_node(to)); - knot_rrset_t *from_sig = knot_node_get_rrset(from, KNOT_RRTYPE_RRSIG); - if (from_sig == NULL) { + knot_rrset_t from_sig = knot_node_rrset(from, KNOT_RRTYPE_RRSIG); + if (knot_rrset_empty(&from_sig)) { return KNOT_EOK; } - return knot_node_add_rrset(to, from_sig, NULL); + return knot_node_add_rrset(to, &from_sig, NULL); } /*! @@ -165,9 +165,6 @@ static int copy_signatures(const knot_zone_tree_t *from, knot_zone_tree_t *to) /*! * \brief Custom NSEC3 tree free function. * - * - Leaves RRSIGs, as these are only referenced (shallow copied). - * - Deep frees NSEC3 RRs, as these nodes were created. - * */ static void free_nsec3_tree(knot_zone_tree_t *nodes) { @@ -178,9 +175,10 @@ static void free_nsec3_tree(knot_zone_tree_t *nodes) for (/* NOP */; !hattrie_iter_finished(it); hattrie_iter_next(it)) { knot_node_t *node = (knot_node_t *)*hattrie_iter_val(it); // newly allocated NSEC3 nodes - knot_rrset_t *nsec3 = knot_node_get_rrset(node, - KNOT_RRTYPE_NSEC3); - knot_rrset_free(&nsec3, NULL); + knot_rrs_t *nsec3 = knot_node_get_rrs(node, KNOT_RRTYPE_NSEC3); + knot_rrs_t *rrsig = knot_node_get_rrs(node, KNOT_RRTYPE_RRSIG); + knot_rrs_clear(nsec3, NULL); + knot_rrs_clear(rrsig, NULL); knot_node_free(&node); } @@ -250,32 +248,25 @@ static void nsec3_fill_rdata(uint8_t *rdata, const knot_nsec3_params_t *params, * * \return Pointer to created RRSet on success, NULL on errors. */ -static knot_rrset_t *create_nsec3_rrset(knot_dname_t *owner, - const knot_nsec3_params_t *params, - const bitmap_t *rr_types, - const uint8_t *next_hashed, - uint32_t ttl) +static int create_nsec3_rrset(knot_rrset_t *rrset, + knot_dname_t *owner, + const knot_nsec3_params_t *params, + const bitmap_t *rr_types, + const uint8_t *next_hashed, + uint32_t ttl) { + assert(rrset); assert(owner); assert(params); assert(rr_types); - knot_rrset_t *rrset; - rrset = knot_rrset_new(owner, KNOT_RRTYPE_NSEC3, KNOT_CLASS_IN, NULL); - if (!rrset) { - return NULL; - } + knot_rrset_init(rrset, owner, KNOT_RRTYPE_NSEC3, KNOT_CLASS_IN); size_t rdata_size = nsec3_rdata_size(params, rr_types); - uint8_t *rdata = knot_rrset_create_rr(rrset, rdata_size, ttl, NULL); - if (!rdata) { - knot_rrset_free(&rrset, NULL); - return NULL; - } - + uint8_t rdata[rdata_size]; nsec3_fill_rdata(rdata, params, rr_types, next_hashed, ttl); - return rrset; + return knot_rrset_add_rr(rrset, rdata, rdata_size, ttl, NULL); } /*! @@ -298,16 +289,17 @@ static knot_node_t *create_nsec3_node(knot_dname_t *owner, return NULL; } - knot_rrset_t *nsec3_rrset; - nsec3_rrset = create_nsec3_rrset(owner, nsec3_params, - rr_types, NULL, ttl); - if (!nsec3_rrset) { + knot_rrset_t nsec3_rrset; + int ret = create_nsec3_rrset(&nsec3_rrset, owner, nsec3_params, + rr_types, NULL, ttl); + if (ret != KNOT_EOK) { knot_node_free(&new_node); return NULL; } - if (knot_node_add_rrset_no_merge(new_node, nsec3_rrset) != KNOT_EOK) { - knot_rrset_free(&nsec3_rrset, NULL); + ret = knot_node_add_rrset(new_node, &nsec3_rrset, NULL); + knot_rrset_clear(&nsec3_rrset, NULL); + if (ret != KNOT_EOK) { knot_node_free(&new_node); return NULL; } @@ -375,16 +367,16 @@ static int connect_nsec3_nodes(knot_node_t *a, knot_node_t *b, assert(a->rrset_count == 1); - knot_rrset_t *a_rrset = knot_node_get_rrset(a, KNOT_RRTYPE_NSEC3); - assert(a_rrset); - uint8_t algorithm = knot_rdata_nsec3_algorithm(a_rrset, 0); + knot_rrs_t *a_rrs = knot_node_get_rrs(a, KNOT_RRTYPE_NSEC3); + assert(a_rrs); + uint8_t algorithm = knot_rrs_nsec3_algorithm(a_rrs, 0); if (algorithm == 0) { return KNOT_EINVAL; } uint8_t *raw_hash = NULL; uint8_t raw_length = 0; - knot_rdata_nsec3_next_hashed(a_rrset, 0, &raw_hash, &raw_length); + knot_rrs_nsec3_next_hashed(a_rrs, 0, &raw_hash, &raw_length); if (raw_hash == NULL) { return KNOT_EINVAL; } @@ -447,7 +439,7 @@ static int create_nsec3_nodes(const knot_zone_contents_t *zone, uint32_t ttl, if (result != KNOT_EOK) { break; } - if (knot_node_rrset(node, KNOT_RRTYPE_NSEC)) { + if (knot_node_rrtype_exists(node, KNOT_RRTYPE_NSEC)) { knot_node_set_removed_nsec(node); } if (knot_node_is_non_auth(node) || knot_node_is_empty(node)) { @@ -637,4 +629,3 @@ int knot_nsec3_create_chain(const knot_zone_contents_t *zone, uint32_t ttl, return result; } - diff --git a/src/knot/dnssec/zone-events.c b/src/knot/dnssec/zone-events.c index e84f95a13c61764214d4cd1d2a2c74f872fc61b3..a07117ecec5fdfeb1c189bb0c352cafc490ac158 100644 --- a/src/knot/dnssec/zone-events.c +++ b/src/knot/dnssec/zone-events.c @@ -128,12 +128,10 @@ static int zone_sign(knot_zone_contents_t *zone, conf_zone_t *zone_config, } // update SOA if there were any changes - const knot_rrset_t *soa = knot_node_rrset(zone->apex, - KNOT_RRTYPE_SOA); - const knot_rrset_t *rrsigs = knot_node_rrset(zone->apex, - KNOT_RRTYPE_RRSIG); - assert(soa); - result = knot_zone_sign_update_soa(soa, rrsigs, &zone_keys, &policy, + knot_rrset_t soa = knot_node_rrset(zone->apex, KNOT_RRTYPE_SOA); + knot_rrset_t rrsigs = knot_node_rrset(zone->apex, KNOT_RRTYPE_RRSIG); + assert(!knot_rrset_empty(&soa)); + result = knot_zone_sign_update_soa(&soa, &rrsigs, &zone_keys, &policy, new_serial, out_ch); if (result != KNOT_EOK) { log_zone_error("%s Cannot update SOA record (%s). Not signing" @@ -240,12 +238,10 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone, } // Update SOA RRSIGs - ret = knot_zone_sign_update_soa(knot_node_rrset(zone->apex, - KNOT_RRTYPE_SOA), - knot_node_rrset(zone->apex, - KNOT_RRTYPE_RRSIG), - &zone_keys, &policy, new_serial, - out_ch); + knot_rrset_t soa = knot_node_rrset(zone->apex, KNOT_RRTYPE_SOA); + knot_rrset_t rrsigs = knot_node_rrset(zone->apex, KNOT_RRTYPE_RRSIG); + ret = knot_zone_sign_update_soa(&soa, &rrsigs, &zone_keys, &policy, + new_serial, out_ch); if (ret != KNOT_EOK) { log_zone_error("%s Failed to sign SOA RR (%s)\n", msgpref, knot_strerror(ret)); diff --git a/src/knot/dnssec/zone-nsec.c b/src/knot/dnssec/zone-nsec.c index b07fdfd2cc772cd913453247eb3f49ca1a5a4ba4..ade08a681ea6ab621417c9c05e6ba36480caa8cd 100644 --- a/src/knot/dnssec/zone-nsec.c +++ b/src/knot/dnssec/zone-nsec.c @@ -93,12 +93,12 @@ static bool get_zone_soa_min_ttl(const knot_zone_contents_t *zone, assert(ttl); knot_node_t *apex = zone->apex; - knot_rrset_t *soa = knot_node_get_rrset(apex, KNOT_RRTYPE_SOA); + const knot_rrs_t *soa = knot_node_rrs(apex, KNOT_RRTYPE_SOA); if (!soa) { return false; } - uint32_t result = knot_rdata_soa_minimum(soa); + uint32_t result = knot_rrs_soa_minimum(soa); if (result == 0) { return false; } @@ -127,9 +127,9 @@ static int mark_nsec3(knot_rrset_t *rrset, void *data) knot_node_t *node = NULL; int ret; - if (knot_rrset_type(rrset) == KNOT_RRTYPE_NSEC3) { + if (rrset->type == KNOT_RRTYPE_NSEC3) { // Find the name in the NSEC3 tree and mark the node - ret = knot_zone_tree_get(nsec3s, knot_rrset_owner(rrset), + ret = knot_zone_tree_get(nsec3s, rrset->owner, &node); if (ret != KNOT_EOK) { return ret; @@ -284,4 +284,3 @@ int knot_zone_create_nsec_chain(const knot_zone_contents_t *zone, // Sign newly created records right away return knot_zone_sign_nsecs_in_changeset(zone_keys, policy, changeset); } - diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c index ccfac99789b8637767dbc0c6a91ab442dc4ff1d4..177c4594c4f1bc5d5d08fba54aa8f4e45626a97e 100644 --- a/src/knot/dnssec/zone-sign.c +++ b/src/knot/dnssec/zone-sign.c @@ -44,12 +44,10 @@ */ static knot_rrset_t *create_empty_rrsigs_for(const knot_rrset_t *covered) { - assert(covered); - - knot_dname_t *owner_copy = knot_dname_copy(covered->owner); + assert(!knot_rrset_empty(covered)); - return knot_rrset_new(owner_copy, KNOT_RRTYPE_RRSIG, covered->rclass, - NULL); + return knot_rrset_new(covered->owner, KNOT_RRTYPE_RRSIG, + covered->rclass, NULL); } /*- private API - signing of in-zone nodes -----------------------------------*/ @@ -73,14 +71,14 @@ static bool valid_signature_exists(const knot_rrset_t *covered, { assert(key); - if (!rrsigs) { + if (knot_rrset_empty(rrsigs)) { return false; } uint16_t rrsigs_rdata_count = knot_rrset_rr_count(rrsigs); for (uint16_t i = 0; i < rrsigs_rdata_count; i++) { - uint16_t keytag = knot_rdata_rrsig_key_tag(rrsigs, i); - uint16_t type_covered = knot_rdata_rrsig_type_covered(rrsigs, i); + uint16_t keytag = knot_rrs_rrsig_key_tag(&rrsigs->rrs, i); + uint16_t type_covered = knot_rrs_rrsig_type_covered(&rrsigs->rrs, i); if (keytag != key->keytag || type_covered != covered->type) { continue; } @@ -138,7 +136,7 @@ static bool all_signatures_exist(const knot_rrset_t *covered, const knot_zone_keys_t *zone_keys, const knot_dnssec_policy_t *policy) { - assert(covered); + assert(!knot_rrset_empty(covered)); assert(zone_keys); for (int i = 0; i < zone_keys->count; i++) { @@ -171,7 +169,7 @@ static const knot_zone_key_t *get_matching_zone_key(const knot_rrset_t *rrsigs, assert(rrsigs && rrsigs->type == KNOT_RRTYPE_RRSIG); assert(keys); - uint16_t keytag = knot_rdata_rrsig_key_tag(rrsigs, pos); + uint16_t keytag = knot_rrs_rrsig_key_tag(&rrsigs->rrs, pos); return knot_get_zone_key(keys, keytag); } @@ -189,7 +187,7 @@ static void note_earliest_expiration(const knot_rrset_t *rrsigs, size_t pos, assert(rrsigs); assert(expires_at); - const uint32_t current = knot_rdata_rrsig_sig_expiration(rrsigs, pos); + const uint32_t current = knot_rrs_rrsig_sig_expiration(&rrsigs->rrs, pos); if (current < *expires_at) { *expires_at = current; } @@ -216,7 +214,7 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered, { assert(changeset); - if (!rrsigs) { + if (knot_rrset_empty(rrsigs)) { return KNOT_EOK; } @@ -225,9 +223,11 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered, knot_rrset_t *to_remove = NULL; int result = KNOT_EOK; - knot_rrset_t *synth_rrsig = NULL; - result = knot_rrset_synth_rrsig(rrsigs->owner, covered->type, - rrsigs, &synth_rrsig, NULL); + knot_rrset_t synth_rrsig; + knot_rrset_init(&synth_rrsig, rrsigs->owner, KNOT_RRTYPE_RRSIG, + KNOT_CLASS_IN); + result = knot_synth_rrsig(covered->type, &rrsigs->rrs, + &synth_rrsig.rrs, NULL); if (result != KNOT_EOK) { if (result != KNOT_ENOENT) { return result; @@ -235,18 +235,18 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered, return KNOT_EOK; } - uint16_t rrsig_rdata_count = knot_rrset_rr_count(synth_rrsig); + uint16_t rrsig_rdata_count = knot_rrset_rr_count(&synth_rrsig); for (uint16_t i = 0; i < rrsig_rdata_count; i++) { const knot_zone_key_t *key; - key = get_matching_zone_key(synth_rrsig, i, zone_keys); + key = get_matching_zone_key(&synth_rrsig, i, zone_keys); if (key && key->is_active && key->context) { - result = knot_is_valid_signature(covered, synth_rrsig, i, + result = knot_is_valid_signature(covered, &synth_rrsig, i, &key->dnssec_key, key->context, policy); if (result == KNOT_EOK) { // valid signature - note_earliest_expiration(synth_rrsig, i, expires_at); + note_earliest_expiration(&synth_rrsig, i, expires_at); continue; } @@ -256,14 +256,15 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered, } if (to_remove == NULL) { - to_remove = create_empty_rrsigs_for(synth_rrsig); + to_remove = create_empty_rrsigs_for(&synth_rrsig); if (to_remove == NULL) { result = KNOT_ENOMEM; break; } } - result = knot_rrset_add_rr_from_rrset(to_remove, synth_rrsig, i, NULL); + knot_rr_t *rr_rem = knot_rrs_rr(&synth_rrsig.rrs, i); + result = knot_rrs_add_rr(&to_remove->rrs, rr_rem, NULL); if (result != KNOT_EOK) { break; } @@ -278,7 +279,7 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered, knot_rrset_free(&to_remove, NULL); } - knot_rrset_free(&synth_rrsig, NULL); + knot_rrs_clear(&synth_rrsig.rrs, NULL); return result; } @@ -300,12 +301,9 @@ static int add_missing_rrsigs(const knot_rrset_t *covered, const knot_dnssec_policy_t *policy, knot_changeset_t *changeset) { - assert(covered); + assert(!knot_rrset_empty(covered)); assert(zone_keys); assert(changeset); - if (knot_rrset_rr_count(covered) == 0) { - return KNOT_EOK; - } int result = KNOT_EOK; knot_rrset_t *to_add = NULL; @@ -361,11 +359,14 @@ static int remove_rrset_rrsigs(const knot_dname_t *owner, uint16_t type, { assert(owner); assert(changeset); - - knot_rrset_t *synth_rrsig = NULL; - int ret = knot_rrset_synth_rrsig(owner, type, rrsigs, &synth_rrsig, - NULL); + knot_rrset_t *synth_rrsig = + knot_rrset_new(owner, KNOT_RRTYPE_RRSIG, KNOT_CLASS_IN, NULL); + if (synth_rrsig == NULL) { + return KNOT_ENOMEM; + } + int ret = knot_synth_rrsig(type, &rrsigs->rrs, &synth_rrsig->rrs, NULL); if (ret != KNOT_EOK) { + knot_rrset_free(&synth_rrsig, NULL); if (ret != KNOT_ENOENT) { return ret; } @@ -397,9 +398,9 @@ static int force_resign_rrset(const knot_rrset_t *covered, const knot_dnssec_policy_t *policy, knot_changeset_t *changeset) { - assert(covered); + assert(!knot_rrset_empty(covered)); - if (rrsigs) { + if (!knot_rrset_empty(rrsigs)) { int result = remove_rrset_rrsigs(covered->owner, covered->type, rrsigs, changeset); if (result != KNOT_EOK) { @@ -428,7 +429,7 @@ static int resign_rrset(const knot_rrset_t *covered, knot_changeset_t *changeset, uint32_t *expires_at) { - assert(covered); + assert(!knot_rrset_empty(covered)); // TODO this function creates some signatures twice (for checking) // maybe merge the two functions into one @@ -457,18 +458,23 @@ static int remove_standalone_rrsigs(const knot_node_t *node, uint16_t rrsigs_rdata_count = knot_rrset_rr_count(rrsigs); for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) { - uint16_t type_covered = knot_rdata_rrsig_type_covered(rrsigs, i); - if (!knot_node_rrset(node, type_covered)) { - knot_rrset_t *to_remove = knot_rrset_new_from(rrsigs, NULL); + uint16_t type_covered = knot_rrs_rrsig_type_covered(&rrsigs->rrs, i); + if (!knot_node_rrtype_exists(node, type_covered)) { + knot_rrset_t *to_remove = knot_rrset_new(rrsigs->owner, + rrsigs->type, + rrsigs->rclass, + NULL); if (to_remove == NULL) { return KNOT_ENOMEM; } - int ret = knot_rrset_add_rr_from_rrset(to_remove, rrsigs, i, NULL); + knot_rr_t *rr_rem = knot_rrs_rr(&rrsigs->rrs, i); + int ret = knot_rrs_add_rr(&to_remove->rrs, rr_rem, NULL); if (ret != KNOT_EOK) { knot_rrset_free(&to_remove, NULL); return ret; } - ret = knot_changeset_add_rr(changeset, to_remove, KNOT_CHANGESET_REMOVE); + ret = knot_changeset_add_rrset(changeset, + to_remove, KNOT_CHANGESET_REMOVE); if (ret != KNOT_EOK) { knot_rrset_free(&to_remove, NULL); return ret; @@ -500,15 +506,15 @@ static int sign_node_rrsets(const knot_node_t *node, assert(policy); int result = KNOT_EOK; - const knot_rrset_t *rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); + knot_rrset_t rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); for (int i = 0; i < node->rrset_count; i++) { - const knot_rrset_t *rrset = node->rrset_tree[i]; - if (rrset->type == KNOT_RRTYPE_RRSIG) { + knot_rrset_t rrset = knot_node_rrset_at(node, i); + if (rrset.type == KNOT_RRTYPE_RRSIG) { continue; } bool should_sign = false; - result = knot_zone_sign_rr_should_be_signed(node, rrset, + result = knot_zone_sign_rr_should_be_signed(node, &rrset, &should_sign); if (result != KNOT_EOK) { return result; @@ -518,10 +524,10 @@ static int sign_node_rrsets(const knot_node_t *node, } if (policy->forced_sign) { - result = force_resign_rrset(rrset, rrsigs, zone_keys, policy, + result = force_resign_rrset(&rrset, &rrsigs, zone_keys, policy, changeset); } else { - result = resign_rrset(rrset, rrsigs, zone_keys, policy, + result = resign_rrset(&rrset, &rrsigs, zone_keys, policy, changeset, expires_at); } @@ -530,7 +536,7 @@ static int sign_node_rrsets(const knot_node_t *node, } } - return remove_standalone_rrsigs(node, rrsigs, changeset); + return remove_standalone_rrsigs(node, &rrsigs, changeset); } /*! @@ -684,7 +690,7 @@ static bool dnskey_rdata_match(const knot_zone_key_t *key, static bool dnskey_exists_in_zone(const knot_rrset_t *dnskeys, const knot_zone_key_t *key) { - assert(dnskeys); + assert(!knot_rrset_empty(dnskeys)); assert(key); uint16_t dnskeys_rdata_count = knot_rrset_rr_count(dnskeys); @@ -730,11 +736,10 @@ static int remove_invalid_dnskeys(const knot_rrset_t *soa, const knot_zone_keys_t *zone_keys, knot_changeset_t *changeset) { - assert(soa); assert(soa->type == KNOT_RRTYPE_SOA); assert(changeset); - if (!dnskeys) { + if (knot_rrset_empty(dnskeys)) { return KNOT_EOK; } assert(dnskeys->type == KNOT_RRTYPE_DNSKEY); @@ -742,9 +747,10 @@ static int remove_invalid_dnskeys(const knot_rrset_t *soa, knot_rrset_t *to_remove = NULL; int result = KNOT_EOK; - if (!knot_rrset_ttl_equal(dnskeys, soa)) { + if (knot_rrset_rr_ttl(dnskeys, 0) != knot_rrset_rr_ttl(soa, 0)) { dbg_dnssec_detail("removing DNSKEYs (SOA TTL differs)\n"); - result = knot_rrset_copy(dnskeys, &to_remove, NULL); + to_remove = knot_rrset_copy(dnskeys, NULL); + result = to_remove ? KNOT_EOK : KNOT_ENOMEM; goto done; } @@ -769,14 +775,18 @@ static int remove_invalid_dnskeys(const knot_rrset_t *soa, dbg_dnssec_detail("removing DNSKEY with tag %d\n", keytag); if (to_remove == NULL) { - to_remove = knot_rrset_new_from(dnskeys, NULL); + to_remove = knot_rrset_new(dnskeys->owner, + dnskeys->type, + dnskeys->rclass, + NULL); if (to_remove == NULL) { result = KNOT_ENOMEM; break; } } - result = knot_rrset_add_rr_from_rrset(to_remove, dnskeys, i, NULL); + knot_rr_t *to_rem = knot_rrs_rr(&dnskeys->rrs, i); + result = knot_rrs_add_rr(&to_remove->rrs, to_rem, NULL); if (result != KNOT_EOK) { break; } @@ -807,13 +817,7 @@ static knot_rrset_t *create_dnskey_rrset_from_soa(const knot_rrset_t *soa) { assert(soa); - knot_dname_t *owner = knot_dname_copy(soa->owner); - if (!owner) { - return NULL; - } - - return knot_rrset_new(owner, KNOT_RRTYPE_DNSKEY, soa->rclass, - NULL); + return knot_rrset_new(soa->owner, KNOT_RRTYPE_DNSKEY, soa->rclass, NULL); } /*! @@ -833,13 +837,14 @@ static int add_missing_dnskeys(const knot_rrset_t *soa, { assert(soa); assert(soa->type == KNOT_RRTYPE_SOA); - assert(!dnskeys || dnskeys->type == KNOT_RRTYPE_DNSKEY); + assert(knot_rrset_empty(dnskeys) || dnskeys->type == KNOT_RRTYPE_DNSKEY); assert(zone_keys); assert(changeset); knot_rrset_t *to_add = NULL; int result = KNOT_EOK; - bool add_all = (dnskeys == NULL || !knot_rrset_ttl_equal(dnskeys, soa)); + bool add_all = (knot_rrset_empty(dnskeys) || + knot_rrset_rr_ttl(dnskeys, 0) != knot_rrset_rr_ttl(soa, 0)); for (int i = 0; i < zone_keys->count; i++) { const knot_zone_key_t *key = &zone_keys->keys[i]; @@ -870,12 +875,6 @@ static int add_missing_dnskeys(const knot_rrset_t *soa, } if (to_add != NULL && result == KNOT_EOK) { - //! \todo Sorting should be handled by changesets application. - result = knot_rrset_sort_rdata(to_add); - if (result != KNOT_EOK) { - knot_rrset_free(&to_add, NULL); - return result; - } result = knot_changeset_add_rrset(changeset, to_add, KNOT_CHANGESET_ADD); } @@ -928,7 +927,8 @@ static int update_dnskeys_rrsigs(const knot_rrset_t *dnskeys, continue; } - result = knot_rrset_add_rr_from_rrset(new_dnskeys, dnskeys, i, NULL); + knot_rr_t *to_add = knot_rrs_rr(&dnskeys->rrs, i); + result = knot_rrs_add_rr(&new_dnskeys->rrs, to_add, NULL); if (result != KNOT_EOK) { goto fail; } @@ -948,18 +948,13 @@ static int update_dnskeys_rrsigs(const knot_rrset_t *dnskeys, } } - result = knot_rrset_sort_rdata(new_dnskeys); - if (result != KNOT_EOK) { - goto fail; - } - result = add_missing_rrsigs(new_dnskeys, NULL, zone_keys, policy, changeset); if (result != KNOT_EOK) { goto fail; } - if (dnskeys) { + if (!knot_rrset_empty(dnskeys)) { result = remove_rrset_rrsigs(dnskeys->owner, dnskeys->type, rrsigs, changeset); } @@ -990,30 +985,30 @@ static int update_dnskeys(const knot_zone_contents_t *zone, assert(changeset); const knot_node_t *apex = zone->apex; - const knot_rrset_t *dnskeys = knot_node_rrset(apex, KNOT_RRTYPE_DNSKEY); - const knot_rrset_t *soa = knot_node_rrset(apex, KNOT_RRTYPE_SOA); - const knot_rrset_t *rrsigs = knot_node_rrset(apex, KNOT_RRTYPE_RRSIG); - - if (!soa) { + knot_rrset_t dnskeys = knot_node_rrset(apex, KNOT_RRTYPE_DNSKEY); + knot_rrset_t soa = knot_node_rrset(apex, KNOT_RRTYPE_SOA); + knot_rrset_t rrsigs = knot_node_rrset(apex, KNOT_RRTYPE_RRSIG); + if (knot_rrset_empty(&soa)) { return KNOT_EINVAL; } int result; size_t changes_before = knot_changeset_size(changeset); - result = remove_invalid_dnskeys(soa, dnskeys, zone_keys, changeset); + result = remove_invalid_dnskeys(&soa, &dnskeys, zone_keys, changeset); if (result != KNOT_EOK) { return result; } - result = add_missing_dnskeys(soa, dnskeys, zone_keys, changeset); + result = add_missing_dnskeys(&soa, &dnskeys, zone_keys, changeset); if (result != KNOT_EOK) { return result; } - - knot_rrset_t *dnskey_rrsig = NULL; - result = knot_rrset_synth_rrsig(apex->owner, KNOT_RRTYPE_DNSKEY, - rrsigs, &dnskey_rrsig, NULL); + knot_rrset_t dnskey_rrsig; + knot_rrset_init(&dnskey_rrsig, apex->owner, KNOT_RRTYPE_RRSIG, + KNOT_CLASS_IN); + result = knot_synth_rrsig(KNOT_RRTYPE_DNSKEY, &rrsigs.rrs, + &dnskey_rrsig.rrs, NULL); if (result != KNOT_EOK) { if (result != KNOT_ENOENT) { return result; @@ -1021,16 +1016,16 @@ static int update_dnskeys(const knot_zone_contents_t *zone, } bool modified = (knot_changeset_size(changeset) != changes_before); - bool signatures_exist = (dnskeys && - all_signatures_exist(dnskeys, dnskey_rrsig, + bool signatures_exist = (!knot_rrset_empty(&dnskeys) && + all_signatures_exist(&dnskeys, &dnskey_rrsig, zone_keys, policy)); - knot_rrset_free(&dnskey_rrsig, NULL); + knot_rrs_clear(&dnskey_rrsig.rrs, NULL); if (!modified && signatures_exist) { return KNOT_EOK; } dbg_dnssec_detail("Creating new signatures for DNSKEYs\n"); - return update_dnskeys_rrsigs(dnskeys, rrsigs, soa, zone_keys, policy, changeset); + return update_dnskeys_rrsigs(&dnskeys, &rrsigs, &soa, zone_keys, policy, changeset); } /*! @@ -1103,7 +1098,7 @@ static int rr_already_signed(const knot_rrset_t *rrset, hattrie_t *t, } memset(info, 0, sizeof(signed_info_t)); // Store actual dname repr - info->dname = knot_dname_copy(rrset->owner); + info->dname = knot_dname_copy(rrset->owner, NULL); if (info->dname == NULL) { free(info); return KNOT_ENOMEM; @@ -1164,20 +1159,18 @@ static int sign_changeset_wrap(knot_rrset_t *chg_rrset, void *data) // If node is not in zone, all its RRSIGs were dropped - no-op if (node) { - const knot_rrset_t *rrsigs = knot_node_rrset(node, - KNOT_RRTYPE_RRSIG); - const knot_rrset_t *zone_rrset = - knot_node_rrset(node, chg_rrset->type); + knot_rrset_t zone_rrset = knot_node_rrset(node, chg_rrset->type); + knot_rrset_t rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); bool should_sign = false; - int ret = knot_zone_sign_rr_should_be_signed(node, zone_rrset, + int ret = knot_zone_sign_rr_should_be_signed(node, &zone_rrset, &should_sign); if (ret != KNOT_EOK) { return ret; } // Check for RRSet in the 'already_signed' table - if (args->signed_tree && (should_sign && zone_rrset == NULL)) { + if (args->signed_tree && (should_sign && knot_rrset_empty(&zone_rrset))) { bool already_signed = false; int ret = rr_already_signed(chg_rrset, args->signed_tree, @@ -1192,7 +1185,7 @@ static int sign_changeset_wrap(knot_rrset_t *chg_rrset, void *data) } if (should_sign) { - return force_resign_rrset(zone_rrset, rrsigs, + return force_resign_rrset(&zone_rrset, &rrsigs, args->zone_keys, args->policy, args->changeset); @@ -1208,7 +1201,7 @@ static int sign_changeset_wrap(knot_rrset_t *chg_rrset, void *data) * the zone. We need to drop them as well. */ return remove_rrset_rrsigs(chg_rrset->owner, - chg_rrset->type, rrsigs, + chg_rrset->type, &rrsigs, args->changeset); } } @@ -1230,8 +1223,8 @@ static int free_helper_trie_node(value_t *val, void *d) WALK_LIST_FREE(*(info->type_list)); } free(info->type_list); - knot_dname_free(&info->dname); - knot_dname_free(&info->hashed_dname); + knot_dname_free(&info->dname, NULL); + knot_dname_free(&info->hashed_dname, NULL); free(info); return KNOT_EOK; } @@ -1310,10 +1303,10 @@ bool knot_zone_sign_soa_expired(const knot_zone_contents_t *zone, return KNOT_EINVAL; } - const knot_rrset_t *soa = knot_node_rrset(zone->apex, KNOT_RRTYPE_SOA); - const knot_rrset_t *rrsigs = knot_node_rrset(zone->apex, KNOT_RRTYPE_RRSIG); - assert(soa); - return !all_signatures_exist(soa, rrsigs, zone_keys, policy); + knot_rrset_t soa = knot_node_rrset(zone->apex, KNOT_RRTYPE_SOA); + knot_rrset_t rrsigs = knot_node_rrset(zone->apex, KNOT_RRTYPE_RRSIG); + assert(!knot_rrset_empty(&soa)); + return !all_signatures_exist(&soa, &rrsigs, zone_keys, policy); } /*! @@ -1326,13 +1319,13 @@ int knot_zone_sign_update_soa(const knot_rrset_t *soa, uint32_t new_serial, knot_changeset_t *changeset) { - if (!soa || !zone_keys || !policy || !changeset) { + if (knot_rrset_empty(soa) || !zone_keys || !policy || !changeset) { return KNOT_EINVAL; } dbg_dnssec_verb("Updating SOA...\n"); - uint32_t serial = knot_rdata_soa_serial(soa); + uint32_t serial = knot_rrs_soa_serial(&soa->rrs); if (serial == UINT32_MAX && policy->soa_up == KNOT_SOA_SERIAL_UPDATE) { // TODO: this is wrong, the value should be 'rewound' to 0 in this case return KNOT_EINVAL; @@ -1349,7 +1342,7 @@ int knot_zone_sign_update_soa(const knot_rrset_t *soa, // remove signatures for old SOA (if there are any) - if (rrsigs) { + if (!knot_rrset_empty(rrsigs)) { result = remove_rrset_rrsigs(soa->owner, soa->type, rrsigs, changeset); if (result != KNOT_EOK) { @@ -1362,18 +1355,18 @@ int knot_zone_sign_update_soa(const knot_rrset_t *soa, knot_rrset_t *soa_from = NULL; knot_rrset_t *soa_to = NULL; - result = knot_rrset_copy(soa, &soa_from, NULL); - if (result != KNOT_EOK) { - return result; + soa_from = knot_rrset_copy(soa, NULL); + if (soa_from == NULL) { + return KNOT_ENOMEM; } - result = knot_rrset_copy(soa, &soa_to, NULL); - if (result != KNOT_EOK) { + soa_to = knot_rrset_copy(soa, NULL); + if (soa_to == NULL) { knot_rrset_free(&soa_from, NULL); - return result; + return KNOT_ENOMEM; } - knot_rdata_soa_serial_set(soa_to, new_serial); + knot_rrs_soa_serial_set(&soa_to->rrs, new_serial); // add signatures for new SOA @@ -1386,6 +1379,9 @@ int knot_zone_sign_update_soa(const knot_rrset_t *soa, // save the result + assert(changeset->soa_from == NULL); + assert(changeset->soa_to == NULL); + changeset->soa_from = soa_from; changeset->soa_to = soa_to; changeset->serial_from = serial; @@ -1469,7 +1465,7 @@ int knot_zone_sign_rr_should_be_signed(const knot_node_t *node, } *should_sign = false; // Only one case at the end is set to true - if (node == NULL || rrset == NULL) { + if (node == NULL || knot_rrset_empty(rrset)) { return KNOT_EOK; } @@ -1499,12 +1495,11 @@ int knot_zone_sign_rr_should_be_signed(const knot_node_t *node, // These RRs have their signatures stored in changeset already if (knot_node_is_removed_nsec(node) - && ((knot_rrset_type(rrset) == KNOT_RRTYPE_NSEC) - || (knot_rrset_type(rrset) == KNOT_RRTYPE_NSEC3))) { + && ((rrset->type == KNOT_RRTYPE_NSEC) + || (rrset->type == KNOT_RRTYPE_NSEC3))) { return KNOT_EOK; } *should_sign = true; return KNOT_EOK; } - diff --git a/src/knot/modules/synth_record.c b/src/knot/modules/synth_record.c index a14f2dcc6ead095354407ddd183e6506bad59054..b7ce6241a2b33990585acf4e11feba687eef2ea6 100644 --- a/src/knot/modules/synth_record.c +++ b/src/knot/modules/synth_record.c @@ -128,10 +128,10 @@ static int forward_addr_parse(struct query_data *qdata, synth_template_t *tpl, c if (addr_label == NULL || addr_label[0] <= prefix_len) { return KNOT_EINVAL; } - + int addr_len = *addr_label - prefix_len; memcpy(addr_str, addr_label + 1 + prefix_len, addr_len); - + /* Restore correct address format. */ char sep = str_separator(tpl->subnet.ss.ss_family); str_subst(addr_str, addr_len, '-', sep); @@ -197,7 +197,7 @@ static int reverse_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, kn rr->type = KNOT_RRTYPE_PTR; knot_rrset_add_rr(rr, ptrname, knot_dname_size(ptrname), tpl->ttl, &pkt->mm); - knot_dname_free(&ptrname); + knot_dname_free(&ptrname, NULL); return KNOT_EOK; } @@ -227,11 +227,9 @@ static int forward_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, kn static knot_rrset_t *synth_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, struct query_data *qdata) { - /* Synthetize empty RR. */ - knot_dname_t* qname = knot_dname_copy(qdata->name); - knot_rrset_t *rr = knot_rrset_new(qname, 0, KNOT_CLASS_IN, &pkt->mm); + knot_rrset_t *rr = knot_rrset_new(qdata->name, 0, KNOT_CLASS_IN, + &pkt->mm); if (rr == NULL) { - knot_dname_free(&qname); return NULL; } @@ -367,7 +365,7 @@ int synth_record_load(struct query_plan *plan, struct query_module *self) MODULE_ERR("invalid zone '%s'.\n", tpl->zone); return KNOT_EMALF; } - knot_dname_free(&check_name); + knot_dname_free(&check_name, NULL); } /* Parse TTL. */ diff --git a/src/knot/nameserver/axfr.c b/src/knot/nameserver/axfr.c index 357719c220b5952b766509b905e2653fc5a31d4d..1fb1be0f2a70da8307d55d245022c1d18b5fdfa4 100644 --- a/src/knot/nameserver/axfr.c +++ b/src/knot/nameserver/axfr.c @@ -14,7 +14,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ - #include "knot/nameserver/axfr.h" #include "knot/nameserver/internet.h" #include "knot/nameserver/process_query.h" @@ -36,14 +35,14 @@ static int put_rrsets(knot_pkt_t *pkt, knot_node_t *node, struct axfr_proc *stat int i = state->cur_rrset; int rrset_count = knot_node_rrset_count(node); unsigned flags = KNOT_PF_NOTRUNC; - const knot_rrset_t **rrset = knot_node_rrsets_no_copy(node); /* Append all RRs. */ for (;i < rrset_count; ++i) { - if (rrset[i]->type == KNOT_RRTYPE_SOA) { + knot_rrset_t rrset = knot_node_rrset_at(node, i); + if (rrset.type == KNOT_RRTYPE_SOA) { continue; } - ret = knot_pkt_put(pkt, 0, rrset[i], flags); + ret = knot_pkt_put(pkt, 0, &rrset, flags); /* If something failed, remember the current RR for later. */ if (ret != KNOT_EOK) { @@ -135,11 +134,11 @@ int xfr_process_list(knot_pkt_t *pkt, xfr_put_cb process_item, struct query_data mm_ctx_t *mm = qdata->mm; struct xfr_proc *xfer = qdata->ext; knot_zone_contents_t *zone = qdata->zone->contents; - knot_rrset_t *soa_rr = knot_node_get_rrset(zone->apex, KNOT_RRTYPE_SOA); + knot_rrset_t soa_rr = knot_node_rrset(zone->apex, KNOT_RRTYPE_SOA); /* Prepend SOA on first packet. */ if (xfer->npkts == 0) { - ret = knot_pkt_put(pkt, 0, soa_rr, KNOT_PF_NOTRUNC); + ret = knot_pkt_put(pkt, 0, &soa_rr, KNOT_PF_NOTRUNC); if (ret != KNOT_EOK) { return ret; } @@ -160,7 +159,7 @@ int xfr_process_list(knot_pkt_t *pkt, xfr_put_cb process_item, struct query_data /* Append SOA on last packet. */ if (ret == KNOT_EOK) { - ret = knot_pkt_put(pkt, 0, soa_rr, KNOT_PF_NOTRUNC); + ret = knot_pkt_put(pkt, 0, &soa_rr, KNOT_PF_NOTRUNC); } /* Update counters. */ diff --git a/src/knot/nameserver/chaos.c b/src/knot/nameserver/chaos.c index aa2cab5f7f1f4d92649acbed0f9f044205debc6b..0a3cd2b526e1025e55dfe5b760086aed4ce77cb9 100644 --- a/src/knot/nameserver/chaos.c +++ b/src/knot/nameserver/chaos.c @@ -50,11 +50,12 @@ static const char *get_txt_response_string(const knot_dname_t *qname) * \param owner RR owner name. * \param response String to be saved in RDATA. Truncated to 255 chars. * \param mm Memory context. + * \param rrset Store here. * - * \return Allocated RRset or NULL in case of error. + * \return KNOT_EOK */ -static knot_rrset_t *create_txt_rrset(const knot_dname_t *owner, - const char *response, mm_ctx_t *mm) +static int create_txt_rrset(knot_rrset_t *rrset, const knot_dname_t *owner, + const char *response, mm_ctx_t *mm) { // truncate response to one TXT label size_t response_len = strlen(response); @@ -62,27 +63,24 @@ static knot_rrset_t *create_txt_rrset(const knot_dname_t *owner, response_len = KNOT_DNAME_MAXLEN; } - knot_dname_t *rowner = knot_dname_copy(owner); + knot_dname_t *rowner = knot_dname_copy(owner, mm); if (!rowner) { - return NULL; + return KNOT_ENOMEM; } - knot_rrset_t *rrset; - rrset = knot_rrset_new(rowner, KNOT_RRTYPE_TXT, KNOT_CLASS_CH, mm); - if (!rrset) { - return NULL; - } - - uint8_t *rdata = knot_rrset_create_rr(rrset, response_len + 1, 0, mm); - if (!rdata) { - knot_rrset_free(&rrset, mm); - return NULL; - } + knot_rrset_init(rrset, rowner, KNOT_RRTYPE_TXT, KNOT_CLASS_CH); + uint8_t rdata[response_len + 1]; rdata[0] = response_len; memcpy(&rdata[1], response, response_len); - return rrset; + int ret = knot_rrset_add_rr(rrset, rdata, response_len + 1, 0, mm); + if (ret != KNOT_EOK) { + knot_dname_free(&rrset->owner, mm); + return ret; + } + + return KNOT_EOK; } /*! @@ -99,15 +97,15 @@ static int answer_txt(knot_pkt_t *response) return KNOT_RCODE_REFUSED; } - knot_rrset_t *rrset = create_txt_rrset(qname, response_str, - &response->mm); - if (!rrset) { + knot_rrset_t rrset; + int ret = create_txt_rrset(&rrset, qname, response_str, &response->mm); + if (ret != KNOT_EOK) { return KNOT_RCODE_SERVFAIL; } - int result = knot_pkt_put(response, 0, rrset, KNOT_PF_FREE); + int result = knot_pkt_put(response, 0, &rrset, KNOT_PF_FREE); if (result != KNOT_EOK) { - knot_rrset_free(&rrset, &response->mm); + knot_rrset_clear(&rrset, &response->mm); return KNOT_RCODE_SERVFAIL; } diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c index a1fdfb590d00ee88e41d55f3cbca8affc004ef49..fbffd55513fccecc28bcb13bc4d087a094b81fdc 100644 --- a/src/knot/nameserver/internet.c +++ b/src/knot/nameserver/internet.c @@ -1,4 +1,3 @@ - #include "knot/nameserver/internet.h" #include "knot/nameserver/nsec_proofs.h" #include "knot/nameserver/process_query.h" @@ -8,6 +7,7 @@ #include "common/debug.h" #include "common/descriptor.h" #include "knot/server/zones.h" +#include "libknot/dnssec/rrset-sign.h" /*! \brief Check if given node was already visited. */ static int wildcard_has_visited(struct query_data *qdata, const knot_node_t *node) @@ -41,47 +41,46 @@ static int wildcard_visit(struct query_data *qdata, const knot_node_t *node, con } /*! \brief Synthetizes a CNAME RR from a DNAME. */ -static knot_rrset_t *dname_cname_synth(const knot_rrset_t *dname_rr, - const knot_dname_t *qname, mm_ctx_t *mm) +static int dname_cname_synth(const knot_rrset_t *dname_rr, + const knot_dname_t *qname, + knot_rrset_t *cname_rrset, + mm_ctx_t *mm) { - dbg_ns("%s(%p, %p)\n", __func__, dname_rr, qname); - knot_dname_t *owner = knot_dname_copy(qname); - if (owner == NULL) { - return NULL; + if (cname_rrset == NULL) { + return KNOT_EINVAL; } + dbg_ns("%s(%p, %p)\n", __func__, dname_rr, qname); - knot_rrset_t *cname_rrset = knot_rrset_new(owner, KNOT_RRTYPE_CNAME, - KNOT_CLASS_IN, - mm); - if (cname_rrset == NULL) { - knot_dname_free(&owner); - return NULL; + knot_dname_t *owner_copy = knot_dname_copy(qname, mm); + if (owner_copy == NULL) { + return KNOT_ENOMEM; } + knot_rrset_init(cname_rrset, owner_copy, KNOT_RRTYPE_CNAME, dname_rr->rclass); /* Replace last labels of qname with DNAME. */ - const knot_dname_t *dname_wire = knot_rrset_owner(dname_rr); - const knot_dname_t *dname_tgt = knot_rdata_dname_target(dname_rr); + const knot_dname_t *dname_wire = dname_rr->owner; + const knot_dname_t *dname_tgt = knot_rrs_dname_target(&dname_rr->rrs); int labels = knot_dname_labels(dname_wire, NULL); knot_dname_t *cname = knot_dname_replace_suffix(qname, labels, dname_tgt); if (cname == NULL) { - knot_rrset_free(&cname_rrset, NULL); - return NULL; + knot_dname_free(&owner_copy, mm); + return KNOT_ENOMEM; } /* Store DNAME into RDATA. */ int cname_size = knot_dname_size(cname); - uint8_t *cname_rdata = knot_rrset_create_rr(cname_rrset, cname_size, - knot_rrset_rr_ttl(dname_rr, 0), - mm); - if (cname_rdata == NULL) { - knot_rrset_free(&cname_rrset, NULL); - knot_dname_free(&cname); - return NULL; - } + uint8_t cname_rdata[cname_size]; memcpy(cname_rdata, cname, cname_size); - knot_dname_free(&cname); + knot_dname_free(&cname, NULL); - return cname_rrset; + int ret = knot_rrset_add_rr(cname_rrset, cname_rdata, cname_size, + knot_rrset_rr_ttl(dname_rr, 0), mm); + if (ret != KNOT_EOK) { + knot_dname_free(&owner_copy, mm); + return ret; + } + + return KNOT_EOK; } /*! @@ -91,8 +90,8 @@ static knot_rrset_t *dname_cname_synth(const knot_rrset_t *dname_rr, static bool dname_cname_cannot_synth(const knot_rrset_t *rrset, const knot_dname_t *qname) { if (knot_dname_labels(qname, NULL) - - knot_dname_labels(knot_rrset_owner(rrset), NULL) - + knot_dname_labels(knot_rdata_dname_target(rrset), NULL) + - knot_dname_labels(rrset->owner, NULL) + + knot_dname_labels(knot_rrs_dname_target(&rrset->rrs), NULL) > KNOT_DNAME_MAXLABELS) { return true; } else { @@ -113,9 +112,9 @@ static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type, knot_rrinfo_t *rrinfo, struct query_data *qdata) { - knot_rrset_t *synth_sig = NULL; - int ret = knot_rrset_synth_rrsig(sig_owner, type, rrsigs, - &synth_sig, qdata->mm); + knot_rrs_t synth_rrs; + knot_rrs_init(&synth_rrs); + int ret = knot_synth_rrsig(type, &rrsigs->rrs, &synth_rrs, qdata->mm); if (ret == KNOT_ENOENT) { // No signature return KNOT_EOK; @@ -123,14 +122,25 @@ static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type, if (ret != KNOT_EOK) { return ret; } - struct rrsig_info *info = mm_alloc(qdata->mm, - sizeof(struct rrsig_info)); + + /* Create rrsig info structure. */ + struct rrsig_info *info = mm_alloc(qdata->mm, sizeof(struct rrsig_info)); if (info == NULL) { - ERR_ALLOC_FAILED; - knot_rrset_free(&synth_sig, qdata->mm); + knot_rrs_clear(&synth_rrs, qdata->mm); + return KNOT_ENOMEM; + } + + /* Store RRSIG into info structure. */ + knot_dname_t *owner_copy = knot_dname_copy(sig_owner, qdata->mm); + if (owner_copy == NULL) { + mm_free(qdata->mm, info); + knot_rrs_clear(&synth_rrs, qdata->mm); return KNOT_ENOMEM; } - info->synth_rrsig = synth_sig; + knot_rrset_init(&info->synth_rrsig, owner_copy, rrsigs->type, rrsigs->rclass); + /* Store filtered signature. */ + info->synth_rrsig.rrs = synth_rrs; + info->rrinfo = rrinfo; add_tail(&qdata->rrsigs, &info->n); @@ -142,8 +152,8 @@ static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type, */ static int put_answer(knot_pkt_t *pkt, uint16_t type, struct query_data *qdata) { - const knot_rrset_t *rrset = NULL; - knot_rrset_t **rrsets = knot_node_get_rrsets_no_copy(qdata->node); + knot_rrset_t rrset; + knot_rrset_init_empty(&rrset); /* Wildcard expansion or exact match, either way RRSet owner is * is QNAME. We can fake name synthesis by setting compression hint to @@ -157,7 +167,7 @@ static int put_answer(knot_pkt_t *pkt, uint16_t type, struct query_data *qdata) int ret = KNOT_EOK; switch (type) { - case KNOT_RRTYPE_ANY: /* Append all RRSets. */ + case KNOT_RRTYPE_ANY: /* Append all RRSets. */ { /* If ANY not allowed, set TC bit. */ if ((qdata->param->proc_flags & NS_QUERY_LIMIT_ANY) && (qdata->zone->conf->disable_any)) { @@ -166,17 +176,19 @@ static int put_answer(knot_pkt_t *pkt, uint16_t type, struct query_data *qdata) return KNOT_ESPACE; } for (unsigned i = 0; i < knot_node_rrset_count(qdata->node); ++i) { - ret = ns_put_rr(pkt, rrsets[i], NULL, compr_hint, 0, qdata); + rrset = knot_node_rrset_at(qdata->node, i); + ret = ns_put_rr(pkt, &rrset, NULL, compr_hint, 0, qdata); if (ret != KNOT_EOK) { break; } } break; + } default: /* Single RRSet of given type. */ - rrset = knot_node_get_rrset(qdata->node, type); - if (rrset) { - const knot_rrset_t *rrsigs = knot_node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); - ret = ns_put_rr(pkt, rrset, rrsigs, compr_hint, 0, qdata); + rrset = knot_node_rrset(qdata->node, type); + if (!knot_rrset_empty(&rrset)) { + knot_rrset_t rrsigs = knot_node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); + ret = ns_put_rr(pkt, &rrset, &rrsigs, compr_hint, 0, qdata); } break; } @@ -202,10 +214,10 @@ static int put_authority_ns(knot_pkt_t *pkt, struct query_data *qdata) return KNOT_EOK; } - const knot_rrset_t *ns_rrset = knot_node_rrset(zone->apex, KNOT_RRTYPE_NS); - if (ns_rrset) { - const knot_rrset_t *rrsigs = knot_node_rrset(zone->apex, KNOT_RRTYPE_RRSIG); - return ns_put_rr(pkt, ns_rrset, rrsigs, COMPR_HINT_NONE, + knot_rrset_t ns_rrset = knot_node_rrset(zone->apex, KNOT_RRTYPE_NS); + if (!knot_rrset_empty(&ns_rrset)) { + knot_rrset_t rrsigs = knot_node_rrset(zone->apex, KNOT_RRTYPE_RRSIG); + return ns_put_rr(pkt, &ns_rrset, &rrsigs, COMPR_HINT_NONE, KNOT_PF_NOTRUNC|KNOT_PF_CHECKDUP, qdata); } else { dbg_ns("%s: no NS RRSets in this zone, fishy...\n", __func__); @@ -218,28 +230,35 @@ static int put_authority_soa(knot_pkt_t *pkt, struct query_data *qdata, const knot_zone_contents_t *zone) { dbg_ns("%s(%p, %p)\n", __func__, pkt, zone); - knot_rrset_t *soa_rrset = knot_node_get_rrset(zone->apex, KNOT_RRTYPE_SOA); - assert(soa_rrset); - const knot_rrset_t *rrsigs = knot_node_rrset(zone->apex, KNOT_RRTYPE_RRSIG); + knot_rrset_t soa_rrset = knot_node_rrset(zone->apex, KNOT_RRTYPE_SOA); + knot_rrset_t rrsigs = knot_node_rrset(zone->apex, KNOT_RRTYPE_RRSIG); // if SOA's TTL is larger than MINIMUM, copy the RRSet and set // MINIMUM as TTL int ret = KNOT_EOK; uint32_t flags = KNOT_PF_NOTRUNC; - uint32_t min = knot_rdata_soa_minimum(soa_rrset); - if (min < knot_rrset_rr_ttl(soa_rrset, 0)) { - ret = knot_rrset_copy(soa_rrset, &soa_rrset, &pkt->mm); + uint32_t min = knot_rrs_soa_minimum(&soa_rrset.rrs); + if (min < knot_rrset_rr_ttl(&soa_rrset, 0)) { + knot_rrset_t copy; + knot_dname_t *dname_cpy = knot_dname_copy(soa_rrset.owner, &pkt->mm); + if (dname_cpy == NULL) { + return KNOT_ENOMEM; + } + knot_rrset_init(©, dname_cpy, soa_rrset.type, soa_rrset.rclass); + int ret = knot_rrs_copy(©.rrs, &soa_rrset.rrs, &pkt->mm); if (ret != KNOT_EOK) { + knot_dname_free(&dname_cpy, &pkt->mm); return ret; } + knot_rrset_rr_set_ttl(©, 0, min); - knot_rrset_rr_set_ttl(soa_rrset, 0, min); flags |= KNOT_PF_FREE; + soa_rrset = copy; } - ret = ns_put_rr(pkt, soa_rrset, rrsigs, COMPR_HINT_NONE, flags, qdata); + ret = ns_put_rr(pkt, &soa_rrset, &rrsigs, COMPR_HINT_NONE, flags, qdata); if (ret != KNOT_EOK && (flags & KNOT_PF_FREE)) { - knot_rrset_free(&soa_rrset, &pkt->mm); + knot_rrset_clear(&soa_rrset, &pkt->mm); } return ret; @@ -254,9 +273,9 @@ static int put_delegation(knot_pkt_t *pkt, struct query_data *qdata) } /* Insert NS record. */ - const knot_rrset_t *rrset = knot_node_rrset(qdata->node, KNOT_RRTYPE_NS); - const knot_rrset_t *rrsigs = knot_node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); - return ns_put_rr(pkt, rrset, rrsigs, COMPR_HINT_NONE, 0, qdata); + knot_rrset_t rrset = knot_node_rrset(qdata->node, KNOT_RRTYPE_NS); + knot_rrset_t rrsigs = knot_node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); + return ns_put_rr(pkt, &rrset, &rrsigs, COMPR_HINT_NONE, 0, qdata); } /*! \brief Put additional records for given RR. */ @@ -272,7 +291,6 @@ static int put_additional(knot_pkt_t *pkt, const knot_rrset_t *rr, uint32_t flags = KNOT_PF_NOTRUNC|KNOT_PF_CHECKDUP; uint16_t hint = COMPR_HINT_NONE; const knot_node_t *node = NULL; - const knot_rrset_t *additional = NULL; /* All RRs should have additional node cached or NULL. */ uint16_t rr_rdata_count = knot_rrset_rr_count(rr); @@ -284,13 +302,14 @@ static int put_additional(knot_pkt_t *pkt, const knot_rrset_t *rr, if (node == NULL) { continue; } - const knot_rrset_t *rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); + + knot_rrset_t rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); for (int k = 0; k < ar_type_count; ++k) { - additional = knot_node_rrset(node, ar_type_list[k]); - if (additional == NULL) { + knot_rrset_t additional = knot_node_rrset(node, ar_type_list[k]); + if (knot_rrset_empty(&additional)) { continue; } - ret = ns_put_rr(pkt, additional, rrsigs, + ret = ns_put_rr(pkt, &additional, &rrsigs, hint, flags, qdata); if (ret != KNOT_EOK) { break; @@ -306,18 +325,18 @@ static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, struct query_data *qda dbg_ns("%s(%p, %p)\n", __func__, pkt, qdata); const knot_node_t *cname_node = qdata->node; - knot_rrset_t *cname_rr = knot_node_get_rrset(qdata->node, rrtype); - const knot_rrset_t *rrsigs = knot_node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); + knot_rrset_t cname_rr = knot_node_rrset(qdata->node, rrtype); + knot_rrset_t rrsigs = knot_node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); int ret = KNOT_EOK; - assert(cname_rr != NULL); + assert(!knot_rrset_empty(&cname_rr)); /* Check whether RR is already in the packet. */ uint16_t flags = KNOT_PF_CHECKDUP; /* Now, try to put CNAME to answer. */ uint16_t rr_count_before = pkt->rrset_count; - ret = ns_put_rr(pkt, cname_rr, rrsigs, 0, flags, qdata); + ret = ns_put_rr(pkt, &cname_rr, &rrsigs, 0, flags, qdata); switch (ret) { case KNOT_EOK: break; case KNOT_ESPACE: return TRUNC; @@ -327,19 +346,25 @@ static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, struct query_data *qda /* Check if RR count increased. */ if (pkt->rrset_count <= rr_count_before) { dbg_ns("%s: RR %p already inserted => CNAME loop\n", - __func__, cname_rr); + __func__, &cname_rr); qdata->node = NULL; /* Act is if the name leads to nowhere. */ return HIT; } /* Synthesize CNAME if followed DNAME. */ if (rrtype == KNOT_RRTYPE_DNAME) { - if (dname_cname_cannot_synth(cname_rr, qdata->name)) { + if (dname_cname_cannot_synth(&cname_rr, qdata->name)) { qdata->rcode = KNOT_RCODE_YXDOMAIN; return ERROR; } - cname_rr = dname_cname_synth(cname_rr, qdata->name, &pkt->mm); - ret = ns_put_rr(pkt, cname_rr, NULL, 0, KNOT_PF_FREE, qdata); + knot_rrset_t dname_rr = cname_rr; + ret = dname_cname_synth(&dname_rr, qdata->name, &cname_rr, + &pkt->mm); + if (ret != KNOT_EOK) { + qdata->rcode = KNOT_RCODE_SERVFAIL; + return ERROR; + } + ret = ns_put_rr(pkt, &cname_rr, NULL, 0, KNOT_PF_FREE, qdata); switch (ret) { case KNOT_EOK: break; case KNOT_ESPACE: return TRUNC; @@ -367,7 +392,7 @@ static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, struct query_data *qda } /* Now follow the next CNAME TARGET. */ - qdata->name = knot_rdata_cname_name(cname_rr); + qdata->name = knot_rrs_cname_name(&cname_rr.rrs); #ifdef KNOT_NS_DEBUG char *cname_str = knot_dname_to_str(cname_node->owner); @@ -385,7 +410,7 @@ static int name_found(knot_pkt_t *pkt, struct query_data *qdata) uint16_t qtype = knot_pkt_qtype(pkt); dbg_ns("%s(%p, %p)\n", __func__, pkt, qdata); - if (knot_node_rrset(qdata->node, KNOT_RRTYPE_CNAME) != NULL + if (knot_node_rrtype_exists(qdata->node, KNOT_RRTYPE_CNAME) && qtype != KNOT_RRTYPE_CNAME && qtype != KNOT_RRTYPE_RRSIG && qtype != KNOT_RRTYPE_ANY) { @@ -445,9 +470,8 @@ static int name_not_found(knot_pkt_t *pkt, struct query_data *qdata) } /* Name is under DNAME, use it for substitution. */ - knot_rrset_t *dname_rrset = knot_node_get_rrset(qdata->encloser, KNOT_RRTYPE_DNAME); - if (dname_rrset != NULL - && knot_rrset_rr_count(dname_rrset) > 0) { + knot_rrset_t dname_rrset = knot_node_rrset(qdata->encloser, KNOT_RRTYPE_DNAME); + if (!knot_rrset_empty(&dname_rrset)) { dbg_ns("%s: solving DNAME for name %p\n", __func__, qdata->name); qdata->node = qdata->encloser; /* Follow encloser as new node. */ return follow_cname(pkt, KNOT_RRTYPE_DNAME, qdata); @@ -566,7 +590,6 @@ static int solve_authority_dnssec(int state, knot_pkt_t *pkt, struct query_data int ret = KNOT_ERROR; - /* Authenticated denial of existence. */ switch (state) { case HIT: ret = KNOT_EOK; break; @@ -609,11 +632,11 @@ static int solve_additional(int state, knot_pkt_t *pkt, struct query_data *qdata /* Scan all RRs in ANSWER/AUTHORITY. */ for (uint16_t i = 0; i < pkt->rrset_count; ++i) { /* Skip types for which it doesn't apply. */ - if (!rrset_additional_needed(pkt->rr[i]->type)) { + if (!knot_rrtype_additional_needed(pkt->rr[i].type)) { continue; } /* Put additional records for given type. */ - ret = put_additional(pkt, pkt->rr[i], qdata, &pkt->rr_info[i]); + ret = put_additional(pkt, &pkt->rr[i], qdata, &pkt->rr_info[i]); if (ret != KNOT_EOK) { break; } @@ -646,10 +669,8 @@ int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr, const knot_rrset_t *rrsigs, uint16_t compr_hint, uint32_t flags, struct query_data *qdata) { - /* RFC3123 s.6 - empty APL is valid, ignore other empty RRs. */ - if (knot_rrset_rr_count(rr) < 1 && - knot_rrset_type(rr) != KNOT_RRTYPE_APL) { - dbg_ns("%s: refusing to put empty RR of type %u\n", __func__, knot_rrset_type(rr)); + if (knot_rrset_rr_count(rr) < 1) { + dbg_ns("%s: refusing to put empty RR of type %u\n", __func__, rr->type); return KNOT_EMALF; } @@ -664,27 +685,33 @@ int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr, * we can just insert RRSet and fake synthesis by using compression * hint. */ int ret = KNOT_EOK; + knot_rrset_t to_add; if (compr_hint == COMPR_HINT_NONE && expand) { - ret = knot_rrset_copy(rr, (knot_rrset_t **)&rr, &pkt->mm); - if (ret != KNOT_EOK) { + knot_dname_t *qname_cpy = knot_dname_copy(qdata->name, &pkt->mm); + if (qname_cpy == NULL) { return KNOT_ENOMEM; } - - knot_rrset_set_owner((knot_rrset_t *)rr, qdata->name); + knot_rrset_init(&to_add, qname_cpy, rr->type, rr->rclass); + int ret = knot_rrs_copy(&to_add.rrs, &rr->rrs, &pkt->mm); + if (ret != KNOT_EOK) { + knot_dname_free(&qname_cpy, &pkt->mm); + } + to_add.additional = rr->additional; flags |= KNOT_PF_FREE; + } else { + to_add = *rr; } uint16_t prev_count = pkt->rrset_count; - ret = knot_pkt_put(pkt, compr_hint, rr, flags); - if (ret != KNOT_EOK) { - if (flags & KNOT_PF_FREE) { - knot_rrset_free((knot_rrset_t **)&rr, &pkt->mm); - } + ret = knot_pkt_put(pkt, compr_hint, &to_add, flags); + if (ret != KNOT_EOK && (flags & KNOT_PF_FREE)) { + knot_rrset_clear(&to_add, &pkt->mm); return ret; } - bool inserted = (prev_count != pkt->rrset_count); - if (inserted && rrsigs && rr->type != KNOT_RRTYPE_RRSIG) { + const bool inserted = (prev_count != pkt->rrset_count); + if (inserted && + !knot_rrset_empty(rrsigs) && rr->type != KNOT_RRTYPE_RRSIG) { // Get rrinfo of just inserted RR. knot_rrinfo_t *rrinfo = &pkt->rr_info[pkt->rrset_count - 1]; ret = put_rrsig(rr->owner, rr->type, rrsigs, rrinfo, qdata); diff --git a/src/knot/nameserver/ixfr.c b/src/knot/nameserver/ixfr.c index 83ffa1d9db42b53b55b26e33afc156d2da8ebc34..422d7aab0e758a2193d31a5888c9ecf1a03b73ca 100644 --- a/src/knot/nameserver/ixfr.c +++ b/src/knot/nameserver/ixfr.c @@ -1,4 +1,3 @@ - #include "knot/nameserver/ixfr.h" #include "knot/nameserver/axfr.h" #include "knot/nameserver/internet.h" @@ -130,10 +129,8 @@ static int ixfr_load_chsets(knot_changesets_t **chgsets, const zone_t *zone, assert(zone); /* Compare serials. */ - const knot_node_t *apex = zone->contents->apex; - const knot_rrset_t *our_soa = knot_node_rrset(apex, KNOT_RRTYPE_SOA); - uint32_t serial_to = knot_rdata_soa_serial(our_soa); - uint32_t serial_from = knot_rdata_soa_serial(their_soa); + uint32_t serial_to = knot_zone_serial(zone->contents); + uint32_t serial_from = knot_rrs_soa_serial(&their_soa->rrs); int ret = knot_serial_compare(serial_to, serial_from); if (ret <= 0) { /* We have older/same age zone. */ return KNOT_EUPTODATE; @@ -162,8 +159,8 @@ static int ixfr_query_check(struct query_data *qdata) NS_NEED_QTYPE(qdata, KNOT_RRTYPE_IXFR, KNOT_RCODE_FORMERR); /* Need SOA authority record. */ const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY); - const knot_rrset_t *their_soa = authority->rr[0]; - if (authority->count < 1 || knot_rrset_type(their_soa) != KNOT_RRTYPE_SOA) { + const knot_rrset_t *their_soa = &authority->rr[0]; + if (authority->count < 1 || their_soa->type != KNOT_RRTYPE_SOA) { qdata->rcode = KNOT_RCODE_FORMERR; return NS_PROC_FAIL; } @@ -203,7 +200,7 @@ static int ixfr_answer_init(struct query_data *qdata) } /* Compare serials. */ - const knot_rrset_t *their_soa = knot_pkt_section(qdata->query, KNOT_AUTHORITY)->rr[0]; + const knot_rrset_t *their_soa = &knot_pkt_section(qdata->query, KNOT_AUTHORITY)->rr[0]; knot_changesets_t *chgsets = NULL; int ret = ixfr_load_chsets(&chgsets, qdata->zone, their_soa); if (ret != KNOT_EOK) { @@ -265,8 +262,11 @@ static int ixfr_answer_soa(knot_pkt_t *pkt, struct query_data *qdata) /* Guaranteed to have zone contents. */ const knot_node_t *apex = qdata->zone->contents->apex; - const knot_rrset_t *soa_rr = knot_node_rrset(apex, KNOT_RRTYPE_SOA); - int ret = knot_pkt_put(pkt, 0, soa_rr, 0); + knot_rrset_t soa_rr = knot_node_rrset(apex, KNOT_RRTYPE_SOA); + if (knot_rrset_empty(&soa_rr)) { + return NS_PROC_FAIL; + } + int ret = knot_pkt_put(pkt, 0, &soa_rr, 0); if (ret != KNOT_EOK) { qdata->rcode = KNOT_RCODE_SERVFAIL; return NS_PROC_FAIL; @@ -297,8 +297,8 @@ int ixfr_answer(knot_pkt_t *pkt, struct query_data *qdata) case KNOT_EOK: /* OK */ ixfr = (struct ixfr_proc*)qdata->ext; IXFR_LOG(LOG_INFO, "Started (serial %u -> %u).", - knot_rdata_soa_serial(ixfr->soa_from), - knot_rdata_soa_serial(ixfr->soa_to)); + knot_rrs_soa_serial(&ixfr->soa_from->rrs), + knot_rrs_soa_serial(&ixfr->soa_to->rrs)); break; case KNOT_EUPTODATE: /* Our zone is same age/older, send SOA. */ IXFR_LOG(LOG_INFO, "Zone is up-to-date."); @@ -385,20 +385,10 @@ int ixfr_process_answer(knot_pkt_t *pkt, knot_ns_xfr_t *xfr) case XFRIN_RES_SOA_ONLY: { // compare the SERIAL from the changeset with the zone's // serial - const knot_node_t *apex = zone->contents->apex; - if (apex == NULL) { - return KNOT_ERROR; - } - - const knot_rrset_t *zone_soa = knot_node_rrset( - apex, KNOT_RRTYPE_SOA); - if (zone_soa == NULL) { - return KNOT_ERROR; - } - + uint32_t zone_serial = knot_zone_serial(zone->contents); if (knot_serial_compare( - knot_rdata_soa_serial(chgsets->first_soa), - knot_rdata_soa_serial(zone_soa)) + knot_rrs_soa_serial(&chgsets->first_soa->rrs), + zone_serial) > 0) { if ((xfr->flags & XFR_FLAG_UDP) != 0) { // IXFR over UDP diff --git a/src/knot/nameserver/nsec_proofs.c b/src/knot/nameserver/nsec_proofs.c index cdf53938a016433b812272c2bf5e33f0401c9217..1fa9e4cd71ad0e0539e94ba0d95c29469c002b1b 100644 --- a/src/knot/nameserver/nsec_proofs.c +++ b/src/knot/nameserver/nsec_proofs.c @@ -1,4 +1,3 @@ - #include "knot/nameserver/nsec_proofs.h" #include "knot/nameserver/process_query.h" #include "knot/nameserver/internet.h" @@ -44,7 +43,7 @@ static knot_dname_t *ns_next_closer(const knot_dname_t *closest_encloser, name = knot_wire_next_label(name, NULL); } - return knot_dname_copy(name); + return knot_dname_copy(name, NULL); } /*----------------------------------------------------------------------------*/ @@ -59,18 +58,15 @@ static int ns_put_nsec3_from_node(const knot_node_t *node, struct query_data *qdata, knot_pkt_t *resp) { - knot_rrset_t *rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC3); - const knot_rrset_t *rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); - if (rrset == NULL) { + knot_rrset_t rrset = knot_node_rrset(node, KNOT_RRTYPE_NSEC3); + knot_rrset_t rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); + if (knot_rrset_empty(&rrset)) { // bad zone, ignore return KNOT_EOK; } - int res = KNOT_EOK; - if (knot_rrset_rr_count(rrset)) { - res = ns_put_rr(resp, rrset, rrsigs, COMPR_HINT_NONE, - KNOT_PF_CHECKDUP, qdata); - } + int res = ns_put_rr(resp, &rrset, &rrsigs, COMPR_HINT_NONE, + KNOT_PF_CHECKDUP, qdata); /*! \note TC bit is already set, if something went wrong. */ @@ -230,7 +226,7 @@ dbg_ns_exec_verb( ); ret = ns_put_covering_nsec3(zone, new_next_closer, qdata, resp); - knot_dname_free(&new_next_closer); + knot_dname_free(&new_next_closer, NULL); } else { ret = ns_put_covering_nsec3(zone, next_closer, qdata, resp); } @@ -301,14 +297,13 @@ static int ns_put_nsec_wildcard(const knot_zone_contents_t *zone, } } - const knot_rrset_t *rrset = knot_node_rrset(previous, KNOT_RRTYPE_NSEC); - const knot_rrset_t *rrsigs = knot_node_rrset(previous, KNOT_RRTYPE_RRSIG); - + knot_rrset_t rrset = knot_node_rrset(previous, KNOT_RRTYPE_NSEC); int ret = KNOT_EOK; - if (rrset != NULL && knot_rrset_rr_count(rrset) > 0) { + if (!knot_rrset_empty(&rrset)) { + knot_rrset_t rrsigs = knot_node_rrset(previous, KNOT_RRTYPE_RRSIG); // NSEC proving that there is no node with the searched name - ret = ns_put_rr(resp, rrset, rrsigs, COMPR_HINT_NONE, 0, qdata); + ret = ns_put_rr(resp, &rrset, &rrsigs, COMPR_HINT_NONE, 0, qdata); } return ret; @@ -347,7 +342,7 @@ static int ns_put_nsec3_no_wildcard_child(const knot_zone_contents_t *zone, ret = ns_put_covering_nsec3(zone, wildcard, qdata, resp); /* Directly discard wildcard. */ - knot_dname_free(&wildcard); + knot_dname_free(&wildcard, NULL); } return ret; @@ -404,7 +399,7 @@ dbg_ns_exec_verb( int ret = ns_put_covering_nsec3(zone, next_closer, qdata, resp); /* Duplicate from ns_next_close(), safe to discard. */ - knot_dname_free(&next_closer); + knot_dname_free(&next_closer, NULL); return ret; } @@ -478,8 +473,8 @@ static int ns_put_nsec_nxdomain(const knot_dname_t *qname, struct query_data *qdata, knot_pkt_t *resp) { - knot_rrset_t *rrset = NULL; - const knot_rrset_t *rrsigs = NULL; + knot_rrset_t rrset = { 0 }; + knot_rrset_t rrsigs = { 0 }; // check if we have previous; if not, find one using the tree if (previous == NULL) { @@ -503,16 +498,15 @@ dbg_ns_exec_verb( ); // 1) NSEC proving that there is no node with the searched name - rrset = knot_node_get_rrset(previous, KNOT_RRTYPE_NSEC); - rrsigs = knot_node_get_rrset(previous, KNOT_RRTYPE_RRSIG); - if (rrset == NULL) { + rrset = knot_node_rrset(previous, KNOT_RRTYPE_NSEC); + rrsigs = knot_node_rrset(previous, KNOT_RRTYPE_RRSIG); + if (knot_rrset_empty(&rrset)) { // no NSEC records //return NS_ERR_SERVFAIL; return KNOT_EOK; - } - int ret = ns_put_rr(resp, rrset, rrsigs, COMPR_HINT_NONE, 0, qdata); + int ret = ns_put_rr(resp, &rrset, &rrsigs, COMPR_HINT_NONE, 0, qdata); if (ret != KNOT_EOK) { dbg_ns("Failed to add NSEC for NXDOMAIN to response: %s\n", knot_strerror(ret)); @@ -553,16 +547,16 @@ dbg_ns_exec_verb( ); /* Directly discard dname. */ - knot_dname_free(&wildcard); + knot_dname_free(&wildcard, NULL); if (prev_new != previous) { - rrset = knot_node_get_rrset(prev_new, KNOT_RRTYPE_NSEC); - rrsigs = knot_node_get_rrset(prev_new, KNOT_RRTYPE_RRSIG); - if (rrset == NULL) { + rrset = knot_node_rrset(prev_new, KNOT_RRTYPE_NSEC); + rrsigs = knot_node_rrset(prev_new, KNOT_RRTYPE_RRSIG); + if (knot_rrset_empty(&rrset)) { // bad zone, ignore return KNOT_EOK; } - ret = ns_put_rr(resp, rrset, rrsigs, COMPR_HINT_NONE, 0, qdata); + ret = ns_put_rr(resp, &rrset, &rrsigs, COMPR_HINT_NONE, 0, qdata); if (ret != KNOT_EOK) { dbg_ns("Failed to add second NSEC for NXDOMAIN to " "response: %s\n", knot_strerror(ret)); @@ -681,8 +675,6 @@ static int ns_put_nsec_nsec3_nodata(const knot_node_t *node, /*! \todo Maybe distinguish different errors. */ int ret = KNOT_ERROR; - knot_rrset_t *rrset = NULL; - if (knot_is_nsec3_enabled(zone)) { /* RFC5155 7.2.5 Wildcard No Data Responses */ @@ -710,11 +702,11 @@ static int ns_put_nsec_nsec3_nodata(const knot_node_t *node, } } else { dbg_ns("%s: adding NSEC NODATA\n", __func__); - if ((rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC)) - != NULL) { + knot_rrset_t rrset = knot_node_rrset(node, KNOT_RRTYPE_NSEC); + if (!knot_rrset_empty(&rrset)) { dbg_ns_detail("Putting the RRSet to Authority\n"); - const knot_rrset_t *rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); - ret = ns_put_rr(resp, rrset, rrsigs, COMPR_HINT_NONE, 0, qdata); + knot_rrset_t rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); + ret = ns_put_rr(resp, &rrset, &rrsigs, COMPR_HINT_NONE, 0, qdata); } } @@ -766,10 +758,10 @@ int nsec_prove_dp_security(knot_pkt_t *pkt, struct query_data *qdata) dbg_ns("%s(%p, %p)\n", __func__, pkt, qdata); /* Add DS record if present. */ - knot_rrset_t *rrset = knot_node_get_rrset(qdata->node, KNOT_RRTYPE_DS); - if (rrset != NULL) { - const knot_rrset_t *rrsigs = knot_node_get_rrset(qdata->node, KNOT_RRTYPE_RRSIG); - return ns_put_rr(pkt, rrset, rrsigs, COMPR_HINT_NONE, 0, qdata); + knot_rrset_t rrset = knot_node_rrset(qdata->node, KNOT_RRTYPE_DS); + if (!knot_rrset_empty(&rrset)) { + knot_rrset_t rrsigs = knot_node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); + return ns_put_rr(pkt, &rrset, &rrsigs, COMPR_HINT_NONE, 0, qdata); } /* DS doesn't exist => NODATA proof. */ @@ -791,13 +783,14 @@ int nsec_append_rrsigs(knot_pkt_t *pkt, struct query_data *qdata, bool optional) /* Append RRSIGs for section. */ struct rrsig_info *info = NULL; WALK_LIST(info, qdata->rrsigs) { - knot_rrset_t *rrsig = info->synth_rrsig; + knot_rrset_t *rrsig = &info->synth_rrsig; uint16_t compr_hint = info->rrinfo->compress_ptr[COMPR_HINT_OWNER]; ret = knot_pkt_put(pkt, compr_hint, rrsig, flags); if (ret != KNOT_EOK) { break; } - info->synth_rrsig = NULL; /* RRSIG is owned by packet now. */ + /* RRSIG is owned by packet now. */ + knot_rrs_init(&info->synth_rrsig.rrs); }; /* Clear the list. */ @@ -814,8 +807,8 @@ void nsec_clear_rrsigs(struct query_data *qdata) struct rrsig_info *info = NULL; WALK_LIST(info, qdata->rrsigs) { - knot_rrset_t *rrsig = info->synth_rrsig; - knot_rrset_free(&rrsig, qdata->mm); + knot_rrset_t *rrsig = &info->synth_rrsig; + knot_rrset_clear(rrsig, qdata->mm); }; ptrlist_free(&qdata->rrsigs, qdata->mm); diff --git a/src/knot/nameserver/process_query.c b/src/knot/nameserver/process_query.c index a462028416c1697f214dbc9b22a9c0760c0ec759..f7592f6491c732c7a35656bcca13bff74270cc00 100644 --- a/src/knot/nameserver/process_query.c +++ b/src/knot/nameserver/process_query.c @@ -232,7 +232,7 @@ bool process_query_acl_check(acl_t *acl, struct query_data *qdata) /* Authenticate with NOKEY if the packet isn't signed. */ if (query->tsig_rr) { - key_name = knot_rrset_owner(query->tsig_rr); + key_name = query->tsig_rr->owner; key_alg = tsig_rdata_alg(query->tsig_rr); } acl_match_t *match = acl_find(acl, query_source, key_name); diff --git a/src/knot/nameserver/process_query.h b/src/knot/nameserver/process_query.h index 7868d5e680a98ef786851fd3d9946e665864e2d2..eadbc664835f904fc162627567feb8627a957d49 100644 --- a/src/knot/nameserver/process_query.h +++ b/src/knot/nameserver/process_query.h @@ -108,7 +108,7 @@ struct wildcard_hit { /*! \brief RRSIG info node list. */ struct rrsig_info { node_t n; - knot_rrset_t *synth_rrsig; /* Synthesized RRSIG. */ + knot_rrset_t synth_rrsig; /* Synthesized RRSIG. */ knot_rrinfo_t *rrinfo; /* RR info. */ }; diff --git a/src/knot/nameserver/update.c b/src/knot/nameserver/update.c index afa4e8199c82741a60c4bce0ae70b4328a59887d..43698da6ed474213b298e3a93d562db82d32af79 100644 --- a/src/knot/nameserver/update.c +++ b/src/knot/nameserver/update.c @@ -1,4 +1,3 @@ - #include "knot/nameserver/update.h" #include "knot/nameserver/internet.h" #include "knot/nameserver/process_query.h" @@ -84,21 +83,8 @@ static int update_prereq_check(struct query_data *qdata) { knot_pkt_t *query = qdata->query; const knot_zone_contents_t *contents = qdata->zone->contents; - - /* - * 2) DDNS Prerequisities Section processing (RFC2136, Section 3.2). - * - * \note Permissions section means probably policies and fine grained - * access control, not transaction security. - */ - knot_ddns_prereq_t *prereqs = NULL; - int ret = knot_ddns_process_prereqs(query, &prereqs, &qdata->rcode); - if (ret == KNOT_EOK) { - ret = knot_ddns_check_prereqs(contents, &prereqs, &qdata->rcode); - knot_ddns_prereqs_free(&prereqs); - } - - return ret; + // DDNS Prerequisities Section processing (RFC2136, Section 3.2). + return knot_ddns_process_prereqs(query, contents, &qdata->rcode); } static int update_process(knot_pkt_t *resp, struct query_data *qdata) @@ -186,71 +172,24 @@ int update_answer(knot_pkt_t *pkt, struct query_data *qdata) } } -/* - * This function should: - * 1) Create zone shallow copy and the changes structure. - * 2) Call knot_ddns_process_update(). - * - If something went bad, call xfrin_rollback_update() and return an error. - * - If everything went OK, continue. - * 3) Finalize the updated zone. - * - * NOTE: Mostly copied from xfrin_apply_changesets(). Should be refactored in - * order to get rid of duplicate code. - */ static int knot_ns_process_update(const knot_pkt_t *query, - knot_zone_contents_t *old_contents, - knot_zone_contents_t **new_contents, + zone_t *old_zone, knot_changesets_t *chgs, uint16_t *rcode, uint32_t new_serial) { - if (query == NULL || old_contents == NULL || chgs == NULL || - EMPTY_LIST(chgs->sets) || new_contents == NULL || rcode == NULL) { + if (query == NULL || old_zone == NULL || chgs == NULL || + EMPTY_LIST(chgs->sets) || rcode == NULL) { return KNOT_EINVAL; } dbg_ns("Applying UPDATE to zone...\n"); - // 1) Create zone shallow copy. - dbg_ns_verb("Creating shallow copy of the zone...\n"); - knot_zone_contents_t *contents_copy = NULL; - int ret = xfrin_prepare_zone_copy(old_contents, &contents_copy); - if (ret != KNOT_EOK) { - dbg_ns("Failed to prepare zone copy: %s\n", - knot_strerror(ret)); - *rcode = KNOT_RCODE_SERVFAIL; - return ret; - } - - // 2) Apply the UPDATE and create changesets. + // Create changesets from UPDATE dbg_ns_verb("Applying the UPDATE and creating changeset...\n"); - ret = knot_ddns_process_update(contents_copy, query, - knot_changesets_get_last(chgs), - chgs->changes, rcode, new_serial); - if (ret != KNOT_EOK) { - dbg_ns("Failed to apply UPDATE to the zone copy or no update" - " made: %s\n", (ret < 0) ? knot_strerror(ret) - : "No change made."); - xfrin_rollback_update(old_contents, &contents_copy, - chgs->changes); - return ret; - } - - // 3) Finalize zone - dbg_ns_verb("Finalizing updated zone...\n"); - ret = xfrin_finalize_updated_zone(contents_copy, false); - if (ret != KNOT_EOK) { - dbg_ns("Failed to finalize updated zone: %s\n", - knot_strerror(ret)); - xfrin_rollback_update(old_contents, &contents_copy, - chgs->changes); - *rcode = (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR - : KNOT_RCODE_SERVFAIL; - return ret; - } - - *new_contents = contents_copy; - - return KNOT_EOK; + int ret = knot_ddns_process_update(old_zone->contents, query, + knot_changesets_get_last(chgs), + rcode, new_serial); + return ret; } static int replan_zone_sign_after_ddns(zone_t *zone, uint32_t refresh_at) @@ -311,7 +250,7 @@ static int zones_process_update_auth(struct query_data *qdata) return ret; } - // Process the UPDATE packet, apply to zone, create changesets. + // Process the UPDATE packet, create changesets. if (knot_changesets_create_changeset(chgsets) == NULL) { knot_changesets_free(&chgsets); free(msg); @@ -321,21 +260,36 @@ static int zones_process_update_auth(struct query_data *qdata) uint32_t new_serial = zones_next_serial(zone); - knot_zone_contents_t *new_contents = NULL; knot_zone_contents_t *old_contents = zone->contents; - ret = knot_ns_process_update(qdata->query, old_contents, &new_contents, - chgsets, &qdata->rcode, new_serial); + ret = knot_ns_process_update(qdata->query, zone, chgsets, &qdata->rcode, new_serial); if (ret != KNOT_EOK) { - if (ret > 0) { - log_zone_notice("%s: No change to zone made.\n", msg); - qdata->rcode = KNOT_RCODE_NOERROR; - } + knot_changesets_free(&chgsets); + free(msg); + return ret; + } + knot_zone_contents_t *new_contents = NULL; + const bool change_made = + !knot_changeset_is_empty(knot_changesets_get_last(chgsets)); + if (!change_made) { + log_zone_notice("%s: No change to zone made.\n", msg); + qdata->rcode = KNOT_RCODE_NOERROR; knot_changesets_free(&chgsets); free(msg); - return (ret < 0) ? ret : KNOT_EOK; + return KNOT_EOK; + } else { + ret = xfrin_apply_changesets(zone, chgsets, &new_contents); + if (ret != KNOT_EOK) { + log_zone_notice("%s: Failed to process: %s.\n", msg, knot_strerror(ret)); + qdata->rcode = KNOT_RCODE_SERVFAIL; + knot_changesets_free(&chgsets); + free(msg); + return ret; + } } + assert(new_contents); + knot_changesets_t *sec_chs = NULL; knot_changeset_t *sec_ch = NULL; uint32_t refresh_at = 0; @@ -344,8 +298,7 @@ static int zones_process_update_auth(struct query_data *qdata) sec_chs = knot_changesets_create(); sec_ch = knot_changesets_create_changeset(sec_chs); if (sec_chs == NULL || sec_ch == NULL) { - xfrin_rollback_update(old_contents, &new_contents, - chgsets->changes); + xfrin_rollback_update(chgsets, &new_contents); knot_changesets_free(&chgsets); free(msg); return KNOT_ENOMEM; @@ -368,17 +321,15 @@ static int zones_process_update_auth(struct query_data *qdata) } else { // Sign the created changeset ret = knot_dnssec_sign_changeset(new_contents, zone_config, - knot_changesets_get_last(chgsets), - sec_ch, KNOT_SOA_SERIAL_KEEP, - &refresh_at, - new_serial); + knot_changesets_get_last(chgsets), + sec_ch, KNOT_SOA_SERIAL_KEEP, + &refresh_at, new_serial); } if (ret != KNOT_EOK) { log_zone_error("%s: Failed to sign incoming update (%s)" "\n", msg, knot_strerror(ret)); - xfrin_rollback_update(old_contents, &new_contents, - chgsets->changes); + xfrin_rollback_update(chgsets, &new_contents); knot_changesets_free(&chgsets); knot_changesets_free(&sec_chs); free(msg); @@ -393,8 +344,7 @@ static int zones_process_update_auth(struct query_data *qdata) if (ret != KNOT_EOK) { log_zone_error("%s: Failed to save new entry to journal (%s)\n", msg, knot_strerror(ret)); - xfrin_rollback_update(old_contents, &new_contents, - chgsets->changes); + xfrin_rollback_update(chgsets, &new_contents); zones_free_merged_changesets(chgsets, sec_chs); free(msg); return ret; @@ -403,15 +353,18 @@ static int zones_process_update_auth(struct query_data *qdata) bool new_signatures = !knot_changeset_is_empty(sec_ch); // Apply DNSSEC changeset if (new_signatures) { - ret = xfrin_apply_changesets_dnssec_ddns(old_contents, - new_contents, - sec_chs, - chgsets); + ret = xfrin_apply_changesets_dnssec_ddns(zone, + new_contents, + sec_chs, + chgsets); if (ret != KNOT_EOK) { log_zone_error("%s: Failed to sign incoming update (%s)" "\n", msg, knot_strerror(ret)); zones_store_changesets_rollback(transaction); + xfrin_rollback_update(chgsets, &new_contents); + xfrin_rollback_update(sec_chs, &new_contents); zones_free_merged_changesets(chgsets, sec_chs); + free(msg); return ret; } @@ -422,7 +375,10 @@ static int zones_process_update_auth(struct query_data *qdata) log_zone_error("%s: Failed to replan zone sign (%s)\n", msg, knot_strerror(ret)); zones_store_changesets_rollback(transaction); + xfrin_rollback_update(chgsets, &new_contents); + xfrin_rollback_update(sec_chs, &new_contents); zones_free_merged_changesets(chgsets, sec_chs); + free(msg); return ret; } } else { @@ -430,9 +386,8 @@ static int zones_process_update_auth(struct query_data *qdata) ret = knot_zone_contents_adjust_nsec3_pointers(new_contents); if (ret != KNOT_EOK) { zones_store_changesets_rollback(transaction); + xfrin_rollback_update(chgsets, &new_contents); zones_free_merged_changesets(chgsets, sec_chs); - xfrin_rollback_update(old_contents, &new_contents, - chgsets->changes); free(msg); return ret; } @@ -444,8 +399,8 @@ static int zones_process_update_auth(struct query_data *qdata) if (ret != KNOT_EOK) { log_zone_error("%s: Failed to commit new journal entry " "(%s).\n", msg, knot_strerror(ret)); - xfrin_rollback_update(old_contents, &new_contents, - chgsets->changes); + xfrin_rollback_update(chgsets, &new_contents); + xfrin_rollback_update(sec_chs, &new_contents); zones_free_merged_changesets(chgsets, sec_chs); free(msg); return ret; @@ -458,8 +413,8 @@ static int zones_process_update_auth(struct query_data *qdata) log_zone_error("%s: Failed to replace current zone (%s)\n", msg, knot_strerror(ret)); // Cleanup old and new contents - xfrin_rollback_update(old_contents, &new_contents, - chgsets->changes); + xfrin_rollback_update(chgsets, &new_contents); + xfrin_rollback_update(sec_chs, &new_contents); /* Free changesets, but not the data. */ zones_free_merged_changesets(chgsets, sec_chs); @@ -467,10 +422,8 @@ static int zones_process_update_auth(struct query_data *qdata) } // Cleanup. - xfrin_cleanup_successful_update(chgsets->changes); - if (sec_chs) { - xfrin_cleanup_successful_update(sec_chs->changes); - } + xfrin_cleanup_successful_update(chgsets); + xfrin_cleanup_successful_update(sec_chs); // Free changesets, but not the data. zones_free_merged_changesets(chgsets, sec_chs); diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c index 1102404428ab623edbc8ec1835db04a26699c051..5efc59c9debc5c48b7c06102cc3e217733d103ef 100644 --- a/src/knot/server/notify.c +++ b/src/knot/server/notify.c @@ -51,8 +51,9 @@ int notify_create_request(const zone_t *zone, knot_pkt_t *pkt) knot_wire_set_aa(pkt->wire); knot_wire_set_opcode(pkt->wire, KNOT_OPCODE_NOTIFY); - const knot_rrset_t *soa_rr = knot_node_rrset(contents->apex, KNOT_RRTYPE_SOA); - return knot_pkt_put_question(pkt, soa_rr->owner, soa_rr->rclass, soa_rr->type); + knot_rrset_t soa_rr = knot_node_rrset(contents->apex, KNOT_RRTYPE_SOA); + assert(!knot_rrset_empty(&soa_rr)); + return knot_pkt_put_question(pkt, soa_rr.owner, soa_rr.rclass, soa_rr.type); } int notify_process_response(knot_pkt_t *notify, int msgid) @@ -93,9 +94,9 @@ int internet_notify(knot_pkt_t *pkt, struct query_data *qdata) unsigned serial = 0; const knot_pktsection_t *answer = knot_pkt_section(qdata->query, KNOT_ANSWER); if (answer->count > 0) { - const knot_rrset_t *soa = answer->rr[0]; - if (knot_rrset_type(soa) == KNOT_RRTYPE_SOA) { - serial = knot_rdata_soa_serial(soa); + const knot_rrset_t *soa = &answer->rr[0]; + if (soa->type == KNOT_RRTYPE_SOA) { + serial = knot_rrs_soa_serial(&soa->rrs); dbg_ns("%s: received serial %u\n", __func__, serial); } else { /* Ignore */ dbg_ns("%s: NOTIFY answer != SOA_RR\n", __func__); diff --git a/src/knot/server/serialization.c b/src/knot/server/serialization.c new file mode 100644 index 0000000000000000000000000000000000000000..097b0eff07176d07a72b22f0c04c64b2b9d14908 --- /dev/null +++ b/src/knot/server/serialization.c @@ -0,0 +1,196 @@ +/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include "knot/server/serialization.h" +#include "common/errcode.h" + +static size_t rr_binary_size(const knot_rrset_t *rrset, size_t rdata_pos) +{ + const knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, rdata_pos); + if (rr) { + // RR size + TTL + return knot_rr_rdata_size(rr) + sizeof(uint32_t); + } else { + return 0; + } +} + +static uint64_t rrset_binary_size(const knot_rrset_t *rrset) +{ + if (rrset == NULL || knot_rrset_rr_count(rrset) == 0) { + return 0; + } + uint64_t size = sizeof(uint64_t) + // size at the beginning + knot_dname_size(rrset->owner) + // owner data + sizeof(uint16_t) + // type + sizeof(uint16_t) + // class + sizeof(uint16_t); //RR count + uint16_t rdata_count = knot_rrset_rr_count(rrset); + for (uint16_t i = 0; i < rdata_count; i++) { + /* Space to store length of one RR. */ + size += sizeof(uint32_t); + /* Actual data. */ + size += rr_binary_size(rrset, i); + } + + return size; +} + +static void serialize_rr(const knot_rrset_t *rrset, size_t rdata_pos, + uint8_t *stream) +{ + const knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, rdata_pos); + assert(rr); + uint32_t ttl = knot_rr_ttl(rr); + memcpy(stream, &ttl, sizeof(uint32_t)); + memcpy(stream + sizeof(uint32_t), knot_rr_rdata(rr), knot_rr_rdata_size(rr)); +} + +static int deserialize_rr(knot_rrset_t *rrset, const uint8_t *stream, uint32_t rdata_size) +{ + uint32_t ttl; + memcpy(&ttl, stream, sizeof(uint32_t)); + return knot_rrset_add_rr(rrset, stream + sizeof(uint32_t), + rdata_size - sizeof(uint32_t), ttl, NULL); +} + +int changeset_binary_size(const knot_changeset_t *chgset, size_t *size) +{ + if (chgset == NULL || size == NULL) { + return KNOT_EINVAL; + } + + size_t soa_from_size = rrset_binary_size(chgset->soa_from); + size_t soa_to_size = rrset_binary_size(chgset->soa_to); + + size_t remove_size = 0; + knot_rr_ln_t *rr_node = NULL; + WALK_LIST(rr_node, chgset->remove) { + knot_rrset_t *rrset = rr_node->rr; + remove_size += rrset_binary_size(rrset); + } + + size_t add_size = 0; + WALK_LIST(rr_node, chgset->add) { + knot_rrset_t *rrset = rr_node->rr; + add_size += rrset_binary_size(rrset); + } + + *size = soa_from_size + soa_to_size + remove_size + add_size; + /* + Changeset flags. */ + *size += sizeof(uint32_t); + + return KNOT_EOK; +} + +int rrset_serialize(const knot_rrset_t *rrset, uint8_t *stream, size_t *size) +{ + if (rrset == NULL || rrset->rrs.data == NULL) { + return KNOT_EINVAL; + } + + uint64_t rrset_length = rrset_binary_size(rrset); + memcpy(stream, &rrset_length, sizeof(uint64_t)); + + size_t offset = sizeof(uint64_t); + /* Save RR count. */ + const uint16_t rr_count = knot_rrset_rr_count(rrset); + memcpy(stream + offset, &rr_count, sizeof(uint16_t)); + offset += sizeof(uint16_t); + /* Save owner. */ + offset += knot_dname_to_wire(stream + offset, rrset->owner, rrset_length - offset); + + /* Save static data. */ + memcpy(stream + offset, &rrset->type, sizeof(uint16_t)); + offset += sizeof(uint16_t); + memcpy(stream + offset, &rrset->rclass, sizeof(uint16_t)); + offset += sizeof(uint16_t); + + /* Copy RDATA. */ + for (uint16_t i = 0; i < rr_count; i++) { + uint32_t knot_rr_size = rr_binary_size(rrset, i); + memcpy(stream + offset, &knot_rr_size, sizeof(uint32_t)); + offset += sizeof(uint32_t); + serialize_rr(rrset, i, stream + offset); + offset += knot_rr_size; + } + + *size = offset; + assert(*size == rrset_length); + return KNOT_EOK; +} + +int rrset_deserialize(const uint8_t *stream, size_t *stream_size, + knot_rrset_t **rrset) +{ + if (sizeof(uint64_t) > *stream_size) { + return KNOT_ESPACE; + } + uint64_t rrset_length = 0; + memcpy(&rrset_length, stream, sizeof(uint64_t)); + if (rrset_length > *stream_size) { + return KNOT_ESPACE; + } + + size_t offset = sizeof(uint64_t); + uint16_t rdata_count = 0; + memcpy(&rdata_count, stream + offset, sizeof(uint16_t)); + offset += sizeof(uint16_t); + /* Read owner from the stream. */ + unsigned owner_size = knot_dname_size(stream + offset); + knot_dname_t *owner = knot_dname_copy_part(stream + offset, owner_size, NULL); + assert(owner); + offset += owner_size; + /* Read type. */ + uint16_t type = 0; + memcpy(&type, stream + offset, sizeof(uint16_t)); + offset += sizeof(uint16_t); + /* Read class. */ + uint16_t rclass = 0; + memcpy(&rclass, stream + offset, sizeof(uint16_t)); + offset += sizeof(uint16_t); + + /* Create new RRSet. */ + *rrset = knot_rrset_new(owner, type, rclass, NULL); + knot_dname_free(&owner, NULL); + if (*rrset == NULL) { + return KNOT_ENOMEM; + } + + /* Read RRs. */ + for (uint16_t i = 0; i < rdata_count; i++) { + /* + * There's always size of rdata in the beginning. + * Needed because of remainders. + */ + uint32_t rdata_size = 0; + memcpy(&rdata_size, stream + offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + int ret = deserialize_rr((*rrset), stream + offset, rdata_size); + if (ret != KNOT_EOK) { + knot_rrset_free(rrset, NULL); + return ret; + } + offset += rdata_size; + } + + *stream_size = *stream_size - offset; + + return KNOT_EOK; +} + diff --git a/src/knot/server/serialization.h b/src/knot/server/serialization.h new file mode 100644 index 0000000000000000000000000000000000000000..4627d60697e27876abd691a9876d24b25412f86e --- /dev/null +++ b/src/knot/server/serialization.h @@ -0,0 +1,65 @@ +/*! + * \file rr.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief API for changeset serialization. + * + * \addtogroup server + * @{ + */ +/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdint.h> +#include "libknot/rrset.h" +#include "knot/updates/changesets.h" + +/*! + * \brief Returns size of changeset in serialized form. + * + * \param chgset Changeset whose size we want to compute. + * \param size Output size parameter. + * + * \return KNOT_E* + */ +int changeset_binary_size(const knot_changeset_t *chgset, size_t *size); + +/*! + * \brief Serializes one RRSet into given stream. + * + * \param rrset RRSet to be serialized. + * \param stream Stream to store RRSet into. + * \param size Output size of serialized RRSet in the stream. + * + * \return KNOT_E* + */ +int rrset_serialize(const knot_rrset_t *rrset, uint8_t *stream, size_t *size); + +/*! + * \brief Deserializes RRSet from given stream. + * + * \param stream Stream containing serialized RRSet. + * \param stream_size Output stream size after RRSet has been deserialized. + * \param rrset Output deserialized rrset. + * + * \return KNOT_E* + */ +int rrset_deserialize(const uint8_t *stream, size_t *stream_size, + knot_rrset_t **rrset); + diff --git a/src/knot/server/zone-load.c b/src/knot/server/zone-load.c index 226df65026ff5d8239a5598ba565e7eb0a0539b8..6edf5f32284f91277a78b74131e93665f0979521 100644 --- a/src/knot/server/zone-load.c +++ b/src/knot/server/zone-load.c @@ -203,9 +203,9 @@ static void log_zone_load_info(const zone_t *zone, const char *zone_name, int64_t serial = 0; if (zone->contents && zone->contents->apex) { - const knot_rrset_t *soa; - soa = knot_node_rrset(zone->contents->apex, KNOT_RRTYPE_SOA); - serial = knot_rdata_soa_serial(soa); + const knot_rrs_t *soa = knot_node_rrs(zone->contents->apex, + KNOT_RRTYPE_SOA); + serial = knot_rrs_soa_serial(soa); } log_zone_info("Zone '%s' %s (serial %" PRId64 ")\n", zone_name, action, serial); @@ -386,7 +386,7 @@ static int zone_loader_thread(dthread_t *thread) return KNOT_ENOMEM; } zone_t *old_zone = knot_zonedb_find(ctx->db_old, apex); - knot_dname_free(&apex); + knot_dname_free(&apex, NULL); /* Update the zone. */ zone = update_zone(old_zone, zone_config, ctx->server); diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 3ae97a2d6027c4b9c5a02da0edc28b9069fc8bca..bd3538966f09d52ebc93d33ab19b62c1add7ea1f 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -27,6 +27,7 @@ #include "knot/server/xfr-handler.h" #include "knot/server/zone-load.h" #include "knot/server/zones.h" +#include "knot/server/serialization.h" #include "knot/zone/zone-dump.h" #include "libknot/dname.h" #include "libknot/dnssec/random.h" @@ -64,7 +65,7 @@ static uint32_t zones_jitter(uint32_t interval) * \param rr_func RDATA specificator. * \return Timer in miliseconds. */ -static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rrset_t*)) +static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rrs_t*)) { if (!zone) { dbg_zones_verb("zones: zones_soa_timer() called " @@ -75,7 +76,7 @@ static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rrs uint32_t ret = 0; /* Retrieve SOA RDATA. */ - const knot_rrset_t *soa_rrs = 0; + const knot_rrs_t *soa_rrs = NULL; rcu_read_lock(); @@ -85,7 +86,7 @@ static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rrs return 0; } - soa_rrs = knot_node_rrset(zc->apex, KNOT_RRTYPE_SOA); + soa_rrs = knot_node_rrs(zc->apex, KNOT_RRTYPE_SOA); assert(soa_rrs != NULL); ret = rr_func(soa_rrs); @@ -103,7 +104,7 @@ static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rrs */ static uint32_t zones_soa_refresh(zone_t *zone) { - return zones_soa_timer(zone, knot_rdata_soa_refresh); + return zones_soa_timer(zone, knot_rrs_soa_refresh); } /*! @@ -114,7 +115,7 @@ static uint32_t zones_soa_refresh(zone_t *zone) */ static uint32_t zones_soa_retry(zone_t *zone) { - return zones_soa_timer(zone, knot_rdata_soa_retry); + return zones_soa_timer(zone, knot_rrs_soa_retry); } /*! @@ -125,7 +126,7 @@ static uint32_t zones_soa_retry(zone_t *zone) */ static uint32_t zones_soa_expire(zone_t *zone) { - return zones_soa_timer(zone, knot_rdata_soa_expire); + return zones_soa_timer(zone, knot_rrs_soa_expire); } /*! @@ -506,9 +507,9 @@ int zones_changesets_from_binary(knot_changesets_t *chgsets) * be set, check it. */ dbg_xfr_verb("xfr: reading RRSets to REMOVE, first RR is %hu\n", - knot_rrset_type(rrset)); - assert(knot_rrset_type(rrset) == KNOT_RRTYPE_SOA); - assert(chs->serial_from == knot_rdata_soa_serial(rrset)); + rrset->type); + assert(rrset->type == KNOT_RRTYPE_SOA); + assert(chs->serial_from == knot_rrs_soa_serial(&rrset->rrs)); knot_changeset_add_soa(chs, rrset, KNOT_CHANGESET_REMOVE); /* Read remaining RRSets */ @@ -527,7 +528,7 @@ int zones_changesets_from_binary(knot_changesets_t *chgsets) } /* Check for next SOA. */ - if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { + if (rrset->type == KNOT_RRTYPE_SOA) { /* Move to ADD section if in REMOVE. */ if (in_remove_section) { @@ -710,14 +711,8 @@ void zones_free_merged_changesets(knot_changesets_t *diff_chs, knot_changesets_free(&sec_chs); knot_changesets_free(&diff_chs); } else { - /*! - * Ending SOA from the merged changeset was used in - * zone (same as in DNSSEC changeset). It must not - * be freed. - */ assert(knot_changesets_get_last(diff_chs)->serial_to == knot_changesets_get_last(sec_chs)->serial_to); - knot_changesets_get_last(diff_chs)->soa_to = NULL; knot_changesets_free(&diff_chs); /*! @@ -831,14 +826,14 @@ static bool apex_rr_changed(const knot_zone_contents_t *old_contents, const knot_zone_contents_t *new_contents, uint16_t type) { - const knot_rrset_t *old_rr = knot_node_rrset(old_contents->apex, type); - const knot_rrset_t *new_rr = knot_node_rrset(new_contents->apex, type); - if (old_rr== NULL) { - return new_rr != NULL; - } else if (new_rr == NULL) { - return old_rr != NULL; - } - return !knot_rrset_equal(old_rr, new_rr, KNOT_RRSET_COMPARE_WHOLE); + knot_rrset_t old_rr = knot_node_rrset(old_contents->apex, type); + knot_rrset_t new_rr = knot_node_rrset(new_contents->apex, type); + if (knot_rrset_empty(&old_rr)) { + return !knot_rrset_empty(&new_rr); + } else if (knot_rrset_empty(&new_rr)) { + return !knot_rrset_empty(&old_rr); + } + return !knot_rrset_equal(&old_rr, &new_rr, KNOT_RRSET_COMPARE_WHOLE); } bool zones_dnskey_changed(const knot_zone_contents_t *old_contents, @@ -853,8 +848,6 @@ bool zones_nsec3param_changed(const knot_zone_contents_t *old_contents, return apex_rr_changed(old_contents, new_contents, KNOT_RRTYPE_NSEC3PARAM); } - - /*----------------------------------------------------------------------------*/ static int zones_open_free_filename(const char *old_name, char **new_name) @@ -958,11 +951,11 @@ int zones_zonefile_sync(zone_t *zone, journal_t *journal) } /* Latest zone serial. */ - const knot_rrset_t *soa_rrs = 0; - soa_rrs = knot_node_rrset(contents->apex, KNOT_RRTYPE_SOA); + const knot_rrs_t *soa_rrs = knot_node_rrs(contents->apex, + KNOT_RRTYPE_SOA); assert(soa_rrs != NULL); - int64_t serial_ret = knot_rdata_soa_serial(soa_rrs); + int64_t serial_ret = knot_rrs_soa_serial(soa_rrs); if (serial_ret < 0) { rcu_read_unlock(); pthread_mutex_unlock(&zone->lock); @@ -1161,7 +1154,7 @@ int zones_save_zone(const knot_ns_xfr_t *xfr) const knot_dname_t *new_name = NULL; new_name = knot_node_owner(knot_zone_contents_apex(new_zone)); int r = knot_dname_cmp(cur_name, new_name); - knot_dname_free(&cur_name); + knot_dname_free(&cur_name, NULL); if (r != 0) { rcu_read_unlock(); return KNOT_EINVAL; @@ -1175,40 +1168,6 @@ int zones_save_zone(const knot_ns_xfr_t *xfr) return ret; } -/*----------------------------------------------------------------------------*/ -/* Counting size of changeset in serialized form. */ -/*----------------------------------------------------------------------------*/ - -int zones_changeset_binary_size(const knot_changeset_t *chgset, size_t *size) -{ - if (chgset == NULL || size == NULL) { - return KNOT_EINVAL; - } - - size_t soa_from_size = rrset_binary_size(chgset->soa_from); - size_t soa_to_size = rrset_binary_size(chgset->soa_to); - - size_t remove_size = 0; - knot_rr_ln_t *rr_node = NULL; - WALK_LIST(rr_node, chgset->remove) { - knot_rrset_t *rrset = rr_node->rr; - remove_size += rrset_binary_size(rrset); - } - - size_t add_size = 0; - WALK_LIST(rr_node, chgset->add) { - knot_rrset_t *rrset = rr_node->rr; - add_size += rrset_binary_size(rrset); - } - - /*! \todo How is the changeset serialized? Any other parts? */ - *size = soa_from_size + soa_to_size + remove_size + add_size; - /* + Changeset flags. */ - *size += sizeof(uint32_t); - - return KNOT_EOK; -} - /*----------------------------------------------------------------------------*/ /* Changeset serialization and storing (new) */ /*----------------------------------------------------------------------------*/ @@ -1239,7 +1198,7 @@ static int zones_serialize_and_store_chgset(const knot_changeset_t *chs, int ret = zones_rrset_write_to_mem(chs->soa_from, &entry, &max_size); if (ret != KNOT_EOK) { dbg_zones("%s:%d ret = %s\n", __func__, __LINE__, knot_strerror(ret)); - return KNOT_ERROR; /*! \todo Other code? */ + return ret; } /* Serialize RRSets from the 'remove' section. */ @@ -1249,7 +1208,7 @@ static int zones_serialize_and_store_chgset(const knot_changeset_t *chs, ret = zones_rrset_write_to_mem(rrset, &entry, &max_size); if (ret != KNOT_EOK) { dbg_zones("%s:%d ret = %s\n", __func__, __LINE__, knot_strerror(ret)); - return KNOT_ERROR; /*! \todo Other code? */ + return ret; } } @@ -1257,7 +1216,7 @@ static int zones_serialize_and_store_chgset(const knot_changeset_t *chs, ret = zones_rrset_write_to_mem(chs->soa_to, &entry, &max_size); if (ret != KNOT_EOK) { dbg_zones("%s:%d ret = %s\n", __func__, __LINE__, knot_strerror(ret)); - return KNOT_ERROR; /*! \todo Other code? */ + return ret; } /* Serialize RRSets from the 'add' section. */ @@ -1266,7 +1225,7 @@ static int zones_serialize_and_store_chgset(const knot_changeset_t *chs, ret = zones_rrset_write_to_mem(rrset, &entry, &max_size); if (ret != KNOT_EOK) { dbg_zones("%s:%d ret = %s\n", __func__, __LINE__, knot_strerror(ret)); - return KNOT_ERROR; /*! \todo Other code? */ + return ret; } } @@ -1290,7 +1249,7 @@ static int zones_store_changeset(const knot_changeset_t *chs, journal_t *j, /* Count the size of the entire changeset in serialized form. */ size_t entry_size = 0; - int ret = zones_changeset_binary_size(chs, &entry_size); + int ret = changeset_binary_size(chs, &entry_size); assert(ret == KNOT_EOK); dbg_xfr_verb("Size in serialized form: %zu\n", entry_size); @@ -1478,8 +1437,7 @@ int zones_store_and_apply_chgsets(knot_changesets_t *chs, /* Commit transaction. */ ret = zones_store_changesets_commit(transaction); if (ret != KNOT_EOK) { - xfrin_rollback_update(zone->contents, new_contents, - chs->changes); + xfrin_rollback_update(chs, new_contents); log_zone_error("%s Failed to commit stored changesets.\n", msgpref); knot_changesets_free(&chs); return ret; @@ -1495,15 +1453,14 @@ int zones_store_and_apply_chgsets(knot_changesets_t *chs, if (switch_ret != KNOT_EOK) { log_zone_error("%s Failed to replace current zone.\n", msgpref); // Cleanup old and new contents - xfrin_rollback_update(zone->contents, new_contents, - chs->changes); + xfrin_rollback_update(chs, new_contents); /* Free changesets, but not the data. */ knot_changesets_free(&chs); return KNOT_ERROR; } - xfrin_cleanup_successful_update(chs->changes); + xfrin_cleanup_successful_update(chs); /* Free changesets, but not the data. */ knot_changesets_free(&chs); @@ -1779,7 +1736,7 @@ int zones_verify_tsig_query(const knot_pkt_t *query, return KNOT_TSIG_EBADKEY; } - const knot_dname_t *kname = knot_rrset_owner(query->tsig_rr); + const knot_dname_t *kname = query->tsig_rr->owner; assert(kname != NULL); /* @@ -1879,10 +1836,10 @@ int zones_journal_apply(zone_t *zone) } /* Fetch SOA serial. */ - const knot_rrset_t *soa_rrs = 0; - soa_rrs = knot_node_rrset(contents->apex, KNOT_RRTYPE_SOA); + const knot_rrs_t *soa_rrs = 0; + soa_rrs = knot_node_rrs(contents->apex, KNOT_RRTYPE_SOA); assert(soa_rrs != NULL); - int64_t serial_ret = knot_rdata_soa_serial(soa_rrs); + int64_t serial_ret = knot_rrs_soa_serial(soa_rrs); if (serial_ret < 0) { rcu_read_unlock(); return KNOT_EINVAL; @@ -1930,8 +1887,7 @@ int zones_journal_apply(zone_t *zone) XFR_TYPE_IIN); rcu_read_lock(); if (apply_ret == KNOT_EOK) { - xfrin_cleanup_successful_update( - chsets->changes); + xfrin_cleanup_successful_update(chsets); } else { log_zone_error("Failed to apply " "changesets to '%s' - Switch failed: " @@ -1940,9 +1896,8 @@ int zones_journal_apply(zone_t *zone) ret = KNOT_ERROR; // Cleanup old and new contents - xfrin_rollback_update(zone->contents, - &contents, - chsets->changes); + xfrin_rollback_update(chsets, + &contents); } } } @@ -2023,10 +1978,7 @@ static int diff_after_load(zone_t *zone, zone_t *old_zone, if (*diff_chs != NULL) { assert(!zones_changesets_empty(*diff_chs)); /* Apply DNSSEC changeset to the new zone. */ - ret = xfrin_apply_changesets_directly(zone->contents, - (*diff_chs)->changes, - *diff_chs); - + ret = xfrin_apply_changesets_directly(zone->contents, *diff_chs); if (ret == KNOT_EOK) { ret = xfrin_finalize_updated_zone( zone->contents, true); @@ -2042,7 +1994,7 @@ static int diff_after_load(zone_t *zone, zone_t *old_zone, return ret; } - xfrin_cleanup_successful_update((*diff_chs)->changes); + xfrin_cleanup_successful_update(*diff_chs); knot_changesets_free(diff_chs); assert(zone->conf->build_diffs); } @@ -2113,7 +2065,6 @@ static int store_chgsets_after_load(zone_t *old_zone, zone_t *zone, assert(!old_zone || old_zone->contents != zone->contents); ret = xfrin_apply_changesets_directly(zone->contents, - diff_chs->changes, diff_chs); if (ret == KNOT_EOK) { ret = xfrin_finalize_updated_zone( @@ -2137,7 +2088,7 @@ static int store_chgsets_after_load(zone_t *old_zone, zone_t *zone, return ret; } - xfrin_cleanup_successful_update(diff_chs->changes); + xfrin_cleanup_successful_update(diff_chs); } /* Commit transaction. */ @@ -2166,8 +2117,7 @@ static int store_chgsets_after_load(zone_t *old_zone, zone_t *zone, "switching zone (%s).\n", zone->conf->name, knot_strerror(ret)); // Cleanup old and new contents - xfrin_rollback_update(zone->contents, &new_contents, - diff_chs->changes); + xfrin_rollback_update(diff_chs, &new_contents); return ret; } diff --git a/src/knot/updates/changesets.c b/src/knot/updates/changesets.c index 23d21100bc84901668d135a0f7ce7bcf640ec272..0acb99476a8b1e9062ee1b2e537f8cb4e5af75a8 100644 --- a/src/knot/updates/changesets.c +++ b/src/knot/updates/changesets.c @@ -27,12 +27,6 @@ #include "common/debug.h" #include "libknot/rdata.h" -static int knot_changeset_rrsets_match(const knot_rrset_t *rrset1, - const knot_rrset_t *rrset2) -{ - return knot_rrset_equal(rrset1, rrset2, KNOT_RRSET_COMPARE_HEADER); -} - int knot_changesets_init(knot_changesets_t **changesets) { // Create new changesets structure @@ -54,14 +48,6 @@ int knot_changesets_init(knot_changesets_t **changesets) // Init list with changesets init_list(&(*changesets)->sets); - // Init changes structure - (*changesets)->changes = xmalloc(sizeof(knot_changes_t)); - // Init changes' allocator (storing RRs) - (*changesets)->changes->mem_ctx = (*changesets)->mmc_rr; - // Init changes' lists - init_list(&(*changesets)->changes->new_rrsets); - init_list(&(*changesets)->changes->old_rrsets); - return KNOT_EOK; } @@ -98,6 +84,10 @@ knot_changeset_t *knot_changesets_create_changeset(knot_changesets_t *ch) init_list(&set->add); init_list(&set->remove); + // Init change lists + init_list(&set->new_data); + init_list(&set->old_data); + // Insert into list of sets add_tail(&ch->sets, (node_t *)set); @@ -115,24 +105,6 @@ knot_changeset_t *knot_changesets_get_last(const knot_changesets_t *chs) return (knot_changeset_t *)(TAIL(chs->sets)); } -const knot_rrset_t *knot_changeset_last_rr(const knot_changeset_t *ch, - knot_changeset_part_t part) -{ - if (ch == NULL) { - return NULL; - } - - if (part == KNOT_CHANGESET_ADD) { - knot_rr_ln_t *n = TAIL(ch->add); - return n ? n->rr : NULL; - } else if (part == KNOT_CHANGESET_REMOVE) { - knot_rr_ln_t *n = TAIL(ch->remove); - return n ? n->rr : NULL; - } - - return NULL; -} - int knot_changeset_add_rrset(knot_changeset_t *chgs, knot_rrset_t *rrset, knot_changeset_part_t part) { @@ -155,60 +127,11 @@ int knot_changeset_add_rrset(knot_changeset_t *chgs, knot_rrset_t *rrset, return KNOT_EOK; } -int knot_changeset_add_rr(knot_changeset_t *chgs, knot_rrset_t *rr, - knot_changeset_part_t part) -{ - // Just check the last RRSet. If the RR belongs to it, merge it, - // otherwise just add the RR to the end of the list - list_t *l = part == KNOT_CHANGESET_ADD ? &(chgs->add) : &(chgs->remove); - knot_rrset_t *tail_rr = - EMPTY_LIST(*l) ? NULL : ((knot_rr_ln_t *)(TAIL(*l)))->rr; - - if (tail_rr && knot_changeset_rrsets_match(tail_rr, rr)) { - // Create changesets exactly as they came, with possibly - // duplicate records - if (knot_rrset_merge(tail_rr, rr, NULL) != KNOT_EOK) { - return KNOT_ERROR; - } - - knot_rrset_free(&rr, NULL); - return KNOT_EOK; - } else { - return knot_changeset_add_rrset(chgs, rr, part); - } -} - -int knot_changes_add_rrset(knot_changes_t *ch, knot_rrset_t *rrset, - knot_changes_part_t part) -{ - if (ch == NULL || rrset == NULL) { - return KNOT_EINVAL; - } - - knot_rr_ln_t *rr_node = - ch->mem_ctx.alloc(ch->mem_ctx.ctx, sizeof(knot_rr_ln_t)); - if (rr_node == NULL) { - // This will not happen with mp_alloc, but allocator can change - ERR_ALLOC_FAILED; - return KNOT_ENOMEM; - } - rr_node->rr = rrset; - - if (part == KNOT_CHANGES_NEW) { - add_tail(&ch->new_rrsets, (node_t *)rr_node); - } else { - assert(part == KNOT_CHANGES_OLD); - add_tail(&ch->old_rrsets, (node_t *)rr_node); - } - - return KNOT_EOK; -} - static void knot_changeset_store_soa(knot_rrset_t **chg_soa, uint32_t *chg_serial, knot_rrset_t *soa) { *chg_soa = soa; - *chg_serial = knot_rdata_soa_serial(soa); + *chg_serial = knot_rrs_soa_serial(&soa->rrs); } void knot_changeset_add_soa(knot_changeset_t *changeset, knot_rrset_t *soa, @@ -337,7 +260,6 @@ void knot_changesets_free(knot_changesets_t **changesets) knot_rrset_free(&(*changesets)->first_soa, NULL); - free((*changesets)->changes); free(*changesets); *changesets = NULL; } diff --git a/src/knot/updates/changesets.h b/src/knot/updates/changesets.h index f1a893ac74c9bf60aa0517285f48cb01cf478963..e17819a8e3c35ae89dcaed5e92034a1ed1024f20 100644 --- a/src/knot/updates/changesets.h +++ b/src/knot/updates/changesets.h @@ -41,7 +41,6 @@ typedef enum { KNOT_CHANGESET_TYPE_DNSSEC = 1 << 2 } knot_changeset_flag_t; - /*! \brief One changeset received from wire, with parsed RRs. */ typedef struct knot_changeset { node_t n; /*!< List node. */ @@ -55,6 +54,8 @@ typedef struct knot_changeset { uint32_t serial_from; /*!< SOA start serial. */ uint32_t serial_to; /*!< SOA destination serial. */ uint32_t flags; /*!< DDNS / IXFR flags. */ + list_t old_data; /*!< Old data, to be freed after succesfull update. */ + list_t new_data; /*!< New data, to be freed after failed update. */ } knot_changeset_t; /*----------------------------------------------------------------------------*/ @@ -65,23 +66,6 @@ typedef struct knot_rr_ln { knot_rrset_t *rr; /*!< Actual usable data. */ } knot_rr_ln_t; -/*! \brief Partial changes done to zones - used for update/transfer rollback. */ -typedef struct { - /*! - * Memory context. Ideally a pool allocator since there is a possibility - * of many changes in one transfer/update. - */ - mm_ctx_t mem_ctx; - /*! - * Deleted after successful update. - */ - list_t old_rrsets; - /*! - * Deleted after failed update. - */ - list_t new_rrsets; -} knot_changes_t; - /*----------------------------------------------------------------------------*/ /*! @@ -95,7 +79,6 @@ typedef struct { size_t count; /*!< Changeset count. */ knot_rrset_t *first_soa; /*!< First received SOA. */ uint32_t flags; /*!< DDNS / IXFR flags. */ - knot_changes_t *changes; /*!< Partial changes. */ } knot_changesets_t; /*----------------------------------------------------------------------------*/ @@ -105,11 +88,6 @@ typedef enum { KNOT_CHANGESET_REMOVE } knot_changeset_part_t; -typedef enum { - KNOT_CHANGES_OLD, - KNOT_CHANGES_NEW, -} knot_changes_part_t; - /*----------------------------------------------------------------------------*/ /*! @@ -156,9 +134,6 @@ knot_changeset_t *knot_changesets_create_changeset(knot_changesets_t *ch); */ knot_changeset_t *knot_changesets_get_last(const knot_changesets_t *ch); -const knot_rrset_t *knot_changeset_last_rr(const knot_changeset_t *ch, - knot_changeset_part_t part); - /*! * \brief Add RRSet to changeset. RRSet is either inserted to 'add' or to * 'remove' list. Will *not* try to merge with previous RRSets. @@ -173,20 +148,6 @@ const knot_rrset_t *knot_changeset_last_rr(const knot_changeset_t *ch, int knot_changeset_add_rrset(knot_changeset_t *chgs, knot_rrset_t *rrset, knot_changeset_part_t part); -/*! - * \brief Add RRSet to changeset. RRSet is either inserted to 'add' or to - * 'remove' list. *Will* try to merge with previous RRSets. - * - * \param chgs Changeset to add RRSet into. - * \param rrset RRSet to be added. - * \param part Add to 'add' or 'remove'? - * - * \retval KNOT_EOK on success. - * \retval Error code on failure. - */ -int knot_changeset_add_rr(knot_changeset_t *chgs, - knot_rrset_t *rrset, knot_changeset_part_t part); - /*! * \brief Adds a source/destination SOA RRSet to changeset. * @@ -246,20 +207,6 @@ int knot_changeset_apply(knot_changeset_t *changeset, */ void knot_changesets_free(knot_changesets_t **changesets); -/*! - * \brief Add RRSet to changes structure. - * RRSet is either inserted to 'old' or to 'new' list. - * - * \param chgs Change to add RRSet into. - * \param rrset RRSet to be added. - * \param part Add to 'old' or 'new'? - * - * \retval KNOT_EOK on success. - * \retval Error code on failure. - */ -int knot_changes_add_rrset(knot_changes_t *ch, knot_rrset_t *rrset, - knot_changes_part_t part); - /*! * \brief Merges two changesets together, second changeset's lists are kept. * @@ -275,11 +222,6 @@ int knot_changes_add_rrset(knot_changes_t *ch, knot_rrset_t *rrset, */ int knot_changeset_merge(knot_changeset_t *ch1, knot_changeset_t *ch2); -/*! - * \param changes Double pointer of changes structure to be freed. - */ -void knot_changes_free(knot_changes_t **changes); - #endif /* _KNOT_CHANGESETS_H_ */ /*! @} */ diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c index a6ffa47f65a5930b5fef20432202b9b7895d8276..f8637a7f36d7863f1e38bc0eb2d2de9ce6c52579 100644 --- a/src/knot/updates/ddns.c +++ b/src/knot/updates/ddns.c @@ -29,199 +29,56 @@ #include "libknot/consts.h" #include "common/mempattern.h" #include "common/descriptor.h" +#include "common/lists.h" -static bool rrset_empty(const knot_rrset_t *rrset) -{ - uint16_t rr_count = knot_rrset_rr_count(rrset); - if (rr_count == 0) { - return true; - } - if (rr_count == 1) { - return knot_rrset_rr_size(rrset, 0) == 0; - } - return false; -} +/* ----------------------------- prereq check ------------------------------- */ -/*----------------------------------------------------------------------------*/ -// Copied from XFR - maybe extract somewhere else -static int knot_ddns_prereq_check_rrsets(knot_rrset_t ***rrsets, - size_t *count, size_t *allocated) +/*!< \brief Clears prereq RRSet list. */ +static void rrset_list_clear(list_t *l) { - /* This is really confusing, it's ptr -> array of "knot_rrset_t*" */ - char *arr = (char*)*rrsets; - int ret = 0; - ret = mreserve(&arr, sizeof(knot_rrset_t*), *count + 1, 0, allocated); - if (ret < 0) { - return KNOT_ENOMEM; - } - - *rrsets = (knot_rrset_t**)arr; - - return KNOT_EOK; + node_t *n, *nxt; + WALK_LIST_DELSAFE(n, nxt, *l) { + ptrnode_t *ptr_n = (ptrnode_t *)n; + knot_rrset_t *rrset = (knot_rrset_t *)ptr_n->d; + knot_rrset_free(&rrset, NULL); + free(n); + }; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_prereq_check_dnames(knot_dname_t ***dnames, - size_t *count, size_t *allocated) +/*!< \brief Adds RR to prereq RRSet list, merges RRs into RRSets. */ +static int add_rr_to_list(list_t *l, const knot_rrset_t *rr) { - /* This is really confusing, it's ptr -> array of "knot_dname_t*" */ - char *arr = (char*)*dnames; - int ret = 0; - ret = mreserve(&arr, sizeof(knot_dname_t*), *count + 1, 0, allocated); - if (ret < 0) { - return KNOT_ENOMEM; - } - - *dnames = (knot_dname_t**)arr; - - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_add_prereq_rrset(const knot_rrset_t *rrset, - knot_rrset_t ***rrsets, - size_t *count, size_t *allocd) -{ - // check if such RRSet is not already there and merge if needed - int ret; - for (int i = 0; i < *count; ++i) { - if (knot_rrset_equal(rrset, (*rrsets)[i], - KNOT_RRSET_COMPARE_HEADER)) { - ret = knot_rrset_merge((*rrsets)[i], rrset, NULL); - if (ret != KNOT_EOK) { - return ret; - } else { - return KNOT_EOK; - } + node_t *n; + WALK_LIST(n, *l) { + ptrnode_t *ptr_n = (ptrnode_t *)n; + knot_rrset_t *rrset = (knot_rrset_t *)ptr_n->d; + if (knot_rrset_equal(rr, rrset, KNOT_RRSET_COMPARE_HEADER)) { + return knot_rrs_merge(&rrset->rrs, &rr->rrs, NULL); } - } - - // if we are here, the RRSet was not found - ret = knot_ddns_prereq_check_rrsets(rrsets, count, allocd); - if (ret != KNOT_EOK) { - return ret; - } - - knot_rrset_t *new_rrset = NULL; - ret = knot_rrset_copy(rrset, &new_rrset, NULL); - if (ret != KNOT_EOK) { - return ret; - } - - (*rrsets)[(*count)++] = new_rrset; - - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ + }; -static int knot_ddns_add_prereq_dname(const knot_dname_t *dname, - knot_dname_t ***dnames, - size_t *count, size_t *allocd) -{ - // we do not have to check if the name is not already there - // if it is, we will just check it twice in the zone - - int ret = knot_ddns_prereq_check_dnames(dnames, count, allocd); - if (ret != KNOT_EOK) { - return ret; - } - - knot_dname_t *dname_new = knot_dname_copy(dname); - if (dname_new == NULL) { + knot_rrset_t *rr_copy = knot_rrset_copy(rr, NULL); + if (rr_copy == NULL) { return KNOT_ENOMEM; } - - (*dnames)[(*count)++] = dname_new; - - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_add_prereq(knot_ddns_prereq_t *prereqs, - const knot_rrset_t *rrset, uint16_t qclass) -{ - assert(prereqs != NULL); - assert(rrset != NULL); - - if (knot_rrset_rr_ttl(rrset, 0) != 0) { - dbg_ddns("ddns: add_prereq: Wrong TTL.\n"); - return KNOT_EMALF; - } - - int ret; - - if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) { - if (!rrset_empty(rrset)) { - dbg_ddns("ddns: add_prereq: Extra data\n"); - return KNOT_EMALF; - } - if (knot_rrset_type(rrset) == KNOT_RRTYPE_ANY) { - ret = knot_ddns_add_prereq_dname( - knot_rrset_owner(rrset), &prereqs->in_use, - &prereqs->in_use_count, - &prereqs->in_use_allocd); - } else { - ret = knot_ddns_add_prereq_rrset(rrset, - &prereqs->exist, - &prereqs->exist_count, - &prereqs->exist_allocd); - } - } else if (knot_rrset_class(rrset) == KNOT_CLASS_NONE) { - if (!rrset_empty(rrset)) { - dbg_ddns("ddns: add_prereq: Extra data\n"); - return KNOT_EMALF; - } - if (knot_rrset_type(rrset) == KNOT_RRTYPE_ANY) { - ret = knot_ddns_add_prereq_dname( - knot_rrset_owner(rrset), &prereqs->not_in_use, - &prereqs->not_in_use_count, - &prereqs->not_in_use_allocd); - } else { - ret = knot_ddns_add_prereq_rrset(rrset, - &prereqs->not_exist, - &prereqs->not_exist_count, - &prereqs->not_exist_allocd); - } - } else if (knot_rrset_class(rrset) == qclass) { - ret = knot_ddns_add_prereq_rrset(rrset, - &prereqs->exist_full, - &prereqs->exist_full_count, - &prereqs->exist_full_allocd); - } else { - dbg_ddns("ddns: add_prereq: Bad class.\n"); - return KNOT_EMALF; - } - - return ret; + return ptrlist_add(l, rr_copy, NULL) != NULL ? KNOT_EOK : KNOT_ENOMEM; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_check_exist(const knot_zone_contents_t *zone, - const knot_rrset_t *rrset, uint16_t *rcode) +/*!< \brief Checks whether RR type exists in the zone. */ +static int check_type_exist(const knot_zone_contents_t *zone, + const knot_rrset_t *rrset, uint16_t *rcode) { assert(zone != NULL); assert(rrset != NULL); assert(rcode != NULL); - assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY); - assert(knot_rrset_class(rrset) == KNOT_CLASS_ANY); - - if (!knot_dname_is_sub(knot_rrset_owner(rrset), - knot_node_owner(knot_zone_contents_apex(zone)))) { - *rcode = KNOT_RCODE_NOTZONE; - return KNOT_EOUTOFZONE; - } + assert(rrset->type != KNOT_RRTYPE_ANY); + assert(rrset->rclass == KNOT_CLASS_ANY); - const knot_node_t *node; - node = knot_zone_contents_find_node(zone, knot_rrset_owner(rrset)); + const knot_node_t *node = knot_zone_contents_find_node(zone, rrset->owner); if (node == NULL) { *rcode = KNOT_RCODE_NXRRSET; return KNOT_ENONODE; - } else if (knot_node_rrset(node, knot_rrset_type(rrset)) == NULL) { + } else if (!knot_node_rrtype_exists(node, rrset->type)) { *rcode = KNOT_RCODE_NXRRSET; return KNOT_ENORRSET; } @@ -229,40 +86,26 @@ static int knot_ddns_check_exist(const knot_zone_contents_t *zone, return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_check_exist_full(const knot_zone_contents_t *zone, - const knot_rrset_t *rrset, - uint16_t *rcode) +/*!< \brief Checks whether RRSet exists in the zone. */ +static int check_rrset_exists(const knot_zone_contents_t *zone, + const knot_rrset_t *rrset, uint16_t *rcode) { assert(zone != NULL); assert(rrset != NULL); assert(rcode != NULL); - assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY); - - if (!knot_dname_is_sub(knot_rrset_owner(rrset), - knot_node_owner(knot_zone_contents_apex(zone)))) { - *rcode = KNOT_RCODE_NOTZONE; - return KNOT_EOUTOFZONE; - } - - const knot_node_t *node; - const knot_rrset_t *found; + assert(rrset->type != KNOT_RRTYPE_ANY); - node = knot_zone_contents_find_node(zone, knot_rrset_owner(rrset)); + const knot_node_t *node = knot_zone_contents_find_node(zone, rrset->owner); if (node == NULL) { *rcode = KNOT_RCODE_NXRRSET; return KNOT_EPREREQ; - } else if ((found = knot_node_rrset(node, knot_rrset_type(rrset))) - == NULL) { + } else if (!knot_node_rrtype_exists(node, rrset->type)) { *rcode = KNOT_RCODE_NXRRSET; return KNOT_EPREREQ; } else { - // do not have to compare the header, it is already done - assert(knot_rrset_type(found) == knot_rrset_type(rrset)); - assert(knot_dname_cmp(knot_rrset_owner(found), - knot_rrset_owner(rrset)) == 0); - if (!knot_rrset_equal(found, rrset, KNOT_RRSET_COMPARE_WHOLE)) { + knot_rrset_t found = knot_node_rrset(node, rrset->type); + assert(!knot_rrset_empty(&found)); + if (!knot_rrset_equal(&found, rrset, KNOT_RRSET_COMPARE_WHOLE)) { *rcode = KNOT_RCODE_NXRRSET; return KNOT_EPREREQ; } @@ -271,58 +114,53 @@ static int knot_ddns_check_exist_full(const knot_zone_contents_t *zone, return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ +/*!< \brief Checks whether RRSets in the list exist in the zone. */ +static int check_stored_rrsets(list_t *l, const knot_zone_contents_t *zone, + uint16_t *rcode) +{ + node_t *n; + WALK_LIST(n, *l) { + ptrnode_t *ptr_n = (ptrnode_t *)n; + knot_rrset_t *rrset = (knot_rrset_t *)ptr_n->d; + int ret = check_rrset_exists(zone, rrset, rcode); + if (ret != KNOT_EOK) { + return ret; + } + }; -static int knot_ddns_check_not_exist(const knot_zone_contents_t *zone, - const knot_rrset_t *rrset, - uint16_t *rcode) + return KNOT_EOK; +} + +/*!< \brief Checks whether RR type is not in the zone. */ +static int check_type_not_exist(const knot_zone_contents_t *zone, + const knot_rrset_t *rrset, uint16_t *rcode) { assert(zone != NULL); assert(rrset != NULL); assert(rcode != NULL); - assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY); - assert(knot_rrset_class(rrset) == KNOT_CLASS_NONE); - - if (!knot_dname_is_sub(knot_rrset_owner(rrset), - knot_node_owner(knot_zone_contents_apex(zone)))) { - *rcode = KNOT_RCODE_NOTZONE; - return KNOT_EOUTOFZONE; - } - - const knot_node_t *node; + assert(rrset->type != KNOT_RRTYPE_ANY); + assert(rrset->rclass == KNOT_CLASS_NONE); - node = knot_zone_contents_find_node(zone, knot_rrset_owner(rrset)); + const knot_node_t *node = knot_zone_contents_find_node(zone, rrset->owner); if (node == NULL) { return KNOT_EOK; - } else if (knot_node_rrset(node, knot_rrset_type(rrset)) == NULL) { + } else if (!knot_node_rrtype_exists(node, rrset->type)) { return KNOT_EOK; } - /* RDATA is always empty for simple RRset checks. */ - *rcode = KNOT_RCODE_YXRRSET; return KNOT_EPREREQ; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_check_in_use(const knot_zone_contents_t *zone, - const knot_dname_t *dname, - uint16_t *rcode) +/*!< \brief Checks whether DNAME is in the zone. */ +static int check_in_use(const knot_zone_contents_t *zone, + const knot_dname_t *dname, uint16_t *rcode) { assert(zone != NULL); assert(dname != NULL); assert(rcode != NULL); - if (!knot_dname_is_sub(dname, - knot_node_owner(knot_zone_contents_apex(zone)))) { - *rcode = KNOT_RCODE_NOTZONE; - return KNOT_EOUTOFZONE; - } - - const knot_node_t *node; - - node = knot_zone_contents_find_node(zone, dname); + const knot_node_t *node = knot_zone_contents_find_node(zone, dname); if (node == NULL) { *rcode = KNOT_RCODE_NXDOMAIN; return KNOT_EPREREQ; @@ -334,25 +172,15 @@ static int knot_ddns_check_in_use(const knot_zone_contents_t *zone, return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_check_not_in_use(const knot_zone_contents_t *zone, - const knot_dname_t *dname, - uint16_t *rcode) +/*!< \brief Checks whether DNAME is not in the zone. */ +static int check_not_in_use(const knot_zone_contents_t *zone, + const knot_dname_t *dname, uint16_t *rcode) { assert(zone != NULL); assert(dname != NULL); assert(rcode != NULL); - if (!knot_dname_is_sub(dname, - knot_node_owner(knot_zone_contents_apex(zone)))) { - *rcode = KNOT_RCODE_NOTZONE; - return KNOT_EOUTOFZONE; - } - - const knot_node_t *node; - - node = knot_zone_contents_find_node(zone, dname); + const knot_node_t *node = knot_zone_contents_find_node(zone, dname); if (node == NULL) { return KNOT_EOK; } else if (knot_node_rrset_count(node) == 0) { @@ -363,1439 +191,832 @@ static int knot_ddns_check_not_in_use(const knot_zone_contents_t *zone, return KNOT_EPREREQ; } -/*----------------------------------------------------------------------------*/ -/* API functions */ -/*----------------------------------------------------------------------------*/ - -int knot_ddns_check_zone(const knot_zone_contents_t *zone, - const knot_pkt_t *query, uint16_t *rcode) -{ - if (zone == NULL || query == NULL || rcode == NULL) { - if (rcode != NULL) { - *rcode = KNOT_RCODE_SERVFAIL; - } - return KNOT_EINVAL; - } - - if (knot_pkt_qtype(query) != KNOT_RRTYPE_SOA) { - *rcode = KNOT_RCODE_FORMERR; - return KNOT_EMALF; - } - - // check zone CLASS - if (knot_zone_contents_class(zone) != - knot_pkt_qclass(query)) { - *rcode = KNOT_RCODE_NOTAUTH; - return KNOT_ENOZONE; - } - - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - -int knot_ddns_process_prereqs(const knot_pkt_t *query, - knot_ddns_prereq_t **prereqs, uint16_t *rcode) +/*!< \brief Returns true if rrset has 0 data or RDATA of size 0 (we need TTL). */ +static bool rrset_empty(const knot_rrset_t *rrset) { - if (query == NULL || prereqs == NULL || rcode == NULL) { - return KNOT_EINVAL; + uint16_t rr_count = knot_rrset_rr_count(rrset); + if (rr_count == 0) { + return true; } - - dbg_ddns("Processing prerequisities.\n"); - - // allocate space for the prerequisities - *prereqs = (knot_ddns_prereq_t *)calloc(1, sizeof(knot_ddns_prereq_t)); - CHECK_ALLOC_LOG(*prereqs, KNOT_ENOMEM); - - int ret; - - const knot_pktsection_t *answer = knot_pkt_section(query, KNOT_ANSWER); - for (int i = 0; i < answer->count; ++i) { - // we must copy the RRSets, because all those stored in the - // packet will be destroyed - dbg_ddns_detail("Creating prereqs from following RRSet:\n"); - ret = knot_ddns_add_prereq(*prereqs, - answer->rr[i], - knot_pkt_qclass(query)); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to add prerequisity RRSet:%s\n", - knot_strerror(ret)); - *rcode = (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR - : KNOT_RCODE_SERVFAIL; - knot_ddns_prereqs_free(prereqs); - return ret; - } + if (rr_count == 1) { + return knot_rrset_rr_size(rrset, 0) == 0; } - - return KNOT_EOK; + return false; } -/*----------------------------------------------------------------------------*/ - -int knot_ddns_check_prereqs(const knot_zone_contents_t *zone, - knot_ddns_prereq_t **prereqs, uint16_t *rcode) +/*!< \brief Checks prereq for given packet RR. */ +static int process_prereq(const knot_rrset_t *rrset, uint16_t qclass, + const knot_zone_contents_t *zone, uint16_t *rcode, + list_t *rrset_list) { - int i, ret; - - dbg_ddns("Checking 'exist' prerequisities.\n"); - - for (i = 0; i < (*prereqs)->exist_count; ++i) { - ret = knot_ddns_check_exist(zone, (*prereqs)->exist[i], rcode); - if (ret != KNOT_EOK) { - return ret; - } - } - - dbg_ddns("Checking 'exist full' prerequisities.\n"); - for (i = 0; i < (*prereqs)->exist_full_count; ++i) { - ret = knot_ddns_check_exist_full(zone, - (*prereqs)->exist_full[i], - rcode); - if (ret != KNOT_EOK) { - return ret; - } - } - - dbg_ddns("Checking 'not exist' prerequisities.\n"); - for (i = 0; i < (*prereqs)->not_exist_count; ++i) { - ret = knot_ddns_check_not_exist(zone, (*prereqs)->not_exist[i], - rcode); - if (ret != KNOT_EOK) { - return ret; - } - } - - dbg_ddns("Checking 'in use' prerequisities.\n"); - for (i = 0; i < (*prereqs)->in_use_count; ++i) { - ret = knot_ddns_check_in_use(zone, (*prereqs)->in_use[i], - rcode); - if (ret != KNOT_EOK) { - return ret; - } - } - - dbg_ddns("Checking 'not in use' prerequisities.\n"); - for (i = 0; i < (*prereqs)->not_in_use_count; ++i) { - ret = knot_ddns_check_not_in_use(zone, - (*prereqs)->not_in_use[i], - rcode); - if (ret != KNOT_EOK) { - return ret; - } + if (knot_rrset_rr_ttl(rrset, 0) != 0) { + return KNOT_EMALF; } - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_check_update(const knot_rrset_t *rrset, - const knot_pkt_t *query, - uint16_t *rcode) -{ - /* Accept both subdomain and dname match. */ - dbg_ddns("Checking UPDATE packet.\n"); - const knot_dname_t *owner = knot_rrset_owner(rrset); - const knot_dname_t *qname = knot_pkt_qname(query); - int is_sub = knot_dname_is_sub(owner, qname); - if (!is_sub && knot_dname_cmp(owner, qname) != 0) { + if (!knot_dname_is_sub(rrset->owner, zone->apex->owner)) { *rcode = KNOT_RCODE_NOTZONE; return KNOT_EOUTOFZONE; } - if (knot_rrtype_is_ddns_forbidden(rrset->type)) { - *rcode = KNOT_RCODE_REFUSED; - log_zone_error("Refusing to update DNSSEC-related record!\n"); - return KNOT_EDENIED; - } - - if (knot_rrset_class(rrset) == knot_pkt_qclass(query)) { - if (knot_rrtype_is_metatype(knot_rrset_type(rrset))) { - *rcode = KNOT_RCODE_FORMERR; + if (rrset->rclass == KNOT_CLASS_ANY) { + if (!rrset_empty(rrset)) { return KNOT_EMALF; } - } else if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) { - if (!rrset_empty(rrset) - || (knot_rrtype_is_metatype(knot_rrset_type(rrset)) - && knot_rrset_type(rrset) != KNOT_RRTYPE_ANY)) { - *rcode = KNOT_RCODE_FORMERR; - return KNOT_EMALF; + if (rrset->type == KNOT_RRTYPE_ANY) { + return check_in_use(zone, rrset->owner, rcode); + } else { + return check_type_exist(zone, rrset, rcode); } - } else if (knot_rrset_class(rrset) == KNOT_CLASS_NONE) { - if (knot_rrset_rr_ttl(rrset, 0) != 0 - || knot_rrtype_is_metatype(knot_rrset_type(rrset))) { - *rcode = KNOT_RCODE_FORMERR; + } else if (rrset->rclass == KNOT_CLASS_NONE) { + if (!rrset_empty(rrset)) { return KNOT_EMALF; } + if (rrset->type == KNOT_RRTYPE_ANY) { + return check_not_in_use(zone, rrset->owner, rcode); + } else { + return check_type_not_exist(zone, rrset, rcode); + } + } else if (rrset->rclass == qclass) { + // Store RRs for full check into list + return add_rr_to_list(rrset_list, rrset); } else { - *rcode = KNOT_RCODE_FORMERR; return KNOT_EMALF; } - - return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ +/* --------------------------- DDNS processing ------------------------------ */ -void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq) -{ - dbg_ddns("Freeing prerequisities.\n"); - - int i; +/* ----------------------- changeset lists helpers -------------------------- */ - for (i = 0; i < (*prereq)->exist_count; ++i) { - knot_rrset_free(&(*prereq)->exist[i], NULL); - } - free((*prereq)->exist); - - for (i = 0; i < (*prereq)->exist_full_count; ++i) { - knot_rrset_free(&(*prereq)->exist_full[i], NULL); - } - free((*prereq)->exist_full); +#warning TODO: Store changesets as a lookup structure - for (i = 0; i < (*prereq)->not_exist_count; ++i) { - knot_rrset_free(&(*prereq)->not_exist[i], NULL); - } - free((*prereq)->not_exist); +/*!< \brief Returns true if \a cmp code returns true for one RR in list. */ +#define LIST_MATCH(l, cmp) \ + knot_rr_ln_t *_n; \ + WALK_LIST(_n, l) { \ + const knot_rrset_t *list_rr = _n->rr; \ + if (cmp) { \ + return true; \ + } \ + }; \ + return false; - for (i = 0; i < (*prereq)->in_use_count; ++i) { - knot_dname_free(&(*prereq)->in_use[i]); - } - free((*prereq)->in_use); +/*!< \brief Deletes RR from list if \a cmp code returns true for it. */ +#define LIST_DEL_MATCH(l, cmp) \ + knot_rr_ln_t *_n; \ + node_t *_nxt; \ + WALK_LIST_DELSAFE(_n, _nxt, l) { \ + knot_rrset_t *list_rr = _n->rr; \ + if (cmp) { \ + knot_rrset_free(&list_rr, NULL); \ + rem_node((node_t *)_n); \ + } \ + }; + +/*!< \brief Checks whether RR was already removed. */ +static bool removed_rr(const knot_changeset_t *changeset, const knot_rrset_t *rr) +{ + LIST_MATCH(changeset->remove, + knot_rrset_equal(rr, list_rr, KNOT_RRSET_COMPARE_WHOLE)); +} - for (i = 0; i < (*prereq)->not_in_use_count; ++i) { - knot_dname_free(&(*prereq)->not_in_use[i]); - } - free((*prereq)->not_in_use); +/*!< \brief Checks whether any CNAME RR under dname was added. */ +static bool cname_added(const knot_changeset_t *changeset, const knot_dname_t *d) +{ + knot_rrset_t mock_cname; + knot_rrset_init(&mock_cname, (knot_dname_t *)d, + KNOT_RRTYPE_CNAME, KNOT_CLASS_IN); + LIST_MATCH(changeset->add, + knot_rrset_equal(&mock_cname, list_rr, KNOT_RRSET_COMPARE_HEADER)); +} - free(*prereq); - *prereq = NULL; +/*!< \brief Checks whether any RR under given name was added. */ +static bool name_added(const knot_changeset_t *changeset, const knot_dname_t *d) +{ + LIST_MATCH(changeset->add, knot_dname_is_equal(d, list_rr->owner)); } -/*----------------------------------------------------------------------------*/ -/* New DDNS processing - */ -/*----------------------------------------------------------------------------*/ +/*!< \brief Removes RR from list, full equality check. */ +static void remove_rr_from_list(list_t *l, const knot_rrset_t *rr) +{ + LIST_DEL_MATCH(*l, knot_rrset_equal(list_rr, rr, KNOT_RRSET_COMPARE_WHOLE)); +} -static int knot_ddns_check_remove_rr(knot_changeset_t *changeset, - const knot_dname_t *owner, - const knot_rrset_t *rr, - knot_rrset_t ***removed, - size_t *removed_count) +/*!< \brief Removes RR from list, owner and type check. */ +static void remove_header_from_list(list_t *l, const knot_rrset_t *rr) { - assert(changeset != NULL); - assert(removed != NULL); - assert(removed_count != NULL); - - /*!< \todo This seems like a waste of memory to me. Also, list_size takes a long time. */ - *removed_count = 0; - *removed = (knot_rrset_t **)malloc(list_size(&changeset->add) - * sizeof(knot_rrset_t *)); - if (*removed == NULL) { - ERR_ALLOC_FAILED; - return KNOT_ENOMEM; - } + LIST_DEL_MATCH(*l, knot_rrset_equal(list_rr, rr, KNOT_RRSET_COMPARE_HEADER)); +} - knot_rrset_t *remove = NULL; +/*!< \brief Removes RR from list, owner check. */ +static void remove_owner_from_list(list_t *l, const knot_dname_t *owner) +{ + LIST_DEL_MATCH(*l, knot_dname_is_equal(list_rr->owner, owner)); +} - /* - * We assume that each RR in the ADD section of the changeset is in its - * own RRSet. It should be, as this is how they are stored there by the - * ddns_process_add() function. - */ +/* --------------------- true/false helper functions ------------------------ */ - dbg_ddns_verb("Removing possible redundant RRs from changeset.\n"); - knot_rr_ln_t *rr_node = NULL; - node_t *nxt = NULL; - WALK_LIST_DELSAFE(rr_node, nxt, changeset->add) { - knot_rrset_t *rrset = rr_node->rr; - // Removing RR(s) from this owner -dbg_ddns_exec_detail( - char *name = knot_dname_to_str(rrset->owner); - dbg_ddns_detail("ddns: remove_rr: Removing RR of type=%u owned by %s\n", - knot_rrset_type(rrset), name); - free(name); -); - if (knot_dname_is_equal(knot_rrset_owner(rrset), owner)) { - // Removing one or all RRSets - if (rrset_empty(rr) - && (knot_rrset_type(rr) == knot_rrset_type(rrset) - || knot_rrset_type(rr) == KNOT_RRTYPE_ANY)) { - dbg_ddns_detail("Removing one or all RRSets\n"); - remove = rrset; - rem_node((node_t *)rr_node); - (*removed)[(*removed_count)++] = remove; - } else if (knot_rrset_type(rr) == - knot_rrset_type(rrset)) { - // Removing specific RR - assert(knot_rrset_rr_count(rr) != 0); - - // We must check if the RDATA match - if (knot_rrset_equal(rr, rrset, - KNOT_RRSET_COMPARE_WHOLE)) { - remove = rrset; - rem_node((node_t *)rr_node); - (*removed)[(*removed_count)++] = remove; - } - } - } - } +static inline bool is_addition(const knot_rrset_t *rr) +{ + return rr->rclass == KNOT_CLASS_IN; +} - return KNOT_EOK; +static inline bool is_removal(const knot_rrset_t *rr) +{ + return rr->rclass == KNOT_CLASS_NONE || rr->rclass == KNOT_CLASS_ANY; } -/*----------------------------------------------------------------------------*/ +static inline bool is_rr_removal(const knot_rrset_t *rr) +{ + return rr->rclass == KNOT_CLASS_NONE; +} -static void knot_ddns_check_add_rr(knot_changeset_t *changeset, - const knot_rrset_t *rr, - knot_rrset_t **removed) +static inline bool is_rrset_removal(const knot_rrset_t *rr) { - assert(changeset != NULL); - assert(rr != NULL); - assert(removed != NULL); + return rr->rclass == KNOT_CLASS_ANY && rr->type != KNOT_RRTYPE_ANY; +} - *removed = NULL; +static inline bool is_node_removal(const knot_rrset_t *rr) +{ + return rr->rclass == KNOT_CLASS_ANY && rr->type == KNOT_RRTYPE_ANY; +} - dbg_ddns_verb("Removing possible redundant RRs from changeset.\n"); - knot_rr_ln_t *rr_node = NULL; - node_t *nxt = NULL; - WALK_LIST_DELSAFE(rr_node, nxt, changeset->remove) { - knot_rrset_t *rrset = rr_node->rr; - assert(rrset); - /* Just check exact match, the changeset contains only - * whole RRs that have been removed. - */ - if (knot_rrset_equal(rr, rrset, - KNOT_RRSET_COMPARE_WHOLE) == 1) { - *removed = rrset; - rem_node((node_t *)rr_node); - break; - } +/*!< \brief Returns true if last addition of certain types is to be replaced. */ +static bool should_replace(const knot_rrset_t *chg_rrset, + const knot_rrset_t *rrset) +{ + if (rrset->type != KNOT_RRTYPE_CNAME && + rrset->type != KNOT_RRTYPE_NSEC3PARAM) { + return false; + } else { + return chg_rrset->type == rrset->type; } } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_process_add_cname(knot_node_t *node, - const knot_rrset_t *rr, - knot_changeset_t *changeset, - knot_changes_t *changes) +/*!< \brief Returns true if node will be empty after update application. */ +static bool node_empty(const knot_node_t *node, knot_dname_t *owner, + const knot_changeset_t *changeset) { - assert(node != NULL); - assert(rr != NULL); - assert(changeset != NULL); - assert(changes != NULL); - - dbg_ddns_detail("Adding CNAME RR.\n"); - - int ret = 0; - - /* Get the current CNAME RR from the node. */ - knot_rrset_t *removed = knot_node_get_rrset(node, KNOT_RRTYPE_CNAME); - - if (removed != NULL) { - /* If they are identical, ignore. */ - if (knot_rrset_equal(removed, rr, KNOT_RRSET_COMPARE_WHOLE) - == 1) { - dbg_ddns_verb("CNAME identical to one in the node.\n"); - return 1; - } - - /* b) Store it to 'changes' */ - ret = knot_changes_add_rrset(changes, removed, KNOT_CHANGES_OLD); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to add removed RRSet to " - "'changes': %s\n", knot_strerror(ret)); - return ret; - } - - /* c) And remove it from the node. */ - UNUSED(knot_node_remove_rrset(node, KNOT_RRTYPE_CNAME)); - - /* d) Check if this CNAME was not previously added by - * the UPDATE. If yes, remove it from the ADD - * section and do not add it to the REMOVE section. - */ - knot_rrset_t **from_chgset = NULL; - size_t from_chgset_count = 0; - ret = knot_ddns_check_remove_rr( - changeset, knot_rrset_owner(removed), - removed, &from_chgset, &from_chgset_count); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to remove possible redundant " - "RRs from ADD section: %s.\n", - knot_strerror(ret)); - free(from_chgset); - return ret; - } - - assert(from_chgset_count <= 1); + if (node == NULL && name_added(changeset, owner)) { + // Node created in update. + return false; + } - if (from_chgset_count == 1) { - /* Just delete the RRSet. */ - knot_rrset_free(&(from_chgset[0]), NULL); - } else { - /* Otherwise copy the removed CNAME and add it - * to the REMOVE section. - */ - knot_rrset_t *removed_copy; - ret = knot_rrset_copy(removed, &removed_copy, NULL); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to copy removed RRSet:" - " %s\n", knot_strerror(ret)); - free(from_chgset); - return ret; - } + if (node == NULL) { + // Node empty. + return true; + } - ret = knot_changeset_add_rrset( - changeset, removed_copy, KNOT_CHANGESET_REMOVE); - if (ret != KNOT_EOK) { - knot_rrset_free(&removed_copy, NULL); - dbg_ddns("Failed to add removed CNAME " - "to changeset: %s\n", - knot_strerror(ret)); - free(from_chgset); - return ret; + for (uint16_t i = 0; i < node->rrset_count; ++i) { + knot_rrset_t node_rrset = knot_node_rrset_at(node, i); + knot_rrset_t node_rr; + knot_rrset_init(&node_rr, node->owner, node_rrset.type, KNOT_CLASS_IN); + for (uint16_t j = 0; j < node_rrset.rrs.rr_count; ++j) { + knot_rr_t *add_rr = knot_rrs_rr(&node_rrset.rrs, j); + knot_rrs_add_rr(&node_rr.rrs, add_rr, NULL); + if (!removed_rr(changeset, &node_rr)) { + // One of the RRs from node was not removed. + knot_rrs_clear(&node_rr.rrs, NULL); + return false; } + knot_rrs_clear(&node_rr.rrs, NULL); } - free(from_chgset); - } else if (knot_node_rrset_count(node) != 0) { - /* 2) Other occupied node => ignore. */ - return 1; } - return KNOT_EOK; + return true; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_process_add_soa(knot_node_t *node, - const knot_rrset_t *rr, - knot_changes_t *changes) +/*!< \brief Returns true if node contains given RR in its RRSets. */ +static bool node_contains_rr(const knot_node_t *node, + const knot_rrset_t *rr) { - assert(node != NULL); - assert(rr != NULL); - assert(changes != NULL); - - dbg_ddns_detail("Adding SOA RR.\n"); - - int ret = 0; - - /* - * Just remove the SOA from the node, together with its RRSIGs. - * Adding the RR is done in the caller function. Note that only SOA - * with larger SERIAL than the current one will get to these functions, - * so we don't have to check the SERIALS again. But an assert won't - * hurt. - */ - - /* Get the current SOA RR from the node. */ - knot_rrset_t *removed = knot_node_get_rrset(node, KNOT_RRTYPE_SOA); - - if (removed != NULL) { - dbg_ddns_detail("Found SOA in the node.\n"); - /* If they are identical, ignore. */ - if (knot_rrset_equal(removed, rr, KNOT_RRSET_COMPARE_WHOLE) - == 1) { - dbg_ddns_detail("Old and new SOA identical.\n"); - return 1; - } - - /* Check that the serial is indeed larger than the current one*/ - assert(knot_serial_compare(knot_rdata_soa_serial(removed), - knot_rdata_soa_serial(rr)) < 0); - - /* 1) Store it to 'changes', together with its RRSIGs. */ - ret = knot_changes_add_rrset(changes, removed, KNOT_CHANGES_OLD); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to add removed RRSet to " - "'changes': %s\n", knot_strerror(ret)); - return ret; - } - - /* 2) And remove it from the node. */ - UNUSED(knot_node_remove_rrset(node, KNOT_RRTYPE_SOA)); - - /* No changeset processing needed in this case. */ + const knot_rrs_t *zone_rrs = knot_node_rrs(node, rr->type); + if (zone_rrs) { + assert(rr->rrs.rr_count == 1); + const bool compare_ttls = false; + return knot_rrs_member(zone_rrs, knot_rrs_rr(&rr->rrs, 0), + compare_ttls); } else { - dbg_ddns_detail("No SOA in node, ignoring.\n"); - /* If there is no SOA in the node, ignore. */ - return 1; + return false; } - - return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_add_rr_new_normal(knot_node_t *node, knot_rrset_t *rr_copy, - knot_changes_t *changes) +/*!< \brief Returns true if CNAME is in this node. */ +static bool adding_to_cname(const knot_dname_t *owner, + const knot_node_t *node, + knot_changeset_t *changeset) { - assert(node != NULL); - assert(rr_copy != NULL); - assert(changes != NULL); - - dbg_ddns_verb("Adding normal RR.\n"); + if (cname_added(changeset, owner)) { + // Added a CNAME in this update. + return true; + } - /* Add the RRSet to 'changes'. */ + if (node == NULL) { + // Node did not exist before update. + return false; + } - int ret = knot_changes_add_rrset(changes, rr_copy, KNOT_CHANGES_NEW); - if (ret != KNOT_EOK) { - knot_rrset_free(&rr_copy, NULL); - dbg_ddns("Failed to store copy of the added RR: " - "%s\n", knot_strerror(ret)); - return ret; + knot_rrset_t cname = knot_node_rrset(node, KNOT_RRTYPE_CNAME); + if (knot_rrset_empty(&cname)) { + // Node did not contain CNAME before update. + return false; } - /* Add the RRSet to the node. */ - ret = knot_node_add_rrset_no_merge(node, rr_copy); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to add RR to node: %s\n", knot_strerror(ret)); - return ret; + if (removed_rr(changeset, &cname)) { + // Node did contain CNAME, but it was removed in this update. + return false; } - return KNOT_EOK; + // CNAME present + return true; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_add_rr_merge_normal(knot_rrset_t *node_rrset_copy, - knot_rrset_t **rr_copy) +/*!< \brief Used to ignore SOA deletions and SOAs with lower serial than zone. */ +static bool skip_soa(const knot_rrset_t *rr, int64_t sn) { - assert(node_rrset_copy != NULL); - assert(rr_copy != NULL); - assert(*rr_copy != NULL); - - dbg_ddns_verb("Merging normal RR to existing RRSet.\n"); - - /* First check if the TTL of the new RR is equal to that of the first - * RR in the node's RRSet. If not, refuse the UPDATE. - */ - if (!knot_rrset_ttl_equal(*rr_copy, node_rrset_copy)) { - assert(knot_rrset_type(*rr_copy) != KNOT_RRTYPE_RRSIG); - char type_str[16] = { '\0' }; - knot_rrtype_to_string(knot_rrset_type(*rr_copy), type_str, - sizeof(type_str)); - char *name = knot_dname_to_str(knot_rrset_owner(*rr_copy)); - log_zone_error("UPDATE: TTL mismatch in %s, type %s\n", - name, type_str); - free(name); - return KNOT_ETTL; + if (rr->type == KNOT_RRTYPE_SOA + && (rr->rclass == KNOT_CLASS_NONE + || rr->rclass == KNOT_CLASS_ANY + || knot_serial_compare(knot_rrs_soa_serial(&rr->rrs), + sn) <= 0)) { + return true; } - int rdata_in_copy = knot_rrset_rr_count(*rr_copy); - int merged = 0, deleted_rrs = 0; - int ret = knot_rrset_merge_sort(node_rrset_copy, *rr_copy, &merged, - &deleted_rrs, NULL); - dbg_ddns_detail("Merge returned: %d\n", ret); - - if (ret != KNOT_EOK) { - dbg_ddns("Failed to merge UPDATE RR to node RRSet: %s." - "\n", knot_strerror(ret)); - return ret; - } + return false; +} - knot_rrset_free(rr_copy, NULL); +/* ---------------------- changeset manipulation ---------------------------- */ - if (rdata_in_copy == deleted_rrs) { - /* All RDATA have been removed, because they were duplicates - * or there were none (0). In general this means, that no - * change was made. - */ - return 1; +/*!< \brief Checks whether record should be added or replaced. */ +static bool skip_record_addition(knot_changeset_t *changeset, + knot_rrset_t *rr) +{ + knot_rr_ln_t *rr_node = NULL; + WALK_LIST(rr_node, changeset->add) { + knot_rrset_t *rrset = rr_node->rr; + if (should_replace(rr, rrset)) { + // Replacing singleton RR. + knot_rrset_free(&rrset, NULL); + rr_node->rr = rr; + return true; + } else if (knot_rrset_equal(rr, rrset, KNOT_RRSET_COMPARE_WHOLE)) { + // Freeing duplication. + knot_rrset_free(&rr, NULL); + return true; + } } - return KNOT_EOK; + return false; } -/*----------------------------------------------------------------------------*/ -/*! - * \todo We should check, how it's possible that IXFR is not leaking due to the - * same issue with merge. Or maybe it is, we should try it!! - */ +/*!< \brief Adds RR into add section of changeset if it is deemed worthy. */ +static int add_rr_to_chgset(const knot_rrset_t *rr, knot_changeset_t *changeset, + int *apex_ns_rem) +{ + knot_rrset_t *rr_copy = knot_rrset_copy(rr, NULL); + if (rr_copy == NULL) { + return KNOT_ENOMEM; + } -/*----------------------------------------------------------------------------*/ + rr_copy->rclass = KNOT_CLASS_IN; -static int knot_ddns_add_rr(knot_node_t *node, const knot_rrset_t *rr, - knot_changes_t *changes, knot_rrset_t **rr_copy) -{ - assert(node != NULL); - assert(rr != NULL); - assert(changes != NULL); - assert(rr_copy != NULL); - - /* Copy the RRSet from the packet. */ - //knot_rrset_t *rr_copy; - int ret = knot_rrset_copy(rr, rr_copy, NULL); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to copy RR: %s\n", knot_strerror(ret)); - return ret; + if (skip_record_addition(changeset, rr_copy)) { + return KNOT_EOK; } - /* If the RR belongs to a RRSet already present in the node, we must - * take this RRSet from the node, copy it, and merge this RR into it. - * - * This code is more or less copied from xfr-in.c. - */ - knot_rrset_t *node_rrset_copy = NULL; - ret = xfrin_copy_rrset(node, rr->type, &node_rrset_copy, changes, 0); - if (ret < 0) { - dbg_ddns("Failed to copy RRSet: %s\n", knot_strerror(ret)); - knot_rrset_free(rr_copy, NULL); - return ret; + if (apex_ns_rem) { + // Increase post update apex NS count. + (*apex_ns_rem)--; } - if (node_rrset_copy == NULL) { - /* No such RRSet in the node. Add the whole UPDATE RRSet. */ - dbg_ddns_detail("Adding whole UPDATE RR to the zone.\n"); - ret = knot_ddns_add_rr_new_normal(node, *rr_copy, - changes); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to add new RR to node.\n"); - return ret; - } - dbg_ddns_detail("RRSet added successfully.\n"); - } else { - /* We have copied the RRSet from the node. */ - ret = knot_ddns_add_rr_merge_normal(node_rrset_copy, rr_copy); - - if (ret < KNOT_EOK) { - dbg_ddns("Failed to merge UPDATE RR to node RRSet.\n"); - knot_rrset_free(rr_copy, NULL); - knot_rrset_free(&node_rrset_copy, NULL); - return ret; - } + return knot_changeset_add_rrset(changeset, rr_copy, KNOT_CHANGESET_ADD); +} - // save the new RRSet together with the new RDATA to 'changes' - // do not overwrite 'ret', it have to be returned - int r = knot_changes_add_rrset(changes, node_rrset_copy, - KNOT_CHANGES_NEW); - if (r != KNOT_EOK) { - dbg_ddns("Failed to store RRSet copy to 'changes'\n"); - knot_rrset_free(&node_rrset_copy, NULL); - return r; +/*!< \brief Checks whether record should be removed (duplicate check). */ +static bool skip_record_removal(knot_changeset_t *changeset, knot_rrset_t *rr) +{ + knot_rr_ln_t *rr_node = NULL; + WALK_LIST(rr_node, changeset->remove) { + knot_rrset_t *rrset = rr_node->rr; + if (knot_rrset_equal(rr, rrset, KNOT_RRSET_COMPARE_WHOLE)) { + // Removing the same RR, drop. + knot_rrset_free(&rr, NULL); + return true; } } - assert(ret >= 0); - return ret; + return false; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_final_soa_to_chgset(const knot_rrset_t *soa, - knot_changeset_t *changeset) +/*!< \brief Adds RR into remove section of changeset if it is deemed worthy. */ +static int rem_rr_to_chgset(const knot_rrset_t *rr, knot_changeset_t *changeset, + int *apex_ns_rem) { - assert(soa != NULL); - assert(changeset != NULL); + knot_rrset_t *rr_copy = knot_rrset_copy(rr, NULL); + if (rr_copy == NULL) { + return KNOT_ENOMEM; + } - knot_rrset_t *soa_copy = NULL; - int ret = knot_rrset_copy(soa, &soa_copy, NULL); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to copy SOA RR to the changeset: " - "%s\n", knot_strerror(ret)); - return ret; + rr_copy->rclass = KNOT_CLASS_IN; + + if (skip_record_removal(changeset, rr_copy)) { + return KNOT_EOK; } - knot_changeset_add_soa(changeset, soa_copy, KNOT_CHANGESET_ADD); + if (apex_ns_rem) { + // Decrease post update apex NS count. + (*apex_ns_rem)++; + } - return KNOT_EOK; + return knot_changeset_add_rrset(changeset, rr_copy, KNOT_CHANGESET_REMOVE); } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_add_rr_to_chgset(const knot_rrset_t *rr, - knot_changeset_t *changeset) +/*!< \brief Adds all RRs from RRSet into remove section of changeset. */ +static int rem_rrset_to_chgset(const knot_rrset_t *rrset, + knot_changeset_t *changeset, + int *apex_ns_rem) { - assert(rr != NULL); - assert(changeset != NULL); - - int ret = 0; - knot_rrset_t *chgset_rr = NULL; - knot_ddns_check_add_rr(changeset, rr, &chgset_rr); - if (chgset_rr == NULL) { - ret = knot_rrset_copy(rr, &chgset_rr, NULL); + knot_rrset_t rr; + knot_rrset_init(&rr, rrset->owner, rrset->type, rrset->rclass); + for (uint16_t i = 0; i < rrset->rrs.rr_count; ++i) { + knot_rr_t *rr_add = knot_rrs_rr(&rrset->rrs, i); + int ret = knot_rrs_add_rr(&rr.rrs, rr_add, NULL); if (ret != KNOT_EOK) { - dbg_ddns("Failed to copy RR to the changeset: " - "%s\n", knot_strerror(ret)); return ret; } - /* No such RR in the changeset, add it. */ - ret = knot_changeset_add_rrset(changeset, chgset_rr, - KNOT_CHANGESET_ADD); + ret = rem_rr_to_chgset(&rr, changeset, apex_ns_rem); + knot_rrs_clear(&rr.rrs, NULL); if (ret != KNOT_EOK) { - knot_rrset_free(&chgset_rr, NULL); - dbg_ddns("Failed to add RR to changeset: %s.\n", - knot_strerror(ret)); return ret; } - } else { - knot_rrset_free(&chgset_rr, NULL); } return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ +/* ------------------------ RR processing logic ----------------------------- */ -static int knot_ddns_process_add(const knot_rrset_t *rr, - knot_node_t **node, - knot_zone_contents_t *zone, - knot_changeset_t *changeset, - knot_changes_t *changes, - knot_rrset_t **rr_copy) -{ - assert(rr != NULL); - assert(node != NULL); - assert(zone != NULL); - assert(changeset != NULL); - assert(changes != NULL); - assert(rr_copy != NULL); +/* --------------------------- RR additions --------------------------------- */ - dbg_ddns_verb("Adding RR.\n"); +/*!< \brief Processes CNAME addition (replace or ignore) */ +static int process_add_cname(const knot_node_t *node, + const knot_rrset_t *rr, + knot_changeset_t *changeset) +{ + knot_rrset_t cname = knot_node_rrset(node, KNOT_RRTYPE_CNAME); + if (!knot_rrset_empty(&cname)) { + // If they are identical, ignore. + if (knot_rrset_equal(&cname, rr, KNOT_RRSET_COMPARE_WHOLE)) { + return KNOT_EOK; + } - if (*node == NULL) { - // create new node, connect it to the zone nodes - dbg_ddns_detail("Node not found. Creating new.\n"); - int ret = knot_zone_contents_create_node(zone, rr, node); + int ret = rem_rr_to_chgset(&cname, changeset, NULL); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to create new node in zone.\n"); return ret; } - } - assert(*node); - - uint16_t type = knot_rrset_type(rr); - *rr_copy = NULL; - int ret = 0; - - /* - * First, rule out special cases: CNAME, SOA and adding to CNAME node. - */ - if (type == KNOT_RRTYPE_CNAME) { - ret = knot_ddns_process_add_cname(*node, rr, changeset, changes); - } else if (type == KNOT_RRTYPE_SOA) { - ret = knot_ddns_process_add_soa(*node, rr, changes); - } else if (type == KNOT_RRTYPE_NSEC3PARAM) { - if (!knot_dname_is_equal((*node)->owner, zone->apex->owner)) { - log_zone_error("NSEC3PARAM RR may be added under apex name only!\n"); - return KNOT_EDENIED; - } - if (knot_node_rrset(*node, KNOT_RRTYPE_NSEC3PARAM)) { - /* Ignore if there is one already in the zone.*/ - log_zone_warning("NSEC3PARAM already present in the zone. " - "Ignoring NSEC3PARAM from the UPDATE.\n"); - return KNOT_EOK; - } - } else if (knot_node_rrset(*node, KNOT_RRTYPE_CNAME) != NULL) { - /* - * Adding RR to CNAME node. Ignore the UPDATE RR. - * - * TODO: This may or may not be according to the RFC, it's quite - * unclear (see 3.4.2.2) - */ - return KNOT_EOK; - } - if (ret == 1) { - dbg_ddns_detail("Ignoring the added RR.\n"); - // Ignore + return add_rr_to_chgset(rr, changeset, NULL); + } else if (!node_empty(node, rr->owner, changeset)) { + // Other occupied node => ignore. return KNOT_EOK; - } else if (ret != KNOT_EOK) { - dbg_ddns_detail("Adding RR failed.\n"); - return ret; + } else { + // Can add. + return add_rr_to_chgset(rr, changeset, NULL); } +} - /* - * In all other cases, the RR should just be added to the node. - */ - - /* Add the RRSet to the node (RRSIGs handled in the function). */ - dbg_ddns_detail("Adding RR to the node.\n"); - ret = knot_ddns_add_rr(*node, rr, changes, rr_copy); - if (ret < 0) { - dbg_ddns("Failed to add RR to the node.\n"); - return ret; +/*!< \brief Processes CNAME addition (ignore when not removed, or non-apex) */ +static int process_add_nsec3param(const knot_node_t *node, + const knot_rrset_t *rr, + knot_changeset_t *changeset) +{ + if (node == NULL || !knot_node_rrtype_exists(node, KNOT_RRTYPE_SOA)) { + // Ignore non-apex additions + char *owner = knot_dname_to_str(rr->owner); + log_server_warning("Refusing to add NSEC3PARAM owned " + "by %s to non-apex node.\n", owner); + free(owner); + return KNOT_EDENIED; } - - /* - * If adding SOA, it should not be stored in the changeset. - * (This is done in the calling function, and the SOA is stored in the - * soa_final field.) - */ - if (type == KNOT_RRTYPE_SOA) { - return KNOT_EOK; + knot_rrset_t param = knot_node_rrset(node, KNOT_RRTYPE_NSEC3PARAM); + if (knot_rrset_empty(¶m) || removed_rr(changeset, ¶m)) { + return add_rr_to_chgset(rr, changeset, NULL); } - /* Add the RR to ADD section of the changeset. */ - /* If the RR was previously removed, do not add it to the - * changeset, and remove the entry from the REMOVE section. - * - * If there was no change (i.e. all RDATA were duplicates), do not add - * the RR to the changeset. - */ - if (ret == KNOT_EOK) { - dbg_ddns_detail("Adding RR to the changeset.\n"); - ret = knot_ddns_add_rr_to_chgset(rr, changeset); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to add the UPDATE RR to the changeset." - "\n"); - return ret; - } - } + char *owner = knot_dname_to_str(rr->owner); + log_server_warning("Refusing to add NSEC3PARAM owned " + "by %s. NSEC3PARAM already present, remove it first.\n", + owner); + free(owner); return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ /*! - * \todo Geez, this is soooooo long even I don't exactly know what it does... - * Refactor! + * \brief Processes SOA addition (ignore when non-apex), lower serials + * dropped before. */ -static int knot_ddns_process_rem_rr(const knot_rrset_t *rr, - knot_node_t *node, - knot_zone_contents_t *zone, - knot_changeset_t *changeset, - knot_changes_t *changes, uint16_t qclass) +static int process_add_soa(const knot_node_t *node, + const knot_rrset_t *rr, + knot_changeset_t *changeset) { - assert(rr != NULL); - assert(node != NULL); - assert(zone != NULL); - assert(changeset != NULL); - assert(changes != NULL); - - uint16_t type = knot_rrset_type(rr); - dbg_ddns_verb("Removing one RR.\n"); - - /* - * When doing changes to RRSets, we must: - * 1) Copy the RRSet (same as in IXFR changeset applying, maybe the - * function xfrin_copy_rrset() may be used for this). - * 2) Remove the RDATA (in this case only one). Check if it is not the - * last NS RR in the zone. - * 3) Store the removed RDATA in 'changes'. - * 4) If the RRSet is empty, remove it and store in 'changes'. - * 5) Check redundant RRs in changeset. - * 6) Store the RRSet containing the one RDATA in the changeset. We may - * use the RRSet from the packet for this - copy it, set CLASS - * and TTL. - * - */ - - assert(type != KNOT_RRTYPE_SOA); - int is_apex = knot_node_rrset(node, KNOT_RRTYPE_SOA) != NULL; - - /* If removing NS from an apex and there is only one NS left, ignore - * this removal right away. We do not have to check if the RRs match: - * - if they don't match, the removal will be ignored - * - if they match, the last NS cannot be removed anyway. - */ - if (is_apex && type == KNOT_RRTYPE_NS - && knot_rrset_rr_count(knot_node_rrset(node, type)) == 1) { + if (node == NULL || !knot_node_rrtype_exists(node, KNOT_RRTYPE_SOA)) { + // Adding SOA to non-apex node, ignore return KNOT_EOK; } - /* - * 1) Copy the RRSet. - */ - knot_rrset_t *rrset_copy = NULL; - int ret = xfrin_copy_rrset(node, type, &rrset_copy, changes, 1); - if (ret < 0) { - dbg_ddns("Failed to copy RRSet for removal: %s\n", - knot_strerror(ret)); - return ret; - } - - if (rrset_copy == NULL) { - dbg_ddns_verb("RRSet not found.\n"); + // Get current SOA RR. + knot_rrset_t removed = knot_node_rrset(node, KNOT_RRTYPE_SOA); + if (knot_rrset_equal(&removed, rr, KNOT_RRSET_COMPARE_WHOLE)) { + // If they are identical, ignore. return KNOT_EOK; } - /* - * Set some variables needed, according to the modified RR type. - */ - - knot_rrset_t *to_modify = rrset_copy; - - /* - * 2) Remove the proper RDATA from the RRSet copy - */ - knot_rrset_t *rr_remove = NULL; - ret = knot_rrset_remove_rr_using_rrset(to_modify, rr, &rr_remove, NULL); - if (ret != KNOT_EOK) { - dbg_ddns("ddns: proces_rem_rr: Could not remove RDATA from" - " RRSet (%s).\n", knot_strerror(ret)); - return ret; + // Store SOA copy into changeset. + if (changeset->soa_to != NULL) { + // Discard previous SOA - "There can be only one!" + knot_rrset_free(&changeset->soa_to, NULL); } - - /* No such RR in the RRSet. */ - if (knot_rrset_rr_count(rr_remove) == 0) { - knot_rrset_free(&rr_remove, NULL); - dbg_ddns_detail("No such RR found to be removed.\n"); - return KNOT_EOK; + knot_rrset_t *soa_cpy = knot_rrset_copy(rr, NULL); + if (soa_cpy == NULL) { + return KNOT_ENOMEM; } - /* If we removed NS from apex, there should be at least one more. */ - assert(!is_apex || type != KNOT_RRTYPE_NS - || knot_rrset_rr_count(rrset_copy)); + knot_changeset_add_soa(changeset, soa_cpy, KNOT_CHANGESET_ADD); + return KNOT_EOK; +} - /* - * 3) If the RRSet is empty, remove it and store in 'changes'. - */ - if (knot_rrset_rr_count(to_modify) == 0) { - // The RRSet should not be empty if we were removing NSs from - // apex in case of DDNS -// assert(!is_apex); - // add the removed RRSet to list of old RRSets - ret = knot_changes_add_rrset(changes, rrset_copy, - KNOT_CHANGES_OLD); - if (ret != KNOT_EOK) { - knot_rrset_free(&rr_remove, NULL); - dbg_ddns("Failed to add RRSet to changes.\n"); - return ret; - } +/*!< \brief Adds normal RR, ignores when CNAME exists in node. */ +static int process_add_normal(const knot_node_t *node, + const knot_rrset_t *rr, + knot_changeset_t *changeset, + int *apex_ns_rem) +{ + if (adding_to_cname(rr->owner, node, changeset)) { + // Adding RR to CNAME node, ignore. + return KNOT_EOK; + } - knot_rrset_t *tmp = knot_node_remove_rrset(node, type); - dbg_xfrin_detail("Removed whole RRSet (%p).\n", tmp); - assert(tmp == rrset_copy); + if (node && node_contains_rr(node, rr)) { + // Adding existing RR, remove removal from changeset if it's there. + remove_rr_from_list(&changeset->remove, rr); + // And ignore. + return KNOT_EOK; } - /* - * 4) Check if the RR is not in the ADD section. If yes, remove it - * from there and do not add it to the REMOVE section. + /* First check if the TTL of the new RR is equal to that of the first + * RR in the node's RRSet. If not, refuse the UPDATE. */ - knot_rrset_t **from_chgset = NULL; - size_t from_chgset_count = 0; - ret = knot_ddns_check_remove_rr(changeset, knot_node_owner(node), - rr, &from_chgset, &from_chgset_count); - if (ret != KNOT_EOK) { - knot_rrset_free(&rr_remove, NULL); - dbg_ddns("Failed to remove possible redundant RRs from ADD " - "section: %s.\n", knot_strerror(ret)); - free(from_chgset); - return ret; + knot_rrset_t rr_in_zone = knot_node_rrset(node, rr->type); + if (knot_node_rrtype_exists(node, rr->type) && + knot_rrset_rr_ttl(rr, 0) != knot_rrset_rr_ttl(&rr_in_zone, 0)) { + return KNOT_ETTL; } - assert(from_chgset_count <= 1); + const bool apex_ns = knot_node_rrtype_exists(node, KNOT_RRTYPE_SOA) && + rr->type == KNOT_RRTYPE_NS; + return add_rr_to_chgset(rr, changeset, apex_ns ? apex_ns_rem : NULL); +} - if (from_chgset_count == 1) { - knot_rrset_free(&(from_chgset[0]), NULL); - knot_rrset_free(&rr_remove, NULL); - /* Finish processing, no adding to changeset. */ - free(from_chgset); - return KNOT_EOK; +/*!< \brief Decides what to do with RR addition. */ +static int process_add(const knot_rrset_t *rr, + const knot_node_t *node, + knot_changeset_t *changeset, + int *apex_ns_rem) +{ + switch(rr->type) { + case KNOT_RRTYPE_CNAME: + return process_add_cname(node, rr, changeset); + case KNOT_RRTYPE_SOA: + return process_add_soa(node, rr, changeset); + case KNOT_RRTYPE_NSEC3PARAM: + return process_add_nsec3param(node, rr, changeset); + default: + return process_add_normal(node, rr, changeset, apex_ns_rem); } +} - free(from_chgset); - +/* --------------------------- RR deletions --------------------------------- */ - /* - * 5) Store the removed data in 'changes'. - */ - ret = knot_changes_add_rrset(changes, rr_remove, KNOT_CHANGES_OLD); - if (ret != KNOT_EOK) { - knot_rrset_free(&rr_remove, NULL); - dbg_ddns_detail("Failed to add data to changes.\n"); - return ret; +/*!< \brief Removes single RR from zone. */ +static int process_rem_rr(const knot_rrset_t *rr, + const knot_node_t *node, + knot_changeset_t *changeset, + int *apex_ns_rem) +{ + const bool apex_ns = knot_node_rrtype_exists(node, KNOT_RRTYPE_SOA) && + rr->type == KNOT_RRTYPE_NS; + if (apex_ns) { + const knot_rrs_t *ns_rrs = knot_node_rrs(node, KNOT_RRTYPE_NS); + if (*apex_ns_rem == ns_rrs->rr_count - 1) { + // Cannot remove last apex NS RR + return KNOT_EOK; + } } - /* - * 6) Store the RRSet containing the one RDATA in the changeset. We may - * use the RRSet from the packet for this - copy it, set CLASS - * and TTL. - */ - knot_rrset_t *to_chgset = NULL; - ret = knot_rrset_copy(rr, &to_chgset, NULL); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to copy RRSet from packet to changeset.\n"); - return ret; + // Remove possible previously added RR + remove_rr_from_list(&changeset->add, rr); + if (node == NULL) { + // Removing from node that did not exists before update + return KNOT_EOK; } - to_chgset->rclass = qclass; - uint16_t rr_count = knot_rrset_rr_count(to_chgset); - for (uint16_t i = 0; i < rr_count; ++i) { - knot_rrset_rr_set_ttl(to_chgset, - knot_rrset_rr_ttl(to_modify, i), i); + + knot_rrset_t to_modify = knot_node_rrset(node, rr->type); + if (knot_rrset_empty(&to_modify)) { + // No such RRSet + return KNOT_EOK; } - ret = knot_changeset_add_rrset(changeset, to_chgset, - KNOT_CHANGESET_REMOVE); + knot_rrset_t intersection; + knot_rrset_init(&intersection, to_modify.owner, to_modify.type, KNOT_CLASS_IN); + int ret = knot_rrs_intersect(&to_modify.rrs, &rr->rrs, &intersection.rrs, + NULL); if (ret != KNOT_EOK) { - dbg_ddns("Failed to store the RRSet copy to changeset: %s.\n", - knot_strerror(ret)); - knot_rrset_free(&to_chgset, NULL); return ret; } - return KNOT_EOK; + if (knot_rrset_empty(&intersection)) { + // No such RR + return KNOT_EOK; + } + assert(intersection.rrs.rr_count == 1); + ret = rem_rr_to_chgset(&intersection, changeset, + apex_ns ? apex_ns_rem : NULL); + knot_rrs_clear(&intersection.rrs, NULL); + return ret; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_process_rem_rrset(const knot_rrset_t *rrset, - knot_node_t *node, - knot_changeset_t *changeset, - knot_changes_t *changes) +/*!< \brief Removes RRSet from zone. */ +static int process_rem_rrset(const knot_rrset_t *rrset, + const knot_node_t *node, + knot_changeset_t *changeset) { - assert(node != NULL); - assert(rrset != NULL); - assert(changeset != NULL); - assert(changes != NULL); - - uint16_t type = knot_rrset_type(rrset); - - // this should be ruled out before - assert(type != KNOT_RRTYPE_SOA); - - if (knot_node_rrset(node, KNOT_RRTYPE_SOA) != NULL - && type == KNOT_RRTYPE_NS) { - // if removing NS from apex, ignore + if (rrset->type == KNOT_RRTYPE_SOA || + knot_rrtype_is_ddns_forbidden(rrset->type)) { + // Ignore SOA and DNSSEC removals. return KNOT_EOK; } - knot_rrset_t **removed = NULL; - size_t removed_count = 0; - int ret = 0; - - /* Remove the RRSet from the node. */ - removed = malloc(sizeof(knot_rrset_t *)); - if (!removed) { - ERR_ALLOC_FAILED; - return KNOT_ENOMEM; + if (knot_node_rrtype_exists(node, KNOT_RRTYPE_SOA) && + rrset->type == KNOT_RRTYPE_NS) { + // Ignore NS apex RRSet removals. + return KNOT_EOK; } - dbg_ddns_detail("Removing RRSet of type: %d\n", type); + // Remove all previously added RRs with this owner and type from changeset + remove_header_from_list(&changeset->add, rrset); + if (node == NULL) { + return KNOT_EOK; + } - *removed = knot_node_remove_rrset(node, type); - if (*removed != NULL) { - removed_count = 1; - } else { - removed_count = 0; + if (!knot_node_rrtype_exists(node, rrset->type)) { + // no such RR, ignore + return KNOT_EOK; } - dbg_ddns_detail("Removed: %p (first item: %p), removed count: %zu\n", - removed, (removed == NULL) ? (void *)"none" : *removed, - removed_count); + knot_rrset_t to_remove = knot_node_rrset(node, rrset->type); + return rem_rrset_to_chgset(&to_remove, changeset, NULL); +} + +/*!< \brief Removes node from zone. */ +static int process_rem_node(const knot_rrset_t *rr, + const knot_node_t *node, knot_changeset_t *changeset) +{ + // Remove all previously added records with given owner from changeset + remove_owner_from_list(&changeset->add, rr->owner); - // no such RR - if (removed_count == 0) { - // ignore - free(removed); + if (node == NULL) { return KNOT_EOK; } - /* 2) Store them to 'changes' for later deallocation, together with - * their RRSIGs. - */ - for (uint i = 0; i < removed_count; ++i) { - ret = knot_changes_add_rrset(changes, removed[i], - KNOT_CHANGES_OLD); + // Remove all RRSets from node + for (int i = 0; i < node->rrset_count; ++i) { + knot_rrset_t rrset = knot_node_rrset_at(node, i); + int ret = process_rem_rrset(&rrset, node, changeset); if (ret != KNOT_EOK) { - dbg_ddns("Failed to add removed " - "RRSet to 'changes': %s.\n", - knot_strerror(ret)); - free(removed); return ret; } } - /* 3) Copy the RRSets, so that they can be stored to the changeset. */ - knot_rrset_t **to_chgset = malloc(removed_count - * sizeof(knot_rrset_t *)); - if (to_chgset == NULL) { - dbg_ddns("Failed to allocate space for RRSets going to " - "changeset.\n"); - free(removed); - return KNOT_ENOMEM; - } + return KNOT_EOK; +} - for (int i = 0; i < removed_count; ++i) { - ret = knot_rrset_copy(removed[i], &to_chgset[i], NULL); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to copy the removed RRSet: %s.\n", - knot_strerror(ret)); - for (int j = 0; j < i; ++j) { - knot_rrset_free(&to_chgset[j], NULL); - } - free(to_chgset); - free(removed); - return ret; - } +/*!< \brief Decides what to with removal. */ +static int process_remove(const knot_rrset_t *rr, + const knot_node_t *node, + knot_changeset_t *changeset, + int *apex_ns_rem) +{ + if (is_rr_removal(rr)) { + return process_rem_rr(rr, node, changeset, apex_ns_rem); + } else if (is_rrset_removal(rr)) { + return process_rem_rrset(rr, node, changeset); + } else if (is_node_removal(rr)) { + return process_rem_node(rr, node, changeset); + } else { + return KNOT_EINVAL; } +} - free(removed); +/* --------------------------- validity checks ------------------------------ */ - /* 4) But we must check if some of the RRs were not previously added - * by the same UPDATE. If yes, these must be removed from the ADD - * section of the changeset and also from this RRSet copy (so they - * are neither stored in the REMOVE section of the changeset). - */ - knot_rrset_t **from_chgset = NULL; - size_t from_chgset_count = 0; - - /* 4 a) Remove redundant RRs from the ADD section of the changeset. */ - knot_dname_t *owner_copy = knot_dname_copy(rrset->owner); - knot_rrset_t *empty_rrset = - knot_rrset_new(owner_copy, type, rrset->rclass, NULL); - if (empty_rrset == NULL) { - free(to_chgset); - knot_dname_free(&owner_copy); - return KNOT_ENOMEM; - } - ret = knot_ddns_check_remove_rr(changeset, knot_node_owner(node), - empty_rrset, &from_chgset, - &from_chgset_count); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to remove possible redundant RRs from ADD " - "section: %s.\n", knot_strerror(ret)); - for (int i = 0; i < removed_count; ++i) { - knot_rrset_free(&to_chgset[i], NULL); - } - free(from_chgset); - free(to_chgset); - knot_rrset_free(&empty_rrset, NULL); - return ret; - } - knot_rrset_free(&empty_rrset, NULL); - - /* 4 b) Remove these RRs from the copy of the RRSets removed from zone*/ - for (int j = 0; j < removed_count; ++j) { - /* In each RRSet removed from the node (each can have more - * RDATAs) ... - */ - for (int i = 0; i < from_chgset_count; ++i) { - /* ...try to remove redundant RDATA. Each RRSet in - * 'from_chgset' contains only one RDATA. - */ - knot_rrset_t *removed = NULL; - ret = knot_rrset_remove_rr_using_rrset(to_chgset[j], - from_chgset[i], &removed, NULL); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to remove RR from RRSet" - "(%s).\n", knot_strerror(ret)); - free(from_chgset); - free(to_chgset); - return ret; - } - knot_rrset_free(&removed, NULL); - } +/*!< \brief Checks whether addition has not violated DNAME rules. */ +static bool sem_check(const knot_rrset_t *rr, + const knot_node_t *zone_node, + const knot_zone_contents_t *zone) +{ + // Check that we have not added DNAME child + const knot_dname_t *parent_dname = knot_wire_next_label(rr->owner, NULL); + const knot_node_t *parent = + knot_zone_contents_find_node(zone, parent_dname); + if (parent == NULL) { + return true; } - /* The array is cleared, we may delete the redundant RRs. */ - for (int i = 0; i < from_chgset_count; ++i) { - knot_rrset_free(&from_chgset[i], NULL); + if (knot_node_rrtype_exists(parent, KNOT_RRTYPE_DNAME)) { + // Parent has DNAME RRSet, refuse update + return false; } - free(from_chgset); - /* 5) Store the remaining RRSet to the changeset. Do not try to merge - * to some previous RRSet, there should be none. - */ - for (int i = 0; i < removed_count; ++i) { - if (knot_rrset_rr_count(to_chgset[i]) == 0) { - // Empty RRs caused by add + remove combo, skip. - knot_rrset_free(&to_chgset[i], NULL); - continue; - } - ret = knot_changeset_add_rrset(changeset, to_chgset[i], - KNOT_CHANGESET_REMOVE); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to store the RRSet copy to changeset: " - "%s.\n", knot_strerror(ret)); - for (int j = i; j < removed_count; ++j) { - knot_rrset_free(&to_chgset[j], NULL); - } - free(to_chgset); - return ret; - } + if (rr->type != KNOT_RRTYPE_DNAME || zone_node == NULL) { + return true; } - free(to_chgset); + // Check that we have not created node with DNAME children. + if (zone_node->children > 0) { + // Updated node has children and DNAME was added, refuse update + return false; + } - return KNOT_EOK; + return true; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_process_rem_all(knot_node_t *node, - knot_changeset_t *changeset, - knot_changes_t *changes) +/*!< \brief Checks whether we can accept this RR. */ +static int check_update(const knot_rrset_t *rrset, + const knot_pkt_t *query, + uint16_t *rcode) { - assert(node != NULL); - assert(changeset != NULL); - assert(changes != NULL); - - /*! \note - * This basically means to call knot_ddns_process_rem_rrset() for every - * type present in the node. - * - * In case of SOA and NS in apex, the RRSets should not be removed, but - * what about their RRSIGs?? - * - * If the zone has to remain properly signed, the UPDATE will have to - * contain at least new SOA and RRSIGs for it (as the auto-incremented - * SOA would not be signed). So it should not matter if we leave the - * RRSIGs there or not. But in case of the NSs it's not that clear. - * - * For now, we will leave the RRSIGs there. It's easier to implement. - * - * \todo Should document this!! - */ - int ret = 0; - // The copy of rrsets is important here. - knot_rrset_t **rrsets = knot_node_get_rrsets(node); - int count = knot_node_rrset_count(node); - - if (rrsets == NULL && count != 0) { - dbg_ddns("Failed to fetch RRSets from node.\n"); - return KNOT_ENOMEM; + /* Accept both subdomain and dname match. */ + const knot_dname_t *owner = rrset->owner; + const knot_dname_t *qname = knot_pkt_qname(query); + int is_sub = knot_dname_is_sub(owner, qname); + if (!is_sub && knot_dname_cmp(owner, qname) != 0) { + *rcode = KNOT_RCODE_NOTZONE; + return KNOT_EOUTOFZONE; } - int is_apex = knot_node_rrset(node, KNOT_RRTYPE_SOA) != NULL; + if (knot_rrtype_is_ddns_forbidden(rrset->type)) { + *rcode = KNOT_RCODE_REFUSED; + log_zone_error("Refusing to update DNSSEC-related record!\n"); + return KNOT_EDENIED; + } - dbg_ddns_verb("Removing all RRSets (count: %d).\n", count); - for (int i = 0; i < count; ++i) { - // Skip DNSSEC records - automatic signing will handle this - if (knot_rrtype_is_ddns_forbidden(rrsets[i]->type)) { - continue; + if (rrset->rclass == knot_pkt_qclass(query)) { + if (knot_rrtype_is_metatype(rrset->type)) { + *rcode = KNOT_RCODE_FORMERR; + return KNOT_EMALF; } - // If the node is apex, skip NS and SOA as well - if (is_apex && - (knot_rrset_type(rrsets[i]) == KNOT_RRTYPE_SOA - || knot_rrset_type(rrsets[i]) == KNOT_RRTYPE_NS)) { - continue; + } else if (rrset->rclass == KNOT_CLASS_ANY) { + if (!rrset_empty(rrset) + || (knot_rrtype_is_metatype(rrset->type) + && rrset->type != KNOT_RRTYPE_ANY)) { + *rcode = KNOT_RCODE_FORMERR; + return KNOT_EMALF; } - - ret = knot_ddns_process_rem_rrset(rrsets[i], node, changeset, - changes); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to remove RRSet: %s\n", - knot_strerror(ret)); - free(rrsets); - return ret; + } else if (rrset->rclass == KNOT_CLASS_NONE) { + if (knot_rrset_rr_ttl(rrset, 0) != 0 + || knot_rrtype_is_metatype(rrset->type)) { + *rcode = KNOT_RCODE_FORMERR; + return KNOT_EMALF; } + } else { + *rcode = KNOT_RCODE_FORMERR; + return KNOT_EMALF; } - free(rrsets); return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - -static int knot_ddns_process_rr(const knot_rrset_t *rr, - knot_zone_contents_t *zone, +/*!< \brief Checks RR and decides what to do with it. */ +static int process_rr(const knot_rrset_t *rr, + const knot_zone_contents_t *zone, knot_changeset_t *changeset, - knot_changes_t *changes, uint16_t qclass, - knot_rrset_t **rr_copy) + int *apex_ns_rem) { - assert(rr != NULL); - assert(zone != NULL); - assert(changeset != NULL); - assert(changes != NULL); - assert(rr_copy != NULL); - - /* 1) Find node that will be affected. */ - knot_node_t *node = knot_zone_contents_get_node(zone, rr->owner); - - /* 2) Decide what to do. */ - int ret = KNOT_EOK; - if (knot_rrset_class(rr) == knot_zone_contents_class(zone)) { - ret = knot_ddns_process_add(rr, &node, zone, changeset, - changes, rr_copy); - } else if (node == NULL) { - // Removing from non-existing node, just ignore the entry - return KNOT_EOK; - } else if (knot_rrset_class(rr) == KNOT_CLASS_NONE) { - ret = knot_ddns_process_rem_rr(rr, node, zone, changeset, - changes, qclass); - } else if (knot_rrset_class(rr) == KNOT_CLASS_ANY) { - if (knot_rrset_type(rr) == KNOT_RRTYPE_ANY) { - ret = knot_ddns_process_rem_all(node, changeset, - changes); - } else { - ret = knot_ddns_process_rem_rrset(rr, node, changeset, - changes); + const knot_node_t *node = knot_zone_contents_find_node(zone, rr->owner); + if (is_addition(rr)) { + int ret = process_add(rr, node, changeset, apex_ns_rem); + if (ret == KNOT_EOK) { + if (!sem_check(rr, node, zone)) { + return KNOT_EDENIED; + } } + return ret; + } else if (is_removal(rr)) { + return process_remove(rr, node, changeset, apex_ns_rem); } else { - return KNOT_ERROR; + return KNOT_EMALF; } +} - if (ret == KNOT_EOK) { - assert(node); - // Do a semantic check for changed node. - err_handler_t handler; - err_handler_init(&handler); - bool fatal = false; - ret = sem_check_node_plain(zone, node, &handler, true, &fatal); - if (ret == KNOT_EOK) { - if (fatal) { - ret = KNOT_EDENIED; - } +/*!< \brief Maps Knot return code to RCODE. */ +static uint16_t ret_to_rcode(int ret) +{ + if (ret == KNOT_EMALF) { + return KNOT_RCODE_FORMERR; + } else if (ret == KNOT_EDENIED) { + return KNOT_RCODE_REFUSED; + } else { + return KNOT_RCODE_SERVFAIL; + } +} + +/* ---------------------------------- API ----------------------------------- */ + +int knot_ddns_process_prereqs(const knot_pkt_t *query, const knot_zone_contents_t *zone, + uint16_t *rcode) +{ + if (query == NULL || rcode == NULL || zone == NULL) { + return KNOT_EINVAL; + } + + int ret = KNOT_EOK; + list_t rrset_list; // List used to store merged RRSets + init_list(&rrset_list); + + const knot_pktsection_t *answer = knot_pkt_section(query, KNOT_ANSWER); + for (int i = 0; i < answer->count; ++i) { + // Check what can be checked, store full RRs into list + ret = process_prereq(&answer->rr[i], knot_pkt_qclass(query), + zone, rcode, &rrset_list); + if (ret != KNOT_EOK) { + rrset_list_clear(&rrset_list); + return ret; } } + // Check stored RRSets + ret = check_stored_rrsets(&rrset_list, zone, rcode); + rrset_list_clear(&rrset_list); return ret; } -/*----------------------------------------------------------------------------*/ -/* - * NOTES: - * - 'zone' must be a copy of the current zone. - * - changeset must be allocated - * - changes must be allocated - * - * All this is done in the first parts of xfrin_apply_changesets() - extract - * to separate function, if possible. - * - * If anything fails, rollback must be done. The xfrin_rollback_update() may - * be good for this. - */ -int knot_ddns_process_update(knot_zone_contents_t *zone, +int knot_ddns_process_update(const knot_zone_contents_t *zone, const knot_pkt_t *query, knot_changeset_t *changeset, - knot_changes_t *changes, uint16_t *rcode, uint32_t new_serial) { - if (zone == NULL || query == NULL || changeset == NULL || rcode == NULL - || changes == NULL) { + if (zone == NULL || query == NULL || changeset == NULL || rcode == NULL) { return KNOT_EINVAL; } - int ret = KNOT_EOK; - /* Copy base SOA RR. */ - const knot_rrset_t *soa = knot_node_rrset(knot_zone_contents_apex(zone), - KNOT_RRTYPE_SOA); - knot_rrset_t *soa_begin = NULL; - knot_rrset_t *soa_end = NULL; - ret = knot_rrset_copy(soa, &soa_begin, NULL); - if (ret == KNOT_EOK) { - knot_changeset_add_soa(changeset, soa_begin, - KNOT_CHANGESET_REMOVE); - } else { - *rcode = KNOT_RCODE_SERVFAIL; - return ret; - } - - /* Current SERIAL */ - int64_t sn = knot_rdata_soa_serial(soa_begin); - int64_t sn_new; + knot_rrset_t *soa_begin = knot_node_create_rrset(zone->apex, + KNOT_RRTYPE_SOA); + knot_changeset_add_soa(changeset, soa_begin, KNOT_CHANGESET_REMOVE); - /* Set the new serial according to policy. */ - if (sn > -1) { - sn_new = new_serial; - assert(sn_new != KNOT_EINVAL); - } else { - *rcode = KNOT_RCODE_SERVFAIL; - return ret; - } + int64_t sn_old = knot_zone_serial(zone); /* Process all RRs the Authority (Update) section. */ - const knot_rrset_t *rr = NULL; - knot_rrset_t *rr_copy = NULL; - dbg_ddns("Processing UPDATE section.\n"); + int apex_ns_rem = 0; const knot_pktsection_t *authority = knot_pkt_section(query, KNOT_AUTHORITY); - for (int i = 0; i < authority->count; ++i) { - - rr = authority->rr[i]; + for (uint16_t i = 0; i < authority->count; ++i) { + const knot_rrset_t *rr = &authority->rr[i]; /* Check if the entry is correct. */ - ret = knot_ddns_check_update(rr, query, rcode); + int ret = check_update(rr, query, rcode); if (ret != KNOT_EOK) { - dbg_ddns("Failed to check update RRSet:%s\n", - knot_strerror(ret)); return ret; } - /* Check if the record is SOA. If yes, check the SERIAL. - * If this record should cause the SOA to be replaced in the - * zone, use it as the ending SOA. - * - * Also handle cases where there are multiple SOAs to be added - * in the same UPDATE. The one with the largest SERIAL should - * be used. - * - * TODO: If there are more SOAs in the UPDATE one after another, - * the ddns_add_update() function will merge them into a - * RRSet. This should be handled somehow. - * - * If the serial is not larger than the current zone serial, - * ignore the record and continue. This will ensure that the - * RR processing function receives only SOA RRs that should be - * added to the zone (replacing the old one). - */ - if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA - && (knot_rrset_class(rr) == KNOT_CLASS_NONE - || knot_rrset_class(rr) == KNOT_CLASS_ANY - || knot_serial_compare(knot_rdata_soa_serial(rr), - sn) <= 0)) { - // This ignores also SOA removals - dbg_ddns_verb("Ignoring SOA...\n"); + if (skip_soa(rr, sn_old)) { continue; } - dbg_ddns_verb("Processing RR %p...\n", rr); - ret = knot_ddns_process_rr(rr, zone, changeset, changes, - knot_pkt_qclass(query), - &rr_copy); - + ret = process_rr(rr, zone, changeset, &apex_ns_rem); if (ret != KNOT_EOK) { - dbg_ddns("Failed to process update RR:%s\n", - knot_strerror(ret)); - if (ret == KNOT_EMALF) { - *rcode = KNOT_RCODE_FORMERR; - } else if (ret == KNOT_EDENIED) { - *rcode = KNOT_RCODE_REFUSED; - } else { - *rcode = KNOT_RCODE_SERVFAIL; - } + *rcode = ret_to_rcode(ret); return ret; } - - // we need the RR copy, that's why this code is here - if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) { - int64_t sn_rr = knot_rdata_soa_serial(rr); - dbg_ddns_verb("Replacing SOA. Old serial: %"PRId64", " - "new serial: %"PRId64"\n", sn_new, sn_rr); - assert(knot_serial_compare(sn_rr, sn) > 0); - assert(rr_copy != NULL); - sn_new = sn_rr; - soa_end = rr_copy; - } } - /* Ending SOA (not in the UPDATE) */ - if (soa_end == NULL) { - /* If the changeset is empty, do not process anything further - * and indicate this to the caller, so that the changeset is not - * saved and zone is not switched. - */ + if (changeset->soa_to == NULL) { + // No SOA in the update, create according to current policy if (knot_changeset_is_empty(changeset)) { - return 1; - } - - /* If not set, create new SOA. */ - ret = knot_rrset_copy(soa, &soa_end, NULL); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to copy ending SOA: %s\n", - knot_strerror(ret)); - *rcode = KNOT_RCODE_SERVFAIL; - return ret; + // No change, no new SOA + return KNOT_EOK; } - knot_rdata_soa_serial_set(soa_end, sn_new); - /* And replace it in the zone. */ - ret = xfrin_replace_rrset_in_node( - knot_zone_contents_get_apex(zone), - soa_end, changes, zone); - if (ret != KNOT_EOK) { - dbg_ddns("Failed to copy replace SOA in zone: %s\n", - knot_strerror(ret)); + knot_rrset_t *soa_cpy = knot_rrset_copy(soa_begin, NULL); + if (soa_cpy == NULL) { *rcode = KNOT_RCODE_SERVFAIL; - return ret; + return KNOT_ENOMEM; } + knot_rrs_soa_serial_set(&soa_cpy->rrs, new_serial); + knot_changeset_add_soa(changeset, soa_cpy, KNOT_CHANGESET_ADD); } - ret = knot_ddns_final_soa_to_chgset(soa_end, changeset); - - return ret; + return KNOT_EOK; } diff --git a/src/knot/updates/ddns.h b/src/knot/updates/ddns.h index f6993b65bf3a3a1ec47462bd7a6205083a99aaf8..796b0d56f04a85375dc9208efca987bdac7d313e 100644 --- a/src/knot/updates/ddns.h +++ b/src/knot/updates/ddns.h @@ -2,6 +2,7 @@ * \file ddns.h * * \author Lubos Slovak <lubos.slovak@nic.cz> + * \author Jan Kadlec <jan.kadlec@nic.cz> * * \brief Dynamic updates processing. * @@ -30,49 +31,37 @@ #include "knot/updates/changesets.h" #include "knot/zone/zone.h" #include "libknot/packet/pkt.h" -#include "libknot/rrset.h" #include "libknot/dname.h" -#include "libknot/consts.h" -#include "common/lists.h" - -typedef struct knot_ddns_prereq_t { - knot_rrset_t **exist; - size_t exist_count; - size_t exist_allocd; - - knot_rrset_t **exist_full; - size_t exist_full_count; - size_t exist_full_allocd; - - knot_rrset_t **not_exist; - size_t not_exist_count; - size_t not_exist_allocd; - - knot_dname_t **in_use; - size_t in_use_count; - size_t in_use_allocd; - - knot_dname_t **not_in_use; - size_t not_in_use_count; - size_t not_in_use_allocd; -} knot_ddns_prereq_t; - -int knot_ddns_check_zone(const knot_zone_contents_t *zone, - const knot_pkt_t *query, uint16_t *rcode); +/*! + * \brief Checks update prerequisite section. + * + * \param query DNS message containing the update. + * \param zone Zone to be checked. + * \param rcode Returned DNS RCODE. + * + * \return KNOT_E* + */ int knot_ddns_process_prereqs(const knot_pkt_t *query, - knot_ddns_prereq_t **prereqs, uint16_t *rcode); - -int knot_ddns_check_prereqs(const knot_zone_contents_t *zone, - knot_ddns_prereq_t **prereqs, uint16_t *rcode); - -int knot_ddns_process_update(knot_zone_contents_t *zone, - const knot_pkt_t *query, - knot_changeset_t *changeset, - knot_changes_t *changes, - uint16_t *rcode, uint32_t new_serial); + const knot_zone_contents_t *zone, + uint16_t *rcode); -void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq); +/*! + * \brief Processes DNS update and creates a changeset out of it. Zone is left + * intact. + * + * \param zone Zone to be updated. + * \param query DNS message containing the update. + * \param changeset Output changeset. + * \param rcode Output DNS RCODE. + * \param new_serial New serial to use for updated zone. + * + * \return KNOT_E* + */ +int knot_ddns_process_update(const knot_zone_contents_t *zone, + const knot_pkt_t *query, + knot_changeset_t *changeset, + uint16_t *rcode, uint32_t new_serial); #endif /* _KNOT_DDNS_H_ */ diff --git a/src/knot/updates/xfr-in.c b/src/knot/updates/xfr-in.c index b43fef2cbf7c47a1e5b2d178605ea09e9acac192..90f4e83c86377e1d26f627e7e016fffdbcb7ee6c 100644 --- a/src/knot/updates/xfr-in.c +++ b/src/knot/updates/xfr-in.c @@ -42,6 +42,23 @@ #define KNOT_NS_TSIG_FREQ 100 +/*! + * \brief Post update cleanup: frees data that are in the tree that will not + * be used (old tree if success, new tree if failure). + * Freed data: + * - actual data inside knot_rrs_t. (the rest is part of the node) + * - arrays allocated for additional nodes. (optional, nodes are kept) + */ +static void rrs_list_clear(list_t *l, mm_ctx_t *mm) +{ + ptrnode_t *n; + node_t *nxt; + WALK_LIST_DELSAFE(n, nxt, *l) { + mm_free(mm, (void *)n->d); + mm_free(mm, n); + }; +} + static int knot_ns_tsig_required(int packet_nr) { /*! \bug This can overflow to negative numbers. Proper solution is to @@ -63,10 +80,9 @@ int xfrin_transfer_needed(const knot_zone_contents_t *zone, /* * Retrieve the local Serial */ - const knot_rrset_t *soa_rrset = - knot_node_rrset(knot_zone_contents_apex(zone), - KNOT_RRTYPE_SOA); - if (soa_rrset == NULL) { + const knot_rrs_t *soa_rrs = + knot_node_rrs(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA); + if (soa_rrs == NULL) { char *name = knot_dname_to_str(knot_node_owner( knot_zone_contents_apex(zone))); dbg_xfrin("SOA RRSet missing in the zone %s!\n", name); @@ -74,31 +90,21 @@ int xfrin_transfer_needed(const knot_zone_contents_t *zone, return KNOT_ERROR; } - int64_t local_serial = knot_rdata_soa_serial(soa_rrset); - if (local_serial < 0) { -dbg_xfrin_exec( - char *name = knot_dname_to_str(knot_rrset_owner(soa_rrset)); - dbg_xfrin("Malformed data in SOA of zone %s\n", name); - free(name); -); - return KNOT_EMALF; // maybe some other error - } - + uint32_t local_serial = knot_rrs_soa_serial(soa_rrs); /* * Retrieve the remote Serial */ // the SOA should be the first (and only) RRSet in the response - const knot_pktsection_t *answer = knot_pkt_section(soa_response, KNOT_ANSWER); - if (answer->count < 1 || knot_rrset_type(answer->rr[0]) != KNOT_RRTYPE_SOA) { + if (answer->count < 1) { return KNOT_EMALF; } - - int64_t remote_serial = knot_rdata_soa_serial(answer->rr[0]); - if (remote_serial < 0) { - return KNOT_EMALF; // maybe some other error + knot_rrset_t soa_rr = answer->rr[0]; + if (soa_rr.type != KNOT_RRTYPE_SOA) { + return KNOT_EMALF; } + uint32_t remote_serial = knot_rrs_soa_serial(&soa_rr.rrs); return (knot_serial_compare(local_serial, remote_serial) < 0); } @@ -131,9 +137,10 @@ int xfrin_create_ixfr_query(const zone_t *zone, knot_pkt_t *pkt) /* Add SOA RR to authority section for IXFR. */ knot_node_t *apex = zone->contents->apex; - const knot_rrset_t *soa = knot_node_rrset(apex, KNOT_RRTYPE_SOA); + knot_rrset_t soa = knot_node_rrset(apex, KNOT_RRTYPE_SOA); knot_pkt_begin(pkt, KNOT_AUTHORITY); - return knot_pkt_put(pkt, COMPR_HINT_QNAME, soa, 0); + ret = knot_pkt_put(pkt, COMPR_HINT_QNAME, &soa, 0); + return ret; } /*----------------------------------------------------------------------------*/ @@ -223,18 +230,14 @@ static int xfrin_check_tsig(knot_pkt_t *packet, knot_ns_xfr_t *xfr, /*----------------------------------------------------------------------------*/ -static int xfrin_take_rr(const knot_pktsection_t *answer, knot_rrset_t **rr, uint16_t *cur) +static void xfrin_take_rr(const knot_pktsection_t *answer, const knot_rrset_t **rr, uint16_t *cur) { - int ret = KNOT_EOK; if (*cur < answer->count) { - ret = knot_rrset_copy(answer->rr[*cur], rr, NULL); + *rr = &answer->rr[*cur]; *cur += 1; } else { *rr = NULL; - ret = KNOT_EOK; } - - return ret; } /*----------------------------------------------------------------------------*/ @@ -246,19 +249,17 @@ int xfrin_process_axfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr, knot_zone_con } uint16_t rr_id = 0; - knot_rrset_t *rr = NULL; + const knot_rrset_t *rr = NULL; const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER); - int ret = xfrin_take_rr(answer, &rr, &rr_id); + xfrin_take_rr(answer, &rr, &rr_id); if (*zone == NULL) { // Transfer start, init zone if (rr->type != KNOT_RRTYPE_SOA) { - knot_rrset_free(&rr, NULL); return KNOT_EMALF; } *zone = knot_zone_contents_new(rr->owner); if (*zone == NULL) { - knot_rrset_free(&rr, NULL); return KNOT_ENOMEM; } xfr->packet_nr = 0; @@ -270,32 +271,27 @@ int xfrin_process_axfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr, knot_zone_con zcreator_t zc = {.z = *zone, .master = false, .ret = KNOT_EOK }; - - while (ret == KNOT_EOK && rr) { + while (rr) { if (rr->type == KNOT_RRTYPE_SOA && - knot_node_rrset(zc.z->apex, KNOT_RRTYPE_SOA)) { + knot_node_rrtype_exists(zc.z->apex, KNOT_RRTYPE_SOA)) { // Last SOA, last message, check TSIG. - ret = xfrin_check_tsig(pkt, xfr, 1); - knot_rrset_free(&rr, NULL); + int ret = xfrin_check_tsig(pkt, xfr, 1); if (ret != KNOT_EOK) { return ret; } return 1; // Signal that transfer finished. } else { - ret = zcreator_step(&zc, rr); + int ret = zcreator_step(&zc, rr); if (ret != KNOT_EOK) { - knot_rrset_free(&rr, NULL); + // 'rr' is either inserted, or free'd return ret; } - ret = xfrin_take_rr(answer, &rr, &rr_id); + xfrin_take_rr(answer, &rr, &rr_id); } } - assert(rr == NULL); // Check possible TSIG at the end of DNS message. - ret = xfrin_check_tsig(pkt, xfr, - knot_ns_tsig_required(xfr->packet_nr)); - return ret; // ret == KNOT_EOK means processing continues. + return xfrin_check_tsig(pkt, xfr, knot_ns_tsig_required(xfr->packet_nr)); } /*----------------------------------------------------------------------------*/ @@ -309,45 +305,43 @@ int xfrin_process_ixfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr) } uint16_t rr_id = 0; - knot_rrset_t *rr = NULL; + const knot_rrset_t *rr = NULL; const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER); - int ret = xfrin_take_rr(answer, &rr, &rr_id); - if (ret != KNOT_EOK) { + xfrin_take_rr(answer, &rr, &rr_id); + if (rr == NULL) { return KNOT_EXFRREFUSED; /* Empty, try again with AXFR */ } // state of the transfer // -1 .. a SOA is expected to create a new changeset int state = 0; - - /*! \todo Replace with RRSet duplicate checking. */ -// xfrin_insert_rrset_dnames_to_table(rr, xfr->lookup_tree); - + int ret = KNOT_EOK; if (*chs == NULL) { dbg_xfrin_verb("Changesets empty, creating new.\n"); - ret = knot_changesets_init(chs); if (ret != KNOT_EOK) { - knot_rrset_free(&rr, NULL); return ret; } // the first RR must be a SOA - if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { + if (rr->type != KNOT_RRTYPE_SOA) { dbg_xfrin("First RR is not a SOA RR!\n"); - knot_rrset_free(&rr, NULL); ret = KNOT_EMALF; goto cleanup; } // just store the first SOA for later use - (*chs)->first_soa = rr; + (*chs)->first_soa = knot_rrset_copy(rr, NULL); + if ((*chs)->first_soa == NULL) { + ret = KNOT_ENOMEM; + goto cleanup; + } state = -1; dbg_xfrin_verb("First SOA of IXFR saved, state set to -1.\n"); // take next RR - ret = xfrin_take_rr(answer, &rr, &rr_id); + xfrin_take_rr(answer, &rr, &rr_id); /* * If there is no other records in the response than the SOA, it @@ -368,16 +362,13 @@ int xfrin_process_ixfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr) if (rr == NULL) { dbg_xfrin("Response containing only SOA,\n"); return XFRIN_RES_SOA_ONLY; - } else if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { - knot_rrset_free(&rr, NULL); + } else if (rr->type != KNOT_RRTYPE_SOA) { dbg_xfrin("Fallback to AXFR.\n"); - ret = XFRIN_RES_FALLBACK; - return ret; + return XFRIN_RES_FALLBACK; } } else { if ((*chs)->first_soa == NULL) { dbg_xfrin("Changesets don't contain SOA first!\n"); - knot_rrset_free(&rr, NULL); ret = KNOT_EINVAL; goto cleanup; } @@ -425,7 +416,6 @@ int xfrin_process_ixfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr) dbg_xfrin_detail("State is not -1, deciding...\n"); // there should be at least one started changeset right now if (EMPTY_LIST((*chs)->sets)) { - knot_rrset_free(&rr, NULL); ret = KNOT_EMALF; goto cleanup; } @@ -444,20 +434,12 @@ int xfrin_process_ixfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr) /*! \todo This may be implemented with much less IFs! */ - while (ret == KNOT_EOK && rr != NULL) { -dbg_xfrin_exec_verb( - dbg_xfrin_detail("Next loop, state: %d\n", state); - char *name = knot_dname_to_str(knot_rrset_owner(rr)); - dbg_xfrin_detail("Actual RR: %s, type %u.\n", name, - knot_rrset_type(rr)); - free(name); -); + while (rr != NULL) { if (!knot_dname_is_sub(rr->owner, xfr->zone->name) && !knot_dname_is_equal(rr->owner, xfr->zone->name)) { // out-of-zone domain - knot_rrset_free(&rr, NULL); // take next RR - ret = xfrin_take_rr(answer, &rr, &rr_id); + xfrin_take_rr(answer, &rr, &rr_id); continue; } @@ -467,17 +449,16 @@ dbg_xfrin_exec_verb( // this may be either a start of a changeset or the // last SOA (in case the transfer was empty, but that // is quite weird in fact - if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { + if (rr->type != KNOT_RRTYPE_SOA) { dbg_xfrin("First RR is not a SOA RR!\n"); dbg_xfrin_verb("RR type: %u\n", - knot_rrset_type(rr)); - knot_rrset_free(&rr, NULL); + rr->type); ret = KNOT_EMALF; goto cleanup; } - if (knot_rdata_soa_serial(rr) - == knot_rdata_soa_serial((*chs)->first_soa)) { + if (knot_rrs_soa_serial(&rr->rrs) + == knot_rrs_soa_serial(&(*chs)->first_soa->rrs)) { /*! \note [TSIG] Check TSIG, we're at the end of * transfer. @@ -485,8 +466,6 @@ dbg_xfrin_exec_verb( ret = xfrin_check_tsig(pkt, xfr, 1); // last SOA, discard and end - knot_rrset_free(&rr, NULL); - /*! \note [TSIG] If TSIG validates, consider * transfer complete. */ if (ret == KNOT_EOK) { @@ -501,16 +480,20 @@ dbg_xfrin_exec_verb( ret = KNOT_ESPACE; if (ret != KNOT_EOK) { - knot_rrset_free(&rr, NULL); goto cleanup; } chset = knot_changesets_create_changeset(*chs); if (chset == NULL) { - knot_rrset_free(&rr, NULL); goto cleanup; } - knot_changeset_add_soa(chset, rr, KNOT_CHANGESET_REMOVE); + knot_rrset_t *soa = knot_rrset_copy(rr, NULL); + if (soa == NULL) { + ret = KNOT_ENOMEM; + goto cleanup; + } + + knot_changeset_add_soa(chset, soa, KNOT_CHANGESET_REMOVE); // change state to REMOVE state = KNOT_CHANGESET_REMOVE; @@ -519,20 +502,28 @@ dbg_xfrin_exec_verb( case KNOT_CHANGESET_REMOVE: // if the next RR is SOA, store it and change state to // ADD - if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) { + if (rr->type == KNOT_RRTYPE_SOA) { // we should not be here if soa_from is not set assert(chset->soa_from != NULL); - - knot_changeset_add_soa(chset, rr, KNOT_CHANGESET_ADD); + knot_rrset_t *soa = knot_rrset_copy(rr, NULL); + if (soa == NULL) { + ret = KNOT_ENOMEM; + goto cleanup; + } + knot_changeset_add_soa(chset, soa, KNOT_CHANGESET_ADD); state = KNOT_CHANGESET_ADD; } else { // just add the RR to the REMOVE part and // continue - ret = knot_changeset_add_rr(chset, rr, - KNOT_CHANGESET_REMOVE); + knot_rrset_t *cpy = knot_rrset_copy(rr, NULL); + if (cpy == NULL) { + ret = KNOT_ENOMEM; + goto cleanup; + } + ret = knot_changeset_add_rrset(chset, cpy, + KNOT_CHANGESET_REMOVE); if (ret != KNOT_EOK) { - knot_rrset_free(&rr, NULL); goto cleanup; } } @@ -540,20 +531,23 @@ dbg_xfrin_exec_verb( case KNOT_CHANGESET_ADD: // if the next RR is SOA change to state -1 and do not // parse next RR - if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) { + if (rr->type == KNOT_RRTYPE_SOA) { log_zone_info("%s Serial %u -> %u.\n", xfr->msg, - knot_rdata_soa_serial(chset->soa_from), - knot_rdata_soa_serial(chset->soa_to)); + knot_rrs_soa_serial(&chset->soa_from->rrs), + knot_rrs_soa_serial(&chset->soa_to->rrs)); state = -1; continue; } else { - // just add the RR to the ADD part and continue - ret = knot_changeset_add_rr(chset, rr, - KNOT_CHANGESET_ADD); + knot_rrset_t *cpy = knot_rrset_copy(rr, NULL); + if (cpy == NULL) { + ret = KNOT_ENOMEM; + goto cleanup; + } + ret = knot_changeset_add_rrset(chset, cpy, + KNOT_CHANGESET_ADD); if (ret != KNOT_EOK) { - knot_rrset_free(&rr, NULL); goto cleanup; } } @@ -561,7 +555,7 @@ dbg_xfrin_exec_verb( } // take next RR - ret = xfrin_take_rr(answer, &rr, &rr_id); + xfrin_take_rr(answer, &rr, &rr_id); } /*! \note Check TSIG, we're at the end of packet. It may not be @@ -595,11 +589,29 @@ cleanup: /* Applying changesets to zone */ /*----------------------------------------------------------------------------*/ -void xfrin_zone_contents_free(knot_zone_contents_t **contents) +void xfrin_cleanup_successful_update(knot_changesets_t *chgs) { - /*! \todo This should be all in some API!! */ + if (chgs == NULL) { + return; + } + + knot_changeset_t *change = NULL; + WALK_LIST(change, chgs->sets) { + // Delete old RR data + rrs_list_clear(&change->old_data, NULL); + init_list(&change->old_data); + // Keep new RR data + ptrlist_free(&change->new_data, NULL); + init_list(&change->new_data); + }; +} + +/*----------------------------------------------------------------------------*/ - // free the zone tree with nodes +static void xfrin_zone_contents_free(knot_zone_contents_t **contents) +{ + // free the zone tree, but only the structure + // (nodes are already destroyed) dbg_zone("Destroying zone tree.\n"); knot_zone_tree_deep_free(&(*contents)->nodes); dbg_zone("Destroying NSEC3 zone tree.\n"); @@ -613,577 +625,191 @@ void xfrin_zone_contents_free(knot_zone_contents_t **contents) /*----------------------------------------------------------------------------*/ -int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, - knot_changes_t *changes, int save_new) +static void xfrin_cleanup_failed_update(knot_zone_contents_t **new_contents) { - dbg_xfrin_detail("Copying old RRSet: %p\n", old); - // create new RRSet by copying the old one - int ret = knot_rrset_copy(old, copy, NULL); - if (ret != KNOT_EOK) { - dbg_xfrin("Failed to create RRSet copy.\n"); - return KNOT_ENOMEM; - } - - // add the RRSet to the list of new RRSets - if (save_new) { - ret = knot_changes_add_rrset(changes, *copy, KNOT_CHANGES_NEW); - if (ret != KNOT_EOK) { - knot_rrset_free(copy, NULL); - return ret; - } + if (new_contents == NULL) { + return; } - ret = knot_changes_add_rrset(changes, old, KNOT_CHANGES_OLD); - if (ret != KNOT_EOK) { - return ret; + if (*new_contents != NULL) { + // destroy the shallow copy of zone + xfrin_zone_contents_free(new_contents); } - return KNOT_EOK; } /*----------------------------------------------------------------------------*/ -int xfrin_copy_rrset(knot_node_t *node, uint16_t type, - knot_rrset_t **rrset, knot_changes_t *changes, - int save_new) +void xfrin_rollback_update(knot_changesets_t *chgs, + knot_zone_contents_t **new_contents) { -dbg_xfrin_exec_detail( - char *name = knot_dname_to_str(knot_node_owner(node)); - dbg_xfrin_detail("Removing RRSet of type %u from node %s (%p)\n", - type, name, node); - free(name); -); - knot_rrset_t *old = knot_node_remove_rrset(node, type); - - dbg_xfrin_detail("Removed RRSet: %p\n", old); - dbg_xfrin_detail("Other RRSet of the same type in the node: %p\n", - knot_node_rrset(node, type)); - - if (old == NULL) { - dbg_xfrin_verb("RRSet not found for RR to be removed.\n"); - return 1; - } - - int ret = xfrin_copy_old_rrset(old, rrset, changes, save_new); - if (ret != KNOT_EOK) { - return ret; - } - - dbg_xfrin_detail("Copied old rrset %p to new %p.\n", old, *rrset); - - // replace the RRSet in the node copy by the new one - ret = knot_node_add_rrset_replace(node, *rrset); - if (ret != KNOT_EOK) { - knot_rrset_free(rrset, NULL); - dbg_xfrin("Failed to add RRSet copy to node\n"); - return KNOT_ERROR; - } - - return KNOT_EOK; + if (chgs != NULL) { + knot_changeset_t *change = NULL; + WALK_LIST(change, chgs->sets) { + // Delete new RR data + rrs_list_clear(&change->new_data, NULL); + init_list(&change->new_data); + // Keep old RR data + ptrlist_free(&change->old_data, NULL); + init_list(&change->old_data); + }; + } + xfrin_cleanup_failed_update(new_contents); } /*----------------------------------------------------------------------------*/ -static int xfrin_apply_remove_normal(knot_changes_t *changes, - const knot_rrset_t *remove, - knot_node_t *node, - knot_rrset_t **rrset) +static int xfrin_replace_rrs_with_copy(knot_node_t *node, + uint16_t type) { - assert(changes != NULL); - assert(remove != NULL); - assert(node != NULL); - assert(rrset != NULL); - - int ret; - - // now we have the copy of the node, so lets get the right RRSet - // check if we do not already have it - if (*rrset - && knot_dname_cmp(knot_rrset_owner(*rrset), - knot_node_owner(node)) == 0 - && knot_rrset_type(*rrset) == knot_rrset_type(remove)) { - /*! \todo Does some other case even occur? */ - dbg_xfrin_verb("Using RRSet from previous loop.\n"); - } else { - /*! - * \todo This may happen also with already - * copied RRSet. In that case it would be - * an unnecesary overhead but will - * probably not cause problems. TEST!! - */ - ret = xfrin_copy_rrset(node, - knot_rrset_type(remove), rrset, changes, 1); - if (ret != KNOT_EOK) { - return ret; + // Find data to copy. + struct rr_data *data = NULL; + for (uint16_t i = 0; i < node->rrset_count; ++i) { + if (node->rrs[i].type == type) { + data = &node->rrs[i]; + break; } } + assert(data); - if (*rrset == NULL) { - dbg_xfrin_verb("RRSet not found for RR to be removed.\n"); - return 1; - } - -dbg_xfrin_exec_detail( - char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); - dbg_xfrin_detail("Updating RRSet with owner %s, type %u\n", name, - knot_rrset_type(*rrset)); - free(name); -); - - // remove the specified RRs from the RRSet (de facto difference of sets) - knot_rrset_t *rr_remove = NULL; - ret = knot_rrset_remove_rr_using_rrset(*rrset, remove, &rr_remove, NULL); - if (ret != KNOT_EOK) { - dbg_xfrin("xfr: remove_normal: Could not remove RR (%s).\n", - knot_strerror(ret)); - return ret; - } - /*!< \todo either one of these checks should be enough. */ - if (knot_rrset_rr_count(rr_remove) == 0) { - /* No RDATA, no need to deep free. */ - knot_rrset_free(&rr_remove, NULL); - dbg_xfrin_verb("Failed to remove RDATA from RRSet\n"); - // In this case, the RDATA was not found in the RRSet - return 1; - } - - if (knot_rrset_rr_count(rr_remove) > 0) { - ret = knot_changes_add_rrset(changes, rr_remove, KNOT_CHANGES_OLD); - if (ret != KNOT_EOK) { - knot_rrset_free(&rr_remove, NULL); - return ret; - } - } else { - /* Discard empty RRSet. */ - knot_rrset_free(&rr_remove, NULL); + // Create new data. + knot_rrs_t *rrs = &data->rrs; + void *copy = malloc(knot_rrs_size(rrs)); + if (copy == NULL) { + return KNOT_ENOMEM; } - // if the RRSet is empty, remove from node and add to old RRSets - if (knot_rrset_rr_count(*rrset) == 0) { - knot_rrset_t *tmp = knot_node_remove_rrset(node, - knot_rrset_type(*rrset)); - dbg_xfrin_detail("Removed whole RRSet (%p). Node rr count=%d\n", - tmp, knot_node_rrset_count(node)); + memcpy(copy, rrs->data, knot_rrs_size(rrs)); - // add the removed RRSet to list of old RRSets - - assert(tmp == *rrset); - ret = knot_changes_add_rrset(changes, *rrset, KNOT_CHANGES_OLD); - if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add empty RRSet to the " - "list of old RRSets."); - // delete the RRSet right away - knot_rrset_free(rrset, NULL); - return ret; - } - } + /* + * Clear additional array from node in new tree. It's callers + * responsibility to store it for cleanup. + */ + data->additional = NULL; + // Store new data into node RRS. + rrs->data = copy; return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - -static knot_node_t *xfrin_add_new_node(knot_zone_contents_t *contents, - knot_rrset_t *rrset, int is_nsec3) +static void clear_new_rrs(knot_node_t *node, uint16_t type) { - knot_node_t *node = knot_node_new(knot_rrset_get_owner(rrset), - NULL, 0); - if (node == NULL) { - dbg_xfrin("Failed to create a new node.\n"); - return NULL; + knot_rrs_t *new_rrs = knot_node_get_rrs(node, type); + if (new_rrs) { + knot_rrs_clear(new_rrs, NULL); } - - int ret = 0; - - // insert the node into zone structures and create parents if - // necessary - if (is_nsec3) { - ret = knot_zone_contents_add_nsec3_node(contents, node, 1, 0); - } else { - ret = knot_zone_contents_add_node(contents, node, 1, 0); - } - if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add new node to zone contents.\n"); - knot_node_free(&node); - return NULL; - } - - return node; } -/*----------------------------------------------------------------------------*/ - -int xfrin_replace_rrset_in_node(knot_node_t *node, - knot_rrset_t *rrset_new, - knot_changes_t *changes, - knot_zone_contents_t *contents) +static bool can_remove(const knot_node_t *node, const knot_rrset_t *rr) { - if (node == NULL || rrset_new == NULL || changes == NULL - || contents == NULL) { - return KNOT_EINVAL; - } - - uint16_t type = knot_rrset_type(rrset_new); - // remove RRSet of the proper type from the node - dbg_xfrin_verb("Removing RRSet of type: %u.\n", type); - knot_rrset_t *rrset_old = knot_node_remove_rrset(node, type); - assert(rrset_old != NULL); - - // save also the RDATA, because RDATA are not deleted with the RRSet - // save the new RRSet to the new RRSet, so that it is deleted if the - // apply fails - int ret = knot_changes_add_rrset(changes, rrset_old, KNOT_CHANGES_OLD); - if (ret != KNOT_EOK) { - return ret; + if (node == NULL) { + // Node does not exist, cannot remove anything. + return false; } - - // insert the new RRSet to the node - dbg_xfrin_verb("Adding new RRSet.\n"); - ret = knot_zone_contents_add_rrset(contents, rrset_new, &node, - KNOT_RRSET_DUPL_SKIP); - - if (ret < 0) { - dbg_xfrin("Failed to add RRSet to node.\n"); - return KNOT_ERROR; + const knot_rrs_t *node_rrs = knot_node_rrs(node, rr->type); + if (node_rrs == NULL) { + // Node does not have this type at all. + return false; } - assert(ret == 0); - ret = knot_changes_add_rrset(changes, rrset_new, KNOT_CHANGES_NEW); - if (ret != KNOT_EOK) { - return ret; + const bool compare_ttls = false; + for (uint16_t i = 0; i < rr->rrs.rr_count; ++i) { + knot_rr_t *rr_cmp = knot_rrs_rr(&rr->rrs, i); + if (knot_rrs_member(node_rrs, rr_cmp, compare_ttls)) { + // At least one RR matches. + return true; + } } - return KNOT_EOK; + // Node does have the type, but no RRs match. + return false; } -/*----------------------------------------------------------------------------*/ - -static int xfrin_apply_add_normal(knot_changes_t *changes, - knot_rrset_t *add, - knot_node_t *node, - knot_rrset_t **rrset, - knot_zone_contents_t *contents) +static int add_old_data(knot_changeset_t *chset, knot_rr_t *old_data, + knot_node_t **old_additional) { - assert(changes != NULL); - assert(add != NULL); - assert(node != NULL); - assert(rrset != NULL); - assert(contents != NULL); - - int ret; - - int copied = 0; - /*! \note Reusing RRSet from previous function caused it not to be - * removed from the node. - * Maybe modification of the code would allow reusing the RRSet - * as in apply_add_rrsigs() - the RRSet should not be copied - * in such case. - */ - if (*rrset - && knot_dname_cmp(knot_rrset_owner(*rrset), - knot_node_owner(node)) == 0 - && knot_rrset_type(*rrset) == knot_rrset_type(add)) { - dbg_xfrin_verb("Using RRSet from previous iteration.\n"); - } else { - dbg_xfrin_detail("Removing rrset!\n"); - *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); - - knot_rrset_t *old = *rrset; - - if (*rrset != NULL) { - ret = xfrin_copy_old_rrset(old, rrset, changes, 1); - if (ret != KNOT_EOK) { - return ret; - } - copied = 1; - } - } - - if (*rrset == NULL) { -dbg_xfrin_exec_detail( - char *name = knot_dname_to_str(add->owner); - dbg_xfrin_detail("RRSet to be added not found in zone.\n"); - dbg_xfrin_detail("owner: %s type: %u\n", name, add->type); - free(name); -); - // add the RRSet from the changeset to the node - /*! - * \note The new zone must be adjusted nevertheless, so it - * doesn't matter whether there are some extra dnames to - * be added to the table or not. - */ - ret = knot_zone_contents_add_rrset(contents, add, &node, - KNOT_RRSET_DUPL_SKIP); - - if (ret < 0) { - dbg_xfrin("Failed to add RRSet to node.\n"); - return ret; - } - - assert(ret == 0); - - return 1; // return 1 to indicate the add RRSet was used - } - -dbg_xfrin_exec_detail( - char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); - dbg_xfrin_detail("Found RRSet with owner %s, type %u\n", name, - knot_rrset_type(*rrset)); - free(name); -); - - // merge the changeset RRSet to the copy - /* What if the update fails? - * The changesets will be destroyed - that will destroy 'add', - * and the copied RRSet will be destroyed because it is in the new - * rrsets list. - * - * If the update is successfull, the old RRSet will be destroyed, - * but the one from the changeset will be not!! - * - * TODO: add the 'add' rrset to list of old RRSets? - */ - - /* Check if the added RR has the same TTL as the first RR from the - * zone's RRSet. If not, log a warning. - * We assume that the added RRSet has only one RR, but that should be - * the case here. - */ - if (knot_rrset_type(add) != KNOT_RRTYPE_RRSIG - && !knot_rrset_ttl_equal(add, *rrset)) { - char type_str[16] = { '\0' }; - knot_rrtype_to_string(knot_rrset_type(add), type_str, - sizeof(type_str)); - char *name = knot_dname_to_str(knot_rrset_owner(add)); - char *zname = knot_dname_to_str(knot_node_owner(contents->apex)); - log_zone_warning("Changes application to zone %s: TTL mismatch" - " in %s, type %s\n", zname, name, type_str); - free(name); - free(zname); - } - - int merged, deleted_rrs; - ret = knot_rrset_merge_sort(*rrset, add, &merged, &deleted_rrs, - NULL); - if (ret < 0) { - dbg_xfrin("Failed to merge changeset RRSet.\n"); - return ret; + if (ptrlist_add(&chset->old_data, old_data, NULL) == NULL) { + return KNOT_ENOMEM; } - if (copied) { - ret = knot_node_add_rrset_no_merge(node, *rrset); - if (ret < 0) { - dbg_xfrin("Failed to add merged RRSet to the node.\n"); - return ret; - } + if (!old_additional) { + return KNOT_EOK; } - // return 2 so that the add RRSet is removed from - // the changeset (and thus not deleted) - // and put to list of new RRSets (is this ok?) - // and deleted - return 2; -} - -/*----------------------------------------------------------------------------*/ - -void xfrin_cleanup_successful_update(knot_changes_t *changes) -{ - if (changes == NULL) { - return; - } - // Free old RRSets - knot_rr_ln_t *rr_node = NULL; - WALK_LIST(rr_node, changes->old_rrsets) { - knot_rrset_t *rrset = rr_node->rr; - knot_rrset_free(&rrset, NULL); + if (ptrlist_add(&chset->old_data, old_additional, NULL) == NULL) { + return KNOT_ENOMEM; } -} - -/*----------------------------------------------------------------------------*/ -/* New changeset applying */ -/*----------------------------------------------------------------------------*/ - -static int xfrin_switch_nodes_in_node(knot_node_t **node, void *data) -{ - UNUSED(data); - - assert(node && *node); - assert(knot_node_new_node(*node) == NULL); - - knot_node_update_refs(*node); return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - -static int xfrin_switch_nodes(knot_zone_contents_t *contents_copy) +static int add_new_data(knot_changeset_t *chset, knot_rr_t *new_data) { - assert(contents_copy != NULL); - - // Traverse the trees and for each node check every reference - // stored in that node. The node itself should be new. - int ret = knot_zone_tree_apply(contents_copy->nodes, - xfrin_switch_nodes_in_node, NULL); - if (ret == KNOT_EOK) { - ret = knot_zone_tree_apply(contents_copy->nsec3_nodes, - xfrin_switch_nodes_in_node, NULL); + if (ptrlist_add(&chset->new_data, new_data, NULL) == NULL) { + return KNOT_ENOMEM; } - return ret; -} - -/*----------------------------------------------------------------------------*/ - -static void xfrin_zone_contents_free2(knot_zone_contents_t **contents) -{ - /*! \todo This should be all in some API!! */ - - // free the zone tree, but only the structure - // (nodes are already destroyed) - dbg_zone("Destroying zone tree.\n"); - knot_zone_tree_deep_free(&(*contents)->nodes); - dbg_zone("Destroying NSEC3 zone tree.\n"); - knot_zone_tree_deep_free(&(*contents)->nsec3_nodes); - - knot_nsec3_params_free(&(*contents)->nsec3_params); - - free(*contents); - *contents = NULL; -} - -/*----------------------------------------------------------------------------*/ - -static int xfrin_cleanup_old_nodes(knot_node_t **node, void *data) -{ - UNUSED(data); - assert(node && *node); - - knot_node_set_new_node(*node, NULL); - return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - -static void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents, - knot_zone_contents_t **new_contents) +static int remove_rr(knot_node_t *node, const knot_rrset_t *rr, + knot_changeset_t *chset) { - if (old_contents == NULL && new_contents == NULL) { - return; + knot_rrset_t removed_rrset = knot_node_rrset(node, rr->type); + knot_rr_t *old_data = removed_rrset.rrs.data; + knot_node_t **old_additional = removed_rrset.additional; + int ret = xfrin_replace_rrs_with_copy(node, rr->type); + if (ret != KNOT_EOK) { + return ret; } - if (*new_contents != NULL) { - // destroy the shallow copy of zone - xfrin_zone_contents_free2(new_contents); + // Store old data for cleanup. + ret = add_old_data(chset, old_data, old_additional); + if (ret != KNOT_EOK) { + clear_new_rrs(node, rr->type); + return ret; } - if (old_contents != NULL) { - // cleanup old zone tree - reset pointers to new node to NULL - knot_zone_tree_apply(old_contents->nodes, xfrin_cleanup_old_nodes, - NULL); - - knot_zone_tree_apply(old_contents->nsec3_nodes, xfrin_cleanup_old_nodes, - NULL); - } -} - -/*----------------------------------------------------------------------------*/ - -void xfrin_rollback_update(knot_zone_contents_t *old_contents, - knot_zone_contents_t **new_contents, - knot_changes_t *changes) -{ - if (changes == NULL) { - return; + knot_rrs_t *changed_rrs = knot_node_get_rrs(node, rr->type); + // Subtract changeset RRS from node RRS. + ret = knot_rrs_subtract(changed_rrs, &rr->rrs, NULL); + if (ret != KNOT_EOK) { + clear_new_rrs(node, rr->type); + return ret; } - dbg_xfrin("Rolling back changeset application.\n"); - knot_rr_ln_t *rr_node = NULL; - WALK_LIST(rr_node, changes->new_rrsets) { - knot_rrset_t *rrset = rr_node->rr; - knot_rrset_free(&rrset, NULL); + if (changed_rrs->rr_count > 0) { + // Subtraction left some data in RRSet, store it for rollback. + ret = add_new_data(chset, changed_rrs->data); + if (ret != KNOT_EOK) { + knot_rrs_clear(changed_rrs, NULL); + return ret; + } + } else { + // RRSet is empty now, remove it from node, all data freed. + knot_node_remove_rrset(node, rr->type); } - xfrin_cleanup_failed_update(old_contents, new_contents); + return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - static int xfrin_apply_remove(knot_zone_contents_t *contents, - knot_changeset_t *chset, - knot_changes_t *changes) + knot_changeset_t *chset) { - /* - * Iterate over removed RRSets, and remove them from the new nodes - * in 'contents'. By default, the RRSet should be copied so that - * RDATA may be removed from it. - */ - int ret = 0; - knot_node_t *last_node = NULL; - knot_rrset_t *rrset = NULL; - int is_nsec3 = 0; - knot_rr_ln_t *rr_node = NULL; WALK_LIST(rr_node, chset->remove) { - knot_rrset_t *rr = rr_node->rr; - assert(rr); // No malformed changesets should get here -dbg_xfrin_exec_verb( - char *name = knot_dname_to_str( - knot_rrset_owner(rr)); - dbg_xfrin_verb("Removing RRSet: %s, type %u\n", name, - knot_rrset_type(rr)); - free(name); -); - - is_nsec3 = 0; - - // check if the RRSet belongs to the NSEC3 tree - if ((knot_rrset_type(rr) == KNOT_RRTYPE_NSEC3) - || (knot_rrset_type(rr) == KNOT_RRTYPE_RRSIG - && knot_rdata_rrsig_type_covered(rr, 0) - == KNOT_RRTYPE_NSEC3)) - { - dbg_xfrin_verb("Removed RRSet belongs to NSEC3 tree.\n"); - is_nsec3 = 1; - } + const knot_rrset_t *rr = rr_node->rr; - // check if the old node is not the one we should use - dbg_xfrin_verb("Node:%p Owner: %p Node owner: %p\n", - last_node, knot_rrset_owner(rr), - knot_node_owner(last_node)); - if (!last_node || knot_rrset_owner(rr) - != knot_node_owner(last_node)) { - if (is_nsec3) { - last_node = knot_zone_contents_get_nsec3_node( - contents, - knot_rrset_owner(rr)); - } else { - last_node = knot_zone_contents_get_node(contents, - knot_rrset_owner(rr)); - } - if (last_node == NULL) { - dbg_xfrin_verb("Node not found for RR to be " - "removed!\n"); - continue; - } + // Find node for this owner + knot_node_t *node = zone_contents_find_node_for_rr(contents, + rr); + if (!can_remove(node, rr)) { + // Nothing to remove from, skip. + continue; } - assert(last_node != NULL); - - // The CLASS should not be ANY, we do not accept such chgsets - dbg_xfrin_verb("RRSet class to be removed=%u\n", - knot_rrset_class(rr)); - // this should work also for UPDATE - ret = xfrin_apply_remove_normal(changes, rr, last_node, - &rrset); - - dbg_xfrin_detail("xfrin_apply_remove() ret = %d\n", ret); - - if (ret > 0) { - continue; - } else if (ret != KNOT_EOK) { + int ret = remove_rr(node, rr, chset); + if (ret != KNOT_EOK) { return ret; } } @@ -1191,111 +817,79 @@ dbg_xfrin_exec_verb( return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - -static int xfrin_apply_add(knot_zone_contents_t *contents, - knot_changeset_t *chset, - knot_changes_t *changes) +static int add_rr(knot_node_t *node, const knot_rrset_t *rr, + knot_changeset_t *chset) { - int ret = KNOT_EOK; - knot_node_t *last_node = NULL; - knot_rrset_t *rrset = NULL; - int is_nsec3 = 0; + knot_rrset_t changed_rrset = knot_node_rrset(node, rr->type); + if (!knot_rrset_empty(&changed_rrset)) { + // Modifying existing RRSet. + knot_rr_t *old_data = changed_rrset.rrs.data; + knot_node_t **old_additional = changed_rrset.additional; + int ret = xfrin_replace_rrs_with_copy(node, rr->type); + if (ret != KNOT_EOK) { + return ret; + } - knot_rr_ln_t *rr_node = NULL; - node_t *tmp_node; - WALK_LIST_DELSAFE(rr_node, tmp_node, chset->add) { - knot_rrset_t *rr = rr_node->rr; - assert(rr); // No malformed changesets should get here -dbg_xfrin_exec_verb( - char *name = knot_dname_to_str( - knot_rrset_owner(rr)); - dbg_xfrin_verb("Adding RRSet: %s, type: %u\n", name, - knot_rrset_type(rr)); - free(name); -); - is_nsec3 = 0; - - // check if the RRSet belongs to the NSEC3 tree - if ((knot_rrset_type(rr) == KNOT_RRTYPE_NSEC3) - || (knot_rrset_type(rr) == KNOT_RRTYPE_RRSIG - && knot_rdata_rrsig_type_covered(rr, 0) - == KNOT_RRTYPE_NSEC3)) - { - dbg_xfrin_detail("This is NSEC3-related RRSet.\n"); - is_nsec3 = 1; + // Store old RRS and additional for cleanup. + ret = add_old_data(chset, old_data, old_additional); + if (ret != KNOT_EOK) { + clear_new_rrs(node, rr->type); + return ret; } - // check if the old node is not the one we should use - if (!last_node || knot_rrset_owner(rr) - != knot_node_owner(last_node)) { - dbg_xfrin_detail("Searching for node...\n"); - if (is_nsec3) { - last_node = knot_zone_contents_get_nsec3_node( - contents, - knot_rrset_owner(rr)); - } else { - last_node = knot_zone_contents_get_node(contents, - knot_rrset_owner(rr)); - } - if (last_node == NULL) { - // create new node, connect it properly to the - // zone nodes - dbg_xfrin_detail("Node not found. Creating new." - "\n"); - last_node = xfrin_add_new_node(contents, - rr, - is_nsec3); - if (last_node == NULL) { - dbg_xfrin("Failed to create new node " - "in zone.\n"); - return KNOT_ERROR; - } - } + // Extract copy, merge into it + knot_rrs_t *changed_rrs = knot_node_get_rrs(node, rr->type); + ret = knot_rrs_merge(changed_rrs, &rr->rrs, NULL); + if (ret != KNOT_EOK) { + clear_new_rrs(node, rr->type); + return ret; + } + } else { + // Inserting new RRSet, data will be copied. + bool ttl_err = false; + int ret = knot_node_add_rrset(node, rr, &ttl_err); + if (ret != KNOT_EOK) { + return ret; } - ret = xfrin_apply_add_normal(changes, rr, last_node, - &rrset, contents); - assert(ret <= 3); + if (ttl_err) { + char type_str[16] = { '\0' }; + knot_rrtype_to_string(rr->type, type_str, sizeof(type_str)); + char *name = knot_dname_to_str(rr->owner); + char *zname = knot_dname_to_str(chset->soa_from->owner); + log_zone_warning("Changes application to zone %s: TTL mismatch" + " in %s, type %s\n", zname, name, type_str); + free(name); + free(zname); + } + } - // Not correct anymore, add_normal() returns KNOT_EOK if the - // changeset RR should be removed - //assert(ret != KNOT_EOK); + // Get changed RRS and store for possible rollback. + knot_rrs_t *rrs = knot_node_get_rrs(node, rr->type); + int ret = add_new_data(chset, rrs->data); + if (ret != KNOT_EOK) { + knot_rrs_clear(rrs, NULL); + return ret; + } - dbg_xfrin_detail("xfrin_apply_..() returned %d, rrset: %p\n", - ret, rrset); + return KNOT_EOK; +} - if (ret > 0) { - if (ret == 1) { - // the ADD RRSet was used, i.e. it should be - // removed from the changeset and saved in the - // list of new RRSets - ret = knot_changes_add_rrset(changes, rr, - KNOT_CHANGES_NEW); - if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add old RRSet to " - "list.\n"); - return ret; - } +static int xfrin_apply_add(knot_zone_contents_t *contents, + knot_changeset_t *chset) +{ + knot_rr_ln_t *rr_node = NULL; + WALK_LIST(rr_node, chset->add) { + knot_rrset_t *rr = rr_node->rr; - rem_node((node_t *)rr_node); - } else if (ret == 2) { - // the copy of the RRSet was used, but it was - // already stored in the new RRSets list - // just delete the add RRSet, but without RDATA - // DNAMES as these were merged to the copied RRSet - knot_rrset_free(&rr, NULL); - rem_node((node_t *)rr_node); - } else if (ret == 3) { - // the RRSet was used and both RRSet and RDATA - // were properly stored. Just clear the place - // in the changeset - rem_node((node_t *)rr_node); - } else { - assert(0); - } + // Get or create node with this owner + knot_node_t *node = zone_contents_get_node_for_rr(contents, rr); + if (node == NULL) { + return KNOT_ENOMEM; + } - } else if (ret != KNOT_EOK) { + int ret = add_rr(node, rr, chset); + if (ret != KNOT_EOK) { return ret; } } @@ -1306,30 +900,23 @@ dbg_xfrin_exec_verb( /*----------------------------------------------------------------------------*/ static int xfrin_apply_replace_soa(knot_zone_contents_t *contents, - knot_changes_t *changes, knot_changeset_t *chset) { - dbg_xfrin("Replacing SOA record.\n"); - knot_node_t *node = knot_zone_contents_get_apex(contents); - assert(node != NULL); - - assert(node != NULL); - - int ret = xfrin_replace_rrset_in_node(node, chset->soa_to, changes, - contents); - if (ret == KNOT_EOK) { - // remove the SOA from the changeset, so it will not be deleted - // after successful apply - chset->soa_to = NULL; + assert(chset->soa_from); + int ret = remove_rr(contents->apex, chset->soa_from, chset); + if (ret != KNOT_EOK) { + return ret; } - return ret; + assert(!knot_node_rrtype_exists(contents->apex, KNOT_RRTYPE_SOA)); + + return add_rr(contents->apex, chset->soa_to, chset); } /*----------------------------------------------------------------------------*/ -static int xfrin_apply_changeset(knot_zone_contents_t *contents, - knot_changes_t *changes, +static int xfrin_apply_changeset(list_t *old_rrs, list_t *new_rrs, + knot_zone_contents_t *contents, knot_changeset_t *chset) { /* @@ -1342,25 +929,24 @@ static int xfrin_apply_changeset(knot_zone_contents_t *contents, chset->serial_from, chset->serial_to); // check if serial matches - const knot_rrset_t *soa = knot_node_rrset(contents->apex, - KNOT_RRTYPE_SOA); - if (soa == NULL || knot_rdata_soa_serial(soa) + const knot_rrs_t *soa = knot_node_rrs(contents->apex, KNOT_RRTYPE_SOA); + if (soa == NULL || knot_rrs_soa_serial(soa) != chset->serial_from) { dbg_xfrin("SOA serials do not match!!\n"); - return KNOT_ERROR; + return KNOT_EINVAL; } - int ret = xfrin_apply_remove(contents, chset, changes); + int ret = xfrin_apply_remove(contents, chset); if (ret != KNOT_EOK) { return ret; } - ret = xfrin_apply_add(contents, chset, changes); + ret = xfrin_apply_add(contents, chset); if (ret != KNOT_EOK) { return ret; } - return xfrin_apply_replace_soa(contents, changes, chset); + return xfrin_apply_replace_soa(contents, chset); } /*----------------------------------------------------------------------------*/ @@ -1488,7 +1074,7 @@ int xfrin_prepare_zone_copy(knot_zone_contents_t *old_contents, * updated. * * This will create new zone contents structures (normal nodes' tree, - * NSEC3 tree, hash table, domain name table), and copy all nodes. + * NSEC3 tree), and copy all nodes. * The data in the nodes (RRSets) remain the same though. */ knot_zone_contents_t *contents_copy = NULL; @@ -1503,19 +1089,6 @@ int xfrin_prepare_zone_copy(knot_zone_contents_t *old_contents, assert(knot_zone_contents_apex(contents_copy) != NULL); - /* - * Fix references to new nodes. Some references in new nodes may point - * to old nodes. Hash table contains only old nodes. - */ - dbg_xfrin("Switching ptrs pointing to old nodes to the new nodes.\n"); - ret = xfrin_switch_nodes(contents_copy); - if (ret != KNOT_EOK) { - dbg_xfrin("Failed to switch pointers in nodes.\n"); - knot_zone_contents_free(&contents_copy); - return ret; - } - assert(knot_zone_contents_apex(contents_copy) != NULL); - *new_contents = contents_copy; return KNOT_EOK; @@ -1571,16 +1144,17 @@ int xfrin_finalize_updated_zone(knot_zone_contents_t *contents_copy, /*----------------------------------------------------------------------------*/ int xfrin_apply_changesets_directly(knot_zone_contents_t *contents, - knot_changes_t *changes, knot_changesets_t *chsets) { - if (contents == NULL || changes == NULL || chsets == NULL) { + if (contents == NULL || chsets == NULL) { return KNOT_EINVAL; } knot_changeset_t *set = NULL; WALK_LIST(set, chsets->sets) { - int ret = xfrin_apply_changeset(contents, changes, set); + int ret = xfrin_apply_changeset(&set->old_data, + &set->new_data, + contents, set); if (ret != KNOT_EOK) { return ret; } @@ -1592,12 +1166,12 @@ int xfrin_apply_changesets_directly(knot_zone_contents_t *contents, /*----------------------------------------------------------------------------*/ /* Post-DDNS application, no need to shallow copy. */ -int xfrin_apply_changesets_dnssec_ddns(knot_zone_contents_t *z_old, +int xfrin_apply_changesets_dnssec_ddns(zone_t *zone, knot_zone_contents_t *z_new, knot_changesets_t *sec_chsets, knot_changesets_t *chsets) { - if (z_old == NULL || z_new == NULL || + if (zone == NULL || z_new == NULL || sec_chsets == NULL || chsets == NULL) { return KNOT_EINVAL; } @@ -1606,10 +1180,9 @@ int xfrin_apply_changesets_dnssec_ddns(knot_zone_contents_t *z_old, knot_zone_contents_set_gen_old(z_new); /* Apply changes. */ - int ret = xfrin_apply_changesets_directly(z_new, chsets->changes, - sec_chsets); + int ret = xfrin_apply_changesets_directly(z_new, sec_chsets); if (ret != KNOT_EOK) { - xfrin_rollback_update(z_old, &z_new, chsets->changes); + xfrin_rollback_update(sec_chsets, &z_new); dbg_xfrin("Failed to apply changesets to zone: " "%s\n", knot_strerror(ret)); return ret; @@ -1620,7 +1193,7 @@ int xfrin_apply_changesets_dnssec_ddns(knot_zone_contents_t *z_old, if (ret != KNOT_EOK) { dbg_xfrin("Failed to finalize updated zone: %s\n", knot_strerror(ret)); - xfrin_rollback_update(z_old, &z_new, chsets->changes); + xfrin_rollback_update(sec_chsets, &z_new); return ret; } @@ -1663,10 +1236,11 @@ int xfrin_apply_changesets(zone_t *zone, old_contents->apex, contents_copy->apex); knot_changeset_t *set = NULL; WALK_LIST(set, chsets->sets) { - ret = xfrin_apply_changeset(contents_copy, chsets->changes, set); + ret = xfrin_apply_changeset(&set->old_data, + &set->new_data, + contents_copy, set); if (ret != KNOT_EOK) { - xfrin_rollback_update(old_contents, - &contents_copy, chsets->changes); + xfrin_rollback_update(chsets, &contents_copy); dbg_xfrin("Failed to apply changesets to zone: " "%s\n", knot_strerror(ret)); return ret; @@ -1683,7 +1257,7 @@ int xfrin_apply_changesets(zone_t *zone, if (ret != KNOT_EOK) { dbg_xfrin("Failed to finalize updated zone: %s\n", knot_strerror(ret)); - xfrin_rollback_update(old_contents, &contents_copy, chsets->changes); + xfrin_rollback_update(chsets, &contents_copy); return ret; } diff --git a/src/knot/updates/xfr-in.h b/src/knot/updates/xfr-in.h index 3a7f20654d2c9aac32c601e12c09a02abc809cd6..e6e772129e2db8501861038b33ef64ed3ecd5886 100644 --- a/src/knot/updates/xfr-in.h +++ b/src/knot/updates/xfr-in.h @@ -155,7 +155,6 @@ int xfrin_apply_changesets(zone_t *zone, /*! * \brief Applies DNSSEC changesets after DDNS. * - * \param z_old Old contents for possible rollbacks. * \param z_new Post DDNS/reload zone. * \param sec_chsets Changes with RRSIGs/NSEC(3)s. * \param chsets DDNS/reload changes, for rollback. @@ -165,7 +164,7 @@ int xfrin_apply_changesets(zone_t *zone, * by the UPDATE-processing function. It uses new and old zones from this * operation. */ -int xfrin_apply_changesets_dnssec_ddns(knot_zone_contents_t *z_old, +int xfrin_apply_changesets_dnssec_ddns(zone_t *zone, knot_zone_contents_t *z_new, knot_changesets_t *sec_chsets, knot_changesets_t *chsets); @@ -174,9 +173,6 @@ int xfrin_apply_changesets_dnssec_ddns(knot_zone_contents_t *z_old, * \brief Applies changesets directly to the zone, without copying it. * * \param contents Zone contents to apply the changesets to. Will be modified. - * \param changes Structure to store changes made during application. It - * doesn't have to be empty, present changes will not be - * modified. * \param chsets Changesets to be applied to the zone. * * \retval KNOT_EOK if successful. @@ -184,7 +180,6 @@ int xfrin_apply_changesets_dnssec_ddns(knot_zone_contents_t *z_old, * \return Other error code if the application went wrong. */ int xfrin_apply_changesets_directly(knot_zone_contents_t *contents, - knot_changes_t *changes, knot_changesets_t *chsets); int xfrin_prepare_zone_copy(knot_zone_contents_t *old_contents, @@ -203,25 +198,19 @@ int xfrin_switch_zone(zone_t *zone, knot_zone_contents_t *new_contents, int transfer_type); -void xfrin_cleanup_successful_update(knot_changes_t *changes); - -void xfrin_rollback_update(knot_zone_contents_t *old_contents, - knot_zone_contents_t **new_contents, - knot_changes_t *changes); +void xfrin_rollback_update(knot_changesets_t *chgs, + knot_zone_contents_t **new_contents); int xfrin_copy_rrset(knot_node_t *node, uint16_t type, - knot_rrset_t **rrset, knot_changes_t *changes, - int save_new); + knot_rrset_t **rrset); -int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, - knot_changes_t *changes, int save_new); +int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy); int xfrin_replace_rrset_in_node(knot_node_t *node, knot_rrset_t *rrset_new, - knot_changes_t *changes, knot_zone_contents_t *contents); -void xfrin_zone_contents_free(knot_zone_contents_t **contents); +void xfrin_cleanup_successful_update(knot_changesets_t *chgs); #endif /* _KNOTXFR_IN_H_ */ diff --git a/src/knot/zone/estimator.c b/src/knot/zone/estimator.c index dd793ddf75c3c212f01e8525953727b4391945d2..239ac8aeaa67539d82bca403c3f6327ac6ed07fa 100644 --- a/src/knot/zone/estimator.c +++ b/src/knot/zone/estimator.c @@ -110,7 +110,7 @@ static int insert_dname_into_table(hattrie_t *table, knot_dname_t *d, static void rrset_memsize(zone_estim_t *est, const zs_scanner_t *scanner) { // Handle RRSet's owner - knot_dname_t *owner = knot_dname_copy(scanner->r_owner); + knot_dname_t *owner = knot_dname_copy(scanner->r_owner, NULL); if (owner == NULL) { return; } @@ -123,7 +123,7 @@ static void rrset_memsize(zone_estim_t *est, const zs_scanner_t *scanner) est->dname_size += dname_memsize(owner); // Trie's nodes handled at the end of computation } - knot_dname_free(&owner); + knot_dname_free(&owner, NULL); assert(n); // We will always add RDATA diff --git a/src/knot/zone/node.c b/src/knot/zone/node.c index aae2ed8e3bd97060a4416640630e98b158763171..8a131da05a5e79c1a059b02e87b09287b4134911 100644 --- a/src/knot/zone/node.c +++ b/src/knot/zone/node.c @@ -23,9 +23,11 @@ #include "libknot/common.h" #include "knot/zone/node.h" #include "libknot/rrset.h" +#include "libknot/rr.h" #include "libknot/rdata.h" #include "common/descriptor.h" #include "common/debug.h" +#include "common/mempattern.h" /*----------------------------------------------------------------------------*/ /* Non-API functions */ @@ -67,6 +69,24 @@ static inline void knot_node_flags_clear(knot_node_t *node, uint8_t flag) node->flags &= ~flag; } +static void rr_data_clear(struct rr_data *data, mm_ctx_t *mm) +{ + knot_rrs_clear(&data->rrs, mm); + free(data->additional); +} + +static int rr_data_from(const knot_rrset_t *rrset, struct rr_data *data, mm_ctx_t *mm) +{ + int ret = knot_rrs_copy(&data->rrs, &rrset->rrs, mm); + if (ret != KNOT_EOK) { + return ret; + } + data->type = rrset->type; + data->additional = NULL; + + return KNOT_EOK; +} + /*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -86,11 +106,11 @@ knot_node_t *knot_node_new(const knot_dname_t *owner, knot_node_t *parent, * do the copying (or not if he decides to do so). */ if (owner) { - ret->owner = knot_dname_copy(owner); + ret->owner = knot_dname_copy(owner, NULL); } knot_node_set_parent(ret, parent); - ret->rrset_tree = NULL; + ret->rrs = NULL; ret->flags = flags; assert(ret->children == 0); @@ -98,95 +118,71 @@ knot_node_t *knot_node_new(const knot_dname_t *owner, knot_node_t *parent, return ret; } -int knot_node_add_rrset_no_merge(knot_node_t *node, knot_rrset_t *rrset) +static int knot_node_add_rrset_no_merge(knot_node_t *node, const knot_rrset_t *rrset) { if (node == NULL) { return KNOT_EINVAL; } - size_t nlen = (node->rrset_count + 1) * sizeof(knot_rrset_t*); - void *p = realloc(node->rrset_tree, nlen); + const size_t nlen = (node->rrset_count + 1) * sizeof(struct rr_data); + void *p = realloc(node->rrs, nlen); if (p == NULL) { return KNOT_ENOMEM; } - node->rrset_tree = p; - node->rrset_tree[node->rrset_count] = rrset; + node->rrs = p; + int ret = rr_data_from(rrset, node->rrs + node->rrset_count, NULL); + if (ret != KNOT_EOK) { + return ret; + } ++node->rrset_count; return KNOT_EOK; } -int knot_node_add_rrset_replace(knot_node_t *node, knot_rrset_t *rrset) -{ - if (node == NULL) { - return KNOT_EINVAL; - } - - for (uint16_t i = 0; i < node->rrset_count; ++i) { - if (node->rrset_tree[i]->type == rrset->type) { - node->rrset_tree[i] = rrset; - } - } - - return knot_node_add_rrset_no_merge(node, rrset); -} - -int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, - bool *ttl_err) +int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset, bool *ttl_err) { if (node == NULL || rrset == NULL) { return KNOT_EINVAL; } for (uint16_t i = 0; i < node->rrset_count; ++i) { - if (node->rrset_tree[i]->type == rrset->type) { - int merged, deleted_rrs; + if (node->rrs[i].type == rrset->type) { + struct rr_data *node_data = &node->rrs[i]; /* Check if the added RR has the same TTL as the first * RR in the RRSet. */ - if (ttl_err && knot_rrset_type(rrset) != KNOT_RRTYPE_RRSIG - && !knot_rrset_ttl_equal(rrset, - node->rrset_tree[i])) { + knot_rr_t *first = knot_rrs_rr(&node_data->rrs, 0); + uint32_t inserted_ttl = knot_rrset_rr_ttl(rrset, 0); + if (ttl_err && rrset->type != KNOT_RRTYPE_RRSIG && + inserted_ttl != knot_rr_ttl(first)) { *ttl_err = true; } - int ret = knot_rrset_merge_sort(node->rrset_tree[i], - rrset, &merged, - &deleted_rrs, NULL); - if (ret != KNOT_EOK) { - return ret; - } else if (merged || deleted_rrs) { - return 1; - } else { - return 0; - } + return knot_rrs_merge(&node_data->rrs, &rrset->rrs, NULL); } } + // New RRSet (with one RR) return knot_node_add_rrset_no_merge(node, rrset); } /*----------------------------------------------------------------------------*/ -const knot_rrset_t *knot_node_rrset(const knot_node_t *node, - uint16_t type) +const knot_rrs_t *knot_node_rrs(const knot_node_t *node, uint16_t type) { - return knot_node_get_rrset(node, type); + return (const knot_rrs_t *)knot_node_get_rrs(node, type); } -/*----------------------------------------------------------------------------*/ - -knot_rrset_t *knot_node_get_rrset(const knot_node_t *node, uint16_t type) +knot_rrs_t *knot_node_get_rrs(const knot_node_t *node, uint16_t type) { if (node == NULL) { return NULL; } - knot_rrset_t **rrs = node->rrset_tree; for (uint16_t i = 0; i < node->rrset_count; ++i) { - if (rrs[i]->type == type) { - return rrs[i]; + if (node->rrs[i].type == type) { + return &node->rrs[i].rrs; } } @@ -195,36 +191,39 @@ knot_rrset_t *knot_node_get_rrset(const knot_node_t *node, uint16_t type) /*----------------------------------------------------------------------------*/ -knot_rrset_t *knot_node_remove_rrset(knot_node_t *node, uint16_t type) +knot_rrset_t *knot_node_create_rrset(const knot_node_t *node, uint16_t type) { if (node == NULL) { return NULL; } - uint16_t i = 0; - knot_rrset_t *ret = NULL; - knot_rrset_t **rrs = node->rrset_tree; - for (; i < node->rrset_count && ret == NULL; ++i) { - if (rrs[i]->type == type) { - ret = rrs[i]; - memmove(rrs + i, rrs + i + 1, (node->rrset_count - i - 1) * sizeof(knot_rrset_t *)); - --node->rrset_count; + for (uint16_t i = 0; i < node->rrset_count; ++i) { + if (node->rrs[i].type == type) { + knot_rrset_t rrset = knot_node_rrset_at(node, i); + return knot_rrset_copy(&rrset, NULL); } } - return ret; + return NULL; } /*----------------------------------------------------------------------------*/ -void knot_node_remove_all_rrsets(knot_node_t *node) +void knot_node_remove_rrset(knot_node_t *node, uint16_t type) { if (node == NULL) { return; } - // remove RRSets but do not delete them - node->rrset_count = 0; + for (int i = 0; i < node->rrset_count; ++i) { + if (node->rrs[i].type == type) { + memmove(node->rrs + i, node->rrs + i + 1, (node->rrset_count - i - 1) * sizeof(struct rr_data)); + --node->rrset_count; + return; + } + } + + return; } /*----------------------------------------------------------------------------*/ @@ -240,48 +239,6 @@ short knot_node_rrset_count(const knot_node_t *node) /*----------------------------------------------------------------------------*/ -knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node) -{ - if (node == NULL || node->rrset_count == 0) { - return NULL; - } - - size_t rrlen = node->rrset_count * sizeof(knot_rrset_t*); - knot_rrset_t **cpy = malloc(rrlen); - if (cpy != NULL) { - memcpy(cpy, node->rrset_tree, rrlen); - } - - return cpy; -} - -/*----------------------------------------------------------------------------*/ - -const knot_rrset_t **knot_node_rrsets(const knot_node_t *node) -{ - if (node == NULL) { - return NULL; - } - - return (const knot_rrset_t **)knot_node_get_rrsets(node); -} - -knot_rrset_t **knot_node_get_rrsets_no_copy(const knot_node_t *node) -{ - if (node == NULL) { - return NULL; - } - - return node->rrset_tree; -} - -const knot_rrset_t **knot_node_rrsets_no_copy(const knot_node_t *node) -{ - return (const knot_rrset_t **)knot_node_get_rrsets_no_copy(node); -} - -/*----------------------------------------------------------------------------*/ - const knot_node_t *knot_node_parent(const knot_node_t *node) { if (node == NULL) { @@ -455,63 +412,6 @@ const knot_node_t *knot_node_wildcard_child(const knot_node_t *node) /*----------------------------------------------------------------------------*/ -const knot_node_t *knot_node_new_node(const knot_node_t *node) -{ - if (node == NULL) { - return NULL; - } - - return node->new_node; -} - -/*----------------------------------------------------------------------------*/ - -knot_node_t *knot_node_get_new_node(const knot_node_t *node) -{ - if (node == NULL) { - return NULL; - } - - return node->new_node; -} - -/*----------------------------------------------------------------------------*/ - -void knot_node_set_new_node(knot_node_t *node, - knot_node_t *new_node) -{ - if (node == NULL) { - return; - } - - node->new_node = new_node; -} - -/*----------------------------------------------------------------------------*/ - -void knot_node_update_ref(knot_node_t **ref) -{ - if (*ref != NULL && (*ref)->new_node != NULL) { - *ref = (*ref)->new_node; - } -} - -/*----------------------------------------------------------------------------*/ - -void knot_node_update_refs(knot_node_t *node) -{ - // reference to previous node - knot_node_update_ref(&node->prev); - // reference to parent - knot_node_update_ref(&node->parent); - // reference to wildcard child - knot_node_update_ref(&node->wildcard_child); - // reference to NSEC3 node - knot_node_update_ref(&node->nsec3_node); -} - -/*----------------------------------------------------------------------------*/ - void knot_node_set_deleg_point(knot_node_t *node) { if (node == NULL) { @@ -641,7 +541,6 @@ int knot_node_is_apex(const knot_node_t *node) return knot_node_flags_get(node, KNOT_NODE_FLAGS_APEX); } - /*----------------------------------------------------------------------------*/ void knot_node_free_rrsets(knot_node_t *node) @@ -650,9 +549,8 @@ void knot_node_free_rrsets(knot_node_t *node) return; } - knot_rrset_t **rrs = node->rrset_tree; for (uint16_t i = 0; i < node->rrset_count; ++i) { - knot_rrset_free(&(rrs[i]), NULL); + rr_data_clear(&node->rrs[i], NULL); } } @@ -666,14 +564,14 @@ void knot_node_free(knot_node_t **node) dbg_node_detail("Freeing node: %p\n", *node); - if ((*node)->rrset_tree != NULL) { + if ((*node)->rrs != NULL) { dbg_node_detail("Freeing RRSets.\n"); - free((*node)->rrset_tree); - (*node)->rrset_tree = NULL; + free((*node)->rrs); + (*node)->rrs = NULL; (*node)->rrset_count = 0; } - knot_dname_free(&(*node)->owner); + knot_dname_free(&(*node)->owner, NULL); free(*node); *node = NULL; @@ -694,21 +592,24 @@ int knot_node_shallow_copy(const knot_node_t *from, knot_node_t **to) if (*to == NULL) { return KNOT_ENOMEM; } + memset(*to, 0, sizeof(knot_node_t)); - // do not use the API function to set parent, so that children count - // is not changed - memcpy(*to, from, sizeof(knot_node_t)); - (*to)->owner = knot_dname_copy(from->owner); + // Copy owner + (*to)->owner = knot_dname_copy(from->owner, NULL); + if ((*to)->owner == NULL) { + free(*to); + return KNOT_ENOMEM; + } // copy RRSets - size_t rrlen = sizeof(knot_rrset_t*) * from->rrset_count; - (*to)->rrset_tree = malloc(rrlen); - if ((*to)->rrset_tree == NULL) { - free(*to); - *to = NULL; + (*to)->rrset_count = from->rrset_count; + size_t rrlen = sizeof(struct rr_data) * from->rrset_count; + (*to)->rrs = malloc(rrlen); + if ((*to)->rrs == NULL) { + knot_node_free(to); return KNOT_ENOMEM; } - memcpy((*to)->rrset_tree, from->rrset_tree, rrlen); + memcpy((*to)->rrs, from->rrs, rrlen); return KNOT_EOK; } @@ -719,15 +620,15 @@ bool knot_node_rrtype_is_signed(const knot_node_t *node, uint16_t type) return false; } - const knot_rrset_t *rrsigs = knot_node_rrset(node, KNOT_RRTYPE_RRSIG); + const knot_rrs_t *rrsigs = knot_node_rrs(node, KNOT_RRTYPE_RRSIG); if (rrsigs == NULL) { return false; } - uint16_t rrsigs_rdata_count = knot_rrset_rr_count(rrsigs); + uint16_t rrsigs_rdata_count = rrsigs->rr_count; for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) { const uint16_t type_covered = - knot_rdata_rrsig_type_covered(rrsigs, i); + knot_rrs_rrsig_type_covered(rrsigs, i); if (type_covered == type) { return true; } @@ -735,3 +636,9 @@ bool knot_node_rrtype_is_signed(const knot_node_t *node, uint16_t type) return false; } + +bool knot_node_rrtype_exists(const knot_node_t *node, uint16_t type) +{ + return knot_node_rrs(node, type) != NULL; +} + diff --git a/src/knot/zone/node.h b/src/knot/zone/node.h index c7b00420cf9a6d582c8475d85df3a2d818a41f60..42fd2908697e5945565bd84d02a2e4fbaa86bccb 100644 --- a/src/knot/zone/node.h +++ b/src/knot/zone/node.h @@ -28,13 +28,13 @@ #ifndef _KNOT_NODE_H_ #define _KNOT_NODE_H_ +#include "common/descriptor.h" #include "libknot/dname.h" #include "libknot/rrset.h" +#include "libknot/rr.h" -/*! \brief RRSet count in node if there is only NSEC (and possibly its RRSIG).*/ -#define KNOT_NODE_RRSET_COUNT_ONLY_NSEC 2 +struct rr_data; -/*----------------------------------------------------------------------------*/ /*! * \brief Structure representing one node in a domain name tree, i.e. one domain * name in a zone. @@ -45,8 +45,8 @@ struct knot_node { knot_dname_t *owner; /*!< Domain name being the owner of this node. */ struct knot_node *parent; /*!< Parent node in the name hierarchy. */ - /*! \brief Type-ordered list of RRSets belonging to this node. */ - knot_rrset_t **rrset_tree; + /*! \brief Type-ordered array of RRSets belonging to this node. */ + struct rr_data *rrs; /*! \brief Wildcard node being the direct descendant of this node. */ struct knot_node *wildcard_child; @@ -68,8 +68,6 @@ struct knot_node { */ struct knot_node *nsec3_node; - struct knot_node *new_node; - unsigned int children; uint16_t rrset_count; /*!< Number of RRSets stored in the node. */ @@ -87,6 +85,13 @@ struct knot_node { typedef struct knot_node knot_node_t; +/*!< \brief Structure storing RR data. */ +struct rr_data { + uint16_t type; /*!< \brief RR type of data. */ + knot_rrs_t rrs; /*!< \brief Data of given type. */ + knot_node_t **additional; /*!< \brief Additional nodes with glues. */ +}; + /*----------------------------------------------------------------------------*/ /*! \brief Flags used to mark nodes with some property. */ typedef enum { @@ -125,29 +130,14 @@ knot_node_t *knot_node_new(const knot_dname_t *owner, knot_node_t *parent, * * \param node Node to add the RRSet to. * \param rrset RRSet to add. - * \param rrset Stores destination RRSet in case of merge. * * \retval KNOT_EOK on success. * \retval KNOT_ERROR if the RRSet could not be inserted. */ -int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, - bool *ttl_err); +int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset, bool *ttl_err); -int knot_node_add_rrset_replace(knot_node_t *node, knot_rrset_t *rrset); - -int knot_node_add_rrset_no_merge(knot_node_t *node, knot_rrset_t *rrset); - -/*! - * \brief Returns the RRSet of the given type from the node. - * - * \param node Node to get the RRSet from. - * \param type Type of the RRSet to retrieve. - * - * \return RRSet from node \a node having type \a type, or NULL if no such - * RRSet exists in this node. - */ -const knot_rrset_t *knot_node_rrset(const knot_node_t *node, - uint16_t type); +const knot_rrs_t *knot_node_rrs(const knot_node_t *node, uint16_t type); +knot_rrs_t *knot_node_get_rrs(const knot_node_t *node, uint16_t type); /*! * \brief Returns the RRSet of the given type from the node (non-const version). @@ -158,11 +148,9 @@ const knot_rrset_t *knot_node_rrset(const knot_node_t *node, * \return RRSet from node \a node having type \a type, or NULL if no such * RRSet exists in this node. */ -knot_rrset_t *knot_node_get_rrset(const knot_node_t *node, uint16_t type); +knot_rrset_t *knot_node_create_rrset(const knot_node_t *node, uint16_t type); -knot_rrset_t *knot_node_remove_rrset(knot_node_t *node, uint16_t type); - -void knot_node_remove_all_rrsets(knot_node_t *node); +void knot_node_remove_rrset(knot_node_t *node, uint16_t type); /*! * \brief Returns number of RRSets in the node. @@ -173,31 +161,6 @@ void knot_node_remove_all_rrsets(knot_node_t *node); */ short knot_node_rrset_count(const knot_node_t *node); -/*! - * \brief Returns all RRSets from the node. - * - * \param node Node to get the RRSets from. - * - * \return Newly allocated array of RRSets or NULL if an error occured. - */ -knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node); - -/*! - * \brief Returns all RRSets from the node. - * - * \note This function is identical to knot_node_get_rrsets(), only it returns - * non-modifiable data. - * - * \param node Node to get the RRSets from. - * - * \return Newly allocated array of RRSets or NULL if an error occured. - */ -const knot_rrset_t **knot_node_rrsets(const knot_node_t *node); -const knot_rrset_t **knot_node_rrsets_no_copy(const knot_node_t *node); -knot_rrset_t **knot_node_get_rrsets_no_copy(const knot_node_t *node); - -int knot_node_count_rrsets(const knot_node_t *node); - /*! * \brief Returns the parent of the node. * @@ -321,20 +284,6 @@ void knot_node_set_wildcard_child(knot_node_t *node, knot_node_t *knot_node_get_wildcard_child(const knot_node_t *node); -//const knot_node_t *knot_node_current(const knot_node_t *node); - -//knot_node_t *knot_node_get_current(knot_node_t *node); - -const knot_node_t *knot_node_new_node(const knot_node_t *node); - -knot_node_t *knot_node_get_new_node(const knot_node_t *node); - -void knot_node_set_new_node(knot_node_t *node, knot_node_t *new_node); - -void knot_node_update_ref(knot_node_t **ref); - -void knot_node_update_refs(knot_node_t *node); - /*! * \brief Mark the node as a delegation point. * @@ -417,6 +366,7 @@ int knot_node_shallow_copy(const knot_node_t *from, knot_node_t **to); /*! * \brief Checks whether node contains an RRSIG for given type. + * * \param node Node to check in. * \param node Type to check for. * @@ -424,6 +374,69 @@ int knot_node_shallow_copy(const knot_node_t *from, knot_node_t **to); */ bool knot_node_rrtype_is_signed(const knot_node_t *node, uint16_t type); +/*! + * \brief Checks whether node contains RRSet for given type. + * + * \param node Node to check in. + * \param node Type to check for. + * + * \return True/False. + */ +bool knot_node_rrtype_exists(const knot_node_t *node, uint16_t type); + +/*! + * \brief Returns RRSet structure initialized with data from node. + * + * \param node Node containing RRSet. + * \param type RRSet type we want to get. + * + * \return RRSet structure with wanted type, or empty RRSet. + */ +static inline knot_rrset_t knot_node_rrset(const knot_node_t *node, uint16_t type) +{ + knot_rrset_t rrset; + for (uint16_t i = 0; node && i < node->rrset_count; ++i) { + if (node->rrs[i].type == type) { + struct rr_data *rr_data = &node->rrs[i]; + rrset.owner = node->owner; + rrset.type = type; + rrset.rclass = KNOT_CLASS_IN; + rrset.rrs = rr_data->rrs; + rrset.additional = rr_data->additional; + return rrset; + } + } + knot_rrset_init_empty(&rrset); + return rrset; +} + +/*! + * \brief Returns RRSet structure initialized with data from node at position + * equal to \a pos. + * + * \param node Node containing RRSet. + * \param pos RRSet position we want to get. + * + * \return RRSet structure with data from wanted position, or empty RRSet. + */ +static inline knot_rrset_t knot_node_rrset_at(const knot_node_t *node, size_t pos) +{ + knot_rrset_t rrset; + if (node == NULL || pos >= node->rrset_count) { + knot_rrset_init_empty(&rrset); + return rrset; + } + + struct rr_data *rr_data = &node->rrs[pos]; + rrset.owner = node->owner; + rrset.type = rr_data->type; + rrset.rclass = KNOT_CLASS_IN; + rrset.rrs = rr_data->rrs; + rrset.additional = rr_data->additional; + + return rrset; +} + #endif /* _KNOT_NODE_H_ */ /*! @} */ diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c index e00e2aa0697b28e0056ec1047917a7a6dfd74194..5135adb978fe1c49125e8062abcc067a8612e7dd 100644 --- a/src/knot/zone/semantic-check.c +++ b/src/knot/zone/semantic-check.c @@ -18,13 +18,14 @@ #include <stdint.h> #include <sys/types.h> #include <sys/socket.h> -#include <netinet/in.h> +#include <netinet/in.h> #include <arpa/inet.h> #include "knot/knot.h" #include "knot/other/debug.h" #include "libknot/libknot.h" #include "libknot/dnssec/key.h" +#include "libknot/dnssec/rrset-sign.h" #include "common/base32hex.h" #include "common/crc.h" #include "common/descriptor.h" @@ -110,7 +111,6 @@ static char *error_messages[(-ZC_ERR_UNKNOWN) + 1] = { /* ^ | Important errors (to be logged on first occurence and counted) */ - /* Below are errors of lesser importance, to be counted unless specified otherwise */ @@ -165,7 +165,7 @@ static void log_error_from_node(err_handler_t *handler, log_zone_warning("Unknown error.\n"); return; } - + if (node == NULL) { log_zone_warning("Total number of warnings is: %d for error: %s\n", handler->errors[-error], error_messages[-error]); @@ -195,8 +195,8 @@ int err_handler_handle_error(err_handler_t *handler, const knot_node_t *node, return KNOT_EINVAL; } - /* - * A missing SOA can only occur once, so there needn't be + /* + * A missing SOA can only occur once, so there needn't be * an option for it. */ @@ -286,7 +286,7 @@ static int check_dnskey_rdata(const knot_rrset_t *rrset, size_t rdata_pos) */ static int check_rrsig_rdata(err_handler_t *handler, const knot_node_t *node, - const knot_rrset_t *rrsig, + const knot_rrs_t *rrsig, size_t rr_pos, const knot_rrset_t *rrset, const knot_rrset_t *dnskey_rrset) @@ -294,14 +294,13 @@ static int check_rrsig_rdata(err_handler_t *handler, /* Prepare additional info string. */ char info_str[50] = { '\0' }; char type_str[16] = { '\0' }; - knot_rrtype_to_string(knot_rrset_type(rrset), type_str, sizeof(type_str)); + knot_rrtype_to_string(rrset->type, type_str, sizeof(type_str)); int ret = snprintf(info_str, sizeof(info_str), "Record type: %s.", type_str); if (ret < 0 || ret >= sizeof(info_str)) { return KNOT_ENOMEM; } - if (knot_rdata_rrsig_type_covered(rrsig, 0) != - knot_rrset_type(rrset)) { + if (knot_rrs_rrsig_type_covered(rrsig, 0) != rrset->type) { /* zoneparser would not let this happen * but to be on the safe side */ @@ -311,13 +310,13 @@ static int check_rrsig_rdata(err_handler_t *handler, } /* label number at the 2nd index should be same as owner's */ - uint8_t labels_rdata = knot_rdata_rrsig_labels(rrsig, rr_pos); + uint8_t labels_rdata = knot_rrs_rrsig_labels(rrsig, rr_pos); - int tmp = knot_dname_labels(knot_rrset_owner(rrset), NULL) - labels_rdata; + int tmp = knot_dname_labels(rrset->owner, NULL) - labels_rdata; if (tmp != 0) { /* if name has wildcard, label must not be included */ - if (!knot_dname_is_wildcard(knot_rrset_owner(rrset))) { + if (!knot_dname_is_wildcard(rrset->owner)) { err_handler_handle_error(handler, node, ZC_ERR_RRSIG_RDATA_LABELS, info_str); @@ -331,8 +330,7 @@ static int check_rrsig_rdata(err_handler_t *handler, } /* check original TTL */ - uint32_t original_ttl = - knot_rdata_rrsig_original_ttl(rrsig, rr_pos); + uint32_t original_ttl = knot_rrs_rrsig_original_ttl(rrsig, rr_pos); uint16_t rr_count = knot_rrset_rr_count(rrset); for (uint16_t i = 0; i < rr_count; ++i) { @@ -344,26 +342,25 @@ static int check_rrsig_rdata(err_handler_t *handler, } /* Check for expired signature. */ - if (knot_rdata_rrsig_sig_expiration(rrsig, rr_pos) < time(NULL)) { + if (knot_rrs_rrsig_sig_expiration(rrsig, rr_pos) < time(NULL)) { err_handler_handle_error(handler, node, ZC_ERR_RRSIG_RDATA_EXPIRATION, info_str); } /* Check if DNSKEY exists. */ - if (!dnskey_rrset) { + if (knot_rrset_empty(dnskey_rrset)) { err_handler_handle_error(handler, node, ZC_ERR_RRSIG_NO_DNSKEY, info_str); } /* signer's name is same as in the zone apex */ const knot_dname_t *signer_name = - knot_rdata_rrsig_signer_name(rrsig, rr_pos); + knot_rrs_rrsig_signer_name(rrsig, rr_pos); /* dnskey is in the apex node */ - if (dnskey_rrset && - knot_dname_cmp(signer_name, knot_rrset_owner(dnskey_rrset)) != 0 - ) { + if (!knot_rrset_empty(dnskey_rrset) && + !knot_dname_is_equal(signer_name, dnskey_rrset->owner)) { err_handler_handle_error(handler, node, ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER, info_str); @@ -372,18 +369,18 @@ static int check_rrsig_rdata(err_handler_t *handler, /* Compare algorithm, key tag and signer's name with DNSKEY rrset * one of the records has to match. Signer name has been checked * before */ - + int match = 0; - uint8_t rrsig_alg = knot_rdata_rrsig_algorithm(rrsig, rr_pos); - uint16_t key_tag_rrsig = knot_rdata_rrsig_key_tag(rrsig, rr_pos); + uint8_t rrsig_alg = knot_rrs_rrsig_algorithm(rrsig, rr_pos); + uint16_t key_tag_rrsig = knot_rrs_rrsig_key_tag(rrsig, rr_pos); for (uint16_t i = 0; i < knot_rrset_rr_count(dnskey_rrset) && !match; ++i) { uint8_t dnskey_alg = - knot_rdata_dnskey_alg(dnskey_rrset, i); + knot_rrs_dnskey_alg(&dnskey_rrset->rrs, i); if (rrsig_alg != dnskey_alg) { continue; } - + /* Calculate keytag. */ uint16_t dnskey_key_tag = knot_keytag(knot_rrset_rr_rdata(dnskey_rrset, i), @@ -391,7 +388,7 @@ static int check_rrsig_rdata(err_handler_t *handler, if (key_tag_rrsig != dnskey_key_tag) { continue; } - + /* Final step - check DNSKEY validity. */ if (check_dnskey_rdata(dnskey_rrset, i) == KNOT_EOK) { match = 1; @@ -401,7 +398,7 @@ static int check_rrsig_rdata(err_handler_t *handler, "DNSKEY RDATA not matching."); } } - + if (!match) { err_handler_handle_error(handler, node, ZC_ERR_RRSIG_NO_DNSKEY, info_str); @@ -432,24 +429,24 @@ static int check_rrsig_in_rrset(err_handler_t *handler, /* Prepare additional info string. */ char info_str[50] = { '\0' }; char type_str[16] = { '\0' }; - knot_rrtype_to_string(knot_rrset_type(rrset), type_str, sizeof(type_str)); + knot_rrtype_to_string(rrset->type, type_str, sizeof(type_str)); int ret = snprintf(info_str, sizeof(info_str), "Record type: %s.", type_str); if (ret < 0 || ret >= sizeof(info_str)) { return KNOT_ENOMEM; } - knot_rrset_t *rrsigs = NULL; - ret = knot_rrset_synth_rrsig(rrset->owner, - rrset->type, - knot_node_rrset(node, KNOT_RRTYPE_RRSIG), - &rrsigs, NULL); + knot_rrs_t rrsigs; + knot_rrs_init(&rrsigs); + ret = knot_synth_rrsig(rrset->type, + knot_node_rrs(node, KNOT_RRTYPE_RRSIG), + &rrsigs, NULL); if (ret != KNOT_EOK) { if (ret != KNOT_ENOENT) { return ret; } } - if (rrsigs == NULL) { + if (ret == KNOT_ENOENT) { err_handler_handle_error(handler, node, ZC_ERR_RRSIG_NO_RRSIG, info_str); @@ -464,36 +461,15 @@ static int check_rrsig_in_rrset(err_handler_t *handler, /* Safe to continue, nothing is malformed. */ } - /* Different owner, class, ttl */ - if (knot_dname_cmp(knot_rrset_owner(rrset), - knot_rrset_owner(rrsigs)) != 0) { - err_handler_handle_error(handler, node, - ZC_ERR_RRSIG_OWNER, - info_str); - } - - if (knot_rrset_class(rrset) != knot_rrset_class(rrsigs)) { - err_handler_handle_error(handler, node, - ZC_ERR_RRSIG_CLASS, - info_str); - } - - if (!knot_rrset_ttl_equal(rrset, rrsigs)) { + const knot_rr_t *sig_rr = knot_rrs_rr(&rrsigs, 0); + if (knot_rrset_rr_ttl(rrset, 0) != knot_rr_ttl(sig_rr)) { err_handler_handle_error(handler, node, ZC_ERR_RRSIG_TTL, info_str); } - if (knot_rrset_rr_count(rrsigs) == 0) { - err_handler_handle_error(handler, node, - ZC_ERR_RRSIG_RDATA_SIGNED_WRONG, - info_str); - knot_rrset_free(&rrsigs, NULL); - return KNOT_EOK; - } - - for (uint16_t i = 0; i < knot_rrset_rr_count(rrsigs); ++i) { - int ret = check_rrsig_rdata(handler, node, rrsigs, i, rrset, + for (uint16_t i = 0; i < (&rrsigs)->rr_count; ++i) { + int ret = check_rrsig_rdata(handler, node, &rrsigs, i, rrset, dnskey_rrset); if (ret != KNOT_EOK) { dbg_semcheck("Could not check RRSIG properly (%s).\n", @@ -502,7 +478,7 @@ static int check_rrsig_in_rrset(err_handler_t *handler, } } - knot_rrset_free(&rrsigs, NULL); + knot_rrs_clear(&rrsigs, NULL); return ret; } @@ -533,23 +509,22 @@ static int get_bit(uint8_t *bits, size_t index) * \retval KNOT_OK on success. * \retval KNOT_NOMEM on memory error. */ -static int rdata_nsec_to_type_array(const knot_rrset_t *rrset, size_t pos, - uint16_t **array, size_t *count) +static int rdata_nsec_to_type_array(const knot_rrs_t *rrs, uint16_t type, + size_t pos, uint16_t **array, size_t *count) { assert(*array == NULL); - assert(rrset->type == KNOT_RRTYPE_NSEC || rrset->type == KNOT_RRTYPE_NSEC3); - + uint8_t *data = NULL; uint16_t rr_bitmap_size = 0; - if (rrset->type == KNOT_RRTYPE_NSEC) { - knot_rdata_nsec_bitmap(rrset, &data, &rr_bitmap_size); + if (type == KNOT_RRTYPE_NSEC) { + knot_rrs_nsec_bitmap(rrs, &data, &rr_bitmap_size); } else { - knot_rdata_nsec3_bitmap(rrset, pos, &data, &rr_bitmap_size); + knot_rrs_nsec3_bitmap(rrs, pos, &data, &rr_bitmap_size); } if (data == NULL) { return KNOT_EMALF; } - + *count = 0; int increment = 0; for (int i = 0; i < rr_bitmap_size; i += increment) { @@ -615,7 +590,7 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, if (nsec3_node == NULL) { /* I know it's probably not what RFCs say, but it will have to * do for now. */ - if (knot_node_rrset(node, KNOT_RRTYPE_DS) != NULL) { + if (knot_node_rrtype_exists(node, KNOT_RRTYPE_DS)) { err_handler_handle_error(handler, node, ZC_ERR_NSEC3_UNSECURED_DELEGATION, NULL); @@ -642,15 +617,14 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, assert(nsec3_previous); - const knot_rrset_t *previous_rrset = - knot_node_rrset(nsec3_previous, - KNOT_RRTYPE_NSEC3); + const knot_rrs_t *previous_rrs = + knot_node_rrs(nsec3_previous, KNOT_RRTYPE_NSEC3); - assert(previous_rrset); + assert(previous_rrs); /* check for Opt-Out flag */ uint8_t flags = - knot_rdata_nsec3_flags(previous_rrset, 0); + knot_rrs_nsec3_flags(previous_rrs, 0); uint8_t opt_out_mask = 1; if (!(flags & opt_out_mask)) { @@ -663,32 +637,29 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, } } - const knot_rrset_t *nsec3_rrset = - knot_node_rrset(nsec3_node, KNOT_RRTYPE_NSEC3); - - if (nsec3_rrset == NULL) { + const knot_rrs_t *nsec3_rrs = knot_node_rrs(nsec3_node, + KNOT_RRTYPE_NSEC3); + if (nsec3_rrs == NULL) { err_handler_handle_error(handler, node, ZC_ERR_NSEC3_RDATA_CHAIN, NULL); return KNOT_EOK; } - const knot_rrset_t *soa_rrset = - knot_node_rrset(knot_zone_contents_apex(zone), - KNOT_RRTYPE_SOA); - assert(soa_rrset); - uint32_t minimum_ttl = knot_rdata_soa_minimum(soa_rrset); - - if (knot_rrset_rr_ttl(nsec3_rrset, 0) != minimum_ttl) { - err_handler_handle_error(handler, node, - ZC_ERR_NSEC3_RDATA_TTL, NULL); + const knot_rr_t *nsec3_rr = knot_rrs_rr(nsec3_rrs, 0); + const knot_rrs_t *soa_rrs = knot_node_rrs(zone->apex, KNOT_RRTYPE_SOA); + assert(soa_rrs); + uint32_t minimum_ttl = knot_rrs_soa_minimum(soa_rrs); + if (knot_rr_ttl(nsec3_rr) != minimum_ttl) { + err_handler_handle_error(handler, node, + ZC_ERR_NSEC3_RDATA_TTL, NULL); } /* Result is a dname, it can't be larger */ const knot_node_t *apex = knot_zone_contents_apex(zone); uint8_t *next_dname_str = NULL; uint8_t next_dname_size = 0; - knot_rdata_nsec3_next_hashed(nsec3_rrset, 0, &next_dname_str, - &next_dname_size); + knot_rrs_nsec3_next_hashed(nsec3_rrs, 0, &next_dname_str, + &next_dname_size); knot_dname_t *next_dname = knot_nsec3_hash_to_dname(next_dname_str, next_dname_size, apex->owner); @@ -701,19 +672,18 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, ZC_ERR_NSEC3_RDATA_CHAIN, NULL); } - knot_dname_free(&next_dname); - + knot_dname_free(&next_dname, NULL); + size_t arr_size; uint16_t *array = NULL; /* TODO only works for one NSEC3 RR. */ - int ret = rdata_nsec_to_type_array(nsec3_rrset, 0, &array, &arr_size); + int ret = rdata_nsec_to_type_array(nsec3_rrs, + KNOT_RRTYPE_NSEC3, 0, + &array, &arr_size); if (ret != KNOT_EOK) { - dbg_semcheck("semchecks: check_nsec3_node: Could not " - "convert NSEC to type array. Reason: %s\n", - knot_strerror(ret)); return ret; } - + uint16_t type = 0; for (int j = 0; j < arr_size; j++) { /* test for each type's presence */ @@ -721,22 +691,17 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, if (type == KNOT_RRTYPE_RRSIG) { continue; } - - if (knot_node_rrset(node, type) == NULL) { + + if (!knot_node_rrtype_exists(node, type)) { err_handler_handle_error(handler, node, ZC_ERR_NSEC3_RDATA_BITMAP, NULL); } } - + /* Check that the node only contains NSEC3 and RRSIG. */ - const knot_rrset_t **rrsets = knot_node_rrsets_no_copy(nsec3_node); - if (rrsets == NULL) { - return KNOT_ENOMEM; - } - for (int i = 0; i < knot_node_rrset_count(nsec3_node); i++) { - uint16_t type = knot_rrset_type(rrsets[i]); + uint16_t type = nsec3_node->rrs[i].type; if (!(type == KNOT_RRTYPE_NSEC3 || type == KNOT_RRTYPE_RRSIG)) { err_handler_handle_error(handler, nsec3_node, @@ -753,12 +718,12 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, static int sem_check_node_mandatory(const knot_node_t *node, err_handler_t *handler, bool *fatal_error) { - const knot_rrset_t *cname_rrset = - knot_node_rrset(node, KNOT_RRTYPE_CNAME); - if (cname_rrset) { + const knot_rrs_t *cname_rrs = knot_node_rrs(node, KNOT_RRTYPE_CNAME); + if (cname_rrs) { if (knot_node_rrset_count(node) != 1) { /* With DNSSEC node can contain RRSIGs or NSEC */ - if (!(knot_node_rrset(node, KNOT_RRTYPE_NSEC) || knot_node_rrset(node, KNOT_RRTYPE_RRSIG)) || + if (!(knot_node_rrtype_exists(node, KNOT_RRTYPE_NSEC) || + knot_node_rrtype_exists(node, KNOT_RRTYPE_RRSIG)) || knot_node_rrset_count(node) > 3) { *fatal_error = true; err_handler_handle_error(handler, node, @@ -766,23 +731,22 @@ static int sem_check_node_mandatory(const knot_node_t *node, } } - if (knot_rrset_rr_count(cname_rrset) != 1) { + if (cname_rrs->rr_count != 1) { *fatal_error = true; err_handler_handle_error(handler, node, ZC_ERR_CNAME_MULTIPLE, NULL); } } - const knot_rrset_t *dname_rrset = - knot_node_rrset(node, KNOT_RRTYPE_DNAME); - if (dname_rrset) { - if (cname_rrset) { + const knot_rrs_t *dname_rrs = knot_node_rrs(node, KNOT_RRTYPE_DNAME); + if (dname_rrs) { + if (cname_rrs) { *fatal_error = true; err_handler_handle_error(handler, node, ZC_ERR_CNAME_EXTRA_RECORDS, NULL); } - + if (node->children != 0) { *fatal_error = true; err_handler_handle_error(handler, node, @@ -790,14 +754,14 @@ static int sem_check_node_mandatory(const knot_node_t *node, "Error triggered by parent node."); } } - - if (node->parent && knot_node_rrset(node->parent, KNOT_RRTYPE_DNAME)) { + + if (node->parent && knot_node_rrtype_exists(node->parent, KNOT_RRTYPE_DNAME)) { *fatal_error = true; err_handler_handle_error(handler, node, ZC_ERR_DNAME_CHILDREN, "Error triggered by child node."); } - + return KNOT_EOK; } @@ -805,28 +769,24 @@ static int sem_check_node_optional(const knot_zone_contents_t *zone, const knot_node_t *node, err_handler_t *handler) { - if (knot_node_is_deleg_point(node) || knot_zone_contents_apex(zone) == - node) { - const knot_rrset_t *ns_rrset = - knot_node_rrset(node, KNOT_RRTYPE_NS); - if (ns_rrset == NULL) { - err_handler_handle_error(handler, node, - ZC_ERR_MISSING_NS_DEL_POINT, - NULL); - return KNOT_EOK; - } - - /* TODO How about multiple RRs? */ - knot_dname_t *ns_dname = - knot_dname_copy(knot_rdata_ns_name(ns_rrset, - 0)); - if (ns_dname == NULL) { - return KNOT_ENOMEM; - } + if (!(knot_node_is_deleg_point(node) || knot_zone_contents_apex(zone) == + node)) { + return KNOT_EOK; + } + const knot_rrs_t *ns_rrs = knot_node_rrs(node, KNOT_RRTYPE_NS); + if (ns_rrs == NULL) { + err_handler_handle_error(handler, node, + ZC_ERR_MISSING_NS_DEL_POINT, + NULL); + return KNOT_EOK; + } + for (int i = 0; i < ns_rrs->rr_count; ++i) { + const knot_dname_t *ns_dname = + knot_rrs_ns_name(ns_rrs, i); const knot_node_t *glue_node = - knot_zone_contents_find_node(zone, ns_dname); - + knot_zone_contents_find_node(zone, ns_dname); + if (knot_dname_is_sub(ns_dname, knot_node_owner(knot_zone_contents_apex(zone)))) { if (glue_node == NULL) { @@ -836,37 +796,27 @@ static int sem_check_node_optional(const knot_zone_contents_t *zone, knot_dname_to_wire(wildcard + 2, knot_wire_next_label(ns_dname, NULL), sizeof(wildcard)); - const knot_node_t *wildcard_node = + const knot_node_t *wildcard_node = knot_zone_contents_find_node(zone, wildcard); if (wildcard_node == NULL) { err_handler_handle_error(handler, node, ZC_ERR_GLUE_NODE, NULL ); - } else { - /* Look for A or AAAA. */ - if ((knot_node_rrset(wildcard_node, - KNOT_RRTYPE_A) == NULL) && - (knot_node_rrset(wildcard_node, - KNOT_RRTYPE_AAAA) == NULL)) { - err_handler_handle_error(handler, node, - ZC_ERR_GLUE_RECORD, - NULL); - } - } - } else { - if ((knot_node_rrset(glue_node, - KNOT_RRTYPE_A) == NULL) && - (knot_node_rrset(glue_node, - KNOT_RRTYPE_AAAA) == NULL)) { - err_handler_handle_error(handler, node, - ZC_ERR_GLUE_RECORD, - NULL); + // Cannot continue + return KNOT_EOK; } + glue_node = wildcard_node; + } + if (!knot_node_rrtype_exists(glue_node, KNOT_RRTYPE_A) && + !knot_node_rrtype_exists(glue_node, KNOT_RRTYPE_AAAA)) { + err_handler_handle_error(handler, node, + ZC_ERR_GLUE_RECORD, + NULL); } } - knot_dname_free(&ns_dname); } + return KNOT_EOK; } @@ -918,83 +868,71 @@ int sem_check_node_plain(const knot_zone_contents_t *zone, * \return Appropriate error code if error was found. */ static int semantic_checks_dnssec(knot_zone_contents_t *zone, - knot_node_t *node, - knot_node_t **last_node, - err_handler_t *handler, - char nsec3) + knot_node_t *node, + knot_node_t **last_node, + err_handler_t *handler, + char nsec3) { assert(handler); assert(node); - char auth = !knot_node_is_non_auth(node); - char deleg = knot_node_is_deleg_point(node); - uint rrset_count = knot_node_rrset_count(node); - const knot_rrset_t **rrsets = knot_node_rrsets_no_copy(node); - const knot_rrset_t *dnskey_rrset = - knot_node_rrset(knot_zone_contents_apex(zone), - KNOT_RRTYPE_DNSKEY); + bool auth = !knot_node_is_non_auth(node); + bool deleg = knot_node_is_deleg_point(node); + short rrset_count = knot_node_rrset_count(node); + knot_rrset_t dnskey_rrset = knot_node_rrset(zone->apex, KNOT_RRTYPE_DNSKEY); - int ret = 0; + int ret = KNOT_EOK; for (int i = 0; i < rrset_count; i++) { - const knot_rrset_t *rrset = rrsets[i]; - if (auth && !deleg && rrset->type != KNOT_RRTYPE_RRSIG && + knot_rrset_t rrset = knot_node_rrset_at(node, i); + if (auth && !deleg && rrset.type != KNOT_RRTYPE_RRSIG && (ret = check_rrsig_in_rrset(handler, node, - rrset, dnskey_rrset)) != 0) { + &rrset, &dnskey_rrset)) != 0) { err_handler_handle_error(handler, node, ret, NULL); } if (!nsec3 && auth) { /* check for NSEC record */ - const knot_rrset_t *nsec_rrset = - knot_node_rrset(node, - KNOT_RRTYPE_NSEC); - - if (nsec_rrset == NULL) { + const knot_rrs_t *nsec_rrs = + knot_node_rrs(node, KNOT_RRTYPE_NSEC); + if (nsec_rrs == NULL) { err_handler_handle_error(handler, node, - ZC_ERR_NO_NSEC, NULL); - } else { - /* check NSEC/NSEC3 bitmap */ - size_t count; - uint16_t *array = NULL; - - int ret = rdata_nsec_to_type_array(nsec_rrset, - 0, - &array, - &count); - if (ret != KNOT_EOK) { - dbg_semcheck("semchecks: " - "Could not create type " - "array. Reason: %s.\n", - knot_strerror(ret)); - return ret; - } - - uint16_t type = 0; - for (int j = 0; j < count; j++) { - /* test for each type's presence */ - type = array[j]; - if (type == KNOT_RRTYPE_RRSIG) { - continue; - } - if (knot_node_rrset(node, - type) == NULL) { - err_handler_handle_error( - handler, - node, - ZC_ERR_NSEC_RDATA_BITMAP, NULL); - } - } - free(array); + ZC_ERR_NO_NSEC, NULL); + return KNOT_EOK; } - /* Test that only one record is in the - * NSEC RRSet */ + /* check NSEC/NSEC3 bitmap */ + size_t count; + uint16_t *array = NULL; + int ret = rdata_nsec_to_type_array(nsec_rrs, + KNOT_RRTYPE_NSEC, + 0, + &array, + &count); + if (ret != KNOT_EOK) { + return ret; + } - if (knot_rrset_rr_count(nsec_rrset) != 1) { + uint16_t type = 0; + for (int j = 0; j < count; j++) { + /* test for each type's presence */ + type = array[j]; + if (type == KNOT_RRTYPE_RRSIG) { + continue; + } + if (!knot_node_rrtype_exists(node, type)) { + err_handler_handle_error(handler, + node, + ZC_ERR_NSEC_RDATA_BITMAP, + NULL); + } + } + free(array); + /* Test that only one record is in the NSEC RRSet */ + if (nsec_rrs->rr_count != 1) { err_handler_handle_error(handler, - node, - ZC_ERR_NSEC_RDATA_MULTIPLE, - NULL); + node, + ZC_ERR_NSEC_RDATA_MULTIPLE, + NULL); } /* @@ -1004,31 +942,26 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone, * so checking should only be matter of testing * the next link in each node. */ + const knot_dname_t *next_domain = + knot_rrs_nsec_next(nsec_rrs); + // Convert name to lowercase for trie lookup + knot_dname_t *lowercase = knot_dname_copy(next_domain, NULL); + if (lowercase == NULL) { + return KNOT_ENOMEM; + } + knot_dname_to_lower(lowercase); - if (nsec_rrset != NULL) { - const knot_dname_t *next_domain = - knot_rdata_nsec_next(nsec_rrset); - assert(next_domain); - // Convert name to lowercase for trie lookup - knot_dname_t *lowercase = knot_dname_copy(next_domain); - if (lowercase == NULL) { - return KNOT_ENOMEM; - } - knot_dname_to_lower(lowercase); - - if (knot_zone_contents_find_node(zone, lowercase) == NULL) { - err_handler_handle_error(handler, node, - ZC_ERR_NSEC_RDATA_CHAIN, NULL); - } + if (knot_zone_contents_find_node(zone, lowercase) == NULL) { + err_handler_handle_error(handler, node, + ZC_ERR_NSEC_RDATA_CHAIN, + NULL); + } - if (knot_dname_cmp(lowercase, - knot_node_owner(knot_zone_contents_apex(zone))) - == 0) { - /* saving the last node */ - *last_node = node; - } - knot_dname_free(&lowercase); + if (knot_dname_is_equal(lowercase, zone->apex->owner)) { + /* saving the last node */ + *last_node = node; } + knot_dname_free(&lowercase, NULL); } else if (nsec3 && (auth || deleg)) { /* nsec3 */ int ret = check_nsec3_node_in_zone(zone, node, handler); @@ -1064,7 +997,7 @@ static int do_checks_in_tree(knot_node_t *node, void *data) knot_node_t **last_node = (knot_node_t **)args->arg5; err_handler_t *handler = (err_handler_t *)args->arg6; - + char do_checks = *((char *)(args->arg3)); if (do_checks) { @@ -1113,10 +1046,10 @@ int zone_do_sem_checks(knot_zone_contents_t *zone, int do_checks, if (fatal_error) { return KNOT_ERROR; } - + log_cyclic_errors_in_zone(handler, zone, last_node, first_nsec3_node, last_nsec3_node, do_checks); - + return KNOT_EOK; } @@ -1127,15 +1060,14 @@ void log_cyclic_errors_in_zone(err_handler_t *handler, const knot_node_t *last_nsec3_node, char do_checks) { - if (do_checks == 3) { + if (do_checks == SEM_CHECK_NSEC3) { /* Each NSEC3 node should only contain one RRSET. */ if (last_nsec3_node == NULL || first_nsec3_node == NULL) { return; } - const knot_rrset_t *nsec3_rrset = - knot_node_rrset(last_nsec3_node, - KNOT_RRTYPE_NSEC3); - if (nsec3_rrset == NULL) { + const knot_rrs_t *nsec3_rrs = + knot_node_rrs(last_nsec3_node, KNOT_RRTYPE_NSEC3); + if (nsec3_rrs == NULL) { err_handler_handle_error(handler, last_nsec3_node, ZC_ERR_NSEC3_RDATA_CHAIN, NULL); return; @@ -1145,8 +1077,8 @@ void log_cyclic_errors_in_zone(err_handler_t *handler, const knot_node_t *apex = knot_zone_contents_apex(zone); uint8_t *next_dname_str = NULL; uint8_t next_dname_size = 0; - knot_rdata_nsec3_next_hashed(nsec3_rrset, 0, &next_dname_str, - &next_dname_size); + knot_rrs_nsec3_next_hashed(nsec3_rrs, 0, &next_dname_str, + &next_dname_size); knot_dname_t *next_dname = knot_nsec3_hash_to_dname(next_dname_str, next_dname_size, apex->owner); @@ -1171,7 +1103,7 @@ void log_cyclic_errors_in_zone(err_handler_t *handler, } /* Directly discard. */ - knot_dname_free(&next_dname); + knot_dname_free(&next_dname, NULL); } else if (do_checks == 2 ) { if (last_node == NULL) { @@ -1179,18 +1111,16 @@ void log_cyclic_errors_in_zone(err_handler_t *handler, ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC, NULL); return; } else { - const knot_rrset_t *nsec_rrset = - knot_node_rrset(last_node, - KNOT_RRTYPE_NSEC); + const knot_rrs_t *nsec_rrs = + knot_node_rrs(last_node, KNOT_RRTYPE_NSEC); - if (nsec_rrset == NULL) { + if (nsec_rrs == NULL) { err_handler_handle_error(handler, last_node, ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC, NULL); return; } - const knot_dname_t *next_dname = - knot_rdata_nsec_next(nsec_rrset); + const knot_dname_t *next_dname = knot_rrs_nsec_next(nsec_rrs); assert(next_dname); const knot_dname_t *apex_dname = diff --git a/src/knot/zone/zone-contents.c b/src/knot/zone/zone-contents.c index 9bcdfea775b32d7780bb88eaea22614d2df02dad..ff9155fe2958eb6b5e4d750b542285b05384e034 100644 --- a/src/knot/zone/zone-contents.c +++ b/src/knot/zone/zone-contents.c @@ -152,33 +152,34 @@ static int knot_zone_contents_nsec3_name(const knot_zone_contents_t *zone, } /*! \brief Link pointers to additional nodes for this RRSet. */ -static int discover_additionals(knot_rrset_t *rr, knot_zone_contents_t *zone) +static int discover_additionals(struct rr_data *rr_data, + knot_zone_contents_t *zone) { const knot_node_t *node = NULL, *encloser = NULL, *prev = NULL; const knot_dname_t *dname = NULL; - - /* Free old additional nodes. */ - if (rr->additional != NULL) { - free(rr->additional); - } + const knot_rrs_t *rrs = &rr_data->rrs; /* Create new additional nodes. */ - uint16_t rdcount = knot_rrset_rr_count(rr); - rr->additional = malloc(rdcount * sizeof(knot_node_t*)); - if (rr->additional == NULL) { + uint16_t rdcount = rrs->rr_count; + if (rr_data->additional) { + free(rr_data->additional); + } + rr_data->additional = malloc(rdcount * sizeof(knot_node_t *)); + if (rr_data->additional == NULL) { + ERR_ALLOC_FAILED; return KNOT_ENOMEM; } for (uint16_t i = 0; i < rdcount; i++) { /* Try to find node for the dname in the RDATA. */ - dname = knot_rdata_name(rr, i); + dname = knot_rrs_name(rrs, i, rr_data->type); knot_zone_contents_find_dname(zone, dname, &node, &encloser, &prev); if (node == NULL && encloser && encloser->wildcard_child) { node = encloser->wildcard_child; } - rr->additional[i] = (knot_node_t *)node; + rr_data->additional[i] = (knot_node_t *)node; } return KNOT_EOK; @@ -213,7 +214,7 @@ static int adjust_pointers(knot_node_t **tnode, void *data) || knot_node_is_non_auth(knot_node_parent(node))) ) { knot_node_set_non_auth(node); - } else if (knot_node_rrset(node, KNOT_RRTYPE_NS) != NULL + } else if (knot_node_rrtype_exists(node, KNOT_RRTYPE_NS) && node != args->zone->apex) { knot_node_set_deleg_point(node); } else { @@ -254,7 +255,7 @@ static int adjust_nsec3_pointers(knot_node_t **tnode, void *data) ret = KNOT_EOK; } - knot_dname_free(&nsec3_name); + knot_dname_free(&nsec3_name, NULL); return ret; } @@ -329,12 +330,12 @@ static int adjust_additional(knot_node_t **tnode, void *data) int ret = KNOT_EOK; knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; knot_node_t *node = *tnode; - knot_rrset_t **rrset = node->rrset_tree; /* Lookup additional records for specific nodes. */ for(uint16_t i = 0; i < node->rrset_count; ++i) { - if (rrset_additional_needed(rrset[i]->type)) { - ret = discover_additionals(rrset[i], args->zone); + struct rr_data *rr_data = &node->rrs[i]; + if (knot_rrtype_additional_needed(rr_data->type)) { + ret = discover_additionals(rr_data, args->zone); if (ret != KNOT_EOK) { break; } @@ -385,27 +386,27 @@ static int knot_zone_contents_find_in_tree(knot_zone_tree_t *tree, /*----------------------------------------------------------------------------*/ -static int knot_zc_nsec3_parameters_match(const knot_rrset_t *rrset, +static int knot_zc_nsec3_parameters_match(const knot_rrs_t *rrs, const knot_nsec3_params_t *params, size_t rdata_pos) { - assert(rrset != NULL && params != NULL); + assert(rrs != NULL && params != NULL); dbg_zone_detail("RDATA algo: %u, iterations: %u, salt length: %u, salt:" " %.*s\n", - knot_rdata_nsec3_algorithm(rrset, rdata_pos), - knot_rdata_nsec3_iterations(rrset, rdata_pos), - knot_rdata_nsec3_salt_length(rrset, rdata_pos), - knot_rdata_nsec3_salt_length(rrset, rdata_pos), - knot_rdata_nsec3_salt(rrset, rdata_pos)); + knot_rrs_nsec3_algorithm(rrs, rdata_pos), + knot_rrs_nsec3_iterations(rrs, rdata_pos), + knot_rrs_nsec3_salt_length(rrs, rdata_pos), + knot_rrs_nsec3_salt_length(rrs, rdata_pos), + knot_rrs_nsec3_salt(rrs, rdata_pos)); dbg_zone_detail("NSEC3PARAM algo: %u, iterations: %u, salt length: %u, " "salt: %.*s\n", params->algorithm, params->iterations, params->salt_length, params->salt_length, params->salt); - return (knot_rdata_nsec3_algorithm(rrset, rdata_pos) == params->algorithm - && knot_rdata_nsec3_iterations(rrset, rdata_pos) == params->iterations - && knot_rdata_nsec3_salt_length(rrset, rdata_pos) == params->salt_length - && strncmp((const char *)knot_rdata_nsec3_salt(rrset, rdata_pos), + return (knot_rrs_nsec3_algorithm(rrs, rdata_pos) == params->algorithm + && knot_rrs_nsec3_iterations(rrs, rdata_pos) == params->iterations + && knot_rrs_nsec3_salt_length(rrs, rdata_pos) == params->salt_length + && strncmp((const char *)knot_rrs_nsec3_salt(rrs, rdata_pos), (const char *)params->salt, params->salt_length) == 0); } @@ -484,22 +485,26 @@ void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents) contents->flags |= KNOT_ZONE_FLAGS_GEN_NEW; } -/*----------------------------------------------------------------------------*/ - -uint16_t knot_zone_contents_class(const knot_zone_contents_t *contents) +static knot_node_t *knot_zone_contents_get_node(const knot_zone_contents_t *zone, + const knot_dname_t *name) { - if (contents == NULL || contents->apex == NULL - || knot_node_rrset(contents->apex, KNOT_RRTYPE_SOA) == NULL) { - return KNOT_EINVAL; + if (zone == NULL || name == NULL) { + return NULL; + } + + knot_node_t *n; + int ret = knot_zone_tree_get(zone->nodes, name, &n); + if (ret != KNOT_EOK) { + dbg_zone("Failed to find name in the zone tree.\n"); + return NULL; } - return knot_rrset_class(knot_node_rrset(contents->apex, - KNOT_RRTYPE_SOA)); + return n; } /*----------------------------------------------------------------------------*/ -int knot_zone_contents_add_node(knot_zone_contents_t *zone, +static int knot_zone_contents_add_node(knot_zone_contents_t *zone, knot_node_t *node, int create_parents, uint8_t flags) { @@ -561,7 +566,6 @@ dbg_zone_exec_detail( /* Insert node to a tree. */ dbg_zone_detail("Inserting new node to zone tree.\n"); - assert(knot_zone_contents_find_node(zone, parent) == NULL); ret = knot_zone_tree_insert(zone->nodes, next_node); if (ret != KNOT_EOK) { knot_node_free(&next_node); @@ -594,42 +598,68 @@ dbg_zone_exec_detail( /*----------------------------------------------------------------------------*/ -int knot_zone_contents_create_node(knot_zone_contents_t *contents, - const knot_rrset_t *rr, - knot_node_t **node) +static int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, + knot_node_t *node) { - if (contents == NULL || rr == NULL || node == NULL) { + if (zone == NULL || node == NULL) { return KNOT_EINVAL; } - *node = knot_node_new(rr->owner, NULL, 0); - if (*node == NULL) { - return KNOT_ENOMEM; + int ret = 0; + if ((ret = knot_zone_contents_check_node(zone, node)) != 0) { + dbg_zone("Failed node check: %s\n", knot_strerror(ret)); + return ret; } - /* Add to the proper tree. */ - int ret = KNOT_EOK; - if (knot_rrset_is_nsec3rel(rr)) { - ret = knot_zone_contents_add_nsec3_node(contents, *node, 1, 0); - } else { - ret = knot_zone_contents_add_node(contents, *node, 1, 0); + /* Create NSEC3 tree if not exists. */ + if (zone->nsec3_nodes == NULL) { + zone->nsec3_nodes = knot_zone_tree_create(); + if (zone->nsec3_nodes == NULL) { + return KNOT_ENOMEM; + } } + // how to know if this is successfull?? + ret = knot_zone_tree_insert(zone->nsec3_nodes, node); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add new node to zone contents.\n"); - knot_node_free(node); + dbg_zone("Failed to insert node into NSEC3 tree: %s.\n", + knot_strerror(ret)); return ret; } - return ret; + // no parents to be created, the only parent is the zone apex + // set the apex as the parent of the node + knot_node_set_parent(node, zone->apex); + + // cannot be wildcard child, so nothing to be done + + return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ +static knot_node_t *knot_zone_contents_get_nsec3_node( + const knot_zone_contents_t *zone, const knot_dname_t *name) +{ + if (zone == NULL || name == NULL) { + return NULL; + } + + knot_node_t *n; + int ret = knot_zone_tree_get(zone->nsec3_nodes, name, &n); + + if (ret != KNOT_EOK) { + dbg_zone("Failed to find NSEC3 name in the zone tree." + "\n"); + return NULL; + } + + return n; +} -static int insert_rr(knot_zone_contents_t *z, knot_rrset_t *rr, knot_node_t **n, +static int insert_rr(knot_zone_contents_t *z, + const knot_rrset_t *rr, knot_node_t **n, bool nsec3, bool *ttl_err) { - if (z == NULL || rr == NULL || n == NULL || ttl_err == NULL) { + if (z == NULL || knot_rrset_empty(rr) || n == NULL) { return KNOT_EINVAL; } @@ -649,11 +679,10 @@ static int insert_rr(knot_zone_contents_t *z, knot_rrset_t *rr, knot_node_t **n, if (*n == NULL) { return KNOT_ENOMEM; } - ret = nsec3 ? knot_zone_contents_add_nsec3_node(z, *n, true, 0) : + ret = nsec3 ? knot_zone_contents_add_nsec3_node(z, *n) : knot_zone_contents_add_node(z, *n, true, 0); if (ret != KNOT_EOK) { knot_node_free(n); - return ret; } } } @@ -661,110 +690,114 @@ static int insert_rr(knot_zone_contents_t *z, knot_rrset_t *rr, knot_node_t **n, return knot_node_add_rrset(*n, rr, ttl_err); } -static bool to_nsec3_tree(const knot_rrset_t *rr) -{ - return knot_rrset_is_nsec3rel(rr); -} - -int knot_zone_contents_add_rr(knot_zone_contents_t *z, knot_rrset_t *rr, - knot_node_t **n, bool *ttl_err) +static int recreate_normal_tree(const knot_zone_contents_t *z, + knot_zone_contents_t *out) { - return insert_rr(z, rr, n, to_nsec3_tree(rr), ttl_err); -} - -int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, - knot_rrset_t *rrset, knot_node_t **node, - knot_rrset_dupl_handling_t dupl) -{ - if (zone == NULL || rrset == NULL || zone->apex == NULL - || zone->apex->owner == NULL || node == NULL) { - return KNOT_EINVAL; + out->nodes = hattrie_dup(z->nodes, NULL); + if (out->nodes == NULL) { + return KNOT_ENOMEM; } -dbg_zone_exec_detail( - char *name = knot_dname_to_str(knot_rrset_owner(rrset)); - dbg_zone_detail("Adding RRSet to zone contents: %s, type %d\n", - name, knot_rrset_type(rrset)); - free(name); -); - - // check if the RRSet belongs to the zone - if (!knot_dname_is_equal(rrset->owner, zone->apex->owner) - && !knot_dname_is_sub(rrset->owner, zone->apex->owner)) { - return KNOT_EOUTOFZONE; + // Insert APEX first. + knot_node_t *apex_cpy; + int ret = knot_node_shallow_copy(z->apex, &apex_cpy); + if (ret != KNOT_EOK) { + return ret; } - if ((*node) == NULL - && (*node = knot_zone_contents_get_node(zone, - rrset->owner)) == NULL) { - return KNOT_ENONODE; + // Normal additions need apex ... so we need to insert directly. + ret = knot_zone_tree_insert(out->nodes, apex_cpy); + if (ret != KNOT_EOK) { + knot_node_free(&apex_cpy); + return ret; } - assert(*node != NULL); - - // add all domain names from the RRSet to domain name table - int rc; + out->apex = apex_cpy; - /*! \todo REMOVE RRSET */ - if (dupl == KNOT_RRSET_DUPL_MERGE) { - rc = knot_node_add_rrset(*node, rrset, NULL); - } else { - rc = knot_node_add_rrset_no_merge(*node, rrset); + hattrie_iter_t *itt = hattrie_iter_begin(z->nodes, true); + if (itt == NULL) { + return KNOT_ENOMEM; } - - if (rc < 0) { - dbg_zone("Failed to add RRSet to node.\n"); - return rc; + while (!hattrie_iter_finished(itt)) { + const knot_node_t *to_cpy = (knot_node_t *)*hattrie_iter_val(itt); + if (to_cpy == z->apex) { + // Inserted already. + hattrie_iter_next(itt); + continue; + } + knot_node_t *to_add; + int ret = knot_node_shallow_copy(to_cpy, &to_add); + if (ret != KNOT_EOK) { + hattrie_iter_free(itt); + return ret; + } + ret = knot_zone_contents_add_node(out, to_add, true, 0); + if (ret != KNOT_EOK) { + knot_node_free(&to_add); + hattrie_iter_free(itt); + return ret; + } + hattrie_iter_next(itt); } - int ret = rc; + hattrie_iter_free(itt); + hattrie_build_index(out->nodes); - dbg_zone_detail("RRSet OK (%d).\n", ret); - return ret; + return KNOT_EOK; } -/*----------------------------------------------------------------------------*/ - -int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, - knot_node_t *node, int create_parents, - uint8_t flags) +static int recreate_nsec3_tree(const knot_zone_contents_t *z, + knot_zone_contents_t *out) { - UNUSED(create_parents); - UNUSED(flags); - - if (zone == NULL || node == NULL) { - return KNOT_EINVAL; + out->nsec3_nodes = hattrie_dup(z->nsec3_nodes, NULL); + if (out->nsec3_nodes == NULL) { + return KNOT_ENOMEM; } - int ret = 0; - if ((ret = knot_zone_contents_check_node(zone, node)) != 0) { - dbg_zone("Failed node check: %s\n", knot_strerror(ret)); - return ret; + hattrie_iter_t *itt = hattrie_iter_begin(z->nsec3_nodes, false); + if (itt == NULL) { + return KNOT_ENOMEM; } - - /* Create NSEC3 tree if not exists. */ - if (zone->nsec3_nodes == NULL) { - zone->nsec3_nodes = knot_zone_tree_create(); - if (zone->nsec3_nodes == NULL) { - return KNOT_ENOMEM; + while (!hattrie_iter_finished(itt)) { + const knot_node_t *to_cpy = (knot_node_t *)*hattrie_iter_val(itt); + knot_node_t *to_add; + int ret = knot_node_shallow_copy(to_cpy, &to_add); + if (ret != KNOT_EOK) { + hattrie_iter_free(itt); + return ret; + } + ret = knot_zone_contents_add_nsec3_node(out, to_add); + if (ret != KNOT_EOK) { + hattrie_iter_free(itt); + knot_node_free(&to_add); + return ret; } + hattrie_iter_next(itt); } - // how to know if this is successfull?? - ret = knot_zone_tree_insert(zone->nsec3_nodes, node); - if (ret != KNOT_EOK) { - dbg_zone("Failed to insert node into NSEC3 tree: %s.\n", - knot_strerror(ret)); - return ret; - } + hattrie_iter_free(itt); + hattrie_build_index(out->nsec3_nodes); - // no parents to be created, the only parent is the zone apex - // set the apex as the parent of the node - knot_node_set_parent(node, zone->apex); + return KNOT_EOK; +} - // cannot be wildcard child, so nothing to be done +static bool rrset_is_nsec3rel(const knot_rrset_t *rr) +{ + if (rr == NULL) { + return false; + } - return KNOT_EOK; + /* Is NSEC3 or non-empty RRSIG covering NSEC3. */ + return ((rr->type == KNOT_RRTYPE_NSEC3) + || (rr->type == KNOT_RRTYPE_RRSIG + && knot_rrs_rrsig_type_covered(&rr->rrs, 0) + == KNOT_RRTYPE_NSEC3)); +} + +int knot_zone_contents_add_rr(knot_zone_contents_t *z, + const knot_rrset_t *rr, knot_node_t **n, bool *ttl_err) +{ + return insert_rr(z, rr, n, rrset_is_nsec3rel(rr), ttl_err); } /*----------------------------------------------------------------------------*/ @@ -814,46 +847,6 @@ int knot_zone_contents_remove_nsec3_node(knot_zone_contents_t *contents, /*----------------------------------------------------------------------------*/ -knot_node_t *knot_zone_contents_get_node(const knot_zone_contents_t *zone, - const knot_dname_t *name) -{ - if (zone == NULL || name == NULL) { - return NULL; - } - - knot_node_t *n; - int ret = knot_zone_tree_get(zone->nodes, name, &n); - if (ret != KNOT_EOK) { - dbg_zone("Failed to find name in the zone tree.\n"); - return NULL; - } - - return n; -} - -/*----------------------------------------------------------------------------*/ - -knot_node_t *knot_zone_contents_get_nsec3_node( - const knot_zone_contents_t *zone, const knot_dname_t *name) -{ - if (zone == NULL || name == NULL) { - return NULL; - } - - knot_node_t *n; - int ret = knot_zone_tree_get(zone->nsec3_nodes, name, &n); - - if (ret != KNOT_EOK) { - dbg_zone("Failed to find NSEC3 name in the zone tree." - "\n"); - return NULL; - } - - return n; -} - -/*----------------------------------------------------------------------------*/ - const knot_node_t *knot_zone_contents_find_node( const knot_zone_contents_t *zone,const knot_dname_t *name) { @@ -980,34 +973,6 @@ const knot_node_t *knot_zone_contents_find_previous( } /*----------------------------------------------------------------------------*/ - -knot_node_t *knot_zone_contents_get_previous_nsec3( - const knot_zone_contents_t *zone, const knot_dname_t *name) -{ - if (zone == NULL || name == NULL) { - return NULL; - } - - knot_node_t *found = NULL, *prev = NULL; - - int exact_match = knot_zone_contents_find_in_tree(zone->nsec3_nodes, - name, &found, &prev); - assert(exact_match >= 0); - assert(prev != NULL); - - return prev; -} - -/*----------------------------------------------------------------------------*/ - -const knot_node_t *knot_zone_contents_find_previous_nsec3( - const knot_zone_contents_t *zone, const knot_dname_t *name) -{ - return knot_zone_contents_get_previous_nsec3(zone, name); -} - -/*----------------------------------------------------------------------------*/ - const knot_node_t *knot_zone_contents_find_nsec3_node( const knot_zone_contents_t *zone, const knot_dname_t *name) { @@ -1034,6 +999,7 @@ int knot_zone_contents_find_nsec3_for_name(const knot_zone_contents_t *zone, knot_dname_t *nsec3_name = NULL; int ret = knot_zone_contents_nsec3_name(zone, name, &nsec3_name); + if (ret != KNOT_EOK) { return ret; } @@ -1051,7 +1017,7 @@ dbg_zone_exec_verb( zone->nsec3_nodes, nsec3_name, &found, &prev); assert(exact_match >= 0); - knot_dname_free(&nsec3_name); + knot_dname_free(&nsec3_name, NULL); dbg_zone_exec_detail( if (found) { @@ -1073,13 +1039,6 @@ dbg_zone_exec_detail( ); *nsec3_node = found; - // This check cannot be used now, the function returns proper return - // value if the node was not found -// if (*nsec3_node == NULL) { -// // there is no NSEC3 node even if there should be -// return KNOT_ENSEC3CHAIN; -// } - if (prev == NULL) { // either the returned node is the root of the tree, or it is // the leftmost node in the tree; in both cases node was found @@ -1097,20 +1056,20 @@ dbg_zone_exec_detail( * from the right chain. Check iterations, hash algorithm and salt * values and compare them to the ones from NSEC3PARAM. */ - const knot_rrset_t *nsec3_rrset = knot_node_rrset(*nsec3_previous, - KNOT_RRTYPE_NSEC3); - assert(nsec3_rrset); + const knot_rrs_t *nsec3_rrs = + knot_node_rrs(*nsec3_previous, KNOT_RRTYPE_NSEC3); + assert(nsec3_rrs); const knot_node_t *original_prev = *nsec3_previous; int match = 0; - while (nsec3_rrset && !match) { + while (nsec3_rrs && !match) { for (uint16_t i = 0; - i < knot_rrset_rr_count(nsec3_rrset) && !match; + i < nsec3_rrs->rr_count && !match; i++) { - if (knot_zc_nsec3_parameters_match(nsec3_rrset, - &zone->nsec3_params, - i)) { + if (knot_zc_nsec3_parameters_match(nsec3_rrs, + &zone->nsec3_params, + i)) { /* Matching NSEC3PARAM match at position nr.: i. */ match = 1; } @@ -1122,8 +1081,7 @@ dbg_zone_exec_detail( /* This RRSET was not a match, try the one from previous node. */ *nsec3_previous = knot_node_previous(*nsec3_previous); - nsec3_rrset = knot_node_rrset(*nsec3_previous, - KNOT_RRTYPE_NSEC3); + nsec3_rrs = knot_node_rrs(*nsec3_previous, KNOT_RRTYPE_NSEC3); dbg_zone_exec_detail( char *name = (*nsec3_previous) ? knot_dname_to_str( @@ -1135,7 +1093,7 @@ dbg_zone_exec_detail( free(name); } ); - if (*nsec3_previous == original_prev || nsec3_rrset == NULL) { + if (*nsec3_previous == original_prev || nsec3_rrs == NULL) { // cycle *nsec3_previous = NULL; break; @@ -1161,17 +1119,6 @@ const knot_node_t *knot_zone_contents_apex( /*----------------------------------------------------------------------------*/ -knot_node_t *knot_zone_contents_get_apex(const knot_zone_contents_t *zone) -{ - if (zone == NULL) { - return NULL; - } - - return zone->apex; -} - -/*----------------------------------------------------------------------------*/ - static int knot_zone_contents_adjust_nodes(knot_zone_tree_t *nodes, knot_zone_adjust_arg_t *adjust_arg, knot_zone_tree_apply_cb_t callback) @@ -1321,11 +1268,9 @@ int knot_zone_contents_load_nsec3param(knot_zone_contents_t *zone) return KNOT_EINVAL; } - const knot_rrset_t *rrset = knot_node_rrset(zone->apex, - KNOT_RRTYPE_NSEC3PARAM); - - if (rrset != NULL) { - int r = knot_nsec3_params_from_wire(&zone->nsec3_params, rrset); + const knot_rrs_t *rrs = knot_node_rrs(zone->apex, KNOT_RRTYPE_NSEC3PARAM); + if (rrs!= NULL) { + int r = knot_nsec3_params_from_wire(&zone->nsec3_params, rrs); if (r != KNOT_EOK) { dbg_zone("Failed to load NSEC3PARAM (%s).\n", knot_strerror(r)); @@ -1403,41 +1348,36 @@ int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from, return KNOT_EINVAL; } - int ret = KNOT_EOK; - - knot_zone_contents_t *contents = (knot_zone_contents_t *)calloc( - 1, sizeof(knot_zone_contents_t)); + knot_zone_contents_t *contents = calloc(1, sizeof(knot_zone_contents_t)); if (contents == NULL) { ERR_ALLOC_FAILED; return KNOT_ENOMEM; } - //contents->apex = from->apex; - - contents->node_count = from->node_count; contents->flags = from->flags; - // set the 'new' flag knot_zone_contents_set_gen_new(contents); - if ((ret = knot_zone_tree_deep_copy(from->nodes, - &contents->nodes)) != KNOT_EOK - || (ret = knot_zone_tree_deep_copy(from->nsec3_nodes, - &contents->nsec3_nodes)) != KNOT_EOK) { - goto cleanup; + int ret = recreate_normal_tree(from, contents); + if (ret != KNOT_EOK) { + knot_zone_tree_free(&contents->nodes); + free(contents); + return ret; } - contents->apex = knot_node_get_new_node(from->apex); - - dbg_zone("knot_zone_contents_shallow_copy: finished OK\n"); + if (from->nsec3_nodes) { + ret = recreate_nsec3_tree(from, contents); + if (ret != KNOT_EOK) { + knot_zone_tree_free(&contents->nodes); + knot_zone_tree_free(&contents->nsec3_nodes); + free(contents); + return ret; + } + } else { + contents->nsec3_nodes = NULL; + } *to = contents; return KNOT_EOK; - -cleanup: - knot_zone_tree_free(&contents->nodes); - knot_zone_tree_free(&contents->nsec3_nodes); - free(contents); - return ret; } /*----------------------------------------------------------------------------*/ @@ -1490,12 +1430,65 @@ void knot_zone_contents_deep_free(knot_zone_contents_t **contents) uint32_t knot_zone_serial(const knot_zone_contents_t *zone) { if (!zone) return 0; - const knot_rrset_t *soa = NULL; - soa = knot_node_rrset(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA); - return knot_rdata_soa_serial(soa); + const knot_rrs_t *soa = NULL; + soa = knot_node_rrs(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA); + uint32_t serial = knot_rrs_soa_serial(soa); + return serial; } bool knot_zone_contents_is_signed(const knot_zone_contents_t *zone) { return knot_node_rrtype_is_signed(zone->apex, KNOT_RRTYPE_SOA); } + +knot_node_t *zone_contents_get_node_for_rr(knot_zone_contents_t *zone, + const knot_rrset_t *rrset) +{ + if (zone == NULL || rrset == NULL) { + return NULL; + } + + knot_node_t *node; + const bool nsec3 = rrset_is_nsec3rel(rrset); + if (!nsec3) { + node = knot_zone_contents_get_node(zone, rrset->owner); + } else { + node = knot_zone_contents_get_nsec3_node(zone, rrset->owner); + } + + if (node == NULL) { + int ret = KNOT_EOK; + node = knot_node_new(rrset->owner, NULL, 0); + if (!nsec3) { + ret = knot_zone_contents_add_node(zone, node, 1, 0); + } else { + ret = knot_zone_contents_add_nsec3_node(zone, node); + } + if (ret != KNOT_EOK) { + knot_node_free(&node); + return NULL; + } + + return node; + } else { + return node; + } +} + +knot_node_t *zone_contents_find_node_for_rr(knot_zone_contents_t *zone, + const knot_rrset_t *rrset) +{ + if (zone == NULL || rrset == NULL) { + return NULL; + } + + knot_node_t *node; + const bool nsec3 = rrset_is_nsec3rel(rrset); + if (!nsec3) { + node = knot_zone_contents_get_node(zone, rrset->owner); + } else { + node = knot_zone_contents_get_nsec3_node(zone, rrset->owner); + } + + return node; +} diff --git a/src/knot/zone/zone-contents.h b/src/knot/zone/zone-contents.h index 06b5d2c26d7fc09cfdca217c761d7193964eff32..4331a98451d340da117c68dcaf1b96d14133423f 100644 --- a/src/knot/zone/zone-contents.h +++ b/src/knot/zone/zone-contents.h @@ -29,6 +29,7 @@ #include "knot/zone/node.h" #include "libknot/dnssec/nsec3.h" +#include "common/lists.h" #include "knot/zone/zone-tree.h" @@ -92,89 +93,8 @@ int knot_zone_contents_gen_is_new(const knot_zone_contents_t *contents); void knot_zone_contents_set_gen_old(knot_zone_contents_t *contents); void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents); -uint16_t knot_zone_contents_class(const knot_zone_contents_t *contents); - -/*! - * \brief Adds a node to the given zone. - * - * Checks if the node belongs to the zone, i.e. if its owner is a subdomain of - * the zone's apex. It thus also forbids adding node with the same name as the - * zone apex. - * - * \warning This function may destroy domain names saved in the node, that - * are already present in the zone. - * - * \param zone Zone to add the node into. - * \param node Node to add into the zone. - * - * \retval KNOT_EOK - * \retval KNOT_EINVAL - * \retval KNOT_EOUTOFZONE - * \retval KNOT_EHASH - */ -int knot_zone_contents_add_node(knot_zone_contents_t *contents, - knot_node_t *node, int create_parents, - uint8_t flags); - -/*! - * \brief Create new node in the zone contents for given RRSet. - * - * \param contents Zone to add the node into. - * \param rr Given RRSet. - * \param node Returns created node. - * \return - */ -int knot_zone_contents_create_node(knot_zone_contents_t *contents, - const knot_rrset_t *rr, - knot_node_t **node); - -int knot_zone_contents_add_rr(knot_zone_contents_t *z, knot_rrset_t *rr, - knot_node_t **n, bool *ttl_err); - -/*! - * \brief Adds a RRSet to the given zone. - * - * Checks if the RRSet belongs to the zone, i.e. if its owner is a subdomain of - * the zone's apex. The RRSet is inserted only if the node is given, or if - * a node where the RRSet should belong is found in the zone. - * - * \warning The function does not check if the node is already inserted in the - * zone, just assumes that it is. - * \warning This function may destroy domain names saved in the RRSet, that - * are already present in the zone. - * - * \param zone Zone to add the node into. - * \param rrset RRSet to add into the zone. - * \param node Node the RRSet should be inserted into. (Should be a node of the - * given zone.) If set to NULL, the function will find proper node - * and set it to this parameter. - * - * \retval KNOT_EOK - * \retval KNOT_EINVAL - * \retval KNOT_EOUTOFZONE - */ -int knot_zone_contents_add_rrset(knot_zone_contents_t *contents, - knot_rrset_t *rrset, knot_node_t **node, - knot_rrset_dupl_handling_t dupl); - -/*! - * \brief Adds a node holding NSEC3 records to the given zone. - * - * Checks if the node belongs to the zone, i.e. if its owner is a subdomain of - * the zone's apex. It does not check if the node really contains any NSEC3 - * records, nor if the name is a hash (as there is actually no way of - * determining this). - * - * \param zone Zone to add the node into. - * \param node Node to add into the zone. - * - * \retval KNOT_EOK - * \retval KNOT_EINVAL - * \retval KNOT_EOUTOFZONE - */ -int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *contents, - knot_node_t *node, int create_parents, - uint8_t flags); +int knot_zone_contents_add_rr(knot_zone_contents_t *z, + const knot_rrset_t *rr, knot_node_t **n, bool *ttl_err); int knot_zone_contents_remove_node(knot_zone_contents_t *contents, const knot_dname_t *owner); @@ -182,29 +102,6 @@ int knot_zone_contents_remove_node(knot_zone_contents_t *contents, int knot_zone_contents_remove_nsec3_node(knot_zone_contents_t *contents, const knot_dname_t *owner); -/*! - * \brief Tries to find a node with the specified name in the zone. - * - * \param zone Zone where the name should be searched for. - * \param name Name to find. - * - * \return Corresponding node if found, NULL otherwise. - */ -knot_node_t *knot_zone_contents_get_node( - const knot_zone_contents_t *contents, const knot_dname_t *name); - -/*! - * \brief Tries to find a node with the specified name among the NSEC3 nodes - * of the zone. - * - * \param zone Zone where the name should be searched for. - * \param name Name to find. - * - * \return Corresponding node if found, NULL otherwise. - */ -knot_node_t *knot_zone_contents_get_nsec3_node( - const knot_zone_contents_t *contents, const knot_dname_t *name); - /*! * \brief Tries to find a node with the specified name in the zone. * @@ -251,15 +148,6 @@ int knot_zone_contents_find_dname(const knot_zone_contents_t *contents, const knot_node_t *knot_zone_contents_find_previous( const knot_zone_contents_t *contents, const knot_dname_t *name); -knot_node_t *knot_zone_contents_get_previous( - const knot_zone_contents_t *contents, const knot_dname_t *name); - -const knot_node_t *knot_zone_contents_find_previous_nsec3( - const knot_zone_contents_t *contents, const knot_dname_t *name); - -knot_node_t *knot_zone_contents_get_previous_nsec3( - const knot_zone_contents_t *contents, const knot_dname_t *name); - /*! * \brief Tries to find a node with the specified name among the NSEC3 nodes * of the zone. @@ -311,9 +199,6 @@ int knot_zone_contents_find_nsec3_for_name( const knot_node_t *knot_zone_contents_apex( const knot_zone_contents_t *contents); -knot_node_t *knot_zone_contents_get_apex( - const knot_zone_contents_t *contents); - /*! * \brief Sets parent and previous pointers and node flags. (cheap operation) * For both normal and NSEC3 tree @@ -444,6 +329,12 @@ uint32_t knot_zone_serial(const knot_zone_contents_t *zone); */ bool knot_zone_contents_is_signed(const knot_zone_contents_t *zone); +knot_node_t *zone_contents_get_node_for_rr(knot_zone_contents_t *zone, + const knot_rrset_t *rrset); + +knot_node_t *zone_contents_find_node_for_rr(knot_zone_contents_t *zone, + const knot_rrset_t *rrset); + #endif /*! @} */ diff --git a/src/knot/zone/zone-create.c b/src/knot/zone/zone-create.c index b550b27f63c52b59689c5d5c9a5bbed3bfadb5cf..cc6fd779662d7f66bd07ffb003364cbc2aa5fd3b 100644 --- a/src/knot/zone/zone-create.c +++ b/src/knot/zone/zone-create.c @@ -77,16 +77,15 @@ static bool handle_err(zcreator_t *zc, } } -int zcreator_step(zcreator_t *zc, knot_rrset_t *rr) +int zcreator_step(zcreator_t *zc, const knot_rrset_t *rr) { if (zc == NULL || rr == NULL || knot_rrset_rr_count(rr) != 1) { return KNOT_EINVAL; } if (rr->type == KNOT_RRTYPE_SOA && - knot_node_rrset(zc->z->apex, KNOT_RRTYPE_SOA)) { + knot_node_rrtype_exists(zc->z->apex, KNOT_RRTYPE_SOA)) { // Ignore extra SOA - knot_rrset_free(&rr, NULL); return KNOT_EOK; } @@ -99,7 +98,6 @@ int zcreator_step(zcreator_t *zc, knot_rrset_t *rr) return ret; } // Recoverable error, skip record - knot_rrset_free(&rr, NULL); return KNOT_EOK; } assert(node); @@ -132,10 +130,6 @@ int zcreator_step(zcreator_t *zc, knot_rrset_t *rr) } } - if (ret > 0) { - knot_rrset_free(&rr, NULL); - } - ret = sem_check_node_plain(zc->z, node, &err_handler, true, &sem_fatal_error); @@ -154,37 +148,30 @@ static void loader_process(const zs_scanner_t *scanner) return; } - knot_dname_t *owner = knot_dname_copy(scanner->r_owner); + knot_dname_t *owner = knot_dname_copy(scanner->r_owner, NULL); if (owner == NULL) { zc->ret = KNOT_ENOMEM; return; } knot_dname_to_lower(owner); - knot_rrset_t *rr = knot_rrset_new(owner, - scanner->r_type, - scanner->r_class, - NULL); - if (rr == NULL) { - knot_dname_free(&owner); - zc->ret = KNOT_ENOMEM; - return; - } - - int ret = add_rdata_to_rr(rr, scanner); + knot_rrset_t rr; + knot_rrset_init(&rr, owner, scanner->r_type, scanner->r_class); + int ret = add_rdata_to_rr(&rr, scanner); if (ret != KNOT_EOK) { - char *rr_name = knot_dname_to_str(rr->owner); + char *rr_name = knot_dname_to_str(rr.owner); log_zone_error("%s:%"PRIu64": Can't add RDATA for '%s'.\n", scanner->file_name, scanner->line_counter, rr_name); free(rr_name); - knot_rrset_free(&rr, NULL); + knot_dname_free(&owner, NULL); zc->ret = ret; return; } - ret = zcreator_step(zc, rr); + ret = zcreator_step(zc, &rr); + knot_dname_free(&owner, NULL); + knot_rrs_clear(&rr.rrs, NULL); if (ret != KNOT_EOK) { - knot_rrset_free(&rr, NULL); zc->ret = ret; return; } @@ -201,7 +188,7 @@ static knot_zone_contents_t *create_zone_from_name(const char *origin) } knot_dname_to_lower(owner); knot_zone_contents_t *z = knot_zone_contents_new(owner); - knot_dname_free(&owner); + knot_dname_free(&owner, NULL); return z; } @@ -280,7 +267,7 @@ knot_zone_contents_t *zonefile_load(zloader_t *loader) goto fail; } - if (knot_node_rrset(loader->creator->z->apex, KNOT_RRTYPE_SOA) == NULL) { + if (!knot_node_rrtype_exists(loader->creator->z->apex, KNOT_RRTYPE_SOA)) { log_zone_error("%s: no SOA record in the zone file.\n", loader->source); goto fail; @@ -299,17 +286,14 @@ knot_zone_contents_t *zonefile_load(zloader_t *loader) if (loader->semantic_checks) { int check_level = SEM_CHECK_UNSIGNED; - const knot_rrset_t *soa_rr = - knot_node_rrset(zc->z->apex, - KNOT_RRTYPE_SOA); - assert(soa_rr); // In this point, SOA has to exist - const knot_rrset_t *nsec3param_rr = - knot_node_rrset(zc->z->apex, - KNOT_RRTYPE_NSEC3PARAM); - if (knot_zone_contents_is_signed(zc->z) && nsec3param_rr == NULL) { + knot_rrset_t soa_rr = knot_node_rrset(zc->z->apex, KNOT_RRTYPE_SOA); + assert(!knot_rrset_empty(&soa_rr)); // In this point, SOA has to exist + const bool have_nsec3param = + knot_node_rrtype_exists(zc->z->apex, KNOT_RRTYPE_NSEC3PARAM); + if (knot_zone_contents_is_signed(zc->z) && have_nsec3param) { /* Set check level to DNSSEC. */ check_level = SEM_CHECK_NSEC; - } else if (knot_zone_contents_is_signed(zc->z) && nsec3param_rr) { + } else if (knot_zone_contents_is_signed(zc->z) && have_nsec3param) { check_level = SEM_CHECK_NSEC3; } err_handler_t err_handler; @@ -317,7 +301,7 @@ knot_zone_contents_t *zonefile_load(zloader_t *loader) zone_do_sem_checks(zc->z, check_level, &err_handler, first_nsec3_node, last_nsec3_node); - char *zname = knot_dname_to_str(knot_rrset_owner(soa_rr)); + char *zname = knot_dname_to_str(soa_rr.owner); log_zone_info("Semantic checks completed for zone=%s\n", zname); free(zname); } diff --git a/src/knot/zone/zone-create.h b/src/knot/zone/zone-create.h index 105613d842971a2e0248f5a148d8a07aeed471ce..1b97aeab240e520fcd05967d2fecec0a13b84414 100644 --- a/src/knot/zone/zone-create.h +++ b/src/knot/zone/zone-create.h @@ -82,7 +82,7 @@ knot_zone_contents_t *zonefile_load(zloader_t *loader); */ void zonefile_close(zloader_t *loader); -int zcreator_step(zcreator_t *zl, knot_rrset_t *rr); +int zcreator_step(zcreator_t *zl, const knot_rrset_t *rr); void process_error(const zs_scanner_t *scanner); diff --git a/src/knot/zone/zone-diff.c b/src/knot/zone/zone-diff.c index be3d5a00736e62bec85318af6690d2027558c324..43cd8bb545e00dfe7098bd7fa3b0726260b49973 100644 --- a/src/knot/zone/zone-diff.c +++ b/src/knot/zone/zone-diff.c @@ -46,74 +46,48 @@ static int knot_zone_diff_load_soas(const knot_zone_contents_t *zone1, const knot_node_t *apex1 = knot_zone_contents_apex(zone1); const knot_node_t *apex2 = knot_zone_contents_apex(zone2); if (apex1 == NULL || apex2 == NULL) { - dbg_zonediff("zone_diff: " - "both zones must have apex nodes.\n"); return KNOT_EINVAL; } - knot_rrset_t *soa_rrset1 = knot_node_get_rrset(apex1, KNOT_RRTYPE_SOA); - knot_rrset_t *soa_rrset2 = knot_node_get_rrset(apex2, KNOT_RRTYPE_SOA); - if (soa_rrset1 == NULL || soa_rrset2 == NULL) { - dbg_zonediff("zone_diff: " - "both zones must have apex nodes.\n"); + knot_rrset_t soa_rrset1 = knot_node_rrset(apex1, KNOT_RRTYPE_SOA); + knot_rrset_t soa_rrset2 = knot_node_rrset(apex2, KNOT_RRTYPE_SOA); + if (knot_rrset_empty(&soa_rrset1) || knot_rrset_empty(&soa_rrset2)) { return KNOT_EINVAL; } - if (knot_rrset_rr_count(soa_rrset1) == 0 || - knot_rrset_rr_count(soa_rrset2) == 0) { - dbg_zonediff("zone_diff: " - "both zones must have apex nodes with SOA " - "RRs.\n"); + if (knot_rrset_rr_count(&soa_rrset1) == 0 || + knot_rrset_rr_count(&soa_rrset2) == 0) { return KNOT_EINVAL; } - int64_t soa_serial1 = - knot_rdata_soa_serial(soa_rrset1); - if (soa_serial1 == -1) { - dbg_zonediff("zone_diff: load_soas: Got bad SOA.\n"); - } - - int64_t soa_serial2 = - knot_rdata_soa_serial(soa_rrset2); - if (soa_serial2 == -1) { - dbg_zonediff("zone_diff: load_soas: Got bad SOA.\n"); - } + int64_t soa_serial1 = knot_rrs_soa_serial(&soa_rrset1.rrs); + int64_t soa_serial2 = knot_rrs_soa_serial(&soa_rrset2.rrs); if (knot_serial_compare(soa_serial1, soa_serial2) == 0) { - dbg_zonediff("zone_diff: " - "second zone must have higher serial than the " - "first one. (%"PRId64" vs. %"PRId64")\n", - soa_serial1, soa_serial2); return KNOT_ENODIFF; } if (knot_serial_compare(soa_serial1, soa_serial2) > 0) { - dbg_zonediff("zone_diff: " - "second zone must have higher serial than the " - "first one. (%"PRId64" vs. %"PRId64")\n", - soa_serial1, soa_serial2); return KNOT_ERANGE; } assert(changeset); - int ret = knot_rrset_copy(soa_rrset1, &changeset->soa_from, NULL); - if (ret != KNOT_EOK) { - dbg_zonediff("zone_diff: load_soas: Cannot copy RRSet.\n"); - return ret; + changeset->soa_from = knot_rrset_copy(&soa_rrset1, NULL); + if (changeset->soa_from == NULL) { + return KNOT_ENOMEM; } - - ret = knot_rrset_copy(soa_rrset2, &changeset->soa_to, NULL); - if (ret != KNOT_EOK) { - dbg_zonediff("zone_diff: load_soas: Cannot copy RRSet.\n"); - return ret; + changeset->soa_to = knot_rrset_copy(&soa_rrset2, NULL); + if (changeset->soa_to == NULL) { + knot_rrset_free(&changeset->soa_from, NULL); + return KNOT_ENOMEM; } changeset->serial_from = soa_serial1; changeset->serial_to = soa_serial2; dbg_zonediff_verb("zone_diff: load_soas: SOAs diffed. (%"PRId64" -> %"PRId64")\n", - soa_serial1, soa_serial2); + soa_serial1, soa_serial2); return KNOT_EOK; } @@ -134,15 +108,14 @@ static int knot_zone_diff_changeset_add_rrset(knot_changeset_t *changeset, return KNOT_EOK; } - knot_rrset_t *rrset_copy = NULL; - int ret = knot_rrset_copy(rrset, &rrset_copy, NULL); - if (ret != KNOT_EOK) { + knot_rrset_t *rrset_copy = knot_rrset_copy(rrset, NULL); + if (rrset_copy == NULL) { dbg_zonediff("zone_diff: add_rrset: Cannot copy RRSet.\n"); - return ret; + return KNOT_ENOMEM; } - ret = knot_changeset_add_rrset(changeset, rrset_copy, - KNOT_CHANGESET_ADD); + int ret = knot_changeset_add_rrset(changeset, rrset_copy, + KNOT_CHANGESET_ADD); if (ret != KNOT_EOK) { /* We have to free the copy now! */ knot_rrset_free(&rrset_copy, NULL); @@ -173,15 +146,14 @@ static int knot_zone_diff_changeset_remove_rrset(knot_changeset_t *changeset, return KNOT_EOK; } - knot_rrset_t *rrset_copy = NULL; - int ret = knot_rrset_copy(rrset, &rrset_copy, NULL); - if (ret != KNOT_EOK) { + knot_rrset_t *rrset_copy = knot_rrset_copy(rrset, NULL); + if (rrset_copy == NULL) { dbg_zonediff("zone_diff: remove_rrset: Cannot copy RRSet.\n"); - return ret; + return KNOT_ENOMEM; } - ret = knot_changeset_add_rrset(changeset, rrset_copy, - KNOT_CHANGESET_REMOVE); + int ret = knot_changeset_add_rrset(changeset, rrset_copy, + KNOT_CHANGESET_REMOVE); if (ret != KNOT_EOK) { /* We have to free the copy now. */ knot_rrset_free(&rrset_copy, NULL); @@ -196,74 +168,48 @@ static int knot_zone_diff_changeset_remove_rrset(knot_changeset_t *changeset, static int knot_zone_diff_add_node(const knot_node_t *node, knot_changeset_t *changeset) { - if (node == NULL || changeset == NULL) { - dbg_zonediff("zone_diff: add_node: NULL arguments.\n"); - return KNOT_EINVAL; - } - /* Add all rrsets from node. */ - const knot_rrset_t **rrsets = knot_node_rrsets(node); - if (rrsets == NULL) { - /* Empty non-terminals - legal case. */ - dbg_zonediff_detail("zone_diff: Node has no RRSets.\n"); - return KNOT_EOK; - } - for (uint i = 0; i < knot_node_rrset_count(node); i++) { - assert(rrsets[i]); + knot_rrset_t rrset = knot_node_rrset_at(node, i); int ret = knot_zone_diff_changeset_add_rrset(changeset, - rrsets[i]); + &rrset); if (ret != KNOT_EOK) { dbg_zonediff("zone_diff: add_node: Cannot add RRSet (%s).\n", knot_strerror(ret)); - free(rrsets); return ret; } } - free(rrsets); - return KNOT_EOK; } static int knot_zone_diff_remove_node(knot_changeset_t *changeset, const knot_node_t *node) { - if (changeset == NULL || node == NULL) { - dbg_zonediff("zone_diff: remove_node: NULL parameters.\n"); - return KNOT_EINVAL; - } - - dbg_zonediff("zone_diff: remove_node: Removing node: ...\n"); - - const knot_rrset_t **rrsets = knot_node_rrsets(node); - if (rrsets == NULL) { - dbg_zonediff_verb("zone_diff: remove_node: " - "Nothing to remove.\n"); - return KNOT_EOK; - } - - dbg_zonediff_detail("zone_diff: remove_node: Will be removing %d RRSets.\n", - knot_node_rrset_count(node)); - /* Remove all the RRSets of the node. */ for (uint i = 0; i < knot_node_rrset_count(node); i++) { + knot_rrset_t rrset = knot_node_rrset_at(node, i); int ret = knot_zone_diff_changeset_remove_rrset(changeset, - rrsets[i]); + &rrset); if (ret != KNOT_EOK) { dbg_zonediff("zone_diff: remove_node: Failed to " "remove rrset. Error: %s\n", knot_strerror(ret)); - free(rrsets); return ret; } } - free(rrsets); - return KNOT_EOK; } +static bool rr_exists(const knot_rrset_t *in, const knot_rrset_t *ref, + size_t ref_pos) +{ + knot_rr_t *to_check = knot_rrs_rr(&ref->rrs, ref_pos); + const bool compare_ttls = true; + return knot_rrs_member(&in->rrs, to_check, compare_ttls); +} + static int knot_zone_diff_rdata_return_changes(const knot_rrset_t *rrset1, const knot_rrset_t *rrset2, knot_rrset_t **changes) @@ -282,53 +228,32 @@ static int knot_zone_diff_rdata_return_changes(const knot_rrset_t *rrset1, * changed/removed rdatas. This has awful computation time. */ /* Create fake RRSet, it will be easier to handle. */ - knot_dname_t *owner_copy = knot_dname_copy(knot_rrset_get_owner(rrset1)); - *changes = knot_rrset_new(owner_copy, - knot_rrset_type(rrset1), - knot_rrset_class(rrset1), - NULL); + + *changes = knot_rrset_new(rrset1->owner, rrset1->type, + rrset1->rclass, NULL); if (*changes == NULL) { - knot_dname_free(&owner_copy); dbg_zonediff("zone_diff: diff_rdata: " "Could not create RRSet with changes.\n"); return KNOT_ENOMEM; } const rdata_descriptor_t *desc = - get_rdata_descriptor(knot_rrset_type(rrset1)); + get_rdata_descriptor(rrset1->type); assert(desc); uint16_t rr1_count = knot_rrset_rr_count(rrset1); for (uint16_t i = 0; i < rr1_count; ++i) { - size_t rr_pos = 0; - int ret = knot_rrset_find_rr_pos(rrset2, rrset1, i, &rr_pos); - if (ret == KNOT_ENOENT) { - /* No such RR is present in 'rrset2'. */ - dbg_zonediff("zone_diff: diff_rdata: " - "No match for RR (type=%u owner=%p).\n", - knot_rrset_type(rrset1), - rrset1->owner); - /* We'll copy index 'i' into 'changes' RRSet. */ - ret = knot_rrset_add_rr_from_rrset(*changes, rrset1, i, NULL); + if (!rr_exists(rrset2, rrset1, i)) { + /* + * No such RR is present in 'rrset2'. We'll copy + * index 'i' into 'changes' RRSet. + */ + knot_rr_t *add_rr = knot_rrs_rr(&rrset1->rrs, i); + int ret = knot_rrs_add_rr(&(*changes)->rrs, add_rr, NULL); if (ret != KNOT_EOK) { knot_rrset_free(changes, NULL); return ret; } - } else if (ret == KNOT_EOK) { - if (knot_rrset_rr_ttl(rrset1, i) != - knot_rrset_rr_ttl(rrset2, rr_pos)) { - // TTLs differ add a change - ret = knot_rrset_add_rr_from_rrset(*changes, rrset1, i, NULL); - if (ret != KNOT_EOK) { - knot_rrset_free(changes, NULL); - return ret; - } - } - } else { - dbg_zonediff("zone_diff: diff_rdata: Could not search " - "for RR (%s).\n", knot_strerror(ret)); - knot_rrset_free(changes, NULL); - return ret; } } @@ -449,8 +374,7 @@ static int knot_zone_diff_node(knot_node_t **node_ptr, void *data) dbg_zonediff_detail("zone_diff: diff_node: Node %p is present in " "both trees.\n", node_owner); /* The nodes are in both trees, we have to diff each RRSet. */ - const knot_rrset_t **rrsets = knot_node_rrsets(node); - if (rrsets == NULL) { + if (node->rrset_count == 0) { dbg_zonediff("zone_diff: Node in first tree has no RRSets.\n"); /* * If there are no RRs in the first tree, all of the RRs @@ -468,110 +392,55 @@ static int knot_zone_diff_node(knot_node_t **node_ptr, void *data) for (uint i = 0; i < knot_node_rrset_count(node); i++) { /* Search for the RRSet in the node from the second tree. */ - const knot_rrset_t *rrset = rrsets[i]; - assert(rrset); + knot_rrset_t rrset = knot_node_rrset_at(node, i); - /* SOAs are handled explicitly. */ - if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { + /* SOAs are handled explicitely. */ + if (rrset.type == KNOT_RRTYPE_SOA) { continue; } - const knot_rrset_t *rrset_from_second_node = - knot_node_rrset(node_in_second_tree, - knot_rrset_type(rrset)); - if (rrset_from_second_node == NULL) { - dbg_zonediff("zone_diff: diff_node: There is no counterpart " - "for RRSet of type %u in second tree.\n", - knot_rrset_type(rrset)); + knot_rrset_t rrset_from_second_node = knot_node_rrset(node_in_second_tree, rrset.type); + if (knot_rrset_empty(&rrset_from_second_node)) { /* RRSet has been removed. Make a copy and remove. */ - assert(rrset); int ret = knot_zone_diff_changeset_remove_rrset( param->changeset, - rrset); + &rrset); if (ret != KNOT_EOK) { dbg_zonediff("zone_diff: diff_node: " "Failed to remove RRSet.\n"); - free(rrsets); return ret; } } else { - dbg_zonediff("zone_diff: diff_node: There is a counterpart " - "for RRSet of type %u in second tree.\n", - knot_rrset_type(rrset)); /* Diff RRSets. */ - int ret = knot_zone_diff_rrsets(rrset, - rrset_from_second_node, + int ret = knot_zone_diff_rrsets(&rrset, + &rrset_from_second_node, param->changeset); if (ret != KNOT_EOK) { dbg_zonediff("zone_diff: " "Failed to diff RRSets.\n"); - free(rrsets); return ret; } - -// dbg_zonediff_verb("zone_diff: diff_node: Changes in " -// "RRSIGs.\n"); -// /*! \todo There is ad-hoc solution in the function, maybe handle here. */ -// ret = knot_zone_diff_rrsets(rrset->rrsigs, -// rrset_from_second_node->rrsigs, -// param->changeset); -// if (ret != KNOT_EOK) { -// dbg_zonediff("zone_diff: " -// "Failed to diff RRSIGs.\n"); -// return ret; -// } } } - free(rrsets); - - /*! \todo move to one function with the code above. */ - rrsets = knot_node_rrsets(node_in_second_tree); - if (rrsets == NULL) { - dbg_zonediff("zone_diff: Node in second tree has no RRSets.\n"); - /* - * This can happen when node in second - * tree is empty non-terminal and as such has no RRs. - * Whole node from the first tree has to be removed. - */ - // TODO following code creates duplicated RR in diff. - // IHMO such case should be handled here -// int ret = knot_zone_diff_remove_node(param->changeset, -// node); -// if (ret != KNOT_EOK) { -// dbg_zonediff("zone_diff: diff_node: " -// "Cannot remove node. Reason: %s.\n", -// knot_strerror(ret)); -// } - return KNOT_EOK; - } - for (uint i = 0; i < knot_node_rrset_count(node_in_second_tree); i++) { /* Search for the RRSet in the node from the second tree. */ - const knot_rrset_t *rrset = rrsets[i]; - assert(rrset); + knot_rrset_t rrset = knot_node_rrset_at(node_in_second_tree, i); - /* SOAs are handled explicitly. */ - if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { + /* SOAs are handled explicitely. */ + if (rrset.type == KNOT_RRTYPE_SOA) { continue; } - const knot_rrset_t *rrset_from_first_node = - knot_node_rrset(node, - knot_rrset_type(rrset)); - if (rrset_from_first_node == NULL) { - dbg_zonediff("zone_diff: diff_node: There is no counterpart " - "for RRSet of type %u in first tree.\n", - knot_rrset_type(rrset)); + knot_rrset_t rrset_from_first_node = knot_node_rrset(node, rrset.type); + if (knot_rrset_empty(&rrset_from_first_node)) { /* RRSet has been added. Make a copy and add. */ - assert(rrset); int ret = knot_zone_diff_changeset_add_rrset( param->changeset, - rrset); + &rrset); if (ret != KNOT_EOK) { dbg_zonediff("zone_diff: diff_node: " "Failed to add RRSet.\n"); - free(rrsets); return ret; } } else { @@ -580,8 +449,6 @@ static int knot_zone_diff_node(knot_node_t **node_ptr, void *data) } } - free(rrsets); - return KNOT_EOK; } @@ -657,7 +524,6 @@ static int knot_zone_diff_load_trees(knot_zone_tree_t *nodes1, return result; } - static int knot_zone_diff_load_content(const knot_zone_contents_t *zone1, const knot_zone_contents_t *zone2, knot_changeset_t *changeset) @@ -674,7 +540,6 @@ static int knot_zone_diff_load_content(const knot_zone_contents_t *zone1, return result; } - static int knot_zone_contents_diff(const knot_zone_contents_t *zone1, const knot_zone_contents_t *zone2, knot_changeset_t *changeset) diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c index ee6b916ca30c3447199ed80a04854f14e1b7e801..4443ac2bc4930f0920b56604036ec9513342e41d 100644 --- a/src/knot/zone/zone-dump.c +++ b/src/knot/zone/zone-dump.c @@ -40,27 +40,25 @@ typedef struct { static int apex_node_dump_text(knot_node_t *node, dump_params_t *params) { - const knot_rrset_t *soa = knot_node_rrset(node, KNOT_RRTYPE_SOA); - + knot_rrset_t soa = knot_node_rrset(node, KNOT_RRTYPE_SOA); knot_dump_style_t soa_style = *params->style; // Dump SOA record as a first. if (!params->dump_nsec) { soa_style.show_class = true; - if (knot_rrset_txt_dump(soa, params->buf, params->buflen, + if (knot_rrset_txt_dump(&soa, params->buf, params->buflen, &soa_style) < 0) { return KNOT_ENOMEM; } - params->rr_count += knot_rrset_rr_count(soa); + params->rr_count += knot_rrset_rr_count(&soa); fprintf(params->file, "%s", params->buf); params->buf[0] = '\0'; } - const knot_rrset_t **rrsets = knot_node_rrsets_no_copy(node); - // Dump other records. for (uint16_t i = 0; i < node->rrset_count; i++) { - switch (rrsets[i]->type) { + knot_rrset_t rrset = knot_node_rrset_at(node, i); + switch (rrset.type) { case KNOT_RRTYPE_NSEC: continue; case KNOT_RRTYPE_RRSIG: @@ -71,11 +69,11 @@ static int apex_node_dump_text(knot_node_t *node, dump_params_t *params) break; } - if (knot_rrset_txt_dump(rrsets[i], params->buf, params->buflen, + if (knot_rrset_txt_dump(&rrset, params->buf, params->buflen, params->style) < 0) { return KNOT_ENOMEM; } - params->rr_count += knot_rrset_rr_count(rrsets[i]); + params->rr_count += knot_rrset_rr_count(&rrset); fprintf(params->file, "%s", params->buf); params->buf[0] = '\0'; } @@ -94,11 +92,10 @@ static int node_dump_text(knot_node_t *node, void *data) return KNOT_EOK; } - const knot_rrset_t **rrsets = knot_node_rrsets_no_copy(node); - // Dump non-apex rrsets. for (uint16_t i = 0; i < node->rrset_count; i++) { - switch (rrsets[i]->type) { + knot_rrset_t rrset = knot_node_rrset_at(node, i); + switch (rrset.type) { case KNOT_RRTYPE_RRSIG: if (params->dump_rrsig) { break; @@ -121,11 +118,11 @@ static int node_dump_text(knot_node_t *node, void *data) break; } - if (knot_rrset_txt_dump(rrsets[i], params->buf, params->buflen, + if (knot_rrset_txt_dump(&rrset, params->buf, params->buflen, params->style) < 0) { return KNOT_ENOMEM; } - params->rr_count += knot_rrset_rr_count(rrsets[i]); + params->rr_count += knot_rrset_rr_count(&rrset); fprintf(params->file, "%s", params->buf); params->buf[0] = '\0'; } diff --git a/src/knot/zone/zone-tree.c b/src/knot/zone/zone-tree.c index 3628694878e4255732cdcaf2a39f2857c15961c3..af36361e8c10ab567fc5441d6875800681924b3f 100644 --- a/src/knot/zone/zone-tree.c +++ b/src/knot/zone/zone-tree.c @@ -23,23 +23,6 @@ #include "common/debug.h" #include "common/hattrie/hat-trie.h" -/*----------------------------------------------------------------------------*/ -/* Non-API functions */ -/*----------------------------------------------------------------------------*/ - -static value_t knot_zone_node_copy(value_t v) -{ - return v; -} - -static value_t knot_zone_node_deep_copy(value_t v) -{ - knot_node_t *n = NULL; - knot_node_shallow_copy((knot_node_t *)v, &n); - knot_node_set_new_node((knot_node_t *)v, n); - return (value_t)n; -} - /*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -279,42 +262,6 @@ int knot_zone_tree_apply(knot_zone_tree_t *tree, /*----------------------------------------------------------------------------*/ -int knot_zone_tree_shallow_copy(knot_zone_tree_t *from, - knot_zone_tree_t **to) -{ - if (to == NULL) { - return KNOT_EINVAL; - } - - if (from != NULL) { - *to = hattrie_dup(from, knot_zone_node_copy); - } else { - *to = NULL; - } - - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - -int knot_zone_tree_deep_copy(knot_zone_tree_t *from, - knot_zone_tree_t **to) -{ - if (to == NULL) { - return KNOT_EINVAL; - } - - if (from != NULL) { - *to = hattrie_dup(from, knot_zone_node_deep_copy); - } else { - *to = NULL; - } - - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - void knot_zone_tree_free(knot_zone_tree_t **tree) { if (tree == NULL || *tree == NULL) { diff --git a/src/knot/zone/zone-tree.h b/src/knot/zone/zone-tree.h index cbc234ead678ae371f3bf66c438de3b95733a11b..07fcae54ec38674d3a8fe52204ee5e02735cf115 100644 --- a/src/knot/zone/zone-tree.h +++ b/src/knot/zone/zone-tree.h @@ -207,25 +207,6 @@ int knot_zone_tree_apply_inorder(knot_zone_tree_t *tree, int knot_zone_tree_apply(knot_zone_tree_t *tree, knot_zone_tree_apply_cb_t function, void *data); -/*! - * \brief Copies the whole zone tree structure (but not the data contained - * within). - * - * \warning This function does not check if the target zone tree is empty, - * it just replaces the root pointer. - * - * \param from Original zone tree. - * \param to Zone tree to copy the original one into. - * - * \retval KNOT_EOK - * \retval KNOT_ENOMEM - */ -int knot_zone_tree_shallow_copy(knot_zone_tree_t *from, - knot_zone_tree_t **to); - -int knot_zone_tree_deep_copy(knot_zone_tree_t *from, - knot_zone_tree_t **to); - /*! * \brief Destroys the zone tree, not touching the saved data. * diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c index 3d7d19f70600797481adbb5227a5041abab771d8..09f6ffa3363a77178e1635dc4e337b37da361192 100644 --- a/src/knot/zone/zone.c +++ b/src/knot/zone/zone.c @@ -223,7 +223,7 @@ void zone_free(zone_t **zone_ptr) zone_t *zone = *zone_ptr; - knot_dname_free(&zone->name); + knot_dname_free(&zone->name, NULL); /* Cancel and free timers. */ zone_timer_free(zone->xfr_in.timer); diff --git a/src/libknot/dname.c b/src/libknot/dname.c index 861bbb71f574b2a27b2587c7a11ab9d6db545f86..8688501d01f2624591d99e355e998ff9384b2be2 100644 --- a/src/libknot/dname.c +++ b/src/libknot/dname.c @@ -101,7 +101,8 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp, /*----------------------------------------------------------------------------*/ -knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos) +knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos, + mm_ctx_t *mm) { if (pkt == NULL || pos == NULL) return NULL; @@ -120,7 +121,7 @@ knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos) } /* Allocate space for the name. */ - knot_dname_t *res = malloc(decompressed_len); + knot_dname_t *res = mm_alloc(mm, decompressed_len); if (res) { /* Unpack name (expand compression pointers). */ if (knot_dname_unpack(res, name, decompressed_len, pkt) > 0) { @@ -136,22 +137,23 @@ knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos) /*----------------------------------------------------------------------------*/ -knot_dname_t *knot_dname_copy(const knot_dname_t *name) +knot_dname_t *knot_dname_copy(const knot_dname_t *name, mm_ctx_t *mm) { if (name == NULL) return NULL; - return knot_dname_copy_part(name, knot_dname_size(name)); + return knot_dname_copy_part(name, knot_dname_size(name), mm); } /*----------------------------------------------------------------------------*/ -knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len) +knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len, + mm_ctx_t *mm) { if (name == NULL || len == 0) return NULL; - knot_dname_t *dst = malloc(len); + knot_dname_t *dst = mm_alloc(mm, len); if (knot_dname_to_wire(dst, name, len) < 1) { free(dst); return NULL; @@ -540,12 +542,12 @@ knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned label /*----------------------------------------------------------------------------*/ -void knot_dname_free(knot_dname_t **name) +void knot_dname_free(knot_dname_t **name, mm_ctx_t *mm) { if (name == NULL || *name == NULL) return; - free(*name); + mm_free(mm, *name); *name = NULL; } @@ -615,7 +617,7 @@ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2) /* Like if we are reallocating d1. */ if (ret != NULL) - knot_dname_free(&d1); + knot_dname_free(&d1, NULL); return ret; } diff --git a/src/libknot/dname.h b/src/libknot/dname.h index c69e03fb1640730e9db2e4bce10e21e31bacd5b3..cc5af05c320047a96b18319a88873bf2c566ff7a 100644 --- a/src/libknot/dname.h +++ b/src/libknot/dname.h @@ -32,6 +32,7 @@ #include <stdio.h> #include <stdbool.h> +#include "common/mempattern.h" #include "libknot/consts.h" typedef uint8_t knot_dname_t; @@ -58,10 +59,12 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp, * \param pkt Message in wire format. * \param pos Position of the domain name on wire. * \param maxpos Domain name length. + * \param mm Memory context. * * \return parsed domain name or NULL. */ -knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos); +knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos, + mm_ctx_t *mm); /*! * \brief Duplicates the given domain name. @@ -70,7 +73,7 @@ knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos); * * \return New domain name which is an exact copy of \a dname. */ -knot_dname_t *knot_dname_copy(const knot_dname_t *name); +knot_dname_t *knot_dname_copy(const knot_dname_t *name, mm_ctx_t *mm); /*! * \brief Duplicates part of the given domain name. @@ -80,7 +83,7 @@ knot_dname_t *knot_dname_copy(const knot_dname_t *name); * * \return New domain name which is an partial copy of \a dname. */ -knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len); +knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len, mm_ctx_t *mm); /*! * \brief Copy name to wire as is, no compression pointer expansion will be done. @@ -236,7 +239,7 @@ knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, * * \param name Domain name to be destroyed. */ -void knot_dname_free(knot_dname_t **name); +void knot_dname_free(knot_dname_t **name, mm_ctx_t *mm); /*! * \brief Compares two domain names (case sensitive). diff --git a/src/libknot/dnssec/key.c b/src/libknot/dnssec/key.c index 07fe937907f731a22b030baafdfdde660cef85a0..45edbefe34f52b6744e117ece6093f92ceb4b1be 100644 --- a/src/libknot/dnssec/key.c +++ b/src/libknot/dnssec/key.c @@ -155,7 +155,7 @@ static int get_key_info_from_public_key(const char *filename, return KNOT_KEY_EPUBLIC_KEY_INVALID; } - knot_dname_t *owner = knot_dname_copy(scanner->r_owner); + knot_dname_t *owner = knot_dname_copy(scanner->r_owner, NULL); if (!owner) { zs_scanner_free(scanner); return KNOT_ENOMEM; @@ -167,7 +167,7 @@ static int get_key_info_from_public_key(const char *filename, &rdata_bin); if (result != KNOT_EOK) { zs_scanner_free(scanner); - knot_dname_free(&owner); + knot_dname_free(&owner, NULL); return result; } @@ -385,7 +385,7 @@ int knot_load_key_params(const char *filename, knot_key_params_t *key_params) if (!fp) { free(public_key); free(private_key); - knot_dname_free(&name); + knot_dname_free(&name, NULL); return KNOT_KEY_EPRIVATE_KEY_OPEN; } @@ -425,7 +425,7 @@ int knot_copy_key_params(const knot_key_params_t *src, knot_key_params_t *dst) int ret = 0; if (src->name != NULL) { - dst->name = knot_dname_copy(src->name); + dst->name = knot_dname_copy(src->name, NULL); if (dst->name == NULL) { ret += -1; } @@ -470,7 +470,7 @@ int knot_free_key_params(knot_key_params_t *key_params) return KNOT_EINVAL; } - knot_dname_free(&key_params->name); + knot_dname_free(&key_params->name, NULL); knot_binary_free(&key_params->rdata); knot_binary_free(&key_params->secret); @@ -541,7 +541,7 @@ int knot_tsig_create_key(const char *name, int algorithm, knot_binary_t secret; int result = knot_binary_from_base64(b64secret, &secret); if (result != KNOT_EOK) { - knot_dname_free(&dname); + knot_dname_free(&dname, NULL); return result; } @@ -567,7 +567,7 @@ int knot_tsig_key_from_params(const knot_key_params_t *params, return result; } - key->name = knot_dname_copy(params->name); + key->name = knot_dname_copy(params->name, NULL); key->algorithm = params->algorithm; @@ -583,7 +583,7 @@ int knot_tsig_key_free(knot_tsig_key_t *key) return KNOT_EINVAL; } - knot_dname_free(&key->name); + knot_dname_free(&key->name, NULL); knot_binary_free(&key->secret); memset(key, '\0', sizeof(knot_tsig_key_t)); diff --git a/src/libknot/dnssec/nsec3.c b/src/libknot/dnssec/nsec3.c index 1f80486a112ade4a11532ebdb0a49d9ec99c17fc..f5c152ee0924513ec6812bda090a05b29042f7ab 100644 --- a/src/libknot/dnssec/nsec3.c +++ b/src/libknot/dnssec/nsec3.c @@ -108,23 +108,21 @@ static int nsec3_sha1(const uint8_t *salt, uint8_t salt_length, * \brief Initialize the structure with NSEC3 params from NSEC3PARAM RR set. */ int knot_nsec3_params_from_wire(knot_nsec3_params_t *params, - const knot_rrset_t *rrset) + const knot_rrs_t *rrs) { - if (params == NULL || rrset == NULL || knot_rrset_rr_count(rrset) == 0) { + if (params == NULL || rrs == NULL || rrs->rr_count == 0) { return KNOT_EINVAL; } - assert(rrset->type == KNOT_RRTYPE_NSEC3PARAM); - knot_nsec3_params_t result = { 0 }; - result.algorithm = knot_rdata_nsec3param_algorithm(rrset, 0); - result.iterations = knot_rdata_nsec3param_iterations(rrset, 0); - result.flags = knot_rdata_nsec3param_flags(rrset, 0); - result.salt_length = knot_rdata_nsec3param_salt_length(rrset, 0); + result.algorithm = knot_rrs_nsec3param_algorithm(rrs, 0); + result.iterations = knot_rrs_nsec3param_iterations(rrs, 0); + result.flags = knot_rrs_nsec3param_flags(rrs, 0); + result.salt_length = knot_rrs_nsec3param_salt_length(rrs, 0); if (result.salt_length > 0) { - result.salt = knot_memdup(knot_rdata_nsec3param_salt(rrset, 0), + result.salt = knot_memdup(knot_rrs_nsec3param_salt(rrs, 0), result.salt_length); if (!result.salt) { return KNOT_ENOMEM; diff --git a/src/libknot/dnssec/nsec3.h b/src/libknot/dnssec/nsec3.h index 01ed467e4797f20303220dd8a0d90c189dfd57ad..533adee112747aad5da053ab7b2b23145b60836c 100644 --- a/src/libknot/dnssec/nsec3.h +++ b/src/libknot/dnssec/nsec3.h @@ -37,7 +37,6 @@ /*---------------------------------------------------------------------------*/ - /*! * \brief Get length of the raw NSEC3 hash. * @@ -89,12 +88,12 @@ typedef struct { * \brief Initialize the structure with NSEC3 params from NSEC3PARAM RR set. * * \param params Structure to initialize. - * \param nsec3param The NSEC3PARAM RR set. + * \param nsec3param The NSEC3PARAM RRs. * * \return Error code, KNOT_EOK on success. */ int knot_nsec3_params_from_wire(knot_nsec3_params_t *params, - const knot_rrset_t *rrset); + const knot_rrs_t *rrs); /*! * \brief Clean up structure with NSEC3 params (do not deallocate). * diff --git a/src/libknot/dnssec/rrset-sign.c b/src/libknot/dnssec/rrset-sign.c index 45a312d13efd0ea807a236866ab903249d45bfcc..737cfdf1b808c1cf38c2f9740a4313b7943d54d9 100644 --- a/src/libknot/dnssec/rrset-sign.c +++ b/src/libknot/dnssec/rrset-sign.c @@ -100,62 +100,6 @@ int knot_rrsig_write_rdata(uint8_t *rdata, const knot_dnssec_key_t *key, return KNOT_EOK; } -/*- Creating of RRSIGs from covered RRs -------------------------------------*/ - -/*! - * \brief Create RRSIG RDATA (all fields except signature are filled). - * - * \param[in] rrsigs RR set with RRSIGS. - * \param[in] covered RR covered by the signature. - * \param[in] key Key used for signing. - * \param[in] sig_incepted Timestamp of signature inception. - * \param[in] sig_expires Timestamp of signature expiration. - * \param[out] rdata Created RDATA. - * \param[out] rdata_size Size of created RDATA. - * - * \return Error code, KNOT_EOK if succesful. - */ -static int rrsigs_create_rdata(knot_rrset_t *rrsigs, - const knot_rrset_t *covered, - const knot_dnssec_key_t *key, - uint32_t sig_incepted, uint32_t sig_expires, - uint8_t **rdata, size_t *rdata_size) -{ - assert(rrsigs); - assert(rrsigs->type == KNOT_RRTYPE_RRSIG); - assert(covered); - assert(key); - assert(rdata); - assert(rdata_size); - - size_t size = knot_rrsig_rdata_size(key); - assert(size != 0); - - uint8_t *result = knot_rrset_create_rr(rrsigs, size, - knot_rrset_rr_ttl(covered, 0), - NULL); - if (!result) { - return KNOT_ENOMEM; - } - - uint8_t owner_labels = knot_dname_labels(covered->owner, NULL); - if (knot_dname_is_wildcard(covered->owner)) { - owner_labels -= 1; - } - - int res = knot_rrsig_write_rdata(result, key, covered->type, owner_labels, - knot_rrset_rr_ttl(covered, 0), - sig_incepted, sig_expires); - - assert(res == KNOT_EOK); - UNUSED(res); - - *rdata = result; - *rdata_size = size; - - return KNOT_EOK; -} - /*- Computation of signatures ------------------------------------------------*/ /*! @@ -242,6 +186,66 @@ static int sign_ctx_add_data(knot_dnssec_sign_context_t *ctx, return sign_ctx_add_records(ctx, covered); } +/*! + * \brief Create RRSIG RDATA (all fields except signature are filled). + * + * \param[in] rrsigs RR set with RRSIGS. + * \param[in] rrsigs DNSSEC signing context. + * \param[in] covered RR covered by the signature. + * \param[in] key Key used for signing. + * \param[in] sig_incepted Timestamp of signature inception. + * \param[in] sig_expires Timestamp of signature expiration. + * + * \return Error code, KNOT_EOK if succesful. + */ +static int rrsigs_create_rdata(knot_rrset_t *rrsigs, + knot_dnssec_sign_context_t *context, + const knot_rrset_t *covered, + const knot_dnssec_key_t *key, + uint32_t sig_incepted, uint32_t sig_expires) +{ + assert(rrsigs); + assert(rrsigs->type == KNOT_RRTYPE_RRSIG); + assert(!knot_rrset_empty(covered)); + assert(key); + + size_t size = knot_rrsig_rdata_size(key); + assert(size != 0); + + uint8_t owner_labels = knot_dname_labels(covered->owner, NULL); + if (knot_dname_is_wildcard(covered->owner)) { + owner_labels -= 1; + } + + uint8_t result[size]; + int res = knot_rrsig_write_rdata(result, key, covered->type, owner_labels, + knot_rrset_rr_ttl(covered, 0), + sig_incepted, sig_expires); + assert(res == KNOT_EOK); + + res = knot_dnssec_sign_new(context); + if (res != KNOT_EOK) { + return res; + } + + res = sign_ctx_add_data(context, result, covered); + if (res != KNOT_EOK) { + return res; + } + + const size_t signature_offset = RRSIG_RDATA_SIGNER_OFFSET + knot_dname_size(key->name); + uint8_t *signature = result + signature_offset; + const size_t signature_size = size - signature_offset; + + res = knot_dnssec_sign_write(context, signature, signature_size); + if (res != KNOT_EOK) { + return res; + } + + return knot_rrset_add_rr(rrsigs, result, size, + knot_rrset_rr_ttl(covered, 0), NULL); +} + /*! * \brief Create RRSIG RR for given RR set. */ @@ -250,7 +254,7 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered, knot_dnssec_sign_context_t *sign_ctx, const knot_dnssec_policy_t *policy) { - if (!rrsigs || !covered || !key || !sign_ctx || !policy || + if (knot_rrset_empty(covered) || !key || !sign_ctx || !policy || rrsigs->type != KNOT_RRTYPE_RRSIG || (knot_dname_cmp(rrsigs->owner, covered->owner) != 0) ) { @@ -260,30 +264,33 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered, uint32_t sig_incept = policy->now; uint32_t sig_expire = sig_incept + policy->sign_lifetime; - uint8_t *rdata = NULL; - size_t rdata_size = 0; + return rrsigs_create_rdata(rrsigs, sign_ctx, covered, key, sig_incept, + sig_expire); +} - int result = rrsigs_create_rdata(rrsigs, covered, key, sig_incept, - sig_expire, &rdata, &rdata_size); - if (result != KNOT_EOK) { - return result; +int knot_synth_rrsig(uint16_t type, const knot_rrs_t *rrsig_rrs, + knot_rrs_t *out_sig, mm_ctx_t *mm) +{ + if (rrsig_rrs == NULL) { + return KNOT_ENOENT; } - result = knot_dnssec_sign_new(sign_ctx); - if (result != KNOT_EOK) { - return result; + if (out_sig == NULL || out_sig->rr_count > 0) { + return KNOT_EINVAL; } - result = sign_ctx_add_data(sign_ctx, rdata, covered); - if (result != KNOT_EOK) { - return result; + for (int i = 0; i < rrsig_rrs->rr_count; ++i) { + if (type == knot_rrs_rrsig_type_covered(rrsig_rrs, i)) { + const knot_rr_t *rr_to_copy = knot_rrs_rr(rrsig_rrs, i); + int ret = knot_rrs_add_rr(out_sig, rr_to_copy, mm); + if (ret != KNOT_EOK) { + knot_rrs_clear(out_sig, mm); + return ret; + } + } } - size_t signature_offset = RRSIG_RDATA_SIGNER_OFFSET + knot_dname_size(key->name); - uint8_t *signature = rdata + signature_offset; - size_t signature_size = rdata_size - signature_offset; - - return knot_dnssec_sign_write(sign_ctx, signature, signature_size); + return out_sig->rr_count > 0 ? KNOT_EOK : KNOT_ENOENT; } /*- Verification of signatures -----------------------------------------------*/ @@ -300,11 +307,11 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered, static bool is_expired_signature(const knot_rrset_t *rrsigs, size_t pos, const knot_dnssec_policy_t *policy) { - assert(rrsigs); + assert(!knot_rrset_empty(rrsigs)); assert(rrsigs->type == KNOT_RRTYPE_RRSIG); assert(policy); - uint32_t expiration = knot_rdata_rrsig_sig_expiration(rrsigs, pos); + uint32_t expiration = knot_rrs_rrsig_sig_expiration(&rrsigs->rrs, pos); return (expiration <= policy->refresh_before); } @@ -318,7 +325,8 @@ int knot_is_valid_signature(const knot_rrset_t *covered, knot_dnssec_sign_context_t *ctx, const knot_dnssec_policy_t *policy) { - if (!covered || !rrsigs || !key || !ctx || !policy) { + if (knot_rrset_empty(covered) || + knot_rrset_empty(rrsigs) || !key || !ctx || !policy) { return KNOT_EINVAL; } @@ -335,7 +343,7 @@ int knot_is_valid_signature(const knot_rrset_t *covered, uint8_t *signature = NULL; size_t signature_size = 0; - knot_rdata_rrsig_signature(rrsigs, pos, &signature, &signature_size); + knot_rrs_rrsig_signature(&rrsigs->rrs, pos, &signature, &signature_size); if (!signature) { return KNOT_EINVAL; } @@ -354,3 +362,4 @@ int knot_is_valid_signature(const knot_rrset_t *covered, return knot_dnssec_sign_verify(ctx, signature, signature_size); } + diff --git a/src/libknot/dnssec/rrset-sign.h b/src/libknot/dnssec/rrset-sign.h index 82867e80d2783c4a4670e7f68dbd38bf06c66125..585883d0fd4e9c214b1692d6a6bdbfea44759d53 100644 --- a/src/libknot/dnssec/rrset-sign.h +++ b/src/libknot/dnssec/rrset-sign.h @@ -77,6 +77,22 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, knot_dnssec_sign_context_t *sign_ctx, const knot_dnssec_policy_t *policy); +/*! + * \brief Creates new RRS using \a rrsig_rrs as a source. Only those RRs that + * cover given \a type are copied into \a out_sig + * + * \param type Covered type. + * \param rrsig_rrs Source RRS. + * \param out_sig Output RRS. + * \param mm Memory context. + * + * \retval KNOT_EOK if some RRSIG was found. + * \retval KNOT_EINVAL if no RRSIGs were found. + * \retval Error code other than EINVAL on error. + */ +int knot_synth_rrsig(uint16_t type, const knot_rrs_t *rrsig_rrs, + knot_rrs_t *out_sig, mm_ctx_t *mm); + /*! * \brief Check if RRSIG signature is valid. * diff --git a/src/libknot/dnssec/sig0.c b/src/libknot/dnssec/sig0.c index ff4de0d1dc150dfe77bda3b1479eecb60ee6514f..48ba754f408c9eca193e3d6b79a760929555bcb7 100644 --- a/src/libknot/dnssec/sig0.c +++ b/src/libknot/dnssec/sig0.c @@ -38,11 +38,7 @@ */ static knot_rrset_t *sig0_create_rrset(void) { - knot_dname_t *root = knot_dname_from_str("."); - knot_rrset_t *sig_record = knot_rrset_new(root, KNOT_RRTYPE_SIG, - KNOT_CLASS_ANY, NULL); - - return sig_record; + return knot_rrset_new((uint8_t *)"", KNOT_RRTYPE_SIG, KNOT_CLASS_ANY, NULL); } static void sig0_write_rdata(uint8_t *rdata, const knot_dnssec_key_t *key) @@ -71,15 +67,14 @@ static uint8_t *sig0_create_rdata(knot_rrset_t *rrset, knot_dnssec_key_t *key) assert(key); size_t rdata_size = knot_rrsig_rdata_size(key); - uint32_t ttl = 0; - uint8_t *rdata = knot_rrset_create_rr(rrset, rdata_size, ttl, NULL); - if (!rdata) { + const uint32_t ttl = 0; + uint8_t rdata[rdata_size]; + sig0_write_rdata(rdata, key); + if (knot_rrset_add_rr(rrset, rdata, rdata_size, ttl, NULL) != KNOT_EOK) { return NULL; } - sig0_write_rdata(rdata, key); - - return rdata; + return knot_rrset_rr_rdata(rrset, 0); } /*! diff --git a/src/libknot/dnssec/sign.c b/src/libknot/dnssec/sign.c index 409a1d7cd81c26704c2e9286ee06e02247f9af0f..2fe724d571ee3d82d1b578dae7445b6c870e14ac 100644 --- a/src/libknot/dnssec/sign.c +++ b/src/libknot/dnssec/sign.c @@ -1116,7 +1116,7 @@ int knot_dnssec_key_from_params(const knot_key_params_t *params, return KNOT_EINVAL; } - knot_dname_t *name = knot_dname_copy(params->name); + knot_dname_t *name = knot_dname_copy(params->name, NULL); if (!name) { return KNOT_ENOMEM; } @@ -1124,21 +1124,21 @@ int knot_dnssec_key_from_params(const knot_key_params_t *params, knot_dnssec_key_data_t *data; data = calloc(1, sizeof(knot_dnssec_key_data_t)); if (!data) { - knot_dname_free(&name); + knot_dname_free(&name, NULL); return KNOT_ENOMEM; } knot_binary_t rdata_copy = { 0 }; int result = knot_binary_dup(¶ms->rdata, &rdata_copy); if (result != KNOT_EOK) { - knot_dname_free(&name); + knot_dname_free(&name, NULL); free(data); return result; } result = init_algorithm_data(params, data); if (result != KNOT_EOK) { - knot_dname_free(&name); + knot_dname_free(&name, NULL); free(data); knot_binary_free(&rdata_copy); return result; @@ -1162,7 +1162,7 @@ int knot_dnssec_key_free(knot_dnssec_key_t *key) return KNOT_EINVAL; } - knot_dname_free(&key->name); + knot_dname_free(&key->name, NULL); if (key->data) { clean_algorithm_data(key->data); diff --git a/src/libknot/edns.c b/src/libknot/edns.c index ce5be31053f36aa458a4b253f662426c117c21be..b9d4eb744af05fbf81fb1c26cbb992845dbae298 100644 --- a/src/libknot/edns.c +++ b/src/libknot/edns.c @@ -54,13 +54,13 @@ knot_opt_rr_t *knot_edns_new() int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset) { if (opt_rr == NULL || rrset == NULL - || knot_rrset_type(rrset) != KNOT_RRTYPE_OPT || + || rrset->type != KNOT_RRTYPE_OPT || knot_rrset_rr_count(rrset) == 0) { return KNOT_EINVAL; } dbg_edns_verb("Parsing payload.\n"); - opt_rr->payload = knot_rrset_class(rrset); + opt_rr->payload = rrset->rclass; /* RFC6891, 6.2.5 Value < 512B should be treated as 512. */ if (opt_rr->payload < EDNS_MIN_UDP_PAYLOAD) { @@ -118,7 +118,6 @@ int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset) } } - dbg_edns_verb("EDNS created.\n"); return KNOT_EOK; diff --git a/src/libknot/packet/pkt.c b/src/libknot/packet/pkt.c index c204b02d9222d7fc8b7c5c87193b2ea21390451e..82bb1905995e277d5d4453555aefa9b8e8149631 100644 --- a/src/libknot/packet/pkt.c +++ b/src/libknot/packet/pkt.c @@ -28,14 +28,15 @@ /*! \brief Scan packet for RRSet existence. */ static bool pkt_contains(const knot_pkt_t *packet, - const knot_rrset_t *rrset, - knot_rrset_compare_type_t cmp) + const knot_rrset_t *rrset) { assert(packet); assert(rrset); for (int i = 0; i < packet->rrset_count; ++i) { - if (knot_rrset_equal(packet->rr[i], rrset, cmp)) { + const uint16_t type = packet->rr[i].type; + const uint8_t *data = packet->rr[i].rrs.data; + if (type == rrset->type && data == rrset->rrs.data) { return true; } } @@ -43,18 +44,15 @@ static bool pkt_contains(const knot_pkt_t *packet, return false; } - /*! \brief Free all RRSets and reset RRSet count. */ static void pkt_free_data(knot_pkt_t *pkt) { assert(pkt); /* Free RRSets if applicable. */ - knot_rrset_t *rr = NULL; for (uint16_t i = 0; i < pkt->rrset_count; ++i) { if (pkt->rr_info[i].flags & KNOT_PF_FREE) { - rr = (knot_rrset_t *)pkt->rr[i]; - knot_rrset_free(&rr, &pkt->mm); + knot_rrset_clear(&pkt->rr[i], &pkt->mm); } } @@ -506,11 +504,11 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr, u rrinfo->pos = pkt->size; rrinfo->flags = flags; rrinfo->compress_ptr[0] = compr_hint; - pkt->rr[pkt->rrset_count] = rr; + pkt->rr[pkt->rrset_count] = *rr; /* Check for double insertion. */ if ((flags & KNOT_PF_CHECKDUP) && - pkt_contains(pkt, rr, KNOT_RRSET_COMPARE_PTR)) { + pkt_contains(pkt, rr)) { return KNOT_EOK; /*! \todo return rather a number of added RRs */ } @@ -585,7 +583,7 @@ int knot_pkt_parse_question(knot_pkt_t *pkt) if (pkt == NULL) { return KNOT_EINVAL; } - + /* Check at least header size. */ if (pkt->size < KNOT_WIRE_HEADER_SIZE) { dbg_packet("%s: smaller than DNS header, NOREPLY\n", __func__); @@ -615,7 +613,7 @@ int knot_pkt_parse_question(knot_pkt_t *pkt) if (len <= 0) { return KNOT_EMALF; } - + /* Check QCLASS/QTYPE size. */ uint16_t question_size = len + 2 * sizeof(uint16_t); /* QCLASS + QTYPE */ if (pkt->parsed + question_size > pkt->size) { @@ -623,7 +621,7 @@ int knot_pkt_parse_question(knot_pkt_t *pkt) return KNOT_EMALF; } - pkt->parsed += question_size; + pkt->parsed += question_size; pkt->qname_size = len; return KNOT_EOK; @@ -633,23 +631,23 @@ int knot_pkt_parse_question(knot_pkt_t *pkt) * RRSets should use packet memory context for allocation and * should be copied if they are supposed to be stored in zone permanently. */ -static knot_rrset_t *knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos, - size_t size, mm_ctx_t *mm) +static int knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos, + size_t size, mm_ctx_t *mm, knot_rrset_t *rrset) { dbg_packet("%s(%p, %zu, %zu)\n", __func__, wire, *pos, size); assert(wire); assert(pos); - knot_dname_t *owner = knot_dname_parse(wire, pos, size); + knot_dname_t *owner = knot_dname_parse(wire, pos, size, mm); if (owner == NULL) { - return NULL; + return KNOT_EMALF; } knot_dname_to_lower(owner); if (size - *pos < KNOT_RR_HEADER_SIZE) { dbg_packet("%s: not enough data to parse RR HEADER\n", __func__); - knot_dname_free(&owner); - return NULL; + knot_dname_free(&owner, mm); + return KNOT_EMALF; } uint16_t type = knot_wire_read_u16(wire + *pos); @@ -657,11 +655,6 @@ static knot_rrset_t *knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos, uint32_t ttl = knot_wire_read_u32(wire + *pos + 2 * sizeof(uint16_t)); uint16_t rdlength = knot_wire_read_u16(wire + *pos + 4 * sizeof(uint16_t)); - knot_rrset_t *rrset = knot_rrset_new(owner, type, rclass, mm); - if (rrset == NULL) { - knot_dname_free(&owner); - return NULL; - } *pos += KNOT_RR_HEADER_SIZE; dbg_packet_verb("%s: read type %u, class %u, ttl %u, rdlength %u\n", @@ -669,22 +662,20 @@ static knot_rrset_t *knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos, if (size - *pos < rdlength) { dbg_packet("%s: not enough data to parse RDATA\n", __func__); - knot_rrset_free(&rrset, mm); - return NULL; + knot_dname_free(&owner, mm); + return KNOT_EMALF; } - // parse RDATA - /*! \todo Merge with add_rdata_to_rr in zcompile, should be a rrset func - * probably. */ + knot_rrset_init(rrset, owner, type, rclass); int ret = knot_rrset_rdata_from_wire_one(rrset, wire, pos, size, ttl, rdlength, mm); if (ret != KNOT_EOK) { dbg_packet("%s: couldn't parse RDATA (%d)\n", __func__, ret); - knot_rrset_free(&rrset, mm); - return NULL; + knot_rrset_clear(rrset, mm); + return ret; } - return rrset; + return KNOT_EOK; } int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags) @@ -707,26 +698,25 @@ int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags) /* Parse wire format. */ size_t rr_size = pkt->parsed; - knot_rrset_t *rr = NULL; - rr = knot_pkt_rr_from_wire(pkt->wire, &pkt->parsed, pkt->max_size, - &pkt->mm); - if (rr == NULL) { + knot_rrset_t *rr = &pkt->rr[pkt->rrset_count]; + ret = knot_pkt_rr_from_wire(pkt->wire, &pkt->parsed, pkt->max_size, + &pkt->mm, rr); + if (ret != KNOT_EOK) { dbg_packet("%s: failed to parse RR\n", __func__); - return KNOT_EMALF; + return ret; } - + /* Calculate parsed RR size from before/after parsing. */ rr_size = (pkt->parsed - rr_size); - /* Append to RR list. */ - pkt->rr[pkt->rrset_count] = rr; + /* Update packet RRSet count. */ ++pkt->rrset_count; /* Update section RRSet count. */ ++pkt->sections[pkt->current].count; /* Check RR constraints. */ - switch(knot_rrset_type(rr)) { + switch(rr->type) { case KNOT_RRTYPE_TSIG: // if there is some TSIG already, treat as malformed if (pkt->tsig_rr != NULL) { @@ -814,7 +804,7 @@ int knot_pkt_parse_payload(knot_pkt_t *pkt, unsigned flags) /* TSIG must be last record of AR if present. */ const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL); if (pkt->tsig_rr != NULL) { - if (ar->count > 0 && pkt->tsig_rr != ar->rr[ar->count - 1]) { + if (ar->count > 0 && pkt->tsig_rr->rrs.data != ar->rr[ar->count - 1].rrs.data) { dbg_packet("%s: TSIG not last RR in AR.\n", __func__); return KNOT_EMALF; } diff --git a/src/libknot/packet/pkt.h b/src/libknot/packet/pkt.h index de9cc2ff126530ef2c26ced5c8c80011c0b84b4b..b5aefa0de3694a57af51efdaa537adaeba978698 100644 --- a/src/libknot/packet/pkt.h +++ b/src/libknot/packet/pkt.h @@ -80,9 +80,9 @@ enum { * This structure is required for random access to packet sections. */ typedef struct { - const knot_rrset_t **rr; /*!< Array of RRSets for this section. */ - knot_rrinfo_t *rrinfo; /*!< Compression info for each RRSet. */ - uint16_t count; /*!< Number of RRSets in this section. */ + const knot_rrset_t *rr; /*!< Array of RRSets for this section. */ + knot_rrinfo_t *rrinfo; /*!< Compression info for each RRSet. */ + uint16_t count; /*!< Number of RRSets in this section. */ } knot_pktsection_t; /*! @@ -106,13 +106,13 @@ typedef struct knot_pkt { /* Packet sections. */ knot_section_t current; knot_pktsection_t sections[KNOT_PKT_SECTIONS]; - + /*! \note <== Memory below this point is not cleared on init for performance reasons. */ - + /* Packet RRSet (meta)data. */ knot_rrinfo_t rr_info[KNOT_PKT_MAX_RRS]; - const knot_rrset_t *rr[KNOT_PKT_MAX_RRS]; - + knot_rrset_t rr[KNOT_PKT_MAX_RRS]; + mm_ctx_t mm; /*!< Memory allocation context. */ } knot_pkt_t; @@ -154,7 +154,6 @@ void knot_pkt_free(knot_pkt_t **pkt); */ int knot_pkt_reserve(knot_pkt_t *pkt, uint16_t size); - /*! \brief Classify packet according to the question. * \return see enum knot_pkt_type_t */ @@ -174,7 +173,7 @@ uint16_t knot_pkt_qclass(const knot_pkt_t *pkt); /*! * \brief Begin reading/writing packet section. - * + * * \note You must proceed in the natural order (ANSWER, AUTHORITY, ADDITIONAL). * * \param pkt @@ -211,7 +210,7 @@ int knot_pkt_opt_set(knot_pkt_t *pkt, unsigned opt, const void *data, uint16_t l */ int knot_pkt_put_question(knot_pkt_t *pkt, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype); -/*! \brief Write OPT RR to wireformat. +/*! \brief Write OPT RR to wireformat. * \note Legacy API. */ int knot_pkt_put_opt(knot_pkt_t *pkt); @@ -333,7 +332,6 @@ int knot_pkt_add_opt(knot_pkt_t *resp, /*----------------------------------------------------------------------------*/ /*** >>> #190 DEPRECATED */ - #endif /* _KNOT_PACKET_H_ */ /*! @} */ diff --git a/src/libknot/processing/process.h b/src/libknot/processing/process.h index 8be678a11284389ebf7e746a611b889384999cbf..a6bc1060ea087a4885b9140e8a05251310f4fe37 100644 --- a/src/libknot/processing/process.h +++ b/src/libknot/processing/process.h @@ -36,6 +36,7 @@ * Each state describes the current machine processing step * and determines readiness for next action. */ + enum knot_process_state { NS_PROC_NOOP = 0, /* N/A */ NS_PROC_MORE = 1 << 0, /* More input data. */ diff --git a/src/libknot/rdata.h b/src/libknot/rdata.h index 3af16ef6aa7ef5eea6d9f3417f0d22587fbc2218..fc7f9a0431568330984fb9ac3013b594f66db9c2 100644 --- a/src/libknot/rdata.h +++ b/src/libknot/rdata.h @@ -29,228 +29,183 @@ #include "common/descriptor.h" #include "libknot/dname.h" -#include "libknot/rrset.h" +#include "libknot/rr.h" #include "libknot/util/utils.h" #define KNOT_RDATA_DNSKEY_FLAG_KSK 1 -static inline -const knot_dname_t *knot_rdata_cname_name(const knot_rrset_t *rrset) -{ - if (rrset == NULL) { - return NULL; +#define RRS_CHECK(rrs, pos, code) \ + if (rrs == NULL || rrs->data == NULL || rrs->rr_count == 0 || \ + pos >= rrs->rr_count) { \ + code; \ } - return knot_rrset_rr_rdata(rrset, 0); +static inline uint8_t *data_offset(const knot_rrs_t *rrs, size_t pos, + size_t offset) { + knot_rr_t *rr = knot_rrs_rr(rrs, pos); + return knot_rr_rdata(rr) + offset; } static inline -const knot_dname_t *knot_rdata_dname_target(const knot_rrset_t *rrset) +const knot_dname_t *knot_rrs_cname_name(const knot_rrs_t *rrs) { - if (rrset == NULL) { - return NULL; - } - - return knot_rrset_rr_rdata(rrset, 0); + RRS_CHECK(rrs, 0, return NULL); + return data_offset(rrs, 0, 0); } static inline -const knot_dname_t *knot_rdata_soa_primary_ns(const knot_rrset_t *rrset) +const knot_dname_t *knot_rrs_dname_target(const knot_rrs_t *rrs) { - if (rrset == NULL) { - return NULL; - } - - return knot_rrset_rr_rdata(rrset, 0); + RRS_CHECK(rrs, 0, return NULL); + return data_offset(rrs, 0, 0); } static inline -const knot_dname_t *knot_rdata_soa_mailbox(const knot_rrset_t *rrset) +const knot_dname_t *knot_rrs_soa_primary_ns(const knot_rrs_t *rrs) { - if (rrset == NULL || knot_rrset_rr_count(rrset) == 0) { - return NULL; - } - - return knot_rrset_rr_rdata(rrset, 0) + - knot_dname_size(knot_rrset_rr_rdata(rrset, 0)); + RRS_CHECK(rrs, 0, return NULL); + return data_offset(rrs, 0, 0); } static inline -size_t knot_rrset_rdata_soa_names_len(const knot_rrset_t *rrset) +const knot_dname_t *knot_rrs_soa_mailbox(const knot_rrs_t *rrs) { - if (rrset == NULL) { - return 0; - } - - return knot_dname_size(knot_rdata_soa_primary_ns(rrset)) - + knot_dname_size(knot_rdata_soa_mailbox(rrset)); + RRS_CHECK(rrs, 0, return NULL); + return data_offset(rrs, 0, knot_dname_size(knot_rrs_soa_primary_ns(rrs))); } static inline -uint32_t knot_rdata_soa_serial(const knot_rrset_t *rrset) +size_t knot_rrs_soa_names_len(const knot_rrs_t *rrs) { - if (rrset == NULL) { - return 0; - } - - return knot_wire_read_u32(knot_rrset_rr_rdata(rrset, 0) - + knot_rrset_rdata_soa_names_len(rrset)); + RRS_CHECK(rrs, 0, return 0); + return knot_dname_size(knot_rrs_soa_primary_ns(rrs)) + + knot_dname_size(knot_rrs_soa_mailbox(rrs)); } static inline -void knot_rdata_soa_serial_set(knot_rrset_t *rrset, uint32_t serial) +uint32_t knot_rrs_soa_serial(const knot_rrs_t *rrs) { - if (rrset == NULL) { - return; - } + RRS_CHECK(rrs, 0, return 0); + return knot_wire_read_u32(data_offset(rrs, 0, + knot_rrs_soa_names_len(rrs))); +} +static inline +void knot_rrs_soa_serial_set(knot_rrs_t *rrs, uint32_t serial) +{ + RRS_CHECK(rrs, 0, return); // the number is in network byte order, transform it - knot_wire_write_u32(knot_rrset_rr_rdata(rrset, 0) - + knot_rrset_rdata_soa_names_len(rrset), serial); + knot_wire_write_u32(data_offset(rrs, 0, knot_rrs_soa_names_len(rrs)), + serial); } static inline -uint32_t knot_rdata_soa_refresh(const knot_rrset_t *rrset) +uint32_t knot_rrs_soa_refresh(const knot_rrs_t *rrs) { - if (rrset == NULL) { - return 0; - } - - return knot_wire_read_u32(knot_rrset_rr_rdata(rrset, 0) - + knot_rrset_rdata_soa_names_len(rrset) + 4); + RRS_CHECK(rrs, 0, return 0); + return knot_wire_read_u32(data_offset(rrs, 0, + knot_rrs_soa_names_len(rrs) + 4)); } static inline -uint32_t knot_rdata_soa_retry(const knot_rrset_t *rrset) +uint32_t knot_rrs_soa_retry(const knot_rrs_t *rrs) { - if (rrset == NULL) { - return 0; - } - - return knot_wire_read_u32(knot_rrset_rr_rdata(rrset, 0) - + knot_rrset_rdata_soa_names_len(rrset) + 8); + RRS_CHECK(rrs, 0, return 0); + return knot_wire_read_u32(data_offset(rrs, 0, + knot_rrs_soa_names_len(rrs) + 8)); } static inline -uint32_t knot_rdata_soa_expire(const knot_rrset_t *rrset) +uint32_t knot_rrs_soa_expire(const knot_rrs_t *rrs) { - if (rrset == NULL) { - return 0; - } - - return knot_wire_read_u32(knot_rrset_rr_rdata(rrset, 0) - + knot_rrset_rdata_soa_names_len(rrset) + 12); + RRS_CHECK(rrs, 0, return 0); + return knot_wire_read_u32(data_offset(rrs, 0, + knot_rrs_soa_names_len(rrs) + 12)); } static inline -uint32_t knot_rdata_soa_minimum(const knot_rrset_t *rrset) +uint32_t knot_rrs_soa_minimum(const knot_rrs_t *rrs) { - if (rrset == NULL) { - return 0; - } - - return knot_wire_read_u32(knot_rrset_rr_rdata(rrset, 0) - + knot_rrset_rdata_soa_names_len(rrset) + 16); + RRS_CHECK(rrs, 0, return 0); + return knot_wire_read_u32(data_offset(rrs, 0, + knot_rrs_soa_names_len(rrs) + 16)); } static inline -uint16_t knot_rdata_rrsig_type_covered(const knot_rrset_t *rrset, size_t pos) +uint16_t knot_rrs_rrsig_type_covered(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return knot_wire_read_u16(knot_rrset_rr_rdata(rrset, pos)); + RRS_CHECK(rrs, pos, return 0); + return knot_wire_read_u16(data_offset(rrs, pos, 0)); } static inline -uint8_t knot_rdata_rrsig_algorithm(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_rrsig_algorithm(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return *(knot_rrset_rr_rdata(rrset, pos) + 2); + RRS_CHECK(rrs, pos, return 0); + return *data_offset(rrs, pos, 2); } static inline -uint8_t knot_rdata_rrsig_labels(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_rrsig_labels(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return *(knot_rrset_rr_rdata(rrset, pos) + 3); + RRS_CHECK(rrs, pos, return 0); + return *data_offset(rrs, pos, 3); } static inline -uint32_t knot_rdata_rrsig_original_ttl(const knot_rrset_t *rrset, size_t pos) +uint32_t knot_rrs_rrsig_original_ttl(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return knot_wire_read_u32(knot_rrset_rr_rdata(rrset, pos) + 4); + RRS_CHECK(rrs, pos, return 0); + return knot_wire_read_u32(data_offset(rrs, pos, 4)); } static inline -uint32_t knot_rdata_rrsig_sig_expiration(const knot_rrset_t *rrset, size_t pos) +uint32_t knot_rrs_rrsig_sig_expiration(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return knot_wire_read_u32(knot_rrset_rr_rdata(rrset, pos) + 8); + RRS_CHECK(rrs, pos, return 0); + return knot_wire_read_u32(data_offset(rrs, pos, 8)); } static inline -uint32_t knot_rdata_rrsig_sig_inception(const knot_rrset_t *rrset, size_t pos) +uint32_t knot_rrs_rrsig_sig_inception(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return knot_wire_read_u32(knot_rrset_rr_rdata(rrset, pos) + 12); + RRS_CHECK(rrs, pos, return 0); + return knot_wire_read_u32(data_offset(rrs, pos, 12)); } static inline -uint16_t knot_rdata_rrsig_key_tag(const knot_rrset_t *rrset, size_t pos) +uint16_t knot_rrs_rrsig_key_tag(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return knot_wire_read_u16(knot_rrset_rr_rdata(rrset, pos) + 16); + RRS_CHECK(rrs, pos, return 0); + return knot_wire_read_u16(data_offset(rrs, pos, 16)); } static inline -const knot_dname_t *knot_rdata_rrsig_signer_name(const knot_rrset_t *rrset, +const knot_dname_t *knot_rrs_rrsig_signer_name(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return NULL; - } - - return knot_rrset_rr_rdata(rrset, pos) + 18; + RRS_CHECK(rrs, pos, return 0); + return data_offset(rrs, pos, 18); } static inline -void knot_rdata_rrsig_signature(const knot_rrset_t *rrset, size_t pos, +void knot_rrs_rrsig_signature(const knot_rrs_t *rrs, size_t pos, uint8_t **signature, size_t *signature_size) { if (!signature || !signature_size) { return; } - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { + if (rrs == NULL || pos >= rrs->rr_count) { *signature = NULL; *signature_size = 0; return; } - uint8_t *rdata = knot_rrset_rr_rdata(rrset, pos); + uint8_t *rdata = data_offset(rrs, pos, 0); uint8_t *signer = rdata + 18; - size_t total_size = knot_rrset_rr_size(rrset, pos); + const knot_rr_t *rr = knot_rrs_rr(rrs, pos); + size_t total_size = knot_rr_rdata_size(rr); size_t header_size = 18 + knot_dname_size(signer); *signature = rdata + header_size; @@ -258,245 +213,190 @@ void knot_rdata_rrsig_signature(const knot_rrset_t *rrset, size_t pos, } static inline -uint16_t knot_rdata_dnskey_flags(const knot_rrset_t *rrset, size_t pos) +uint16_t knot_rrs_dnskey_flags(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return knot_wire_read_u16(knot_rrset_rr_rdata(rrset, pos)); + RRS_CHECK(rrs, pos, return 0); + return knot_wire_read_u16(data_offset(rrs, pos, 0)); } static inline -uint8_t knot_rdata_dnskey_proto(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_dnskey_proto(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } + RRS_CHECK(rrs, pos, return 0); - return *(knot_rrset_rr_rdata(rrset, pos) + 2); + return *data_offset(rrs, pos, 2); } static inline -uint8_t knot_rdata_dnskey_alg(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_dnskey_alg(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return *(knot_rrset_rr_rdata(rrset, pos) + 3); + RRS_CHECK(rrs, pos, return 0); + return *data_offset(rrs, pos, 3); } static inline -void knot_rdata_dnskey_key(const knot_rrset_t *rrset, size_t pos, uint8_t **key, +void knot_rrs_dnskey_key(const knot_rrs_t *rrs, size_t pos, uint8_t **key, uint16_t *key_size) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return; - } - - *key = knot_rrset_rr_rdata(rrset, pos) + 4; - *key_size = knot_rrset_rr_size(rrset, pos) - 4; + RRS_CHECK(rrs, pos, return); + *key = data_offset(rrs, pos, 4); + const knot_rr_t *rr = knot_rrs_rr(rrs, pos); + *key_size = knot_rr_rdata_size(rr) - 4; } static inline -const knot_dname_t *knot_rdata_nsec_next(const knot_rrset_t *rrset) +const knot_dname_t *knot_rrs_nsec_next(const knot_rrs_t *rrs) { - return knot_rrset_rr_rdata(rrset, 0); + RRS_CHECK(rrs, 0, return NULL); + return data_offset(rrs, 0, 0); } static inline -void knot_rdata_nsec_bitmap(const knot_rrset_t *rrset, +void knot_rrs_nsec_bitmap(const knot_rrs_t *rrs, uint8_t **bitmap, uint16_t *size) { - uint8_t *rdata = knot_rrset_rr_rdata(rrset, 0); - int next_size = knot_dname_size(rdata); + RRS_CHECK(rrs, 0, return); + knot_rr_t *rr = knot_rrs_rr(rrs, 0); + int next_size = knot_dname_size(knot_rrs_nsec_next(rrs)); - *bitmap = rdata + next_size; - *size = knot_rrset_rr_size(rrset, 0) - next_size; + *bitmap = knot_rr_rdata(rr) + next_size; + *size = knot_rr_rdata_size(rr) - next_size; } static inline -uint8_t knot_rdata_nsec3_algorithm(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_nsec3_algorithm(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return *(knot_rrset_rr_rdata(rrset, pos)); + RRS_CHECK(rrs, pos, return 0); + return *data_offset(rrs, pos, 0); } static inline -uint8_t knot_rdata_nsec3_flags(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_nsec3_flags(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return *(knot_rrset_rr_rdata(rrset, pos) + 1); + RRS_CHECK(rrs, pos, return 0); + return *data_offset(rrs, pos, 1); } static inline -uint16_t knot_rdata_nsec3_iterations(const knot_rrset_t *rrset, size_t pos) +uint16_t knot_rrs_nsec3_iterations(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return knot_wire_read_u16(knot_rrset_rr_rdata(rrset, pos) + 2); + RRS_CHECK(rrs, pos, return 0); + return knot_wire_read_u16(data_offset(rrs, pos, 2)); } static inline -uint8_t knot_rdata_nsec3_salt_length(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_nsec3_salt_length(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return 0; - } - - return *(knot_rrset_rr_rdata(rrset, pos) + 4); + RRS_CHECK(rrs, pos, return 0); + return *(data_offset(rrs, pos, 0) + 4); } static inline -const uint8_t *knot_rdata_nsec3_salt(const knot_rrset_t *rrset, size_t pos) +const uint8_t *knot_rrs_nsec3_salt(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return NULL; - } - - return knot_rrset_rr_rdata(rrset, pos) + 5; + RRS_CHECK(rrs, pos, return NULL); + return data_offset(rrs, pos, 5); } static inline -void knot_rdata_nsec3_next_hashed(const knot_rrset_t *rrset, size_t pos, +void knot_rrs_nsec3_next_hashed(const knot_rrs_t *rrs, size_t pos, uint8_t **name, uint8_t *name_size) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return; - } - - uint8_t salt_size = knot_rdata_nsec3_salt_length(rrset, pos); - *name_size = *(knot_rrset_rr_rdata(rrset, pos) + 4 + salt_size + 1); - *name = knot_rrset_rr_rdata(rrset, pos) + 4 + salt_size + 2; + RRS_CHECK(rrs, pos, return); + uint8_t salt_size = knot_rrs_nsec3_salt_length(rrs, pos); + *name_size = *data_offset(rrs, pos, 4 + salt_size + 1); + *name = data_offset(rrs, pos, 4 + salt_size + 2); } static inline -void knot_rdata_nsec3_bitmap(const knot_rrset_t *rrset, size_t pos, +void knot_rrs_nsec3_bitmap(const knot_rrs_t *rrs, size_t pos, uint8_t **bitmap, uint16_t *size) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return; - } + RRS_CHECK(rrs, pos, return); /* Bitmap is last, skip all the items. */ size_t offset = 6; //hash alg., flags, iterations, salt len., hash len. - offset += knot_rdata_nsec3_salt_length(rrset, pos); //salt + offset += knot_rrs_nsec3_salt_length(rrs, pos); //salt uint8_t *next_hashed = NULL; uint8_t next_hashed_size = 0; - knot_rdata_nsec3_next_hashed(rrset, pos, &next_hashed, - &next_hashed_size); + knot_rrs_nsec3_next_hashed(rrs, pos, &next_hashed, &next_hashed_size); offset += next_hashed_size; //hash - *bitmap = knot_rrset_rr_rdata(rrset, pos) + offset; - *size = knot_rrset_rr_size(rrset, pos) - offset; + *bitmap = data_offset(rrs, pos, offset); + const knot_rr_t *rr = knot_rrs_rr(rrs, pos); + *size = knot_rr_rdata_size(rr) - offset; } static inline -uint8_t knot_rdata_nsec3param_algorithm(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_nsec3param_algorithm(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || knot_rrset_rr_count(rrset) <= pos) { - return 0; - } - - return *(knot_rrset_rr_rdata(rrset, pos)); + RRS_CHECK(rrs, pos, return 0); + return *data_offset(rrs, pos, 0); } static inline -uint8_t knot_rdata_nsec3param_flags(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_nsec3param_flags(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || knot_rrset_rr_count(rrset) <= pos) { - return 0; - } - - return *(knot_rrset_rr_rdata(rrset, pos) + 1); + RRS_CHECK(rrs, pos, return 0); + return *data_offset(rrs, pos, 1); } static inline -uint16_t knot_rdata_nsec3param_iterations(const knot_rrset_t *rrset, size_t pos) +uint16_t knot_rrs_nsec3param_iterations(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || knot_rrset_rr_count(rrset) <= pos) { - return 0; - } - - return knot_wire_read_u16(knot_rrset_rr_rdata(rrset, pos) + 2); + RRS_CHECK(rrs, pos, return 0); + return knot_wire_read_u16(data_offset(rrs, pos, 2)); } static inline -uint8_t knot_rdata_nsec3param_salt_length(const knot_rrset_t *rrset, size_t pos) +uint8_t knot_rrs_nsec3param_salt_length(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || knot_rrset_rr_count(rrset) <= pos) { - return 0; - } - - return *(knot_rrset_rr_rdata(rrset, pos) + 4); + RRS_CHECK(rrs, pos, return 0); + return *data_offset(rrs, pos, 4); } static inline -const uint8_t *knot_rdata_nsec3param_salt(const knot_rrset_t *rrset, size_t pos) +const uint8_t *knot_rrs_nsec3param_salt(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || knot_rrset_rr_count(rrset) <= pos) { - return NULL; - } - - return knot_rrset_rr_rdata(rrset, pos) + 5; + RRS_CHECK(rrs, pos, return 0); + return data_offset(rrs, pos, 5); } static inline -const knot_dname_t *knot_rdata_ns_name(const knot_rrset_t *rrset, size_t pos) +const knot_dname_t *knot_rrs_ns_name(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || knot_rrset_rr_count(rrset) <= pos) { - return NULL; - } - - return knot_rrset_rr_rdata(rrset, pos); + RRS_CHECK(rrs, pos, return 0); + return data_offset(rrs, pos, 0); } static inline -const knot_dname_t *knot_rdata_mx_name(const knot_rrset_t *rrset, size_t pos) +const knot_dname_t *knot_rrs_mx_name(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || knot_rrset_rr_count(rrset) <= pos) { - return NULL; - } - - return knot_rrset_rr_rdata(rrset, pos) + 2; + RRS_CHECK(rrs, pos, return 0); + return data_offset(rrs, pos, 2); } static inline -const knot_dname_t *knot_rdata_srv_name(const knot_rrset_t *rrset, size_t pos) +const knot_dname_t *knot_rrs_srv_name(const knot_rrs_t *rrs, size_t pos) { - if (rrset == NULL || knot_rrset_rr_count(rrset) <= pos) { - return NULL; - } - - return knot_rrset_rr_rdata(rrset, pos) + 6; + RRS_CHECK(rrs, pos, return 0); + return data_offset(rrs, pos, 6); } static inline -const knot_dname_t *knot_rdata_name(const knot_rrset_t *rrset, size_t pos) +const knot_dname_t *knot_rrs_name(const knot_rrs_t *rrs, size_t pos, + uint16_t type) { - if (rrset == NULL || knot_rrset_rr_count(rrset) <= pos) { - return NULL; - } - - switch (rrset->type) { + switch (type) { case KNOT_RRTYPE_NS: - return knot_rdata_ns_name(rrset, pos); + return knot_rrs_ns_name(rrs, pos); case KNOT_RRTYPE_MX: - return knot_rdata_mx_name(rrset, pos); + return knot_rrs_mx_name(rrs, pos); case KNOT_RRTYPE_SRV: - return knot_rdata_srv_name(rrset, pos); + return knot_rrs_srv_name(rrs, pos); case KNOT_RRTYPE_CNAME: - return knot_rdata_cname_name(rrset); + return knot_rrs_cname_name(rrs); } return NULL; diff --git a/src/libknot/rr.c b/src/libknot/rr.c new file mode 100644 index 0000000000000000000000000000000000000000..ddf1df7ed3bba174bebae3e8ad2e0f9c5193b748 --- /dev/null +++ b/src/libknot/rr.c @@ -0,0 +1,409 @@ +/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include "libknot/rr.h" +#include "libknot/rdata.h" +#include "libknot/common.h" +#include "common/errcode.h" + +#ifndef STRICT_ALIGNMENT +#pragma pack(push, 1) +#endif + +/*!< \brief Helper structure - offsets in RR array. */ +struct rr_offsets { + uint32_t ttl; + uint16_t size; + uint8_t rdata[]; +}; + +#ifndef STRICT_ALIGNMENT +#pragma pack(pop) +#endif + +static void *mm_realloc(mm_ctx_t *mm, void *what, size_t size, size_t prev_size) +{ + if (mm) { + void *p = mm->alloc(mm->ctx, size); + if (knot_unlikely(p == NULL)) { + return NULL; + } else { + if (what) { + memcpy(p, what, + prev_size < size ? prev_size : size); + } + if (mm->free) { + mm->free(what); + } + return p; + } + } else { + return realloc(what, size); + } +} + +static knot_rr_t *rr_seek(knot_rr_t *d, size_t pos) +{ + if (d == NULL) { + return NULL; + } + + size_t offset = 0; + for (size_t i = 0; i < pos; i++) { + knot_rr_t *rr = d + offset; + offset += knot_rr_array_size(knot_rr_rdata_size(rr)); + } + + return d + offset; +} + +static int find_rr_pos(const knot_rrs_t *search_in, + const knot_rr_t *rr) +{ + for (uint16_t i = 0; i < search_in->rr_count; ++i) { + const knot_rr_t *search_rr = knot_rrs_rr(search_in, i); + if (knot_rr_cmp(rr, search_rr) == 0) { + return i; + } + } + + return KNOT_ENOENT; +} + +static int add_rr_at(knot_rrs_t *rrs, const knot_rr_t *rr, size_t pos, + mm_ctx_t *mm) +{ + if (rrs == NULL || pos > rrs->rr_count) { + return KNOT_EINVAL; + } + const uint16_t size = knot_rr_rdata_size(rr); + const uint32_t ttl = knot_rr_ttl(rr); + const uint8_t *rdata = knot_rr_rdata(rr); + + size_t total_size = knot_rrs_size(rrs); + + // Realloc data. + void *tmp = mm_realloc(mm, rrs->data, + total_size + knot_rr_array_size(size), + total_size); + if (tmp) { + rrs->data = tmp; + } else { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + if (rrs->rr_count == 0 || pos == rrs->rr_count) { + // No need to rearange RDATA + rrs->rr_count++; + knot_rr_t *new_rr = knot_rrs_rr(rrs, pos); + knot_rr_set_size(new_rr, size); + knot_rr_set_ttl(new_rr, ttl); + memcpy(knot_rr_rdata(new_rr), rdata, size); + return KNOT_EOK; + } + + // RDATA have to be rearanged. + knot_rr_t *last_rr = knot_rrs_rr(rrs, rrs->rr_count - 1); + knot_rr_t *old_rr = knot_rrs_rr(rrs, pos); + assert(last_rr); + assert(old_rr); + + // Make space for new data by moving the array + memmove(old_rr + knot_rr_array_size(size), old_rr, + (last_rr + knot_rr_array_size(knot_rr_rdata_size(last_rr))) - old_rr); + + // Set new RR + knot_rr_set_size(old_rr, size); + knot_rr_set_ttl(old_rr, ttl); + memcpy(knot_rr_rdata(old_rr), rdata, size); + + rrs->rr_count++; + return KNOT_EOK; +} + +static int remove_rr_at(knot_rrs_t *rrs, size_t pos, mm_ctx_t *mm) +{ + if (rrs == NULL || pos >= rrs->rr_count) { + return KNOT_EINVAL; + } + + knot_rr_t *old_rr = knot_rrs_rr(rrs, pos); + knot_rr_t *last_rr = knot_rrs_rr(rrs, rrs->rr_count - 1); + assert(old_rr); + assert(last_rr); + + size_t total_size = knot_rrs_size(rrs); + uint16_t old_size = knot_rr_rdata_size(old_rr); + + void *old_threshold = old_rr + knot_rr_array_size(old_size); + void *last_threshold = last_rr + knot_rr_array_size(knot_rr_rdata_size(last_rr)); + // Move RDATA + memmove(old_rr, old_threshold, + last_threshold - old_threshold); + + if (rrs->rr_count > 1) { + // Realloc RDATA + void *tmp = mm_realloc(mm, rrs->data, + total_size - (knot_rr_array_size(old_size)), + total_size); + if (tmp == NULL) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } else { + rrs->data = tmp; + } + } else { + // Free RDATA + mm_free(mm, rrs->data); + rrs->data = NULL; + } + rrs->rr_count--; + + return KNOT_EOK; +} + +uint16_t knot_rr_rdata_size(const knot_rr_t *rr) +{ + return ((struct rr_offsets *)rr)->size; +} + +void knot_rr_set_size(knot_rr_t *rr, uint16_t size) +{ + ((struct rr_offsets *)rr)->size = size; +} + +uint32_t knot_rr_ttl(const knot_rr_t *rr) +{ + return ((struct rr_offsets *)rr)->ttl; +} + +void knot_rr_set_ttl(knot_rr_t *rr, uint32_t ttl) +{ + ((struct rr_offsets *)rr)->ttl = ttl; +} + +uint8_t *knot_rr_rdata(const knot_rr_t *rr) +{ + return ((struct rr_offsets *)rr)->rdata; +} + +size_t knot_rr_array_size(uint16_t size) +{ + return size + sizeof(struct rr_offsets); +} + +int knot_rr_cmp(const knot_rr_t *rr1, const knot_rr_t *rr2) +{ + assert(rr1 && rr2); + const uint8_t *r1 = knot_rr_rdata(rr1); + const uint8_t *r2 = knot_rr_rdata(rr2); + uint16_t l1 = knot_rr_rdata_size(rr1); + uint16_t l2 = knot_rr_rdata_size(rr2); + int cmp = memcmp(r1, r2, MIN(l1, l2)); + if (cmp == 0 && l1 != l2) { + cmp = l1 < l2 ? -1 : 1; + } + return cmp; +} + +void knot_rrs_init(knot_rrs_t *rrs) +{ + if (rrs) { + rrs->rr_count = 0; + rrs->data = NULL; + } +} + +void knot_rrs_clear(knot_rrs_t *rrs, mm_ctx_t *mm) +{ + if (rrs) { + mm_free(mm, rrs->data); + rrs->data = NULL; + rrs->rr_count = 0; + } +} + +int knot_rrs_copy(knot_rrs_t *dst, const knot_rrs_t *src, mm_ctx_t *mm) +{ + if (dst == NULL || src == NULL) { + return KNOT_EINVAL; + } + + dst->rr_count = src->rr_count; + size_t src_size = knot_rrs_size(src); + dst->data = mm_alloc(mm, src_size); + if (dst->data == NULL) { + ERR_ALLOC_FAILED; + return KNOT_ENOMEM; + } + + memcpy(dst->data, src->data, src_size); + return KNOT_EOK; +} + +knot_rr_t *knot_rrs_rr(const knot_rrs_t *rrs, size_t pos) +{ + if (rrs == NULL || pos >= rrs->rr_count) { + return NULL; + } + + return rr_seek(rrs->data, pos); +} + +size_t knot_rrs_size(const knot_rrs_t *rrs) +{ + if (rrs == NULL) { + return 0; + } + + size_t total_size = 0; + for (size_t i = 0; i < rrs->rr_count; ++i) { + const knot_rr_t *rr = knot_rrs_rr(rrs, i); + assert(rr); + total_size += knot_rr_array_size(knot_rr_rdata_size(rr)); + } + + return total_size; +} + +int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm) +{ + if (rrs == NULL || rr == NULL) { + return KNOT_EINVAL; + } + + for (uint16_t i = 0; i < rrs->rr_count; ++i) { + const knot_rr_t *rrset_rr = knot_rrs_rr(rrs, i); + int cmp = knot_rr_cmp(rrset_rr, rr); + if (cmp == 0) { + // Duplication - no need to add this RR + return KNOT_EOK; + } else if (cmp > 0) { + // Found position to insert + return add_rr_at(rrs, rr, i, mm); + } + } + + // If flow gets here, it means that we should insert at the last position + return add_rr_at(rrs, rr, rrs->rr_count, mm); +} + +bool knot_rrs_eq(const knot_rrs_t *rrs1, const knot_rrs_t *rrs2) +{ + if (rrs1->rr_count != rrs2->rr_count) { + return false; + } + + for (uint16_t i = 0; i < rrs1->rr_count; ++i) { + const knot_rr_t *rr1 = knot_rrs_rr(rrs1, i); + const knot_rr_t *rr2 = knot_rrs_rr(rrs2, i); + if (knot_rr_cmp(rr1, rr2) != 0) { + return false; + } + } + + return true; +} + +bool knot_rrs_member(const knot_rrs_t *rrs, const knot_rr_t *rr, bool cmp_ttl) +{ + for (uint16_t i = 0; i < rrs->rr_count; ++i) { + const knot_rr_t *cmp_rr = knot_rrs_rr(rrs, i); + if (cmp_ttl) { + if (knot_rr_ttl(rr) != knot_rr_ttl(cmp_rr)) { + continue; + } + } + int cmp = knot_rr_cmp(cmp_rr, rr); + if (cmp == 0) { + // Match. + return true; + } + if (cmp > 0) { + // 'Bigger' RR present, no need to continue. + return false; + } + } + return false; +} + +int knot_rrs_merge(knot_rrs_t *rrs1, const knot_rrs_t *rrs2, mm_ctx_t *mm) +{ + if (rrs1 == NULL || rrs2 == NULL) { + return KNOT_EINVAL; + } + + for (uint16_t i = 0; i < rrs2->rr_count; ++i) { + const knot_rr_t *rr = knot_rrs_rr(rrs2, i); + int ret = knot_rrs_add_rr(rrs1, rr, mm); + if (ret != KNOT_EOK) { + return ret; + } + } + + return KNOT_EOK; +} + +int knot_rrs_intersect(const knot_rrs_t *a, const knot_rrs_t *b, + knot_rrs_t *out, mm_ctx_t *mm) +{ + if (a == NULL || b == NULL || out == NULL) { + return KNOT_EINVAL; + } + + knot_rrs_init(out); + const bool compare_ttls = false; + for (uint16_t i = 0; i < a->rr_count; ++i) { + const knot_rr_t *rr = knot_rrs_rr(a, i); + if (knot_rrs_member(b, rr, compare_ttls)) { + // Add RR into output intersection RRSet. + int ret = knot_rrs_add_rr(out, rr, mm); + if (ret != KNOT_EOK) { + knot_rrs_clear(out, mm); + return ret; + } + } + } + + return KNOT_EOK; +} + +int knot_rrs_subtract(knot_rrs_t *from, const knot_rrs_t *what, mm_ctx_t *mm) +{ + if (from == NULL || what == NULL) { + return KNOT_EINVAL; + } + + for (uint16_t i = 0; i < what->rr_count; ++i) { + const knot_rr_t *to_remove = knot_rrs_rr(what, i); + int pos_to_remove = find_rr_pos(from, to_remove); + if (pos_to_remove >= 0) { + int ret = remove_rr_at(from, pos_to_remove, mm); + if (ret != KNOT_EOK) { + return ret; + } + } + } + + return KNOT_EOK; +} + diff --git a/src/libknot/rr.h b/src/libknot/rr.h new file mode 100644 index 0000000000000000000000000000000000000000..4fd46b85a6fcb4877447132bd89a6b14ebf5868b --- /dev/null +++ b/src/libknot/rr.h @@ -0,0 +1,208 @@ +/*! + * \file rr.h + * + * \author Jan Kadlec <jan.kadlec@nic.cz> + * + * \brief API for manipulating RRs and RR arrays. + * + * \addtogroup libknot + * @{ + */ +/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> + +#include "common/mempattern.h" + +/* ---------------------------- Single RR ----------------------------------- */ + +/*! + * \brief knot_rr_t Array holding single RR payload, i.e. ttl, size and RDATA. + */ +typedef uint8_t knot_rr_t; + +/* ------------------------- RR getters/setters ----------------------------- */ + +/*! + * \brief Returns RDATA size of single RR. + * \param rr RR whose size we want. + * \return RR size. + */ +uint16_t knot_rr_rdata_size(const knot_rr_t *rr); + +/*! + * \brief Sets size for given RR. + * \param rr RR whose size we want to set. + * \param size Size to be set. + */ +void knot_rr_set_size(knot_rr_t *rr, uint16_t size); + +/*! + * \brief Returns TTL of single RR. + * \param rr RR whose TTL we want. + * \return RR TTL. + */ +uint32_t knot_rr_ttl(const knot_rr_t *rr); + +/*! + * \brief Sets TTL for given RR. + * \param rr RR whose TTL we want to set. + * \param ttl TTL to be set. + */ +void knot_rr_set_ttl(knot_rr_t *rr, uint32_t ttl); + +/*! + * \brief Returns pointer to RR data. + * \param rr RR whose data we want. + * \return RR data pointer. + */ +uint8_t *knot_rr_rdata(const knot_rr_t *rr); + +/* ----------------------------- RR misc ------------------------------------ */ + +/*! + * \brief Returns actual size of RR structure for given RDATA size. + * \param size RDATA size. + * \return Actual structure size. + */ +size_t knot_rr_array_size(uint16_t size); + +/*! + * \brief Canonical comparison of two RRs. Both RRs *must* exist. + * \param rr1 First RR to compare. + * \param rr2 Second RR to compare. + * \retval 0 if rr1 == rr2. + * \retval < 0 if rr1 < rr2. + * \retval > 0 if rr1 > rr2. + */ +int knot_rr_cmp(const knot_rr_t *rr1, const knot_rr_t *rr2); + +/* --------------------------- Multiple RRs ----------------------------------*/ + +/*!< \brief Array of RRs. */ +typedef struct knot_rrs { + uint16_t rr_count; /*!< \brief Count of RRs stored in the structure. */ + knot_rr_t *data; /*!< \brief Actual data, canonically sorted. */ +} knot_rrs_t; + +/* -------------------------- RRs init/clear ---------------------------------*/ + +/*! + * \brief Initializes RRS structure. + * \param rrs Structure to be initialized. + */ +void knot_rrs_init(knot_rrs_t *rrs); + +/*! + * \brief Frees data initialized by RRS structure, but not the structure itself. + * \param rrs Structure to be cleared. + * \param mm Memory context used to create allocations. + */ +void knot_rrs_clear(knot_rrs_t *rrs, mm_ctx_t *mm); + +/*! + * \brief Deep copies RRS structure. All data are duplicated. + * \param dst Copy destination. + * \param src Copy source. + * \param mm Memory context. + * \return KNOT_E* + */ +int knot_rrs_copy(knot_rrs_t *dst, const knot_rrs_t *src, mm_ctx_t *mm); + +/* ----------------------- RRs getters/setters ------------------------------ */ + +/*! + * \brief Gets RR from RRS structure, using given position. + * \param rrs RRS structure to get RR from. + * \param pos Position to use. + * \return Pointer to RR at \a pos position. + */ +knot_rr_t *knot_rrs_rr(const knot_rrs_t *rrs, size_t pos); + +/*! + * \brief Returns size of array with RRs. + * \param rrs RR array. + * \return Array size. + */ +size_t knot_rrs_size(const knot_rrs_t *rrs); + +/* ----------------------- RRs RR manipulation ------------------------------ */ + +/*! + * \brief Adds single RR into RRS structure. All data are copied. + * \param rrs RRS structure to add RR into. + * \param rr RR to add. + * \param mm Memory context. + * \return KNOT_E* + */ +int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm); + +/* ---------------------- RRs set-like operations --------------------------- */ + +/*! + * \brief RRS equality check. + * \param rrs1 First RRS to be compared. + * \param rrs2 Second RRS to be compared. + * \retval true if rrs1 == rrs2. + * \retval false if rrs1 != rrs2. + */ +bool knot_rrs_eq(const knot_rrs_t *rrs1, const knot_rrs_t *rrs2); + +/*! + * \brief Returns true if \a rr is present in \a rrs, false otherwise. + * \param rrs RRS to search in. + * \param rr RR to compare with. + * \param cmp_ttl If set to true, TTLs will be compared as well. + * \retval true if \a rr is present in \a rrs. + * \retval false if \a rr is not present in \a rrs. + */ +bool knot_rrs_member(const knot_rrs_t *rrs, const knot_rr_t *rr, bool cmp_ttl); + +/*! + * \brief Merges two RRS into the first one. Second RRS is left intact. + * Canonical order is preserved. + * \param rrs1 Destination RRS (merge here). + * \param rrs2 RRS to be merged (merge from). + * \param mm Memory context. + * \return KNOT_E* + */ +int knot_rrs_merge(knot_rrs_t *rrs1, const knot_rrs_t *rrs2, mm_ctx_t *mm); + +/*! + * \brief RRS set-like intersection. Full compare is done. + * \param a First RRS to intersect. + * \param b Second RRS to intersect. + * \param out Output RRS with intersection, RDATA are created anew. + * \param mm Memory context. Will be used to create new RDATA. + * \return KNOT_E* + */ +int knot_rrs_intersect(const knot_rrs_t *a, const knot_rrs_t *b, + knot_rrs_t *out, mm_ctx_t *mm); + +/*! + * \brief Does set-like RRS subtraction. \a from RRS is changed. + * \param from RRS to subtract from. + * \param what RRS to subtract. + * \param mm Memory context use to reallocated \a from data. + * \return KNOT_E* + */ +int knot_rrs_subtract(knot_rrs_t *from, const knot_rrs_t *what, + mm_ctx_t *mm); diff --git a/src/libknot/rrset-dump.c b/src/libknot/rrset-dump.c index 64823b0697d9d8e5e8e88dde695f5347721ab4ad..ab98d68f2c4ca0bfd52b3f9fb1e51d73997df1f6 100644 --- a/src/libknot/rrset-dump.c +++ b/src/libknot/rrset-dump.c @@ -316,7 +316,6 @@ static void wire_type_to_str(rrset_dump_params_t *p) p->ret = 0; } - static int hex_encode(const uint8_t *in, const uint32_t in_len, uint8_t *out, @@ -1797,7 +1796,7 @@ int knot_rrset_txt_dump_data(const knot_rrset_t *rrset, int ret = 0; - switch (knot_rrset_type(rrset)) { + switch (rrset->type) { case KNOT_RRTYPE_A: ret = dump_a(data, data_len, dst, maxlen, style); break; @@ -1978,7 +1977,7 @@ int knot_rrset_txt_dump(const knot_rrset_t *rrset, const size_t maxlen, const knot_dump_style_t *style) { - if (rrset == NULL || dst == NULL || style == NULL) { + if (knot_rrset_empty(rrset) || dst == NULL || style == NULL) { return KNOT_EINVAL; } diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c index 729f0828a493da5376103fc66fbab449368ef0a8..5b79af261db38bf67cd35ae63f0545ac3f4a729e 100644 --- a/src/libknot/rrset.c +++ b/src/libknot/rrset.c @@ -34,85 +34,6 @@ #include "libknot/dname.h" #include "libknot/rdata.h" -typedef uint16_t rr_size_t; -#define RR_META_SIZE (sizeof(rr_size_t) + sizeof(uint32_t)) - -typedef uint8_t rr_t; - -static uint16_t rr_size(const rr_t *rr) -{ - return *((rr_size_t *)rr); -} - -static uint32_t rr_ttl(const rr_t *rr) -{ - return *((uint32_t *)(rr + sizeof(rr_size_t))); -} - -static uint8_t *rr_rdata(rr_t *rr) -{ - return rr + RR_META_SIZE; -} - -static void rr_set_size(rr_t *rr, rr_size_t size) -{ - *((rr_size_t *)rr) = size; -} - -static void rr_set_ttl(rr_t *rr, uint32_t ttl) -{ - *((uint32_t *)(rr + sizeof(rr_size_t))) = ttl; -} - -static void *rdata_seek(void *d, size_t pos) -{ - if (d == NULL) { - return NULL; - } - - size_t offset = 0; - for (size_t i = 0; i < pos; i++) { - rr_t *rr = (rr_t *)(d + offset); - offset += rr_size(rr) + RR_META_SIZE; - } - - return d + offset; -} - -static rr_t *get_rr(const knot_rrset_t *rrset, size_t pos) -{ - if (rrset == NULL || pos >= rrset->rr_count) { - return NULL; - } - - return (rr_t *)rdata_seek(rrset->rrs, pos); -} - -static size_t rrset_rdata_size_total(const knot_rrset_t *rrset) -{ - if (rrset == NULL || rrset->rrs == NULL) { - return 0; - } - - size_t total_size = 0; - for (size_t i = 0; i < rrset->rr_count; ++i) { - rr_t *rr = get_rr(rrset, i); - assert(rr); - total_size += rr_size(rr) + RR_META_SIZE; - } - - return total_size; -} - -uint16_t knot_rrset_rr_count(const knot_rrset_t *rrset) -{ - if (rrset == NULL || rrset->rrs == NULL) { - return 0; - } - - return rrset->rr_count; -} - static uint16_t rrset_rdata_naptr_bin_chunk_size(const knot_rrset_t *rrset, size_t pos) { @@ -146,65 +67,6 @@ static size_t rrset_rdata_remainder_size(const knot_rrset_t *rrset, return ret; } -/*! \brief Canonical order RDATA comparison. */ -static int rrset_rdata_compare_one(const knot_rrset_t *rrset1, - const knot_rrset_t *rrset2, - size_t pos1, size_t pos2) -{ - assert(rrset1 != NULL); - assert(rrset2 != NULL); - assert(rrset1->type == rrset2->type); - - uint8_t *r1 = knot_rrset_rr_rdata(rrset1, pos1); - uint8_t *r2 = knot_rrset_rr_rdata(rrset2, pos2); - uint16_t l1 = knot_rrset_rr_size(rrset1, pos1); - uint16_t l2 = knot_rrset_rr_size(rrset2, pos2); - int cmp = memcmp(r1, r2, MIN(l1, l2)); - if (cmp == 0 && l1 != l2) { - cmp = l1 < l2 ? -1 : 1; - } - return cmp; -} - -/*! - * \brief RRSet RDATA equality check. - * - * \param r1 First RRSet. - * \param r2 Second RRSet. - * - * \return True if RRs in r1 are equal to RRs in r2, false otherwise. - */ -static bool knot_rrset_rdata_equal(const knot_rrset_t *r1, const knot_rrset_t *r2) -{ - if (r1 == NULL || r2 == NULL || (r1->type != r2->type) || - r1->rrs == NULL || r2->rrs == NULL) { - return KNOT_EINVAL; - } - - uint16_t r1_rdata_count = knot_rrset_rr_count(r1); - uint16_t r2_rdata_count = knot_rrset_rr_count(r2); - - if (r1_rdata_count != r2_rdata_count) { - return false; - } - - for (uint16_t i = 0; i < r1_rdata_count; i++) { - bool found = false; - for (uint16_t j = 0; j < r2_rdata_count; j++) { - if (rrset_rdata_compare_one(r1, r2, i, j) == 0) { - found = true; - break; - } - } - - if (!found) { - return false; - } - } - - return true; -} - static int knot_rrset_header_to_wire(const knot_rrset_t *rrset, uint32_t ttl, uint8_t **pos, size_t max_size, knot_compr_t *compr, size_t *size) @@ -279,7 +141,7 @@ static int knot_rrset_header_to_wire(const knot_rrset_t *rrset, uint32_t ttl, /* [code-review] Split to more functions, this one's too long. */ static int knot_rrset_rdata_to_wire_one(const knot_rrset_t *rrset, uint16_t rdata_pos, uint8_t **pos, - size_t max_size, size_t *rr_size, + size_t max_size, size_t *knot_rr_size, knot_compr_t *compr) { assert(rrset); @@ -321,7 +183,6 @@ static int knot_rrset_rdata_to_wire_one(const knot_rrset_t *rrset, for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) { int item = desc->block_types[i]; if (compr && descriptor_item_is_compr_dname(item)) { - dbg_packet("%s: putting compressed name\n", __func__); const knot_dname_t *dname = rdata + offset; int ret = knot_compr_put_dname(dname, *pos, max_size - size - rdlength, @@ -333,25 +194,12 @@ static int knot_rrset_rdata_to_wire_one(const knot_rrset_t *rrset, if (!knot_pkt_compr_hint(compr->rrinfo, hint_id)) { knot_pkt_compr_hint_set(compr->rrinfo, hint_id, compr->wire_pos, ret); } - assert(ret + size + rdlength <= max_size); -dbg_response_exec_detail( - char *name = knot_dname_to_str(dname); - dbg_response_detail("Compressed dname=%s size: %d\n", - name, ret); - free(name); -); *pos += ret; rdlength += ret; offset += knot_dname_size(dname); compr->wire_pos += ret; } else if (descriptor_item_is_dname(item)) { - dbg_packet("%s: putting uncompressed name\n", __func__); const knot_dname_t *dname = rdata + offset; -dbg_rrset_exec_detail( - char *name = knot_dname_to_str(dname); - dbg_rrset_detail("Saving this DNAME=%s\n", name); - free(name); -); // save whole domain name size_t maxb = max_size - size - rdlength; int dname_size = knot_dname_to_wire(*pos, dname, maxb); @@ -361,8 +209,6 @@ dbg_rrset_exec_detail( if (compr && !knot_pkt_compr_hint(compr->rrinfo, hint_id)) { knot_pkt_compr_hint_set(compr->rrinfo, hint_id, compr->wire_pos, dname_size); } - dbg_rrset_detail("Uncompressed dname size: %d\n", - dname_size); *pos += dname_size; rdlength += dname_size; offset += dname_size; @@ -370,8 +216,6 @@ dbg_rrset_exec_detail( compr->wire_pos += dname_size; } } else if (descriptor_item_is_fixed(item)) { - dbg_rrset_detail("Saving static chunk, size=%d\n", - item); /* Fixed length chunk. */ if (size + rdlength + item > max_size) { return KNOT_ESPACE; @@ -388,13 +232,7 @@ dbg_rrset_exec_detail( size_t remainder_size = rrset_rdata_remainder_size(rrset, offset, rdata_pos); - dbg_rrset_detail("Saving remaining chunk, size=%zu, " - "size with remainder=%zu\n", - remainder_size, - size + rdlength + remainder_size); if (size + rdlength + remainder_size > max_size) { - dbg_rrset("rr: to_wire: Remainder does not fit " - "to wire.\n"); return KNOT_ESPACE; } memcpy(*pos, rdata + offset, remainder_size); @@ -410,8 +248,6 @@ dbg_rrset_exec_detail( uint16_t chunk_size = rrset_rdata_naptr_bin_chunk_size(rrset, rdata_pos); if (size + rdlength + chunk_size > max_size) { - dbg_rrset("rr: to_wire: NAPTR chunk does not " - "fit to wire.\n"); return KNOT_ESPACE; } memcpy(*pos, rdata + offset, chunk_size); @@ -427,8 +263,7 @@ dbg_rrset_exec_detail( knot_wire_write_u16(rdlength_pos, rdlength); size += rdlength; - *rr_size = size; - dbg_packet("%s: written rrset %zu bytes\n", __func__, *rr_size); + *knot_rr_size = size; assert(size <= max_size); return KNOT_EOK; } @@ -463,19 +298,19 @@ static int knot_rrset_to_wire_aux(const knot_rrset_t *rrset, uint8_t **pos, for (uint16_t i = 0; i < knot_rrset_rr_count(rrset); ++i) { dbg_rrset_detail("rrset: to_wire: Current max_size=%zu\n", max_size); - size_t rr_size = 0; + size_t knot_rr_size = 0; int ret = knot_rrset_rdata_to_wire_one(rrset, i, pos, max_size, - &rr_size, comp); + &knot_rr_size, comp); if (ret != KNOT_EOK) { dbg_rrset("rrset: to_wire: Cannot convert RR. " "Reason: %s.\n", knot_strerror(ret)); return ret; } - dbg_rrset_detail("Converted RR nr=%d, size=%zu\n", i, rr_size); + dbg_rrset_detail("Converted RR nr=%d, size=%zu\n", i, knot_rr_size); /* Change size of whole RRSet. */ - size += rr_size; + size += knot_rr_size; /* Change max size. */ - max_size -= rr_size; + max_size -= knot_rr_size; } dbg_rrset_detail("Max size: %zu, size: %zu\n", max_size, size); @@ -483,12 +318,9 @@ static int knot_rrset_to_wire_aux(const knot_rrset_t *rrset, uint8_t **pos, return size; } -static int knot_rrset_rdata_store_binary(uint8_t *rdata, size_t *offset, - size_t packet_offset, - const uint8_t *wire, - size_t *pos, - size_t rdlength, - size_t size) +static int binary_store(uint8_t *rdata, size_t *offset, size_t packet_offset, + const uint8_t *wire, size_t *pos, size_t rdlength, + size_t size) { assert(rdata); assert(wire); @@ -509,230 +341,97 @@ static int knot_rrset_rdata_store_binary(uint8_t *rdata, size_t *offset, return KNOT_EOK; } -static size_t rrset_binary_size_one(const knot_rrset_t *rrset, - size_t rdata_pos) -{ - rr_t *rr = get_rr(rrset, rdata_pos); - if (rr) { - // RR size + TTL - return rr_size(rr) + sizeof(uint32_t); - } else { - return 0; - } -} - -static void rrset_serialize_rr(const knot_rrset_t *rrset, size_t rdata_pos, - uint8_t *stream) -{ - rr_t *rr = get_rr(rrset, rdata_pos); - assert(rr); - uint32_t ttl = rr_ttl(rr); - memcpy(stream, &ttl, sizeof(uint32_t)); - memcpy(stream + sizeof(uint32_t), rr_rdata(rr), rr_size(rr)); -} - -static int rrset_deserialize_rr(knot_rrset_t *rrset, - const uint8_t *stream, uint32_t rdata_size) -{ - uint32_t ttl; - memcpy(&ttl, stream, sizeof(uint32_t)); - uint8_t *rdata = knot_rrset_create_rr(rrset, - rdata_size - sizeof(uint32_t), - ttl, NULL); - if (rdata == NULL) { - return KNOT_ENOMEM; - } - - memcpy(rdata, stream + sizeof(uint32_t), rdata_size - sizeof(uint32_t)); - return KNOT_EOK; -} - -int knot_rrset_remove_rdata_pos(knot_rrset_t *rrset, size_t pos, mm_ctx_t *mm) +knot_rrset_t *knot_rrset_new(const knot_dname_t *owner, uint16_t type, + uint16_t rclass, mm_ctx_t *mm) { - if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) { - return KNOT_EINVAL; - } - - rr_t *old_rr = get_rr(rrset, pos); - rr_t *last_rr = get_rr(rrset, rrset->rr_count - 1); - assert(old_rr); - assert(last_rr); - - size_t total_size = rrset_rdata_size_total(rrset); - uint16_t old_size = rr_size(old_rr); - - void *old_threshold = old_rr + rr_size(old_rr) + RR_META_SIZE; - void *last_threshold = last_rr + rr_size(last_rr) + RR_META_SIZE; - // Move RDATA - memmove(old_rr, old_threshold, - last_threshold - old_threshold); - - if (rrset->rr_count > 1) { - // Realloc RDATA - void *tmp = mm_realloc(mm, rrset->rrs, - total_size - (old_size + RR_META_SIZE), - total_size); - if (tmp == NULL) { - ERR_ALLOC_FAILED; - } else { - rrset->rrs = tmp; - } - } else { - // Free RDATA - mm_free(mm, rrset->rrs); - rrset->rrs = NULL; + knot_dname_t *owner_cpy = knot_dname_copy(owner, mm); + if (owner_cpy == NULL) { + return NULL; } - rrset->rr_count--; - - return KNOT_EOK; -} -knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type, - uint16_t rclass, mm_ctx_t *mm) -{ knot_rrset_t *ret = mm_alloc(mm, sizeof(knot_rrset_t)); if (ret == NULL) { ERR_ALLOC_FAILED; + knot_dname_free(&owner_cpy, mm); return NULL; } - ret->rrs = NULL; - - ret->owner = owner; - ret->type = type; - ret->rclass = rclass; - ret->rr_count = 0; - - ret->additional = NULL; + knot_rrset_init(ret, owner_cpy, type, rclass); return ret; } -knot_rrset_t *knot_rrset_new_from(const knot_rrset_t *tpl, mm_ctx_t *mm) +void knot_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner, uint16_t type, + uint16_t rclass) { - if (!tpl) { - return NULL; - } - - knot_dname_t *owner = knot_dname_copy(tpl->owner); - if (!owner) { - return NULL; - } - - return knot_rrset_new(owner, tpl->type, tpl->rclass, mm); + rrset->owner = owner; + rrset->type = type; + rrset->rclass = rclass; + knot_rrs_init(&rrset->rrs); + rrset->additional = NULL; } -int knot_rrset_add_rr(knot_rrset_t *rrset, - const uint8_t *rdata, const uint16_t size, - const uint32_t ttl, mm_ctx_t *mm) +void knot_rrset_init_empty(knot_rrset_t *rrset) { - if (rrset == NULL || rdata == NULL) { - return KNOT_EINVAL; - } - - uint8_t *p = knot_rrset_create_rr(rrset, size, ttl, mm); - memcpy(p, rdata, size); - - return KNOT_EOK; + knot_rrset_init(rrset, NULL, 0, KNOT_CLASS_IN); } -static uint8_t* knot_rrset_create_rr_at_pos(knot_rrset_t *rrset, - size_t pos, uint16_t size, - uint32_t ttl, mm_ctx_t *mm) +knot_rrset_t *knot_rrset_copy(const knot_rrset_t *src, mm_ctx_t *mm) { - if (rrset == NULL || pos > knot_rrset_rr_count(rrset)) { + if (src == NULL) { return NULL; } - if (pos == knot_rrset_rr_count(rrset)) { - // Normal RDATA addition - return knot_rrset_create_rr(rrset, size, ttl, mm); - } - - size_t total_size = rrset_rdata_size_total(rrset); - // Realloc data. - void *tmp = mm_realloc(mm, rrset->rrs, - total_size + size + RR_META_SIZE, - total_size); - if (tmp) { - rrset->rrs = tmp; - } else { - ERR_ALLOC_FAILED; + knot_rrset_t *rrset = knot_rrset_new(src->owner, src->type, + src->rclass, mm); + if (rrset == NULL) { return NULL; } - rr_t *old_rr = get_rr(rrset, pos); - rr_t *last_rr = get_rr(rrset, rrset->rr_count - 1); - assert(old_rr); - assert(last_rr); - - // Make space for new data by moving the array - memmove(old_rr + size + RR_META_SIZE, old_rr, - (last_rr + RR_META_SIZE + rr_size(last_rr)) - old_rr); - - // Set size for new RR - rr_set_size(old_rr, size); - rr_set_ttl(old_rr, ttl); + int ret = knot_rrs_copy(&rrset->rrs, &src->rrs, mm); + if (ret != KNOT_EOK) { + knot_rrset_free(&rrset, mm); + return NULL; + } - rrset->rr_count++; - assert(rr_size(old_rr) > 0); - return rr_rdata(old_rr); + return rrset; } -static int knot_rrset_add_rr_at_pos(knot_rrset_t *rrset, size_t pos, - const uint8_t *rdata, uint16_t size, - uint32_t ttl, mm_ctx_t *mm) +void knot_rrset_free(knot_rrset_t **rrset, mm_ctx_t *mm) { - if (rrset == NULL || rdata == NULL) { - return KNOT_EINVAL; + if (rrset == NULL || *rrset == NULL) { + return; } - uint8_t *p = knot_rrset_create_rr_at_pos(rrset, pos, size, ttl, mm); - if (p == NULL) { - return KNOT_ERROR; - } - memcpy(p, rdata, size); + knot_rrset_clear(*rrset, mm); - return KNOT_EOK; + mm_free(mm, *rrset); + *rrset = NULL; } -/*----------------------------------------------------------------------------*/ - -uint8_t* knot_rrset_create_rr(knot_rrset_t *rrset, const uint16_t size, - const uint32_t ttl, mm_ctx_t *mm) +void knot_rrset_clear(knot_rrset_t *rrset, mm_ctx_t *mm) { - if (rrset == NULL) { - return NULL; + if (rrset) { + knot_rrs_clear(&rrset->rrs, mm); + knot_dname_free(&rrset->owner, mm); } +} - size_t total_size = rrset_rdata_size_total(rrset); - /* Realloc RRs. */ - void *tmp = mm_realloc(mm, rrset->rrs, total_size + size + RR_META_SIZE, - total_size); - if (tmp) { - rrset->rrs = tmp; +uint8_t *knot_rrset_rr_rdata(const knot_rrset_t *rrset, size_t pos) +{ + knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, pos); + if (rr) { + return knot_rr_rdata(rr); } else { - ERR_ALLOC_FAILED; return NULL; } - - rrset->rr_count++; - rr_t *rr = get_rr(rrset, rrset->rr_count - 1); - assert(rr); - - rr_set_size(rr, size); - rr_set_ttl(rr, ttl); - - return rr_rdata(rr); } -/*----------------------------------------------------------------------------*/ - uint16_t knot_rrset_rr_size(const knot_rrset_t *rrset, size_t pos) { - rr_t *rr = get_rr(rrset, pos); + const knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, pos); if (rr) { - return rr_size(rr); + return knot_rr_rdata_size(rr); } else { return 0; } @@ -740,9 +439,9 @@ uint16_t knot_rrset_rr_size(const knot_rrset_t *rrset, size_t pos) uint32_t knot_rrset_rr_ttl(const knot_rrset_t *rrset, size_t pos) { - rr_t *rr = get_rr(rrset, pos); + const knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, pos); if (rr) { - return rr_ttl(rr); + return knot_rr_ttl(rr); } else { return 0; } @@ -750,71 +449,19 @@ uint32_t knot_rrset_rr_ttl(const knot_rrset_t *rrset, size_t pos) void knot_rrset_rr_set_ttl(const knot_rrset_t *rrset, size_t pos, uint32_t ttl) { - rr_t *rr = get_rr(rrset, pos); + knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, pos); if (rr) { - rr_set_ttl(rr, ttl); - } -} - -bool knot_rrset_ttl_equal(const knot_rrset_t *r1, const knot_rrset_t *r2) -{ - if (r1 == NULL || r2 == NULL - || r1->rr_count == 0 || r2->rr_count == 0) { - return false; + knot_rr_set_ttl(rr, ttl); } - - return (knot_rrset_rr_ttl(r1, 0) == knot_rrset_rr_ttl(r2, 0)); -} - -const knot_dname_t *knot_rrset_owner(const knot_rrset_t *rrset) -{ - return rrset->owner; } -knot_dname_t *knot_rrset_get_owner(const knot_rrset_t *rrset) -{ - return rrset->owner; -} - -int knot_rrset_set_owner(knot_rrset_t *rrset, const knot_dname_t *owner) +uint16_t knot_rrset_rr_count(const knot_rrset_t *rrset) { if (rrset == NULL) { - return KNOT_EINVAL; - } - - /* Copy the new owner. */ - knot_dname_t *owner_copy = NULL; - if (owner) { - owner_copy = knot_dname_copy(owner); - if (owner_copy == NULL) { - return KNOT_ENOMEM; - } + return 0; } - /* Free old owner and assign. */ - knot_dname_free(&rrset->owner); - rrset->owner = owner_copy; - return KNOT_EOK; -} - -uint16_t knot_rrset_type(const knot_rrset_t *rrset) -{ - return rrset->type; -} - -uint16_t knot_rrset_class(const knot_rrset_t *rrset) -{ - return rrset->rclass; -} - -uint8_t *knot_rrset_rr_rdata(const knot_rrset_t *rrset, size_t pos) -{ - rr_t *rr = get_rr(rrset, pos); - if (rr) { - return rr_rdata(rr); - } else { - return NULL; - } + return rrset->rrs.rr_count; } int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size, @@ -858,14 +505,16 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset, } if (rdlength == 0) { - return knot_rrset_create_rr(rrset, 0, ttl, mm) == NULL ? - KNOT_ENOMEM : KNOT_EOK; + // Alloc data for empty RR. + uint8_t *empty_rdata = malloc(1); + if (empty_rdata == NULL) { + return KNOT_ENOMEM; + } + int ret = knot_rrset_add_rr(rrset, empty_rdata, 0, ttl, mm); + free(empty_rdata); + return ret; } - dbg_rrset_detail("rr: parse_rdata_wire: Parsing RDATA of size=%zu," - " wire_size=%zu, type=%d.\n", rdlength, total_size, - rrset->type); - const rdata_descriptor_t *desc = get_rdata_descriptor(rrset->type); /* Check for obsolete record. */ @@ -873,10 +522,6 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset, desc = get_obsolete_rdata_descriptor(rrset->type); } - /*! \todo This estimate is very rough - just to have enough space for - * possible unpacked dname. Should be later replaced by exact - * size counting. - */ uint8_t rdata_buffer[rdlength + KNOT_DNAME_MAXLEN]; memset(rdata_buffer, 0, rdlength + KNOT_DNAME_MAXLEN); @@ -884,13 +529,6 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset, size_t parsed = 0; // actual count of parsed octets const size_t packet_offset = *pos; - /*! \todo [RRSet refactor] - * This could be A LOT simpler - copy it as a whole, - * unpack dnames and just do some format checks if necessary. - * But it's questionable, if copying the memory when unpacking - * dnames, wouldn't be too expensive. - */ - for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END && parsed < rdlength; ++i) { const int item = desc->block_types[i]; @@ -910,51 +548,21 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset, parsed += wire_size; -dbg_rrset_exec_detail( - dbg_rrset_detail("rr: parse_rdata_wire: Parsed DNAME, " - "length=%d.\n", wire_size); - char *name = knot_dname_to_str(rdata_buffer + offset); - dbg_rrset_detail("rr: parse_rdata_wire: Parsed " - "DNAME=%s\n", name); - free(name); -); *pos += wire_size; offset += unpacked_size; } else if (descriptor_item_is_fixed(item)) { - dbg_rrset_detail("rr: parse_rdata_wire: Saving static " - "chunk of size=%u\n", item); - int ret = knot_rrset_rdata_store_binary(rdata_buffer, - &offset, - packet_offset, - wire, - pos, - rdlength, - item); + int ret = binary_store(rdata_buffer, &offset, packet_offset, + wire, pos, rdlength, item); if (ret != KNOT_EOK) { - dbg_rrset("rrset: rdata_from_wire: " - "Cannot store fixed RDATA chunk. " - "Reason: %s.\n", knot_strerror(ret)); return ret; } parsed += item; } else if (descriptor_item_is_remainder(item)) { /* Item size has to be calculated. */ size_t remainder_size = rdlength - parsed; - dbg_rrset_detail("rr: parse_rdata_wire: Saving remaining " - "chunk of size=%zu\n", remainder_size); - int ret = knot_rrset_rdata_store_binary(rdata_buffer, - &offset, - packet_offset, - wire, - pos, - rdlength, - remainder_size); + int ret = binary_store(rdata_buffer, &offset, packet_offset, + wire, pos, rdlength, remainder_size); if (ret != KNOT_EOK) { - dbg_rrset("rrset: rdata_from_wire: " - "Cannot store RDATA remainder of " - "size=%zu, RDLENGTH=%zu. " - "Reason: %s.\n", remainder_size, - rdlength, knot_strerror(ret)); return ret; } parsed += remainder_size; @@ -962,52 +570,43 @@ dbg_rrset_exec_detail( assert(rrset->type == KNOT_RRTYPE_NAPTR); /* Read fixed part - 2 shorts. */ const size_t naptr_fixed_part_size = 4; - int ret = knot_rrset_rdata_store_binary(rdata_buffer, - &offset, - packet_offset, - wire, - pos, - rdlength, - naptr_fixed_part_size); + int ret = binary_store(rdata_buffer, &offset, packet_offset, + wire, pos, rdlength, naptr_fixed_part_size); if (ret != KNOT_EOK) { - dbg_rrset("rrset: rdata_from_wire: " - "Cannot store NAPTR fixed part. " - "Reason: %s.\n", knot_strerror(ret)); return ret; } parsed += naptr_fixed_part_size; for (int j = 0; j < 3; ++j) { /* Read sizes of TXT's - one byte. */ uint8_t txt_size = *(wire + (*pos)) + 1; - dbg_rrset_detail("rrset: rdata_from_wire: " - "Read TXT nr=%d size=%d\n", j, - txt_size); - int ret = knot_rrset_rdata_store_binary(rdata_buffer, - &offset, - packet_offset, - wire, - pos, - rdlength, - txt_size); + int ret = binary_store(rdata_buffer, &offset, + packet_offset, wire, pos, + rdlength, txt_size); if (ret != KNOT_EOK) { - dbg_rrset("rrset: rdata_from_wire: " - "Cannot store NAPTR TXTs. " - "Reason: %s.\n", knot_strerror(ret)); - return ret; } parsed += txt_size; } } } - uint8_t *rdata = knot_rrset_create_rr(rrset, offset, ttl, mm); - if (rdata == NULL) { - return KNOT_ENOMEM; + return knot_rrset_add_rr(rrset, rdata_buffer, offset, ttl, mm); +} + +int knot_rrset_add_rr(knot_rrset_t *rrset, + const uint8_t *rdata, const uint16_t size, + const uint32_t ttl, mm_ctx_t *mm) +{ + if (rrset == NULL || rdata == NULL) { + return KNOT_EINVAL; } - memcpy(rdata, rdata_buffer, offset); + // Create knot_rr_t from given data + knot_rr_t rr[knot_rr_array_size(size)]; + knot_rr_set_size(rr, size); + knot_rr_set_ttl(rr, ttl); + memcpy(knot_rr_rdata(rr), rdata, size); - return KNOT_EOK; + return knot_rrs_add_rr(&rrset->rrs, rr, mm); } bool knot_rrset_equal(const knot_rrset_t *r1, @@ -1018,544 +617,24 @@ bool knot_rrset_equal(const knot_rrset_t *r1, return r1 == r2; } - - if (!knot_dname_is_equal(r1->owner, r2->owner)) - return false; - - if (r1->rclass != r2->rclass || r1->type != r2->type) + if (r1->type != r2->type) { return false; - - if (cmp == KNOT_RRSET_COMPARE_WHOLE) - return knot_rrset_rdata_equal(r1, r2); - - return true; -} - -int knot_rrset_copy(const knot_rrset_t *from, knot_rrset_t **to, mm_ctx_t *mm) -{ - if (from == NULL || to == NULL) { - return KNOT_EINVAL; - } - - dbg_rrset_detail("rr: deep_copy: Copying RRs of type %d\n", - from->type); - *to = knot_rrset_new_from(from, mm); - if (*to == NULL) { - *to = NULL; - return KNOT_ENOMEM; - } - - (*to)->additional = NULL; /* Never copy. */ - (*to)->rr_count = from->rr_count; - - (*to)->rrs = mm_alloc(mm, rrset_rdata_size_total(from)); - if ((*to)->rrs == NULL) { - ERR_ALLOC_FAILED; - knot_rrset_free(to, mm); - return KNOT_ENOMEM; - } - memcpy((*to)->rrs, from->rrs, rrset_rdata_size_total(from)); - - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - -static void rrset_deep_free_content(knot_rrset_t *rrset, - mm_ctx_t *mm) -{ - assert(rrset); - - mm_free(mm, rrset->rrs); - knot_dname_free(&rrset->owner); -} - -void knot_rrset_free(knot_rrset_t **rrset, mm_ctx_t *mm) -{ - if (rrset == NULL || *rrset == NULL) { - return; - } - - rrset_deep_free_content(*rrset, mm); - - if (rrset_additional_needed((*rrset)->type)) { - mm_free(mm, (*rrset)->additional); - } - - mm_free(mm, *rrset); - *rrset = NULL; -} - -static int knot_rrset_add_rr_n(knot_rrset_t *rrset, const knot_rrset_t *rr, - size_t pos, mm_ctx_t *mm) -{ - if (rrset == NULL || rr == NULL) { - return KNOT_EINVAL; - } - if (!knot_rrset_equal(rrset, rr, KNOT_RRSET_COMPARE_HEADER)) { - // Adding to a different header - return KNOT_EINVAL; - } - - uint32_t ttl = knot_rrset_rr_ttl(rr, pos); - uint16_t size = knot_rrset_rr_size(rr, pos); - uint8_t *new_rdata = knot_rrset_create_rr(rrset, size, ttl, mm); - if (new_rdata == NULL) { - return KNOT_ERROR; - } - - memcpy(new_rdata, knot_rrset_rr_rdata(rr, pos), - knot_rrset_rr_size(rr, pos)); - - return KNOT_EOK; -} - -int knot_rrset_merge(knot_rrset_t *rrset1, const knot_rrset_t *rrset2, - mm_ctx_t *mm) -{ - if (rrset2 == NULL) { - return KNOT_EINVAL; - } - - uint16_t r2_rdata_count = knot_rrset_rr_count(rrset2); - for (uint16_t i = 0; i < r2_rdata_count; ++i) { - int ret = knot_rrset_add_rr_n(rrset1, rrset2, i, mm); - if (ret != KNOT_EOK) { - return ret; - } - } - - return KNOT_EOK; -} - -static int knot_rrset_add_rr_sort_n(knot_rrset_t *rrset, const knot_rrset_t *rr, - int *merged, int *deleted, size_t pos, - mm_ctx_t *mm) -{ - if (rrset == NULL || rr == NULL) { - dbg_rrset("rrset: add_rr_sort: NULL arguments."); - return KNOT_EINVAL; - } - -dbg_rrset_exec_detail( - char *name = knot_dname_to_str(rrset->owner); - dbg_rrset_detail("rrset: add_rr_sort: Merging %s.\n", name); - free(name); -); - - if ((!knot_dname_is_equal(rrset->owner, rr->owner)) - || rrset->rclass != rr->rclass - || rrset->type != rr->type) { - dbg_rrset("rrset: add_rr_sort: Trying to merge " - "different RRs.\n"); - return KNOT_EINVAL; - } - - int found = 0; - int duplicated = 0; - // Compare RR with all RRs in the first RRSet. - size_t insert_to = 0; - uint16_t rdata_count = knot_rrset_rr_count(rrset); - for (uint16_t j = 0; j < rdata_count && (!duplicated && !found); ++j) { - int cmp = rrset_rdata_compare_one(rrset, rr, j, pos); - if (cmp == 0) { - // Duplication - no need to merge this RR - duplicated = 1; - } else if (cmp > 0) { - // Found position to insert - found = 1; - } else { - // Not yet - it might be next position - insert_to = j + 1; - } - } - - if (!duplicated) { - *merged += 1; // = need to shallow free rrset2 - // Insert RR to RRSet - int ret = knot_rrset_add_rr_at_pos(rrset, insert_to, - knot_rrset_rr_rdata(rr, pos), - knot_rrset_rr_size(rr, pos), - knot_rrset_rr_ttl(rr, pos), - mm); - if (ret != KNOT_EOK) { - dbg_rrset("rrset: add_rr: Could not " - "add RDATA to RRSet. (%s)\n", - knot_strerror(ret)); - return ret; - } - } else { - assert(!found); - *deleted += 1; // = need to shallow free rr - } - - return KNOT_EOK; -} - -int knot_rrset_merge_sort(knot_rrset_t *rrset1, const knot_rrset_t *rrset2, - int *merged_rrs, int *deleted_rrs, mm_ctx_t *mm) -{ - if (rrset2 == NULL) { - return KNOT_EINVAL; - } - int result = KNOT_EOK; - int merged = 0; - int deleted = 0; - - uint16_t r2_rdata_count = knot_rrset_rr_count(rrset2); - for (uint16_t i = 0; i < r2_rdata_count; i++) { - result = knot_rrset_add_rr_sort_n(rrset1, rrset2, &merged, - &deleted, i, mm); - if (result != KNOT_EOK) { - break; - } - } - - if (merged_rrs) { - *merged_rrs = merged; - } - - if (deleted_rrs) { - *deleted_rrs = deleted; - } - - return result; -} - -/*! - * \todo Not optimal, rewrite! - */ -int knot_rrset_sort_rdata(knot_rrset_t *rrset) -{ - if (!rrset) { - return KNOT_EINVAL; - } - - // 1. create temporary rrset - // 2. sort-merge given rrset into temporary rrset - // 3. swap the contents, free the temporary - - knot_rrset_t *sorted = knot_rrset_new_from(rrset, NULL); - if (!sorted) { - return KNOT_ENOMEM; - } - - int result = knot_rrset_merge_sort(sorted, rrset, NULL, NULL, NULL); - if (result != KNOT_EOK) { - knot_rrset_free(&sorted, NULL); - return result; - } - - rrset_deep_free_content(rrset, NULL); - *rrset = *sorted; - free(sorted); - - return KNOT_EOK; -} - -bool knot_rrset_is_nsec3rel(const knot_rrset_t *rr) -{ - assert(rr != NULL); - - /* Is NSEC3 or non-empty RRSIG covering NSEC3. */ - return ((knot_rrset_type(rr) == KNOT_RRTYPE_NSEC3) - || (knot_rrset_type(rr) == KNOT_RRTYPE_RRSIG - && knot_rdata_rrsig_type_covered(rr, 0) - == KNOT_RRTYPE_NSEC3)); -} - -uint64_t rrset_binary_size(const knot_rrset_t *rrset) -{ - if (rrset == NULL || knot_rrset_rr_count(rrset) == 0) { - return 0; - } - uint64_t size = sizeof(uint64_t) + // size at the beginning - knot_dname_size(knot_rrset_owner(rrset)) + // owner data - sizeof(uint16_t) + // type - sizeof(uint16_t) + // class - sizeof(uint16_t); //RR count - uint16_t rdata_count = knot_rrset_rr_count(rrset); - for (uint16_t i = 0; i < rdata_count; i++) { - /* Space to store length of one RR. */ - size += sizeof(uint32_t); - /* Actual data. */ - size += rrset_binary_size_one(rrset, i); - } - - return size; -} - -int rrset_serialize(const knot_rrset_t *rrset, uint8_t *stream, size_t *size) -{ - if (rrset == NULL || rrset->rr_count == 0) { - return KNOT_EINVAL; - } - - uint64_t rrset_length = rrset_binary_size(rrset); - dbg_rrset_detail("rr: serialize: Binary size=%"PRIu64"\n", rrset_length); - memcpy(stream, &rrset_length, sizeof(uint64_t)); - - size_t offset = sizeof(uint64_t); - /* Save RR count. */ - memcpy(stream + offset, &rrset->rr_count, sizeof(uint16_t)); - offset += sizeof(uint16_t); - /* Save owner. */ - offset += knot_dname_to_wire(stream + offset, rrset->owner, rrset_length - offset); - - /* Save static data. */ - memcpy(stream + offset, &rrset->type, sizeof(uint16_t)); - offset += sizeof(uint16_t); - memcpy(stream + offset, &rrset->rclass, sizeof(uint16_t)); - offset += sizeof(uint16_t); - - /* Copy RDATA. */ - for (uint16_t i = 0; i < rrset->rr_count; i++) { - uint32_t rr_size = rrset_binary_size_one(rrset, i); - dbg_rrset_detail("rr: serialize: RR index=%d size=%d\n", - i, rr_size); - memcpy(stream + offset, &rr_size, sizeof(uint32_t)); - offset += sizeof(uint32_t); - rrset_serialize_rr(rrset, i, stream + offset); - offset += rr_size; - } - - *size = offset; - assert(*size == rrset_length); - dbg_rrset_detail("rr: serialize: RRSet serialized, size=%zu\n", *size); - return KNOT_EOK; -} - -int rrset_deserialize(const uint8_t *stream, size_t *stream_size, - knot_rrset_t **rrset) -{ - if (sizeof(uint64_t) > *stream_size) { - dbg_rrset("rr: deserialize: No space for length.\n"); - return KNOT_ESPACE; - } - uint64_t rrset_length = 0; - memcpy(&rrset_length, stream, sizeof(uint64_t)); - if (rrset_length > *stream_size) { - dbg_rrset("rr: deserialize: No space for whole RRSet. " - "(given=%zu needed=%"PRIu64")\n", *stream_size, - rrset_length); - return KNOT_ESPACE; - } - - size_t offset = sizeof(uint64_t); - uint16_t rdata_count = 0; - memcpy(&rdata_count, stream + offset, sizeof(uint16_t)); - offset += sizeof(uint16_t); - /* Read owner from the stream. */ - unsigned owner_size = knot_dname_size(stream + offset); - knot_dname_t *owner = knot_dname_copy_part(stream + offset, owner_size); - assert(owner); - offset += owner_size; - /* Read type. */ - uint16_t type = 0; - memcpy(&type, stream + offset, sizeof(uint16_t)); - offset += sizeof(uint16_t); - /* Read class. */ - uint16_t rclass = 0; - memcpy(&rclass, stream + offset, sizeof(uint16_t)); - offset += sizeof(uint16_t); - - /* Create new RRSet. */ - *rrset = knot_rrset_new(owner, type, rclass, NULL); - if (*rrset == NULL) { - knot_dname_free(&owner); - return KNOT_ENOMEM; - } - - /* Read RRs. */ - for (uint16_t i = 0; i < rdata_count; i++) { - /* - * There's always size of rdata in the beginning. - * Needed because of remainders. - */ - uint32_t rdata_size = 0; - memcpy(&rdata_size, stream + offset, sizeof(uint32_t)); - offset += sizeof(uint32_t); - int ret = rrset_deserialize_rr((*rrset), stream + offset, - rdata_size); - if (ret != KNOT_EOK) { - knot_rrset_free(rrset, NULL); - return ret; - } - offset += rdata_size; - } - - *stream_size = *stream_size - offset; - - return KNOT_EOK; -} - -int knot_rrset_find_rr_pos(const knot_rrset_t *rr_search_in, - const knot_rrset_t *rr_reference, size_t pos, - size_t *pos_out) -{ - bool found = false; - uint16_t rr_count = knot_rrset_rr_count(rr_search_in); - for (uint16_t i = 0; i < rr_count && !found; ++i) { - if (rrset_rdata_compare_one(rr_search_in, - rr_reference, i, pos) == 0) { - *pos_out = i; - found = true; - } - } - - return found ? KNOT_EOK : KNOT_ENOENT; -} - -static int knot_rrset_remove_rr(knot_rrset_t *rrset, - const knot_rrset_t *rr_from, size_t rdata_pos, - mm_ctx_t *mm) -{ - /* - * Position in first and second rrset can differ, we have - * to search for position first. - */ - size_t pos_to_remove = 0; - int ret = knot_rrset_find_rr_pos(rrset, rr_from, rdata_pos, - &pos_to_remove); - if (ret == KNOT_EOK) { - /* Position found, can be removed. */ - dbg_rrset_detail("rr: remove_rr: Counter position found=%zu\n", - pos_to_remove); - assert(pos_to_remove < knot_rrset_rr_count(rrset)); - ret = knot_rrset_remove_rdata_pos(rrset, pos_to_remove, mm); - if (ret != KNOT_EOK) { - dbg_rrset("Cannot remove RDATA from RRSet (%s).\n", - knot_strerror(ret)); - return ret; - } - } else { - dbg_rrset_verb("rr: remove_rr: RDATA not found (%s).\n", - knot_strerror(ret)); - return ret; - } - - return KNOT_EOK; -} - -int knot_rrset_add_rr_from_rrset(knot_rrset_t *dest, const knot_rrset_t *source, - size_t rdata_pos, mm_ctx_t *mm) -{ - if (dest == NULL || source == NULL || - rdata_pos >= knot_rrset_rr_count(source)) { - return KNOT_EINVAL; - } - - /* Get size and TTL of RR to be copied. */ - uint16_t size = knot_rrset_rr_size(source, rdata_pos); - uint32_t ttl = knot_rrset_rr_ttl(source, rdata_pos); - /* Reserve space in dest RRSet. */ - uint8_t *rdata = knot_rrset_create_rr(dest, size, ttl, mm); - if (rdata == NULL) { - dbg_rrset("rr: add_rr_from_rrset: Could not create RDATA.\n"); - return KNOT_ERROR; - } - - /* Copy actual data. */ - memcpy(rdata, knot_rrset_rr_rdata(source, rdata_pos), size); - - return KNOT_EOK; -} - -int knot_rrset_remove_rr_using_rrset(knot_rrset_t *from, - const knot_rrset_t *what, - knot_rrset_t **rr_deleted, - mm_ctx_t *mm) -{ - if (from == NULL || what == NULL || rr_deleted == NULL) { - return KNOT_EINVAL; } - knot_rrset_t *return_rr = knot_rrset_new_from(what, NULL); - if (return_rr == NULL) { - return KNOT_ENOMEM; + if (!knot_dname_is_equal(r1->owner, r2->owner)) { + return false; } - uint16_t what_rdata_count = knot_rrset_rr_count(what); - for (uint16_t i = 0; i < what_rdata_count; ++i) { - int ret = knot_rrset_remove_rr(from, what, i, mm); - if (ret == KNOT_EOK) { - /* RR was removed, can be added to 'return' RRSet. */ - ret = knot_rrset_add_rr_from_rrset(return_rr, what, i, NULL); - if (ret != KNOT_EOK) { - knot_rrset_free(&return_rr, NULL); - dbg_xfrin("xfr: Could not add RR (%s).\n", - knot_strerror(ret)); - return ret; - } - } else if (ret != KNOT_ENOENT) { - /* NOENT is OK, but other errors are not. */ - dbg_rrset("rrset: remove_using_rrset: " - "RRSet removal failed (%s).\n", - knot_strerror(ret)); - knot_rrset_free(&return_rr, NULL); - return ret; - } + if (cmp == KNOT_RRSET_COMPARE_WHOLE) { + return knot_rrs_eq(&r1->rrs, &r2->rrs); } - *rr_deleted = return_rr; - return KNOT_EOK; -} - -int rrset_additional_needed(uint16_t rrtype) -{ - return (rrtype == KNOT_RRTYPE_NS || - rrtype == KNOT_RRTYPE_MX || - rrtype == KNOT_RRTYPE_SRV); -} - -static int add_rdata_to_rrsig(knot_rrset_t *new_sig, uint16_t type, - const knot_rrset_t *rrsigs, mm_ctx_t *mm) -{ - uint16_t rrsigs_rdata_count = knot_rrset_rr_count(rrsigs); - for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) { - const uint16_t type_covered = - knot_rdata_rrsig_type_covered(rrsigs, i); - if (type_covered == type) { - int ret = knot_rrset_add_rr_from_rrset(new_sig, rrsigs, - i, mm); - if (ret != KNOT_EOK) { - return ret; - } - } - } - - return knot_rrset_rr_count(new_sig) > 0 ? KNOT_EOK : KNOT_ENOENT; + return true; } -int knot_rrset_synth_rrsig(const knot_dname_t *owner, uint16_t type, - const knot_rrset_t *rrsigs, - knot_rrset_t **out_sig, mm_ctx_t *mm) +bool knot_rrset_empty(const knot_rrset_t *rrset) { - if (rrsigs == NULL) { - return KNOT_ENOENT; - } - - if (out_sig == NULL || owner == NULL) { - return KNOT_EINVAL; - } - - knot_dname_t *owner_copy = knot_dname_copy(owner); - if (owner_copy == NULL) { - return KNOT_ENOMEM; - } - *out_sig = knot_rrset_new(owner_copy, - KNOT_RRTYPE_RRSIG, rrsigs->rclass, mm); - if (*out_sig == NULL) { - knot_dname_free(&owner_copy); - return KNOT_ENOMEM; - } - - int ret = add_rdata_to_rrsig(*out_sig, type, rrsigs, mm); - if (ret != KNOT_EOK) { - knot_rrset_free(out_sig, mm); - return ret; - } - - return KNOT_EOK; + uint16_t rr_count = knot_rrset_rr_count(rrset); + return rr_count == 0; } diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h index f9fd04d426a6a7d63177c9e182b7dcc875879c10..706bc298819e9c7e3eb6a5f9ef3ee324d73129fe 100644 --- a/src/libknot/rrset.h +++ b/src/libknot/rrset.h @@ -25,8 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _KNOT_RRSET_H_ -#define _KNOT_RRSET_H_ +#pragma once #include <stdint.h> #include <stdbool.h> @@ -34,48 +33,34 @@ #include "common/mempattern.h" #include "libknot/dname.h" +#include "libknot/rr.h" struct knot_compr; struct knot_node; -/*----------------------------------------------------------------------------*/ /*! - * \brief Structure for representing an RRSet. + * \brief Structure for representing RRSet. * - * For definition of a RRSet see RFC2181, Section 5. + * For RRSet definition see RFC2181, Section 5. */ struct knot_rrset { knot_dname_t *owner; /*!< Domain name being the owner of the RRSet. */ uint16_t type; /*!< TYPE of the RRset. */ uint16_t rclass; /*!< CLASS of the RRSet. */ - uint16_t rr_count; /*!< Count of RRs in RRSet */ - /*! \brief RDATA array (for all RRs). DNAMEs stored as full, - * uncompressed wire. Binary data stored in wireformat order. - * Each RR is prepended with RDATA length and TTL, respectively. - * Do not work directly with this value. - */ - uint8_t *rrs; + knot_rrs_t rrs; /*!< RRSet's RRs */ /* Optional fields. */ struct knot_node **additional; /*!< Additional records. */ }; typedef struct knot_rrset knot_rrset_t; -/*----------------------------------------------------------------------------*/ - typedef enum { KNOT_RRSET_COMPARE_PTR, KNOT_RRSET_COMPARE_HEADER, KNOT_RRSET_COMPARE_WHOLE } knot_rrset_compare_type_t; -typedef enum { - KNOT_RRSET_DUPL_MERGE, - KNOT_RRSET_DUPL_REPLACE, - KNOT_RRSET_DUPL_SKIP -} knot_rrset_dupl_handling_t; - -/*----------------------------------------------------------------------------*/ +/* -------------------- Creation / initialization --------------------------- */ /*! * \brief Creates a new RRSet with the given properties. @@ -88,96 +73,59 @@ typedef enum { * * \return New RRSet structure or NULL if an error occured. */ -knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type, - uint16_t rclass, - mm_ctx_t *mm); +knot_rrset_t *knot_rrset_new(const knot_dname_t *owner, uint16_t type, + uint16_t rclass, mm_ctx_t *mm); /*! - * \brief Creates a new RRSet according to given template RRSet. - * - * OWNER, TYPE, CLASS, and TTL values from template RRSet are used. + * \brief Initializes RRSet structure with given data. * - * \param tmp RRSet template. - * - * \return New RRSet, NULL if an error occured. + * \param rrset RRSet to init. + * \param owner RRSet owner to use. + * \param type RR type to use. + * \param rclass Class to use. */ -knot_rrset_t *knot_rrset_new_from(const knot_rrset_t *tpl, mm_ctx_t *mm); +void knot_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner, uint16_t type, + uint16_t rclass); /*! - * \brief Adds the given RDATA to the RRSet. - * - * \param rrset RRSet to add the RDATA to. - * \param rdata RDATA to add to the RRSet. - * \param size Size of RDATA. - * \param size TTL for RR. - * \param mm Memory context. - * - * \return KNOT_E* - */ -int knot_rrset_add_rr(knot_rrset_t *rrset, const uint8_t *rdata, - const uint16_t size, const uint32_t ttl, - mm_ctx_t *mm); - -/*! - * \brief Creates RDATA memory and returns a pointer to it. - * If the RRSet is not empty, function will return a memory - * pointing to a beginning of a new RR. - * - * \param rrset RRSet to add the RDATA to. - * \param size Size of RR RDATA (Size in internal representation) - * \param mm Memory context. + * \brief Initializes given RRSet structure. * - * \retval Pointer to memory to be written to. - * \retval NULL if arguments are invalid / no memory. + * \param rrset RRSet to init. */ -uint8_t* knot_rrset_create_rr(knot_rrset_t *rrset, const uint16_t size, - const uint32_t ttl, mm_ctx_t *mm); +void knot_rrset_init_empty(knot_rrset_t *rrset); /*! - * \brief Returns the Owner of the RRSet. + * \brief Creates new RRSet from \a src RRSet. * - * \param rrset RRSet to get the Owner of. + * \param src Source RRSet. + * \param mm Memory context. * - * \return Owner of the given RRSet. + * \retval Pointer to new RRSet if all went OK. + * \retval NULL on error. */ -const knot_dname_t *knot_rrset_owner(const knot_rrset_t *rrset); +knot_rrset_t *knot_rrset_copy(const knot_rrset_t *src, mm_ctx_t *mm); -/*! - * \brief Returns the Owner of the RRSet. - * - * \param rrset RRSet to get the Owner of. - * - * \return Owner of the given RRSet. - */ -knot_dname_t *knot_rrset_get_owner(const knot_rrset_t *rrset); +/* ---------------------------- Cleanup ------------------------------------- */ /*! - * \brief Set rrset owner to specified dname. - * - * Previous owner will be replaced if exist. + * \brief Destroys the RRSet structure and all its substructures. + ) + * Also sets the given pointer to NULL. * - * \param rrset Specified RRSet. - * \param owner New owner dname. + * \param rrset RRset to be destroyed. + * \param mm Memory context. */ -int knot_rrset_set_owner(knot_rrset_t *rrset, const knot_dname_t *owner); +void knot_rrset_free(knot_rrset_t **rrset, mm_ctx_t *mm); /*! - * \brief Returns the TYPE of the RRSet. + * \brief Frees structures inside RRSet, but not the RRSet itself. * - * \param rrset RRSet to get the TYPE of. - * - * \return TYPE of the given RRSet. + * \param rrset RRSet to be cleared. + * \param mm Memory context used for allocations. */ -uint16_t knot_rrset_type(const knot_rrset_t *rrset); +void knot_rrset_clear(knot_rrset_t *rrset, mm_ctx_t *mm); -/*! - * \brief Returns the CLASS of the RRSet. - * - * \param rrset RRSet to get the CLASS of. - * - * \return CLASS of the given RRSet. - */ -uint16_t knot_rrset_class(const knot_rrset_t *rrset); +/* ----------- Getters / Setters (legacy, functionality in rr_t) ------------ */ /*! * \brief Returns RDATA of RR on given position. @@ -219,17 +167,6 @@ uint32_t knot_rrset_rr_ttl(const knot_rrset_t *rrset, size_t pos); */ void knot_rrset_rr_set_ttl(const knot_rrset_t *rrset, size_t pos, uint32_t ttl); -/*! - * \brief Compares TTL of first RRs of two RRSets. - * - * \param r1 First RRSet. - * \param r2 Second RRSet. - * - * \retval True if TTLs are equal. - * \retval False otherwise. - */ -bool knot_rrset_ttl_equal(const knot_rrset_t *r1, const knot_rrset_t *r2); - /*! * \brief Returns count of RRs in RRSet. * @@ -239,40 +176,7 @@ bool knot_rrset_ttl_equal(const knot_rrset_t *r1, const knot_rrset_t *r2); */ uint16_t knot_rrset_rr_count(const knot_rrset_t *rrset); -/*! - * \brief Compares two RRSets for equality. - * - * \param r1 First RRSet. - * \param r2 Second RRSet. - * \param cmp Type of comparison to perform. - * - * \retval True if RRSets are equal. - * \retval False if RRSets are not equal. - */ -bool knot_rrset_equal(const knot_rrset_t *r1, - const knot_rrset_t *r2, - knot_rrset_compare_type_t cmp); - -/*! - * \brief Complete copy of RRSet structure. - * - * \param from Source data. - * \param to Destionation data. - * \param mm Memory context. - * - * \return KNOT_E* - */ -int knot_rrset_copy(const knot_rrset_t *from, knot_rrset_t **to, mm_ctx_t *mm); - -/*! - * \brief Destroys the RRSet structure and all its substructures. - ) - * Also sets the given pointer to NULL. - * - * \param rrset RRset to be destroyed. - * \param mm Memory context. - */ -void knot_rrset_free(knot_rrset_t **rrset, mm_ctx_t *mm); +/* ---------- Wire conversions (legacy, to be done in knot_pkt_t) ----------- */ /*! * \brief Converts RRSet structure to wireformat, compression included. @@ -289,124 +193,6 @@ void knot_rrset_free(knot_rrset_t **rrset, mm_ctx_t *mm); int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size, size_t max_size, uint16_t *rr_count, struct knot_compr *compr); -/*! - * \brief Merges two RRSets, no duplicate check is done, no sorting either. - * - * \param r1 Pointer to RRSet to be merged into. - * \param r2 Pointer to RRSet to be merged. - * \param mm Memory context. - * - * \return KNOT_E* - */ -int knot_rrset_merge(knot_rrset_t *rrset1, const knot_rrset_t *rrset2, - mm_ctx_t *mm); - -/*! - * \brief Merges two RRSets, duplicate check is done, preserves canonical ordering. - * - * \param r1 Pointer to RRSet to be merged into. - * \param r2 Pointer to RRSet to be merged. - * \param merged Count of merged RRs. - * \param deleted_rrs Count of deleted duplicated RRs. - * \param mm Memory context. - * - * \return KNOT_E* - */ -int knot_rrset_merge_sort(knot_rrset_t *rrset1, const knot_rrset_t *rrset2, - int *merged, int *deleted_rrs, mm_ctx_t *mm); - -/*! - * \brief Sort RDATA in RRSet to be in canonical order. - * \todo Not optimal, rewrite! - * - * \param rrset RRSet to be sorted. - * \return Error code, KNOT_EOK when successful. - */ -int knot_rrset_sort_rdata(knot_rrset_t *rrset); - -/*! - * \brief Return true if the RRSet is an NSEC3 related type. - * - * \param rr RRSet. - */ -bool knot_rrset_is_nsec3rel(const knot_rrset_t *rr); - -/*! - * \brief Returns binary size of RRSet. - * - * \param rrset RRSet. - * - * \return Binary size. - */ -uint64_t rrset_binary_size(const knot_rrset_t *rrset); - -/*! - * \brief Serializes RRSet into given stream. - * - * \param rrset RRSet to be serialized. - * \param stream Output stream - * \param size Size written. - * - * \return KNOT_E* - */ -int rrset_serialize(const knot_rrset_t *rrset, uint8_t *stream, size_t *size); - -/*! - * \brief Deserializes RRSet structure. - * - * \param stream Input stream. - * \param stream_size Input stream size. - * \param rrset Output RRSet. - * - * \return KNOT_E* - */ -int rrset_deserialize(const uint8_t *stream, size_t *stream_size, - knot_rrset_t **rrset); - -/*! - * \brief Adds RR on 'pos' position from 'source' to 'dest'. - * - * \param dest Destination RRSet. - * \param source Source RRSet. - * \param rdata_pos RR position from 'source' to add to 'dest'. - * \param mm Memory context. - * - * \return KNOT_E* - */ -int knot_rrset_add_rr_from_rrset(knot_rrset_t *dest, const knot_rrset_t *source, - size_t rdata_pos, mm_ctx_t *mm); - -/*! - * \brief Removes RRs contained in 'what' RRSet from 'from' RRSet. - * Deleted RRs are returned in 'rr_deleted'. - * - * \param from Delete from. - * \param what Delete what. - * \param rr_deleted Deleted RRs stored here. - * \param mm Memory context. - * - * \return KNOT_E* - */ -int knot_rrset_remove_rr_using_rrset(knot_rrset_t *from, - const knot_rrset_t *what, - knot_rrset_t **rr_deleted, mm_ctx_t *mm); - -/*! - * \brief Finds RR at 'pos' position in 'rr_reference' RRSet in - * 'rr_search_in' RRSet. Position returned in 'pos_out'. - * - * \param rr_search_in Search in this RRSet. - * \param rr_reference Use RR from this RRSet. - * \param pos Index for 'rr_reference'. - * \param pos_out If found, position returned here. - * - * \retval KNOT_EOK if found, pos_out is set. - * \retval KNOT_ENOENT if not found. - */ -int knot_rrset_find_rr_pos(const knot_rrset_t *rr_search_in, - const knot_rrset_t *rr_reference, size_t pos, - size_t *pos_out); - /*! * \brief Creates one RR from wire, stores it into 'rrset' * @@ -425,33 +211,46 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset, size_t total_size, uint32_t ttl, size_t rdlength, mm_ctx_t *mm); +/* ---------- RR addition. (legacy, functionality in knot_rrs_t) ------------ */ + /*! - * \brief Checks whether the given type requires additional processing. - * - * Only MX, NS and SRV types require additional processing. + * \brief Adds the given RDATA to the RRSet. * - * \param rrtype Type to check. + * \param rrset RRSet to add the RDATA to. + * \param rdata RDATA to add to the RRSet. + * \param size Size of RDATA. + * \param ttl TTL for RR. + * \param mm Memory context. * - * \retval <> 0 if additional processing is needed for \a qtype. - * \retval 0 otherwise. + * \return KNOT_E* */ -int rrset_additional_needed(uint16_t rrtype); +int knot_rrset_add_rr(knot_rrset_t *rrset, const uint8_t *rdata, + const uint16_t size, const uint32_t ttl, + mm_ctx_t *mm); + +/* ------------------ Equality / emptines bool checks ----------------------- */ /*! - * \brief Creates RRSIG record from node RRSIGs for given RRSet. + * \brief Compares two RRSets for equality. * - * \param owner Owner to use for the RRSIG. - * \param type Type to cover. - * \param rrsigs Node RRSIGs. - * \param out_sig Output RRSIG. - * \param mm Memory context. + * \param r1 First RRSet. + * \param r2 Second RRSet. + * \param cmp Type of comparison to perform. * - * \return KNOT_E* + * \retval True if RRSets are equal. + * \retval False if RRSets are not equal. */ -int knot_rrset_synth_rrsig(const knot_dname_t *owner, uint16_t type, - const knot_rrset_t *rrsigs, - knot_rrset_t **out_sig, mm_ctx_t *mm); +bool knot_rrset_equal(const knot_rrset_t *r1, const knot_rrset_t *r2, + knot_rrset_compare_type_t cmp); -#endif /* _KNOT_RRSET_H_ */ +/*! + * \brief Checks whether RRSet is empty. + * + * \param rrset RRSet to check. + * + * \retval True if RRSet is empty. + * \retval False if RRSet is not empty. + */ +bool knot_rrset_empty(const knot_rrset_t *rrset); /*! @} */ diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c index 1fddda11cb024a579e8b349b35479a06242638a7..6ff78c9eb86d5dbd4911b568207942a5143368eb 100644 --- a/src/libknot/tsig-op.c +++ b/src/libknot/tsig-op.c @@ -61,7 +61,7 @@ static int knot_tsig_check_key(const knot_rrset_t *tsig_rr, return KNOT_EINVAL; } - const knot_dname_t *tsig_name = knot_rrset_owner(tsig_rr); + const knot_dname_t *tsig_name = tsig_rr->owner; if (!tsig_name) { return KNOT_EMALF; } @@ -195,7 +195,7 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, } /* Copy TSIG variables - starting with key name. */ - const knot_dname_t *tsig_owner = knot_rrset_owner(tsig_rr); + const knot_dname_t *tsig_owner = tsig_rr->owner; if (!tsig_owner) { dbg_tsig("TSIG: write variables: no owner.\n"); return KNOT_EINVAL; @@ -208,9 +208,9 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, /*!< \todo which order? */ /* Copy class. */ - knot_wire_write_u16(wire + offset, knot_rrset_class(tsig_rr)); + knot_wire_write_u16(wire + offset, tsig_rr->rclass); dbg_tsig_verb("TSIG: write variables: written CLASS: %u - \n", - knot_rrset_class(tsig_rr)); + tsig_rr->rclass); dbg_tsig_hex_detail((char *)(wire + offset), sizeof(uint16_t)); offset += sizeof(uint16_t); @@ -449,18 +449,11 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, return KNOT_EINVAL; } - knot_dname_t *key_name_copy = knot_dname_copy(key->name); - if (!key_name_copy) { - dbg_tsig("TSIG: key_name_copy = NULL\n"); - return KNOT_ENOMEM; - } - knot_rrset_t *tmp_tsig = - knot_rrset_new(key_name_copy, - KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, NULL); + knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, + NULL); if (!tmp_tsig) { dbg_tsig("TSIG: tmp_tsig = NULL\n"); - knot_dname_free(&key_name_copy); return KNOT_ENOMEM; } @@ -556,15 +549,9 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; size_t digest_tmp_len = 0; - - /* Create tmp TSIG. */ - knot_dname_t *owner_copy = knot_dname_copy(key->name); - knot_rrset_t *tmp_tsig = knot_rrset_new(owner_copy, - KNOT_RRTYPE_TSIG, - KNOT_CLASS_ANY, - NULL); + knot_rrset_t *tmp_tsig = knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, + KNOT_CLASS_ANY, NULL); if (!tmp_tsig) { - knot_dname_free(&owner_copy); return KNOT_ENOMEM; } @@ -711,7 +698,6 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, memset(wire_to_sign, 0, sizeof(uint8_t) * size); memcpy(wire_to_sign, wire, size); - uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; size_t digest_tmp_len = 0; assert(knot_rrset_rr_count(tsig_rr) > 0); @@ -814,19 +800,11 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, } /*! \todo What key to use, when we do not sign? Does this even work? */ - knot_dname_t *key_name = - knot_dname_copy(knot_rrset_owner(tsig_rr)); - if (key_name == NULL) { - dbg_tsig("TSIG: failed to copy owner\n"); - return KNOT_ERROR; - } - knot_rrset_t *tmp_tsig = - knot_rrset_new(key_name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, - NULL); + knot_rrset_new(tsig_rr->owner, KNOT_RRTYPE_TSIG, + KNOT_CLASS_ANY, NULL); if (!tmp_tsig) { dbg_tsig("TSIG: tmp_tsig = NULL\n"); - knot_dname_free(&key_name); return KNOT_ENOMEM; } @@ -842,11 +820,9 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, /* Set original ID */ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg)); - /* Set other len. */ tsig_rdata_set_other_data(tmp_tsig, 0, 0); - /* Append TSIG RR. */ int ret = knot_tsig_append(msg, msg_len, msg_max_len, tsig_rr); diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c index 50d4f571b9614ff9e7670bf9a790de536157c1e2..c7c8ae75162a676f9198bfab2da6be7828edda64 100644 --- a/src/libknot/tsig.c +++ b/src/libknot/tsig.c @@ -132,15 +132,20 @@ int tsig_create_rdata(knot_rrset_t *rr, const knot_dname_t *alg, uint16_t maclen if (tsig_err != KNOT_RCODE_BADTIME) { rdlen -= TSIG_OTHER_MAXLEN; } - uint8_t *rd = knot_rrset_create_rr(rr, rdlen, 0, NULL); + uint8_t rd[rdlen]; memset(rd, 0, rdlen); /* Copy alg name. */ knot_dname_to_wire(rd, alg, rdlen); /* Set MAC variable length in advance. */ - rd += alg_len + TSIG_OFF_MACLEN; - knot_wire_write_u16(rd, maclen); + size_t offset = alg_len + TSIG_OFF_MACLEN; + knot_wire_write_u16(rd + offset, maclen); + + int ret = knot_rrset_add_rr(rr, rd, rdlen, 0, NULL); + if (ret != KNOT_EOK) { + return ret; + } /* Set error. */ tsig_rdata_set_tsig_error(rr, tsig_err); @@ -352,7 +357,7 @@ size_t tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig) return 0; } /* Key name, Algorithm name and Other data have variable lengths. */ - const knot_dname_t *key_name = knot_rrset_owner(tsig); + const knot_dname_t *key_name = tsig->owner; if (!key_name) { return 0; } @@ -374,7 +379,6 @@ size_t tsig_rdata_tsig_timers_length() return KNOT_TSIG_TIMERS_LENGTH; } - int tsig_rdata_store_current_time(knot_rrset_t *tsig) { if (!tsig) { @@ -444,7 +448,7 @@ size_t tsig_wire_actsize(const knot_rrset_t *tsig) } /*! \todo Used fixed size as a base. */ - return knot_dname_size(knot_rrset_owner(tsig)) + + return knot_dname_size(tsig->owner) + sizeof(uint16_t) + /* TYPE */ sizeof(uint16_t) + /* CLASS */ sizeof(uint32_t) + /* TTL */ diff --git a/src/utils/common/exec.c b/src/utils/common/exec.c index 46288311b7d8db3b1baef4a2a83935b11eaaed9a..a336fc489ac96a96999b59d2968bd7560aabaf21 100644 --- a/src/utils/common/exec.c +++ b/src/utils/common/exec.c @@ -199,10 +199,7 @@ static void print_section_question(const knot_dname_t *owner, { size_t buflen = 8192; char *buf = calloc(buflen, 1); - - knot_dname_t *owner_copy = knot_dname_copy(owner); - knot_rrset_t *question = knot_rrset_new(owner_copy, qtype, - qclass, NULL); + knot_rrset_t *question = knot_rrset_new(owner, qtype, qclass, NULL); if (knot_rrset_txt_dump_header(question, 0, buf, buflen, &(style->style)) < 0) { @@ -215,7 +212,7 @@ static void print_section_question(const knot_dname_t *owner, free(buf); } -static void print_section_full(const knot_rrset_t **rrsets, +static void print_section_full(const knot_rrset_t *rrsets, const uint16_t count, const style_t *style) { @@ -223,11 +220,11 @@ static void print_section_full(const knot_rrset_t **rrsets, char *buf = calloc(buflen, 1); for (size_t i = 0; i < count; i++) { - if (rrsets[i]->type == KNOT_RRTYPE_OPT) { + if (rrsets[i].type == KNOT_RRTYPE_OPT) { continue; } - while (knot_rrset_txt_dump(rrsets[i], buf, buflen, + while (knot_rrset_txt_dump(&rrsets[i], buf, buflen, &(style->style)) < 0) { buflen += 4096; // Oversize protection. @@ -249,7 +246,7 @@ static void print_section_full(const knot_rrset_t **rrsets, free(buf); } -static void print_section_dig(const knot_rrset_t **rrsets, +static void print_section_dig(const knot_rrset_t *rrsets, const uint16_t count, const style_t *style) { @@ -257,7 +254,7 @@ static void print_section_dig(const knot_rrset_t **rrsets, char *buf = calloc(buflen, 1); for (size_t i = 0; i < count; i++) { - const knot_rrset_t *rrset = rrsets[i]; + const knot_rrset_t *rrset = &rrsets[i]; uint16_t rrset_rdata_count = knot_rrset_rr_count(rrset); for (uint16_t j = 0; j < rrset_rdata_count; j++) { while (knot_rrset_txt_dump_data(rrset, j, buf, buflen, @@ -283,7 +280,7 @@ static void print_section_dig(const knot_rrset_t **rrsets, free(buf); } -static void print_section_host(const knot_rrset_t **rrsets, +static void print_section_host(const knot_rrset_t *rrsets, const uint16_t count, const style_t *style) { @@ -291,7 +288,7 @@ static void print_section_host(const knot_rrset_t **rrsets, char *buf = calloc(buflen, 1); for (size_t i = 0; i < count; i++) { - const knot_rrset_t *rrset = rrsets[i]; + const knot_rrset_t *rrset = &rrsets[i]; knot_lookup_table_t *descr; char type[32] = "NULL"; char *owner; diff --git a/src/utils/dig/dig_exec.c b/src/utils/dig/dig_exec.c index 3180f3830a4e2af53669c08364ec7d7efbfda9e4..4244c80b11c147c85d934a18ebb68e68ba1b05b3 100644 --- a/src/utils/dig/dig_exec.c +++ b/src/utils/dig/dig_exec.c @@ -91,7 +91,7 @@ static knot_pkt_t* create_query_packet(const query_t *query) ret = knot_pkt_put_question(packet, qname, query->class_num, query->type_num); if (ret != KNOT_EOK) { - knot_dname_free(&qname); + knot_dname_free(&qname, NULL); knot_pkt_free(&packet); return NULL; } @@ -107,8 +107,8 @@ static knot_pkt_t* create_query_packet(const query_t *query) KNOT_RRTYPE_SOA, query->class_num, &packet->mm); + knot_dname_free(&qname, NULL); if (soa == NULL) { - knot_dname_free(&qname); knot_pkt_free(&packet); return NULL; } @@ -125,7 +125,7 @@ static knot_pkt_t* create_query_packet(const query_t *query) } // Set SOA serial. - knot_rdata_soa_serial_set(soa, query->xfr_serial); + knot_rrs_soa_serial_set(&soa->rrs, query->xfr_serial); // Add authority section. knot_pkt_begin(packet, KNOT_AUTHORITY); @@ -136,7 +136,7 @@ static knot_pkt_t* create_query_packet(const query_t *query) return NULL; } } else { - knot_dname_free(&qname); + knot_dname_free(&qname, NULL); } // Create EDNS section if required. @@ -227,12 +227,12 @@ static int64_t first_serial_check(const knot_pkt_t *reply) return -1; } - const knot_rrset_t *first = answer->rr[0]; + const knot_rrset_t *first = &answer->rr[0]; if (first->type != KNOT_RRTYPE_SOA) { return -1; } else { - return knot_rdata_soa_serial(first); + return knot_rrs_soa_serial(&first->rrs); } } @@ -243,13 +243,12 @@ static bool last_serial_check(const uint32_t serial, const knot_pkt_t *reply) return false; } - const knot_rrset_t *last = answer->rr[answer->count - 1]; + const knot_rrset_t *last = &answer->rr[answer->count - 1]; if (last->type != KNOT_RRTYPE_SOA) { return false; } else { - int64_t last_serial = knot_rdata_soa_serial(last); - + int64_t last_serial = knot_rrs_soa_serial(&last->rrs); if (last_serial == serial) { return true; } else { @@ -510,7 +509,6 @@ static int process_packet_xfr(const knot_pkt_t *query, // Get stop query time and start reply time. gettimeofday(&t_query, NULL); - // Print query packet if required. if (style->show_query) { print_packet(query, net, diff --git a/src/utils/nsec3hash/nsec3hash_main.c b/src/utils/nsec3hash/nsec3hash_main.c index 9821a4ed67cb80a9d9acea34666e26642aec99ff..f7d33d7d61a9cfb4e5d6c7f15ef83d5fcf33bbee 100644 --- a/src/utils/nsec3hash/nsec3hash_main.c +++ b/src/utils/nsec3hash/nsec3hash_main.c @@ -184,7 +184,7 @@ int main(int argc, char *argv[]) fail: knot_nsec3_params_free(&nsec3_params); - knot_dname_free(&dname); + knot_dname_free(&dname, NULL); free(digest); free(b32_digest); diff --git a/src/utils/nsupdate/nsupdate_exec.c b/src/utils/nsupdate/nsupdate_exec.c index 9cd29eea540bc4e35d1e28e9871e1102219e5b20..fefb721d991fd0f35b81420ef610def67f22ec34 100644 --- a/src/utils/nsupdate/nsupdate_exec.c +++ b/src/utils/nsupdate/nsupdate_exec.c @@ -133,7 +133,7 @@ static int dname_isvalid(const char *lp, size_t len) { if (dn == NULL) { return 0; } - knot_dname_free(&dn); + knot_dname_free(&dn, NULL); return 1; } @@ -188,7 +188,7 @@ static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags) { /* Parse only name? */ if (flags & PARSE_NAMEONLY) { - knot_dname_free(&owner); + knot_dname_free(&owner, NULL); return KNOT_EOK; } @@ -218,7 +218,7 @@ static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags) { char cls_s[16] = {0}; knot_rrclass_to_string(s->default_class, cls_s, sizeof(cls_s)); ERR("class mismatch: '%s'\n", cls_s); - knot_dname_free(&owner); + knot_dname_free(&owner, NULL); return KNOT_EPARSEFAIL; } @@ -233,7 +233,7 @@ static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags) { /* Remainder */ if (*lp == '\0') { - knot_dname_free(&owner); + knot_dname_free(&owner, NULL); return ret; /* No RDATA */ } @@ -251,7 +251,7 @@ static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags) { free(owner_s); free(rr); - knot_dname_free(&owner); + knot_dname_free(&owner, NULL); return ret; } @@ -290,16 +290,10 @@ static srv_info_t *parse_host(const char *lp, const char* default_port) /* Append parsed RRSet to list. */ static int rr_list_append(zs_scanner_t *s, list_t *target_list, mm_ctx_t *mm) { - /* Form a rrset. */ - knot_dname_t *owner = knot_dname_copy(s->r_owner); - if (!owner) { - DBG("%s: failed to create dname\n", __func__); - return KNOT_ENOMEM; - } - knot_rrset_t *rr = knot_rrset_new(owner, s->r_type, s->r_class, NULL); + knot_rrset_t *rr = knot_rrset_new(s->r_owner, s->r_type, s->r_class, + NULL); if (!rr) { DBG("%s: failed to create rrset\n", __func__); - knot_dname_free(&owner); return KNOT_ENOMEM; } @@ -357,7 +351,7 @@ static int build_query(nsupdate_params_t *params) knot_wire_set_opcode(query->wire, KNOT_OPCODE_UPDATE); knot_dname_t *qname = knot_dname_from_str(params->zone); int ret = knot_pkt_put_question(query, qname, params->class_num, params->type_num); - knot_dname_free(&qname); + knot_dname_free(&qname, NULL); if (ret != KNOT_EOK) return ret; @@ -383,7 +377,6 @@ static int build_query(nsupdate_params_t *params) return rr_list_to_packet(query, ¶ms->update_list); } - static int pkt_sendrecv(nsupdate_params_t *params) { net_t net; @@ -524,7 +517,6 @@ int cmd_update(const char* lp, nsupdate_params_t *params) return h[bp](tok_skipspace(lp + TOK_L(cmd_array[bp])), params); } - int cmd_add(const char* lp, nsupdate_params_t *params) { DBG("%s: lp='%s'\n", __func__, lp); diff --git a/tests-extra/tests/ddns/basic/test.py b/tests-extra/tests/ddns/basic/test.py index 3018e35701c4c2a5f85c9efc874c9cf55f530877..70c8626811625c7e673ee91e869bd4775d517b3c 100644 --- a/tests-extra/tests/ddns/basic/test.py +++ b/tests-extra/tests/ddns/basic/test.py @@ -158,8 +158,7 @@ def do_normal_tests(master, zone, dnssec=False): resp.check_record(rtype="CNAME", rdata="mail.ddns.") verify(master, zone, dnssec) - # add new node with CNAME + add A to the same node - # the A should be ignored + # add new node with CNAME + add A to the same node, A should be ignored check_log("Add new CNAME node + add A to it") up = master.update(zone) up.add("rrtest3.ddns.", "3600", "CNAME", "dont.ignore.me.ddns.") @@ -167,8 +166,8 @@ def do_normal_tests(master, zone, dnssec=False): up.send("NOERROR") resp = master.dig("rrtest3.ddns.", "ANY") resp.check(rcode="NOERROR") + resp.check_record(rtype="TXT", nordata="ignore") resp.check_record(rtype="CNAME", rdata="dont.ignore.me.ddns.") - compare(resp.count(section="answer"), 1, "Other RRs than CNAME in node") verify(master, zone, dnssec) # add CNAME to CNAME node, should be replaced @@ -238,7 +237,7 @@ def do_normal_tests(master, zone, dnssec=False): "dns1.ddns. hostmaster.ddns. 2010111213 10800 3600 1209600 7200") resp = master.dig("ddns.", "SOA") resp.check(rcode="NOERROR", - rdata="dns1.ddns. hostmaster.ddns. 2014111213 10800 3600 1209600 7200") + rdata="dns1.ddns. hostmaster.ddns. 2013111213 10800 3600 1209600 7200") verify(master, zone, dnssec) # add and remove the same record diff --git a/tests/conf.c b/tests/conf.c index 506e0963116a43bb9a3cd19fd5f620dbdf370529..0e237c18699987a4e7511b032258c001cc9174fa 100644 --- a/tests/conf.c +++ b/tests/conf.c @@ -123,7 +123,7 @@ int main(int argc, char *argv[]) } else { ok(0, "TSIG key dname check - NO KEY FOUND"); } - knot_dname_free(&sample); + knot_dname_free(&sample, NULL); skip_all: diff --git a/tests/dname.c b/tests/dname.c index 338f8faf1137a8ff7abeb13141420d5428483b6a..399e52b898eef7477de600393225ca7b00490cee 100644 --- a/tests/dname.c +++ b/tests/dname.c @@ -77,14 +77,14 @@ int main(int argc, char *argv[]) d = knot_dname_from_str(t); ok(d && knot_dname_size(d) == len && memcmp(d, w, len) == 0, "dname_fromstr: parsed correct non-FQDN name"); - knot_dname_free(&d); + knot_dname_free(&d, NULL); /* 12. parse FQDN from string (correct) .*/ t = "abcd.efg."; d = knot_dname_from_str(t); ok(d && knot_dname_size(d) == len && memcmp(d, w, len) == 0, "dname_fromstr: parsed correct FQDN name"); - knot_dname_free(&d); + knot_dname_free(&d, NULL); /* 13. parse name from string (incorrect) .*/ t = ".."; @@ -97,30 +97,30 @@ int main(int argc, char *argv[]) t = "ab.cd.ef"; d = knot_dname_from_str(t); ok(!knot_dname_is_sub(d, d2), "dname_subdomain: equal name"); - knot_dname_free(&d); + knot_dname_free(&d, NULL); /* 15. true subdomain */ t = "0.ab.cd.ef"; d = knot_dname_from_str(t); ok(knot_dname_is_sub(d, d2), "dname_subdomain: true subdomain"); - knot_dname_free(&d); + knot_dname_free(&d, NULL); /* 16. not subdomain */ t = "cd.ef"; d = knot_dname_from_str(t); ok(!knot_dname_is_sub(d, d2), "dname_subdomain: not subdomain"); - knot_dname_free(&d); + knot_dname_free(&d, NULL); /* 17. root subdomain */ t = "."; d = knot_dname_from_str(t); ok(knot_dname_is_sub(d2, d), "dname_subdomain: root subdomain"); - knot_dname_free(&d); - knot_dname_free(&d2); + knot_dname_free(&d, NULL); + knot_dname_free(&d2, NULL); /* 18-19. dname cat (valid) */ w = "\x03""cat"; - d = knot_dname_copy((const uint8_t *)w); + d = knot_dname_copy((const uint8_t *)w, NULL); t = "*"; d2 = knot_dname_from_str(t); d2 = knot_dname_cat(d2, d); @@ -128,23 +128,23 @@ int main(int argc, char *argv[]) len = 2 + 4 + 1; ok (d2 && len == knot_dname_size(d2), "dname_cat: valid concatenation size"); ok(memcmp(d2, t, len) == 0, "dname_cat: valid concatenation"); - knot_dname_free(&d); - knot_dname_free(&d2); + knot_dname_free(&d, NULL); + knot_dname_free(&d2, NULL); /* 20-21. parse from wire (valid) */ t = "\x04""abcd""\x03""efg"; len = 10; pos = 0; - d = knot_dname_parse((const uint8_t *)t, &pos, len); + d = knot_dname_parse((const uint8_t *)t, &pos, len, NULL); ok(d != NULL, "dname_parse: valid name"); ok(pos == len, "dname_parse: valid name (parsed length)"); - knot_dname_free(&d); + knot_dname_free(&d, NULL); /* 22-23. parse from wire (invalid) */ t = "\x08""dddd"; len = 5; pos = 0; - d = knot_dname_parse((const uint8_t *)t, &pos, len); + d = knot_dname_parse((const uint8_t *)t, &pos, len, NULL); ok(d == NULL, "dname_parse: bad name"); ok(pos == 0, "dname_parse: bad name (parsed length)"); @@ -155,23 +155,23 @@ int main(int argc, char *argv[]) t = "ab.cd.fe"; d2 = knot_dname_from_str(t); ok(!knot_dname_is_equal(d, d2), "dname_is_equal: same label count"); - knot_dname_free(&d2); + knot_dname_free(&d2, NULL); t = "ab.cd"; d2 = knot_dname_from_str(t); ok(!knot_dname_is_equal(d, d2), "dname_is_equal: len(d1) < len(d2)"); - knot_dname_free(&d2); + knot_dname_free(&d2, NULL); t = "ab.cd.ef.gh"; d2 = knot_dname_from_str(t); ok(!knot_dname_is_equal(d, d2), "dname_is_equal: len(d1) > len(d2)"); - knot_dname_free(&d2); + knot_dname_free(&d2, NULL); t = "ab.cd.efe"; d2 = knot_dname_from_str(t); ok(!knot_dname_is_equal(d, d2), "dname_is_equal: last label longer"); - knot_dname_free(&d2); + knot_dname_free(&d2, NULL); t = "ab.cd.e"; d2 = knot_dname_from_str(t); ok(!knot_dname_is_equal(d, d2), "dname_is_equal: last label shorter"); - knot_dname_free(&d2); + knot_dname_free(&d2, NULL); return 0; } diff --git a/tests/dnssec_nsec3.c b/tests/dnssec_nsec3.c index ba57c6c3d04368bae0ecb784cf041dbb54aeb986..8db2af9f3ce581343330c766089aeac946b3f685 100644 --- a/tests/dnssec_nsec3.c +++ b/tests/dnssec_nsec3.c @@ -55,10 +55,13 @@ int main(int argc, char *argv[]) 'a', 'b', 'c', 'd' // salt }; - rrset = knot_rrset_new(NULL, KNOT_RRTYPE_NSEC3PARAM, KNOT_CLASS_IN, NULL); + knot_dname_t *owner = knot_dname_from_str("test."); + rrset = knot_rrset_new(owner, KNOT_RRTYPE_NSEC3PARAM, KNOT_CLASS_IN, NULL); + knot_dname_free(&owner, NULL); + result = knot_rrset_add_rr(rrset, rdata, sizeof(rdata), 0, NULL); if (result == KNOT_EOK) { - result = knot_nsec3_params_from_wire(¶ms, rrset); + result = knot_nsec3_params_from_wire(¶ms, &rrset->rrs); } is_int(1, params.algorithm, "parse algorithm from wire"); @@ -96,7 +99,7 @@ int main(int argc, char *argv[]) free(digest); free(params.salt); - knot_dname_free(&dname); + knot_dname_free(&dname, NULL); return 0; } diff --git a/tests/dnssec_zone_nsec.c b/tests/dnssec_zone_nsec.c index b0361bd7aad4f5c8746215000416f4cfc31c5b32..30d3e2370bf94ea91e3dc27ae186c4ca946d6171 100644 --- a/tests/dnssec_zone_nsec.c +++ b/tests/dnssec_zone_nsec.c @@ -36,10 +36,10 @@ int main(int argc, char *argv[]) knot_dname_t *result = knot_create_nsec3_owner(owner, apex, ¶ms); is_int(0, knot_dname_cmp(result, expect), "create_nsec3_owner()"); - knot_dname_free(&result); - knot_dname_free(&owner); - knot_dname_free(&apex); - knot_dname_free(&expect); + knot_dname_free(&result, NULL); + knot_dname_free(&owner, NULL); + knot_dname_free(&apex, NULL); + knot_dname_free(&expect, NULL); return 0; } diff --git a/tests/pkt.c b/tests/pkt.c index a6a92fb9ce7cf19b0f35922ef2a77cc0376e16c9..7f6857174a53ef359187cc7e67c79dace26e0b6c 100644 --- a/tests/pkt.c +++ b/tests/pkt.c @@ -19,7 +19,6 @@ #include "common/errcode.h" #include "common/mempool.h" -#include "libknot/rrset.h" #include "libknot/rdata.h" #include "libknot/packet/pkt.h" #include "libknot/tsig.h" @@ -104,6 +103,7 @@ int main(int argc, char *argv[]) /* Write ANSWER section. */ rrsets[0] = knot_rrset_new(dnames[0], KNOT_RRTYPE_A, KNOT_CLASS_IN, NULL); + knot_dname_free(&dnames[0], NULL); knot_rrset_add_rr(rrsets[0], RDVAL(0), RDLEN(0), TTL, NULL); ret = knot_pkt_put(out, COMPR_HINT_QNAME, rrsets[0], 0); ok(ret == KNOT_EOK, "pkt: write ANSWER"); @@ -116,6 +116,7 @@ int main(int argc, char *argv[]) ret = KNOT_EOK; for (unsigned i = 1; i < NAMECOUNT; ++i) { rrsets[i] = knot_rrset_new(dnames[i], KNOT_RRTYPE_NS, KNOT_CLASS_IN, NULL); + knot_dname_free(&dnames[i], NULL); knot_rrset_add_rr(rrsets[i], RDVAL(i), RDLEN(i), TTL, NULL); ret |= knot_pkt_put(out, COMPR_HINT_NONE, rrsets[i], 0); } @@ -162,7 +163,7 @@ int main(int argc, char *argv[]) /* Check RRs */ int rr_matched = 0; for (unsigned i = 0; i < NAMECOUNT; ++i) { - if (knot_rrset_equal(out->rr[i], in->rr[i], KNOT_RRSET_COMPARE_WHOLE) > 0) { + if (knot_rrset_equal(&out->rr[i], &in->rr[i], KNOT_RRSET_COMPARE_WHOLE) > 0) { ++rr_matched; } } diff --git a/tests/process_query.c b/tests/process_query.c index 437119dc7793c4d79de88329e62fe8e04fe286ba..2e2ea6049e6b262b65f4eb5a4bb348e228d1a371 100644 --- a/tests/process_query.c +++ b/tests/process_query.c @@ -48,8 +48,7 @@ void create_root_zone(server_t *server, mm_ctx_t *mm) zone_t *root = zone_new(conf); root->contents = knot_zone_contents_new(root->name); - knot_dname_t *root_name = knot_dname_copy(root->name); - knot_rrset_t *soa_rrset = knot_rrset_new(root_name, + knot_rrset_t *soa_rrset = knot_rrset_new(root->name, KNOT_RRTYPE_SOA, KNOT_CLASS_IN, NULL); knot_rrset_add_rr(soa_rrset, SOA_RDATA, SOA_RDLEN, 7200, NULL); @@ -194,9 +193,9 @@ int main(int argc, char *argv[]) /* Forge IXFR query (well formed). */ knot_process_reset(&query_ctx); /* Append SOA RR. */ - knot_rrset_t *soa_rr = knot_node_get_rrset(zone->contents->apex, KNOT_RRTYPE_SOA); + knot_rrset_t soa_rr = knot_node_rrset(zone->contents->apex, KNOT_RRTYPE_SOA); knot_pkt_begin(query, KNOT_AUTHORITY); - knot_pkt_put(query, COMPR_HINT_NONE, soa_rr, 0); + knot_pkt_put(query, COMPR_HINT_NONE, &soa_rr, 0); exec_query(&query_ctx, "IN/ixfr", query->wire, query->size, KNOT_RCODE_NOTAUTH); /* \note Tests below are not possible without proper zone and zone data. */ diff --git a/tests/rrl.c b/tests/rrl.c index dd412ea3644b06889b5069d543aeabc888a9592f..e7e3b6648190bfe3648e5cb66455b1ed7a085316 100644 --- a/tests/rrl.c +++ b/tests/rrl.c @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) knot_dname_t *qname = knot_dname_from_str("beef."); int ret = knot_pkt_put_question(query, qname, KNOT_CLASS_IN, KNOT_RRTYPE_A); - knot_dname_free(&qname); + knot_dname_free(&qname, NULL); if (ret != KNOT_EOK) { knot_pkt_free(&query); return KNOT_ERROR; /* Fatal */ diff --git a/tests/zonedb.c b/tests/zonedb.c index 0edb94cddccde243ac763bf457f4ea9b79611b6a..e89e6836a85b9d190b08c628d02f4b1ae60d6297 100644 --- a/tests/zonedb.c +++ b/tests/zonedb.c @@ -77,7 +77,7 @@ int main(int argc, char *argv[]) } else { diag("knot_zonedb_find(%s) failed", zone_list[i]); } - knot_dname_free(&dname); + knot_dname_free(&dname, NULL); } ok(nr_passed == ZONE_COUNT, "zonedb: find exact zones"); @@ -94,7 +94,7 @@ int main(int argc, char *argv[]) } else { diag("knot_zonedb_find_suffix(%s) failed", buf); } - knot_dname_free(&dname); + knot_dname_free(&dname, NULL); } ok(nr_passed == ZONE_COUNT, "zonedb: find zones for subnames"); @@ -108,7 +108,7 @@ int main(int argc, char *argv[]) } else { diag("knot_zonedb_remove_zone(%s) failed", zone_list[i]); } - knot_dname_free(&dname); + knot_dname_free(&dname, NULL); } ok(nr_passed == ZONE_COUNT, "zonedb: removed all zones"); diff --git a/tests/ztree.c b/tests/ztree.c index f646a268275952ff61e39d278c0cbd1ffeae5da3..56caa7401968fb956434388f361c42cdc6646aaa 100644 --- a/tests/ztree.c +++ b/tests/ztree.c @@ -46,7 +46,7 @@ static void ztree_init_data() static void ztree_free_data() { for (unsigned i = 0; i < NCOUNT; ++i) - knot_dname_free(NAME + i); + knot_dname_free(NAME + i, NULL); } static int ztree_iter_data(knot_node_t **node, void *data) @@ -107,7 +107,7 @@ int main(int argc, char *argv[]) const knot_node_t *prev = NULL; knot_dname_t *tmp_dn = knot_dname_from_str("z.ac."); knot_zone_tree_find_less_or_equal(t, tmp_dn, &node, &prev); - knot_dname_free(&tmp_dn); + knot_dname_free(&tmp_dn, NULL); ok(prev == NODE + 1, "ztree: ordered lookup"); /* 5. ordered traversal */