* [git.ipfire.org] IPFire 2.x development tree branch, next, updated. 27b3a1a5c2e576443d25241bbbdeddeacbdedc5a
@ 2026-07-08 13:37 Michael Tremer
0 siblings, 0 replies; only message in thread
From: Michael Tremer @ 2026-07-08 13:37 UTC (permalink / raw)
To: ipfire-scm
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "IPFire 2.x development tree".
The branch, next has been updated
via 27b3a1a5c2e576443d25241bbbdeddeacbdedc5a (commit)
via ca152073b10bbeb3bda12dc27a94fcfb5692e650 (commit)
from 8ba78662899d1c445ceaeb4e5e7a3238dd75b339 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 27b3a1a5c2e576443d25241bbbdeddeacbdedc5a
Author: Michael Tremer <michael.tremer@ipfire.org>
Date: Wed Jul 8 13:36:46 2026 +0000
core204: Ship Knot Resolver
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
commit ca152073b10bbeb3bda12dc27a94fcfb5692e650
Author: Michael Tremer <michael.tremer@ipfire.org>
Date: Wed Jul 8 13:34:44 2026 +0000
knot-resolver: Make multiple addresses work
Backport of: https://gitlab.nic.cz/knot/knot-resolver/-/merge_requests/1854
Fixes: #14015 - Knot Resolver: returns only first A record (of multiple) for given name
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
-----------------------------------------------------------------------
Summary of changes:
.../{oldcore => core}/204/filelists/knot-resolver | 0
config/rootfiles/core/204/update.sh | 1 +
lfs/knot-resolver | 1 +
src/patches/knot-resolver-6.4.0-1854.patch | 251 +++++++++++++++++++++
4 files changed, 253 insertions(+)
copy config/rootfiles/{oldcore => core}/204/filelists/knot-resolver (100%)
create mode 100644 src/patches/knot-resolver-6.4.0-1854.patch
Difference in files:
diff --git a/config/rootfiles/core/204/filelists/knot-resolver b/config/rootfiles/core/204/filelists/knot-resolver
new file mode 120000
index 000000000..db15178a8
--- /dev/null
+++ b/config/rootfiles/core/204/filelists/knot-resolver
@@ -0,0 +1 @@
+../../../common/knot-resolver
\ No newline at end of file
diff --git a/config/rootfiles/core/204/update.sh b/config/rootfiles/core/204/update.sh
index 116e0267c..0b3d900cc 100644
--- a/config/rootfiles/core/204/update.sh
+++ b/config/rootfiles/core/204/update.sh
@@ -118,6 +118,7 @@ rm -rfv \
# Start services
/etc/init.d/apache start
/etc/init.d/suricata restart
+/etc/init.d/knot-resolver restart
# If 'monit' is installed: update '/etc/monitrc' for use with 'monit v6.0.0'
if [ -e /etc/monitrc ]; then
diff --git a/lfs/knot-resolver b/lfs/knot-resolver
index 14ce5eb7c..3d49a3bc7 100644
--- a/lfs/knot-resolver
+++ b/lfs/knot-resolver
@@ -70,6 +70,7 @@ $(subst %,%_BLAKE2,$(objects)) :
$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
@$(PREBUILD)
@rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/knot-resolver-6.4.0-1854.patch
cd $(DIR_APP) && meson setup \
--prefix=/usr \
-Duser=knot-resolver \
diff --git a/src/patches/knot-resolver-6.4.0-1854.patch b/src/patches/knot-resolver-6.4.0-1854.patch
new file mode 100644
index 000000000..94267c2a4
--- /dev/null
+++ b/src/patches/knot-resolver-6.4.0-1854.patch
@@ -0,0 +1,251 @@
+diff --git a/lib/cache/cdb_api.h b/lib/cache/cdb_api.h
+index 9e8a34d58..b589b564a 100644
+--- a/lib/cache/cdb_api.h
++++ b/lib/cache/cdb_api.h
+@@ -65,11 +65,15 @@ struct kr_cdb_api {
+ * \return error code - accepting RW transactions can fail with LMDB.
+ */
+ int (*commit)(kr_cdb_pt db, struct kr_cdb_stats *stat, bool accept_rw, bool reset_ro);
++ /** Run before a row of operations to ensure they happen in a single RW transaction,
++ * at least in case of successes. */
++ int (*txn_open_rw)(kr_cdb_pt db, struct kr_cdb_stats *stat/*unused*/);
+
+ /* Data access */
+
+ int (*read)(kr_cdb_pt db, struct kr_cdb_stats *stat,
+ const knot_db_val_t *key, knot_db_val_t *val, int maxcount);
++ /* TODO: the behavior of write() around transactions is a bit complex. */
+ int (*write)(kr_cdb_pt db, struct kr_cdb_stats *stat, const knot_db_val_t *key,
+ knot_db_val_t *val, int maxcount);
+
+@@ -111,13 +115,19 @@ struct kr_cdb_api {
+ int (*check_health)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+
+
+- /** Start iterating; return the first *val with *key.
++ /** Start iterating: get the first *val with *key + return error code.
+ *
+- * This only makes sense if !is_cache.
+- * TODO: it only works inside RO transactions for now.
++ * - in cache: ensures a RO transaction (and commits the RW txn if any)
++ * - in ruledb: transaction is preserved if exists, otherwise RO txn gets opened
+ */
+ int (*it_first)(kr_cdb_pt db, struct kr_cdb_stats *stat,
+ const knot_db_val_t *key, knot_db_val_t *val);
+- /** Advance to the next *val with the same key. */
++ /** Advance to the next *val with the same key. Return error code. */
+ int (*it_next)(kr_cdb_pt db, struct kr_cdb_stats *stat, knot_db_val_t *val);
++ /** Delete the current *val + return error code.
++ *
++ * You can it_next() to continue.
++ * This assumed that you got it_first() in a RW txn.
++ */
++ int (*it_del)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+ };
+diff --git a/lib/cache/cdb_lmdb.c b/lib/cache/cdb_lmdb.c
+index 0319b5cbb..6221c9492 100644
+--- a/lib/cache/cdb_lmdb.c
++++ b/lib/cache/cdb_lmdb.c
+@@ -38,12 +38,13 @@ struct lmdb_env
+ *
+ * - only one of (ro,rw) may be active at once
+ * - non-NULL .ro may be active or reset
+- * - non-NULL .rw is always active
++ * - ro_curs can survive an RW transaction and renewed later in an RO txn
++ * - non-NULL .rw is always active, non-NULL rw_curs is always active
+ */
+ struct {
+ bool ro_active, ro_curs_active;
+ MDB_txn *ro, *rw;
+- MDB_cursor *ro_curs;
++ MDB_cursor *ro_curs, *rw_curs;
+ } txn;
+
+ bool is_cache; /**< cache vs. rules; from struct kr_cdb_opts::is_cache */
+@@ -236,6 +237,7 @@ static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept_rw,
+ mdb_txn_abort(env->txn.rw);
+ }
+ env->txn.rw = NULL; /* the transaction got freed even in case of errors */
++ env->txn.rw_curs = NULL; /* auto-closed with txn if existed */
+ } else if (reset_ro && env->txn.ro && env->txn.ro_active) {
+ mdb_txn_reset(env->txn.ro);
+ env->txn.ro_active = false;
+@@ -244,21 +246,39 @@ static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept_rw,
+ return ret;
+ }
+
+-/** Obtain a read-only cursor (and a read-only transaction).
+- * TODO: allow RW transaction (for ruledb iterator) */
++static int cdb_txn_open_rw(kr_cdb_pt db, struct kr_cdb_stats *stat/*unused*/)
++{
++ struct lmdb_env *env = db2env(db);
++ MDB_txn *txn = NULL;
++ return txn_get(env, &txn, false);
++}
++
++/** Obtain a cursor (and a transaction).
++ *
++ * - for cache these are read only
++ * - for policy the RW transaction gets preserved if open */
+ static int txn_curs_get(struct lmdb_env *env, MDB_cursor **curs, struct kr_cdb_stats *stats)
+ {
+ if (kr_fails_assert(env && curs))
+ return kr_error(EINVAL);
+ if (env->txn.ro_curs_active)
+- goto success;
+- /* Only in a read-only txn; TODO: it's a bit messy/coupled
+- * At least for rules we don't do the auto-commit feature. */
+- if (env->txn.rw) {
+- if (!env->is_cache) return kr_error(EINPROGRESS);
++ goto success_ro;
++ /* Only in a read-only txn if for cache; TODO: it's a bit messy/coupled */
++ if (env->txn.rw && env->is_cache) {
+ int ret = cdb_commit(env2db(env), stats, true, false);
+ if (ret) return ret;
+ }
++ if (env->txn.rw && !env->is_cache) {
++ if (!env->txn.rw_curs) {
++ MDB_txn *txn = env->txn.rw;
++ int ret = mdb_cursor_open(txn, env->dbi, &env->txn.rw_curs);
++ if (ret) return lmdb_error(env, ret);
++ }
++ if (kr_fails_assert(env->txn.rw_curs))
++ return kr_error(EINVAL);
++ *curs = env->txn.rw_curs;
++ return kr_ok();
++ }
+ MDB_txn *txn = NULL;
+ int ret = txn_get(env, &txn, true);
+ if (ret) return ret;
+@@ -270,7 +290,7 @@ static int txn_curs_get(struct lmdb_env *env, MDB_cursor **curs, struct kr_cdb_s
+ }
+ if (ret) return lmdb_error(env, ret);
+ env->txn.ro_curs_active = true;
+-success:
++success_ro:
+ kr_assert(env->txn.ro_curs_active && env->txn.ro && env->txn.ro_active
+ && !env->txn.rw);
+ *curs = env->txn.ro_curs;
+@@ -301,6 +321,7 @@ static void txn_abort(struct lmdb_env *env)
+ if (env->txn.rw) {
+ mdb_txn_abort(env->txn.rw);
+ env->txn.rw = NULL; /* the transaction got freed even in case of errors */
++ env->txn.rw_curs = NULL; /* auto-closed with txn if existed */
+ }
+ }
+
+@@ -940,7 +961,7 @@ static int cdb_it_next(kr_cdb_pt db, struct kr_cdb_stats *stats, knot_db_val_t *
+ if (kr_fails_assert(db && val))
+ return kr_error(EINVAL);
+ struct lmdb_env *env = db2env(db);
+- if (kr_fails_assert(!env->is_cache && env->txn.ro_curs_active))
++ if (kr_fails_assert(!env->is_cache && (env->txn.ro_curs_active || env->txn.rw_curs)))
+ return kr_error(EINVAL);
+
+ MDB_cursor *curs = NULL;
+@@ -952,19 +973,35 @@ static int cdb_it_next(kr_cdb_pt db, struct kr_cdb_stats *stats, knot_db_val_t *
+ *val = val_mdb2knot(val2_m);
+ return kr_ok();
+ }
++static int cdb_it_del(kr_cdb_pt db, struct kr_cdb_stats *stats)
++{
++ if (kr_fails_assert(db))
++ return kr_error(EINVAL);
++ struct lmdb_env *env = db2env(db);
++ if (kr_fails_assert(!env->is_cache && env->txn.rw_curs))
++ return kr_error(EINVAL);
++
++ MDB_cursor *curs = NULL;
++ int ret = txn_curs_get(env, &curs, stats);
++ if (ret) return ret;
++ ret = mdb_cursor_del(curs, 0);
++ if (ret) return lmdb_error(env, ret);
++ return kr_ok();
++}
+
+
+ const struct kr_cdb_api *kr_cdb_lmdb(void)
+ {
+ static const struct kr_cdb_api api = {
+ "lmdb",
+- cdb_init, cdb_deinit, cdb_count, cdb_clear, cdb_commit,
++ cdb_init, cdb_deinit, cdb_count, cdb_clear,
++ cdb_commit, cdb_txn_open_rw,
+ cdb_readv, cdb_writev, cdb_remove,
+ cdb_match,
+ cdb_read_leq, cdb_read_less,
+ cdb_usage_percent, cdb_get_maxsize,
+ cdb_check_health,
+- cdb_it_first, cdb_it_next,
++ cdb_it_first, cdb_it_next, cdb_it_del,
+ };
+ return &api;
+ }
+diff --git a/lib/rules/api.c b/lib/rules/api.c
+index d9dbfcf1f..4c213d6f5 100644
+--- a/lib/rules/api.c
++++ b/lib/rules/api.c
+@@ -663,21 +663,27 @@ 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;
++ int ret = ruledb_op(txn_open_rw);
++ if (ret)
++ return kr_error(ret);
+ // 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);
++ // 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
+ uint32_t ttl;
+ if (deserialize_fails_assert(&val, &ttl))
+@@ -700,6 +706,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).
hooks/post-receive
--
IPFire 2.x development tree
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-07-08 13:37 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-08 13:37 [git.ipfire.org] IPFire 2.x development tree branch, next, updated. 27b3a1a5c2e576443d25241bbbdeddeacbdedc5a Michael Tremer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox