]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
catalog: avoid opening catalogDB from worker threads...
authorLibor Peltan <libor.peltan@nic.cz>
Mon, 9 Aug 2021 09:27:03 +0000 (11:27 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Mon, 9 Aug 2021 12:02:48 +0000 (14:02 +0200)
...in case of concurrency, it might lead to server crash on startup
this way, catalogDB is only opened from main thread in advance

src/knot/catalog/catalog_update.c
src/knot/zone/zonedb-load.c
tests-extra/tests/catalog/multi/data/catalog1.zone [new file with mode: 0644]
tests-extra/tests/catalog/multi/data/catalog2.zone [new file with mode: 0644]
tests-extra/tests/catalog/multi/data/catalog3.zone [new file with mode: 0644]
tests-extra/tests/catalog/multi/test.py [new file with mode: 0644]

index effaa8db9fc2f6e9b8c68269008ec458e73f4676..1f2f259bc8d7da38ee011ad21738e480f32cd360 100644 (file)
@@ -350,14 +350,9 @@ static int del_all_cb(const knot_dname_t *member, const knot_dname_t *owner,
 
 int catalog_update_del_all(catalog_update_t *u, catalog_t *cat, const knot_dname_t *zone)
 {
-       int ret = catalog_open(cat);
-       if (ret != KNOT_EOK) {
-               return ret;
-       }
-
        pthread_mutex_lock(&u->mutex);
        del_all_ctx_t ctx = { zone, u };
-       ret = catalog_apply(cat, NULL, del_all_cb, &ctx, false);
+       int ret = catalog_apply(cat, NULL, del_all_cb, &ctx, false);
        pthread_mutex_unlock(&u->mutex);
        return ret;
 }
index 7f7f0b1c0ff62ef87db6c9ef66c2ccd506d100b7..a8152f28d1cd3133d725dbe2197c3d720b34f15a 100644 (file)
@@ -161,6 +161,11 @@ static zone_t *create_zone_new(conf_t *conf, const knot_dname_t *name,
                        zone_free(&zone);
                        return NULL;
                }
+       } else if (conf_opt(&role) == CATALOG_ROLE_INTERPRET) {
+               ret = catalog_open(&server->catalog);
+               if (ret != KNOT_EOK) {
+                       log_error("failed to open catalog database (%s)", knot_strerror(ret));
+               }
        }
 
        if (zone_expired(zone)) {
diff --git a/tests-extra/tests/catalog/multi/data/catalog1.zone b/tests-extra/tests/catalog/multi/data/catalog1.zone
new file mode 100644 (file)
index 0000000..1d49760
--- /dev/null
@@ -0,0 +1,7 @@
+$ORIGIN catalog1.
+$TTL 0
+
+@ SOA ns admin 1 25 25 80 600
+  NS ns
+ns AAAA ::0
+version TXT "2"
diff --git a/tests-extra/tests/catalog/multi/data/catalog2.zone b/tests-extra/tests/catalog/multi/data/catalog2.zone
new file mode 100644 (file)
index 0000000..b392528
--- /dev/null
@@ -0,0 +1,7 @@
+$ORIGIN catalog2.
+$TTL 0
+
+@ SOA ns admin 1 25 25 80 600
+  NS ns
+ns AAAA ::0
+version TXT "2"
diff --git a/tests-extra/tests/catalog/multi/data/catalog3.zone b/tests-extra/tests/catalog/multi/data/catalog3.zone
new file mode 100644 (file)
index 0000000..6a92639
--- /dev/null
@@ -0,0 +1,7 @@
+$ORIGIN catalog3.
+$TTL 0
+
+@ SOA ns admin 1 25 25 80 600
+  NS ns
+ns AAAA ::0
+version TXT "2"
diff --git a/tests-extra/tests/catalog/multi/test.py b/tests-extra/tests/catalog/multi/test.py
new file mode 100644 (file)
index 0000000..bf6129e
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+
+'''Test of multiple Catalog zones.'''
+
+from dnstest.test import Test
+from dnstest.utils import set_err, detail_log
+import dnstest.params
+
+import glob
+import shutil
+from subprocess import DEVNULL, PIPE, Popen
+import subprocess
+import random
+import dns
+
+t = Test()
+
+def cat_zf(server, zone):
+    return server.zones[zone.name].zfile.path
+
+def upd_cat_zf(server, zone, member):
+    uniq = str(random.randint(1000000, 9999999))
+    ptr = "%s.zones.%s 0 PTR %s" % (uniq, zone.name, member)
+    with open(cat_zf(server, zone), "a") as zf:
+        zf.write(ptr + "\n")
+
+def check_exists(server, member, expect_exists, msg):
+    resp = server.dig(member, "SOA")
+    rc = dns.rcode.to_text(resp.resp.rcode())
+    if rc == "SERVFAIL":
+        if not expect_exists:
+            set_err("%s: exists %s" % (msg, member))
+    elif rc == "REFUSED":
+        if expect_exists:
+            set_err("%s: not exists %s" % (msg, member))
+    else:
+        set_err("Unexpected rcode %s" % rc)
+
+master = t.server("knot")
+
+# Zone setup
+zone = t.zone("example.com.") + t.zone("catalog1.", storage=".") + t.zone("catalog2.", storage=".") + t.zone("catalog3.", storage=".")
+
+t.link(zone, master)
+
+master.zones["catalog1."].catalog = True
+master.zones["catalog2."].catalog = True
+master.zones["catalog3."].catalog = True
+
+t.start()
+t.sleep(5)
+
+upd_cat_zf(master, zone[1], "member1.example.")
+upd_cat_zf(master, zone[2], "member2.example.")
+upd_cat_zf(master, zone[3], "member3.example.")
+
+master.ctl("zone-reload %s" % zone[1].name)
+t.sleep(5)
+
+check_exists(master, "member1.example.", True, "First")
+check_exists(master, "member2.example.", False, "First")
+check_exists(master, "member3.example.", False, "First")
+
+master.ctl("zone-reload %s" % zone[2].name)
+t.sleep(5)
+
+check_exists(master, "member1.example.", True, "Second")
+check_exists(master, "member2.example.", True, "Second")
+check_exists(master, "member3.example.", False, "Second")
+
+t.end()