]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
zonedb/reverse: bugfix: removal/modification of zone:
authorLibor Peltan <libor.peltan@nic.cz>
Sun, 3 Aug 2025 13:35:54 +0000 (15:35 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Mon, 4 Aug 2025 15:00:49 +0000 (17:00 +0200)
 * removal of forward zone unlinks all dependent reverses
 * rem/modification of reverse zone first unlinks all to avoid
   leftovers+duplicates

src/contrib/ucw/lists.c
src/contrib/ucw/lists.h
src/knot/zone/zone.c
src/knot/zone/zone.h
src/knot/zone/zonedb-load.c
tests-extra/tests/zone/reverse/test.py

index 01af28f3114b18d34bcd26caca44d156ad4d4482..4d93009dc69183258c8851c1d769e0dd42875e56 100644 (file)
@@ -240,6 +240,22 @@ void ptrlist_rem(ptrnode_t *node, knot_mm_t *mm)
        mm_free(mm, node);
 }
 
+/**
+ * ptrlist_rem - remove all nodes with given pointer
+ * \p list: ptrlist
+ * \p val: pointer to remove
+ * \p mm: memory context
+ */
+void ptrlist_find_rem(list_t *list, void *val, knot_mm_t *mm)
+{
+       ptrnode_t *n, *nxt;
+       WALK_LIST_DELSAFE(n, nxt, *list) {
+               if (n->d == val) {
+                       ptrlist_rem(n, mm);
+               }
+       }
+}
+
 /**
  * ptrlist_deep_free - free all nodes incl referenced data
  * \p list: list nodes
index 1a3ca955e69f58c8b39fe7ea4f5c3dad46c264b6..d8ed449ab6a75eec05f52666a6e1ea828ce704f0 100644 (file)
@@ -68,6 +68,7 @@ typedef struct ptrnode {
 ptrnode_t *ptrlist_add(list_t *, void *, knot_mm_t *);
 void ptrlist_free(list_t *, knot_mm_t *);
 void ptrlist_rem(ptrnode_t *node, knot_mm_t *mm);
+void ptrlist_find_rem(list_t *list, void *val, knot_mm_t *mm);
 void ptrlist_deep_free(list_t *, knot_mm_t *);
 
 typedef void (*ptrlist_free_cb)(void *);
index 3cf34bb2e2a7ce3d0c10870d020aea8966dbbebd..ba11aa1134259af81b6aea24d026226a17531299 100644 (file)
@@ -811,6 +811,11 @@ void zone_local_notify_subscribe(zone_t *zone, zone_t *subscribe)
        ptrlist_add(&zone->internal_notify, subscribe, NULL);
 }
 
+void zone_local_notify_unsubscribe(zone_t *zone, zone_t *subscribe)
+{
+       ptrlist_find_rem(&zone->internal_notify, subscribe, NULL);
+}
+
 void zone_local_notify(zone_t *zone)
 {
        ptrnode_t *n;
index ff2d2747e3a1079e72ab269590bf6dba1be9907e..ef861f2a397a0a7dcedc5a1bcf489fef7397ad92 100644 (file)
@@ -284,6 +284,7 @@ int zone_master_try(conf_t *conf, zone_t *zone, zone_master_cb callback,
 int zone_dump_to_dir(conf_t *conf, zone_t *zone, const char *dir);
 
 void zone_local_notify_subscribe(zone_t *zone, zone_t *subscribe);
+void zone_local_notify_unsubscribe(zone_t *zone, zone_t *subscribe);
 void zone_local_notify(zone_t *zone);
 
 int zone_set_master_serial(zone_t *zone, uint32_t serial);
index e7dc1658ab36e913139f41187f7c2b2807e60005..785820116554222b339c7b3e1ce612ccb63c3dcc 100644 (file)
@@ -389,6 +389,12 @@ static void reg_reverse(conf_t *conf, knot_zonedb_t *db_new, zone_t *zone)
                return;
        }
 
+       ptrnode_t *n;
+       WALK_LIST(n, zone->reverse_from) {
+               zone_local_notify_unsubscribe(n->d, zone);
+       }
+       ptrlist_free(&zone->reverse_from, NULL);
+
        conf_val_t val = conf_zone_get(conf, C_REVERSE_GEN, zone->name);
        while (val.code == KNOT_EOK) {
                const knot_dname_t *forw_name = conf_dname(&val);
@@ -406,6 +412,21 @@ static void reg_reverse(conf_t *conf, knot_zonedb_t *db_new, zone_t *zone)
        }
 }
 
+static void unreg_reverse(zone_t *zone)
+{
+       ptrnode_t *n;
+       WALK_LIST(n, zone->reverse_from) {
+               zone_local_notify_unsubscribe(n->d, zone);
+       }
+       ptrlist_free(&zone->reverse_from, NULL);
+
+       WALK_LIST(n, zone->internal_notify) {
+               zone_t *reverse = n->d;
+               ptrlist_find_rem(&reverse->reverse_from, zone, NULL);
+       }
+       ptrlist_free(&zone->internal_notify, NULL);
+}
+
 static bool same_group(zone_t *old_z, zone_t *new_z)
 {
        if (old_z->catalog_group == NULL || new_z->catalog_group == NULL) {
@@ -450,6 +471,7 @@ static knot_zonedb_t *create_zonedb_commit(conf_t *conf, server_t *server)
                                reg_reverse(conf, db_new, zone);
                        } else if (type & CONF_IO_TUNSET) {
                                zone_t *zone = knot_zonedb_find(db_new, name);
+                               unreg_reverse(zone);
                                knot_zonedb_del(db_new, name);
                                catalog_generate_rem(zone, db_new);
                        } else {
@@ -510,6 +532,7 @@ static knot_zonedb_t *create_zonedb_catalog(conf_t *conf, server_t *server,
                        break;
                case CAT_UPD_REM:
                        zone = knot_zonedb_find(db_new, upd->member);
+                       unreg_reverse(zone);
                        knot_zonedb_del(db_new, upd->member);
                        catalog_generate_rem(zone, db_new);
                        break;
index 81a5c1a230d57ddf6556f8b10c0707cdffb1583c..08ad7e3bf8a031be7b3c45c7ff03a4600b66c0bb 100644 (file)
@@ -6,8 +6,11 @@ Test of autogenerating reverse zone.
 
 from dnstest.utils import *
 from dnstest.test import Test
+from dnstest.libknot import libknot
 import random
 
+DYNAMIC = random.choice([False, True])
+
 t = Test()
 
 knot = t.server("knot")
@@ -70,9 +73,21 @@ knot.zones_wait(zones, serials, equal=True, greater=False) # check that sole rel
 r = knot.dig("8.2.0.192.in-addr.arpa.", "PTR")
 r.check(rcode="NOERROR", rdata="dns1.example2.com.")
 
-knot.zones.pop(zones[2].name)
-knot.gen_confile()
-knot.reload()
+if DYNAMIC:
+    ctl = libknot.control.KnotCtl()
+    ctl.connect(os.path.join(knot.dir, "knot.sock"))
+    ctl.send_block(cmd="conf-begin")
+    resp = ctl.receive_block()
+    ctl.send_block(cmd="conf-unset", section="zone", item="domain", data=zones[2].name)
+    resp = ctl.receive_block()
+    ctl.send_block(cmd="conf-commit")
+    resp = ctl.receive_block()
+    ctl.send(libknot.control.KnotCtlType.END)
+    ctl.close()
+else:
+    knot.zones.pop(zones[2].name)
+    knot.gen_confile()
+    knot.reload()
 t.sleep(5)
 
 knot.update_zonefile(zones[0], version=2)
@@ -85,9 +100,21 @@ r.check(rcode="REFUSED", nordata="dns2.example.com.")
 r = knot.dig("5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.1.0.0.2.ip6.arpa.", "PTR")
 r.check(rcode="NOERROR", rdata="added2.example.com.")
 
-knot.zones.pop(zones[0].name)
-knot.gen_confile()
-knot.reload()
+if DYNAMIC:
+    ctl = libknot.control.KnotCtl()
+    ctl.connect(os.path.join(knot.dir, "knot.sock"))
+    ctl.send_block(cmd="conf-begin")
+    resp = ctl.receive_block()
+    ctl.send_block(cmd="conf-unset", section="zone", item="domain", data=zones[0].name)
+    resp = ctl.receive_block()
+    ctl.send_block(cmd="conf-commit")
+    resp = ctl.receive_block()
+    ctl.send(libknot.control.KnotCtlType.END)
+    ctl.close()
+else:
+    knot.zones.pop(zones[0].name)
+    knot.gen_confile()
+    knot.reload()
 t.sleep(5)
 
 r = knot.dig("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.1.0.0.2.ip6.arpa.", "PTR")