]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/rules: fix kr_rule_local_data_merge() docs-addresses-mu-j4piuy/deployments/9543 1854/head
authorVladimír Čunát <vladimir.cunat@nic.cz>
Wed, 24 Jun 2026 08:10:37 +0000 (10:10 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Wed, 15 Jul 2026 14:12:58 +0000 (16:12 +0200)
This fixes using multiple RRs in an RRset in some interfaces, e.g.
/local-data/addresses* but not /local-data/{records,rpz}

NEWS
lib/rules/api.c
lib/rules/api.h

diff --git a/NEWS b/NEWS
index 76bbb32fb40325eeb806b70eaf099c0a459581a3..3d47e2783344e5cd68dd3e1da094866549ae574b 100644 (file)
--- 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)
 ================================
index d9dbfcf1f7860a6dfc6abae8f3a3f830bf7969d4..6bfab3adb50d7a7ce88471ab5b7b454b2306cd4e 100644 (file)
@@ -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);
index feea98e09e5388c0b85d1d996dbd1e5eab6c6f6b..c3af5901bd016f0f2d0c060317c1b8d88ddecd5b 100644 (file)
@@ -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).