From 098200ba5a1de62308b9542cb4f8a95dc908338b Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Wed, 28 Jan 2026 11:48:53 +0100 Subject: [PATCH] - rpz-zone-load, optimise rpz_insert_local_zones_trigger to remove second local zones tree lookup for non local data cases. --- daemon/remote.c | 2 +- libunbound/libunbound.c | 2 +- services/localzone.c | 13 ++++++++++--- services/localzone.h | 8 +++++++- services/rpz.c | 30 +++++++++++++++++++++++++++++- testcode/unitmain.c | 2 +- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 702aa5f4e..8600a9965 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1339,7 +1339,7 @@ perform_zone_add(RES* ssl, struct local_zones* zones, char* arg) return 1; } if(!local_zones_add_zone(zones, nm, nmlen, - nmlabs, LDNS_RR_CLASS_IN, t)) { + nmlabs, LDNS_RR_CLASS_IN, t, NULL)) { lock_rw_unlock(&zones->lock); ssl_printf(ssl, "error out of memory\n"); return 0; diff --git a/libunbound/libunbound.c b/libunbound/libunbound.c index 9c6a3e309..673ad6ec8 100644 --- a/libunbound/libunbound.c +++ b/libunbound/libunbound.c @@ -1385,7 +1385,7 @@ int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name, return UB_NOERROR; } if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs, - LDNS_RR_CLASS_IN, t)) { + LDNS_RR_CLASS_IN, t, NULL)) { lock_rw_unlock(&ctx->local_zones->lock); return UB_NOMEM; } diff --git a/services/localzone.c b/services/localzone.c index 867e0c47c..18d8a64f0 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -2231,7 +2231,7 @@ set_kiddo_parents(struct local_zone* z, struct local_zone* match, struct local_zone* local_zones_add_zone(struct local_zones* zones, uint8_t* name, size_t len, int labs, uint16_t dclass, - enum localzone_type tp) + enum localzone_type tp, int* duplicate) { int exact; /* create */ @@ -2239,6 +2239,7 @@ struct local_zone* local_zones_add_zone(struct local_zones* zones, struct local_zone* z = local_zone_create(name, len, labs, tp, dclass); if(!z) { free(name); + if(duplicate) *duplicate = 0; return NULL; } lock_rw_wrlock(&z->lock); @@ -2252,8 +2253,14 @@ struct local_zone* local_zones_add_zone(struct local_zones* zones, if(exact||!rbtree_insert(&zones->ztree, &z->node)) { /* duplicate entry! */ lock_rw_unlock(&z->lock); + if(duplicate) { + *duplicate = 1; + z->name = NULL; /* Do not delete the name in + local_zone_delete. */ + } local_zone_delete(z); - log_err("internal: duplicate entry in local_zones_add_zone"); + if(duplicate == NULL) + log_err("internal: duplicate entry in local_zones_add_zone"); return NULL; } @@ -2297,7 +2304,7 @@ local_zones_add_RR(struct local_zones* zones, const char* rr) z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type); if(!z) { z = local_zones_add_zone(zones, rr_name, len, labs, rr_class, - local_zone_transparent); + local_zone_transparent, NULL); if(!z) { lock_rw_unlock(&zones->lock); return 0; diff --git a/services/localzone.h b/services/localzone.h index 6c5db2fb9..611185a00 100644 --- a/services/localzone.h +++ b/services/localzone.h @@ -403,11 +403,17 @@ local_zones_find_le(struct local_zones* zones, * @param labs: labelcount of name. * @param dclass: class to add. * @param tp: type. + * @param duplicate: Allows to check if a NULL return from the function is a + * memory error, or a duplicate entry. Pass NULL to have it not returned, + * the name is freed on errors, and for a duplicate a log message is + * printed. Pass not NULL, and when the error is a duplicate, the function + * returns NULL, and the variable is set true. The name is not freed + * when there is a duplicate, no error is printed by this function. * @return local_zone or NULL on error, caller must printout memory error. */ struct local_zone* local_zones_add_zone(struct local_zones* zones, uint8_t* name, size_t len, int labs, uint16_t dclass, - enum localzone_type tp); + enum localzone_type tp, int* duplicate); /** * Delete a zone. Caller must hold the zones lock. diff --git a/services/rpz.c b/services/rpz.c index cc8e663a2..43ae97328 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -698,6 +698,34 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname, return; } + /* For not a local-data action. + * Insert the zone, then detect a duplicate, instead of find it first, + * for speed of searching the tree once. */ + if(a != RPZ_LOCAL_DATA_ACTION) { + int duplicate = 0; + lock_rw_wrlock(&lz->lock); + tp = rpz_action_to_localzone_type(a); + z = local_zones_add_zone(lz, dname, dnamelen, + dnamelabs, rrclass, tp, &duplicate); + if(z == NULL) { + if(duplicate) { + char* rrstr = dname_rdata_to_str(dname, dnamelen, rrtype, + rrclass, ttl, rdata, rdata_len); + verbose(VERB_ALGO, "rpz: skipping duplicate record: %s", rrstr); + free(rrstr); + free(dname); + lock_rw_unlock(&lz->lock); + return; + } + log_warn("rpz: create failed, out of memory"); + lock_rw_unlock(&lz->lock); + /* dname will be free'd in failed local_zone_create() */ + return; + } + lock_rw_unlock(&lz->lock); + return; + } + lock_rw_wrlock(&lz->lock); /* exact match */ z = local_zones_find(lz, dname, dnamelen, dnamelabs, LDNS_RR_CLASS_IN); @@ -713,7 +741,7 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname, if(z == NULL) { tp = rpz_action_to_localzone_type(a); z = local_zones_add_zone(lz, dname, dnamelen, - dnamelabs, rrclass, tp); + dnamelabs, rrclass, tp, NULL); if(z == NULL) { log_warn("rpz: create failed"); lock_rw_unlock(&lz->lock); diff --git a/testcode/unitmain.c b/testcode/unitmain.c index 79ce45f39..bbbf6750b 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -1265,7 +1265,7 @@ static void localzone_parents_test(void) nmlabs = dname_count_size_labels(nm, &nmlen); lock_rw_wrlock(&z2->lock); local_zones_add_zone(z2, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN, - local_zone_always_nxdomain); + local_zone_always_nxdomain, NULL); lock_rw_unlock(&z2->lock); } /* The trees should be the same, iterate and check the nodes */