Proper parent identification for dynamically entered local zones (#1076)

- Fix #1059: Intermittent DNS blocking failure with local-zone and
  always_nxdomain. Addition of local_zones dynamically via
  unbound-control was not finding the zone's parent correctly.
This commit is contained in:
Yorgos Thessalonikefs
2024-05-24 15:21:40 +02:00
committed by GitHub
parent 7107d3c9e7
commit 6f030e9672
4 changed files with 163 additions and 35 deletions
+102
View File
@@ -1252,6 +1252,107 @@ static void edns_ede_answer_encode_test(void)
regional_destroy(region);
}
#include "services/localzone.h"
/* Utility function that compares two localzone trees */
static void compare_localzone_trees(struct local_zones* z1,
struct local_zones* z2)
{
struct local_zone *node1, *node2;
lock_rw_rdlock(&z1->lock);
lock_rw_rdlock(&z2->lock);
/* size should be the same */
unit_assert(z1->ztree.count == z2->ztree.count);
for(node1=(struct local_zone*)rbtree_first(&z1->ztree),
node2=(struct local_zone*)rbtree_first(&z2->ztree);
(rbnode_type*)node1 != RBTREE_NULL &&
(rbnode_type*)node2 != RBTREE_NULL;
node1=(struct local_zone*)rbtree_next((rbnode_type*)node1),
node2=(struct local_zone*)rbtree_next((rbnode_type*)node2)) {
int labs;
/* the same zone should be at the same nodes */
unit_assert(!dname_lab_cmp(
node1->name, node1->namelabs,
node2->name, node2->namelabs,
&labs));
/* the zone's parent should be the same on both nodes */
unit_assert(
(node1->parent == NULL && node2->parent == NULL) ||
(node1->parent != NULL && node2->parent != NULL));
if(node1->parent) {
unit_assert(!dname_lab_cmp(
node1->parent->name, node1->parent->namelabs,
node2->parent->name, node2->parent->namelabs,
&labs));
}
}
lock_rw_unlock(&z1->lock);
lock_rw_unlock(&z2->lock);
}
/* test that zone addition results in the same tree from both the configuration
* file and the unbound-control commands */
static void localzone_parents_test(void)
{
struct local_zones *z1, *z2;
size_t i;
char* zone_data[] = {
"one",
"a.b.c.one",
"b.c.one",
"c.one",
"two",
"c.two",
"b.c.two",
"a.b.c.two",
"a.b.c.three",
"b.c.three",
"c.three",
"three",
"c.four",
"b.c.four",
"a.b.c.four",
"four",
"."
};
unit_show_feature("localzones parent calculation");
z1 = local_zones_create();
z2 = local_zones_create();
/* parse test data */
for(i=0; i<sizeof(zone_data)/sizeof(zone_data[0]); i++) {
uint8_t* nm;
int nmlabs;
size_t nmlen;
struct local_zone* z;
/* This is the config way */
z = lz_enter_zone(z1, zone_data[i], "always_nxdomain",
LDNS_RR_CLASS_IN);
lock_rw_unlock(&z->lock);
lz_init_parents(z1);
/* This is the unbound-control way */
nm = sldns_str2wire_dname(zone_data[i], &nmlen);
if(!nm) unit_assert(0);
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);
lock_rw_unlock(&z2->lock);
}
/* The trees should be the same, iterate and check the nodes */
compare_localzone_trees(z1, z2);
/* cleanup */
local_zones_delete(z1);
local_zones_delete(z2);
}
/** localzone unit tests */
static void localzone_test(void)
{
localzone_parents_test();
}
void unit_show_func(const char* file, const char* func)
{
printf("test %s:%s\n", file, func);
@@ -1325,6 +1426,7 @@ main(int argc, char* argv[])
tcpreuse_test();
msgparse_test();
edns_ede_answer_encode_test();
localzone_test();
#ifdef CLIENT_SUBNET
ecs_test();
#endif /* CLIENT_SUBNET */