From: Daniel Salzman Date: Wed, 19 Apr 2023 17:28:27 +0000 (+0200) Subject: test-extra: add test for XFR over QUIC X-Git-Tag: v3.4.dev~138^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2b9f79f02ffb9afdc5cee1627a092fcdf5f4621b;p=thirdparty%2Fknot-dns.git test-extra: add test for XFR over QUIC --- diff --git a/tests-extra/tests/quic/xfr/test.py b/tests-extra/tests/quic/xfr/test.py new file mode 100644 index 0000000000..f06330fbb3 --- /dev/null +++ b/tests-extra/tests/quic/xfr/test.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 + +'''Test of zone transfers over QUIC.''' + +from dnstest.test import Test +from dnstest.utils import * +import random + +t = Test(quic=True, tsig=True) # TSIG needed to skip weaker ACL rules + +master = t.server("knot") +slave = t.server("knot") +rnd_zones = t.zone_rnd(1, records=50) + \ + t.zone_rnd(1, records=500) + \ + t.zone_rnd(1, records=1000) +zones = t.zone(".") + rnd_zones + +t.link(zones, master, slave) + +for z in rnd_zones: + master.dnssec(z).enable = True + +MSG_DENIED_NOTIFY = "ACL, denied, action notify" +MSG_DENIED_TRANSFER = "ACL, denied, action transfer" +MSG_RMT_NOTAUTH = "server responded with error 'NOTAUTH'" +MSG_RMT_BADCERT = "failed (unknown certificate key)" +MSG_TSIG_ERROR = "failed (failed to verify TSIG)" + +def check_error(server, msg): + for i in range(10): + if server.log_search(msg): + return + t.sleep(1) + detail_log("Failed log expected") + set_err("MISSING ERROR LOG") + +def upd_check_zones(master, slave, zones, prev_serials): + for z in rnd_zones: + master.random_ddns(z, allow_empty=False) + serials = slave.zones_wait(zones, prev_serials) + t.xfr_diff(master, slave, zones, prev_serials) + return serials + +try: + t.start() +except Failed as e: + stderr = t.out_dir + "/" + str(e).split("'")[1] + "/stderr" + with open(stderr) as fstderr: + if "QUIC" in fstderr.readline(): + raise Skip("QUIC support not compiled in") + raise e + +# Check initial AXFR without cert-key-based authentication +serials = master.zones_wait(zones) +slave.zones_wait(zones, serials, equal=True, greater=False) +if slave.log_search(MSG_TSIG_ERROR): + set_err("INCOMPLETE TRANSFER") +t.xfr_diff(master, slave, zones) + +# Check master not authenticated due to bad cert-key +master.cert_key = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=" +slave.gen_confile() +slave.reload() +master.ctl("zone-notify") +check_error(master, MSG_RMT_NOTAUTH) +check_error(slave, MSG_DENIED_NOTIFY) +slave.ctl("zone-retransfer") +check_error(slave, MSG_RMT_BADCERT) + +# Check IXFR with cert-key-based authenticated master +master.fill_cert_key() +slave.gen_confile() +slave.reload() +serials = upd_check_zones(master, slave, rnd_zones, serials) + +# Check slave not authenticated due to bad cert-key +slave.cert_key = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=" +master.gen_confile() +master.reload() +master.ctl("zone-notify") +check_error(master, MSG_RMT_BADCERT) +slave.ctl("zone-retransfer") +check_error(slave, MSG_RMT_NOTAUTH) +check_error(master, MSG_DENIED_TRANSFER) + +# Check IXFR with cert-key-based authenticated slave +slave.fill_cert_key() +master.gen_confile() +master.reload() +serials = upd_check_zones(master, slave, rnd_zones, serials) + +t.end() diff --git a/tests-extra/tools/dnstest/server.py b/tests-extra/tools/dnstest/server.py index d1e87d33ee..2b2569b1fd 100644 --- a/tests-extra/tools/dnstest/server.py +++ b/tests-extra/tools/dnstest/server.py @@ -158,6 +158,8 @@ class Server(object): self.addr = None self.addr_extra = list() self.port = 53 # Needed for keymgr when port not yet generated + self.quic_port = None + self.cert_key = str() self.udp_workers = None self.bg_workers = None self.fixed_port = False @@ -517,6 +519,17 @@ class Server(object): f.write(self.get_config()) f.close() + def fill_cert_key(self): + try: + out = check_output([self.control_bin] + self.ctl_params + ["status", "cert-key"], + stderr=open(self.dir + "/call.err", mode="a")) + key = out.rstrip().decode('ascii') + if key != "-": + self.cert_key = key + except CalledProcessError as e: + raise Failed("Can't get certificate key, server='%s', ret='%i'" % + (self.name, e.returncode)) + def dig(self, rname, rtype, rclass="IN", udp=None, serial=None, timeout=None, tries=3, flags="", bufsize=None, edns=None, nsid=False, dnssec=False, log_no_sep=False, tsig=None, addr=None, source=None): @@ -1295,6 +1308,8 @@ class Knot(Server): s.item_str("listen", "%s" % self.addr) else: s.item_str("listen", "%s@%s" % (self.addr, self.port)) + if self.quic_port: + s.item_str("listen-quic", "%s@%s" % (self.addr, self.quic_port)) if self.udp_workers: s.item_str("udp-workers", self.udp_workers) if self.bg_workers: @@ -1348,10 +1363,16 @@ class Knot(Server): s.begin("remote") have_remote = True s.id_item("id", master.name) - if master.addr.startswith("/"): - s.item_str("address", "%s" % master.addr) + if master.quic_port: + s.item_str("address", "%s@%s" % (master.addr, master.quic_port)) + s.item_str("quic", "on") + if master.cert_key: + s.item_str("cert-key", master.cert_key) else: - s.item_str("address", "%s@%s" % (master.addr, master.port)) + if master.addr.startswith("/"): + s.item_str("address", "%s" % master.addr) + else: + s.item_str("address", "%s@%s" % (master.addr, master.port)) if self.tsig: s.item_str("key", self.tsig.name) if master.no_xfr_edns: @@ -1363,10 +1384,16 @@ class Knot(Server): s.begin("remote") have_remote = True s.id_item("id", slave.name) - if slave.addr.startswith("/"): - s.item_str("address", "%s" % slave.addr) + if slave.quic_port: + s.item_str("address", "%s@%s" % (slave.addr, slave.quic_port)) + s.item_str("quic", "on") + if slave.cert_key: + s.item_str("cert-key", slave.cert_key) else: - s.item_str("address", "%s@%s" % (slave.addr, slave.port)) + if slave.addr.startswith("/"): + s.item_str("address", "%s" % slave.addr) + else: + s.item_str("address", "%s@%s" % (slave.addr, slave.port)) if self.tsig: s.item_str("key", self.tsig.name) servers.add(slave.name) @@ -1404,6 +1431,8 @@ class Knot(Server): s.item_str("address", master.addr) if master.tsig: s.item_str("key", master.tsig.name) + if master.cert_key: + s.item_str("cert-key", master.cert_key) s.item("action", "notify") servers.add(master.name) for slave in z.slaves: @@ -1416,6 +1445,8 @@ class Knot(Server): s.item_str("address", slave.addr) if slave.tsig: s.item_str("key", slave.tsig.name) + if slave.cert_key: + s.item_str("cert-key", slave.cert_key) s.item("action", "[transfer, update]") servers.add(slave.name) s.end() diff --git a/tests-extra/tools/dnstest/test.py b/tests-extra/tools/dnstest/test.py index 0a06d55e4f..8fcf6355ad 100644 --- a/tests-extra/tools/dnstest/test.py +++ b/tests-extra/tools/dnstest/test.py @@ -31,13 +31,14 @@ class Test(object): rel_time = time.time() start_time = 0 - def __init__(self, address=None, tsig=None, stress=True): + def __init__(self, address=None, tsig=None, stress=True, quic=False): if not os.path.exists(Context().out_dir): raise Exception("Output directory doesn't exist") self.out_dir = Context().out_dir self.data_dir = Context().test_dir + "/data/" self.zones_dir = self.out_dir + "/zones/" + self.quic = quic if address == 4 or address == 6: self.addr = Test.LOCAL_ADDR[address] @@ -196,6 +197,7 @@ class Test(object): server.port = self._gen_port() server.ctlport = self._gen_port() + server.quic_port = self._gen_port() if self.quic else None for server in self.servers: server.gen_confile()