From: Vladimír Čunát Date: Wed, 24 Jun 2026 08:10:37 +0000 (+0200) Subject: lib/rules: fix kr_rule_local_data_merge() X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fc9170231539851a7380800792f9142d33b7fca7;p=thirdparty%2Fknot-resolver.git lib/rules: fix kr_rule_local_data_merge() This fixes using multiple RRs in an RRset in some interfaces, e.g. /local-data/addresses* but not /local-data/{records,rpz} --- diff --git a/NEWS b/NEWS index 76bbb32fb..3d47e2783 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ Improvements - docker: upgrade to Debian 13 (!1856) - update IANA's certificate for root trust anchor bootstrapping (!1845) +Bugfixes +-------- +- /local-data/addresses*: make multiple addresses work (#808, #954) + Knot Resolver 6.4.0 (2026-06-17) ================================ diff --git a/lib/rules/api.c b/lib/rules/api.c index d9dbfcf1f..6bfab3adb 100644 --- a/lib/rules/api.c +++ b/lib/rules/api.c @@ -663,22 +663,26 @@ int kr_rule_local_data_merge(const knot_rrset_t *rrs, const kr_rule_tags_t tags, uint8_t key_data[KEY_MAXLEN]; knot_db_val_t key = local_data_key(rrs, key_data, RULESET_DEFAULT); knot_db_val_t val; - // Transaction: we assume that we're in a RW transaction already, - // so that here we already "have a lock" on the last version. - // FIXME: iterate over multiple tags, once iterator supports RW TXN - int ret = ruledb_op(read, &key, &val, 1); + int ret = ruledb_op(txn_open_rw); // "get a lock" on the last DB version + if (ret) + return kr_error(ret); + // Multiple variants are possible, with different tags. + for (ret = ruledb_op(it_first, &key, &val); ret == 0; ret = ruledb_op(it_next, &val)) { + // we're looking for the same tag-set + kr_rule_tags_t tags_old; + if (deserialize_fails_assert(&val, &tags_old) || tags_old != tags) + continue; + kr_rule_opts_t opts_old; + if (deserialize_fails_assert(&val, &opts_old)) + continue; + break; + } if (abs(ret) == abs(ENOENT)) goto fallback; if (ret) return kr_error(ret); - // check tags - kr_rule_tags_t tags_old; - if (deserialize_fails_assert(&val, &tags_old) || tags_old != tags) - goto fallback; - kr_rule_opts_t opts_old; - if (deserialize_fails_assert(&val, &opts_old)) - goto fallback; - // merge TTLs + + // we found a match; first merge TTLs uint32_t ttl; if (deserialize_fails_assert(&val, &ttl)) goto fallback; @@ -700,6 +704,10 @@ int kr_rule_local_data_merge(const knot_rrset_t *rrs, const kr_rule_tags_t tags, mm_ctx_delete(mm); return kr_error(ret); } + // ATM ruledb does not overwrite, so we `remove` before `write`. + ret = ruledb_op(it_del); + if (ret) + return kr_error(ret); // everything is ready to insert the merged RRset ret = local_data_ins(key, &rrs_new, NULL, tags, opts); mm_ctx_delete(mm); diff --git a/lib/rules/api.h b/lib/rules/api.h index feea98e09..c3af5901b 100644 --- a/lib/rules/api.h +++ b/lib/rules/api.h @@ -144,10 +144,8 @@ const uint32_t KR_RULE_TTL_DEFAULT; KR_EXPORT int kr_rule_local_data_ins(const knot_rrset_t *rrs, const knot_rdataset_t *sig_rds, kr_rule_tags_t tags, kr_rule_opts_t opts); -/** Merge RRs into a local data rule. +/** Merge RRs into a local data rule with the same set of tags. * - * - FIXME: with multiple tags variants for the same name-type pair, - * you typically end up with a single RR per RRset * - RRSIGs get dropped, if any were attached. * - We assume that this is called with a RW transaction open already, * which is always true in normal usage (long RW txn covering whole config).