summaryrefslogtreecommitdiffstats
path: root/tests/knot
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:24:08 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:24:08 +0000
commitf449f278dd3c70e479a035f50a9bb817a9b433ba (patch)
tree8ca2bfb785dda9bb4d573acdf9b42aea9cd51383 /tests/knot
parentInitial commit. (diff)
downloadknot-f449f278dd3c70e479a035f50a9bb817a9b433ba.tar.xz
knot-f449f278dd3c70e479a035f50a9bb817a9b433ba.zip
Adding upstream version 3.2.6.upstream/3.2.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/knot')
-rw-r--r--tests/knot/semantic_check_data/cdnskey.cds123
-rw-r--r--tests/knot/semantic_check_data/cdnskey.delete.both113
-rw-r--r--tests/knot/semantic_check_data/cdnskey.delete.invalid.cdnskey113
-rw-r--r--tests/knot/semantic_check_data/cdnskey.delete.invalid.cds113
-rw-r--r--tests/knot/semantic_check_data/cdnskey.invalid123
-rw-r--r--tests/knot/semantic_check_data/cdnskey.invalid.param123
-rw-r--r--tests/knot/semantic_check_data/cdnskey.nocdnskey101
-rw-r--r--tests/knot/semantic_check_data/cdnskey.nocds110
-rw-r--r--tests/knot/semantic_check_data/cdnskey.nodnskey111
-rw-r--r--tests/knot/semantic_check_data/cdnskey.orphan.cdnskey135
-rw-r--r--tests/knot/semantic_check_data/cdnskey.orphan.cds138
-rw-r--r--tests/knot/semantic_check_data/cname_extra_01.zone18
-rw-r--r--tests/knot/semantic_check_data/cname_extra_02.signed76
-rw-r--r--tests/knot/semantic_check_data/cname_multiple.zone15
-rw-r--r--tests/knot/semantic_check_data/delegation.signed43
-rw-r--r--tests/knot/semantic_check_data/different_signer_name.signed52
-rw-r--r--tests/knot/semantic_check_data/dname_apex_nsec3.signed25
-rw-r--r--tests/knot/semantic_check_data/dname_children.zone16
-rw-r--r--tests/knot/semantic_check_data/dname_extra_ns.zone16
-rw-r--r--tests/knot/semantic_check_data/dname_multiple.zone16
-rw-r--r--tests/knot/semantic_check_data/dnskey_param_error.signed70
-rw-r--r--tests/knot/semantic_check_data/duplicate.signature19
-rw-r--r--tests/knot/semantic_check_data/glue_apex_both.missing14
-rw-r--r--tests/knot/semantic_check_data/glue_apex_one.missing16
-rw-r--r--tests/knot/semantic_check_data/glue_besides.missing17
-rw-r--r--tests/knot/semantic_check_data/glue_deleg.missing17
-rw-r--r--tests/knot/semantic_check_data/glue_in_apex.missing13
-rw-r--r--tests/knot/semantic_check_data/glue_in_deleg.valid16
-rw-r--r--tests/knot/semantic_check_data/glue_no_foreign.valid13
-rw-r--r--tests/knot/semantic_check_data/glue_wildcard.valid22
-rw-r--r--tests/knot/semantic_check_data/invalid_ds.signed106
-rw-r--r--tests/knot/semantic_check_data/missing.signed20
-rw-r--r--tests/knot/semantic_check_data/no_error_delegation_bitmap.signed61
-rw-r--r--tests/knot/semantic_check_data/no_error_nsec3_optout.signed29
-rw-r--r--tests/knot/semantic_check_data/no_rrsig.signed48
-rw-r--r--tests/knot/semantic_check_data/no_rrsig_with_delegation.signed61
-rw-r--r--tests/knot/semantic_check_data/ns_apex.missing11
-rw-r--r--tests/knot/semantic_check_data/nsec3_chain_01.signed80
-rw-r--r--tests/knot/semantic_check_data/nsec3_chain_02.signed94
-rw-r--r--tests/knot/semantic_check_data/nsec3_chain_03.signed94
-rw-r--r--tests/knot/semantic_check_data/nsec3_ds.signed57
-rw-r--r--tests/knot/semantic_check_data/nsec3_missing.signed120
-rw-r--r--tests/knot/semantic_check_data/nsec3_optout.signed81
-rw-r--r--tests/knot/semantic_check_data/nsec3_optout_ent.all15
-rw-r--r--tests/knot/semantic_check_data/nsec3_optout_ent.invalid18
-rw-r--r--tests/knot/semantic_check_data/nsec3_optout_ent.valid20
-rw-r--r--tests/knot/semantic_check_data/nsec3_param_invalid.signed70
-rw-r--r--tests/knot/semantic_check_data/nsec3_wrong_bitmap_01.signed70
-rw-r--r--tests/knot/semantic_check_data/nsec3_wrong_bitmap_02.signed70
-rw-r--r--tests/knot/semantic_check_data/nsec_broken_chain_01.signed72
-rw-r--r--tests/knot/semantic_check_data/nsec_broken_chain_02.signed65
-rw-r--r--tests/knot/semantic_check_data/nsec_missing.signed67
-rw-r--r--tests/knot/semantic_check_data/nsec_multiple.signed66
-rw-r--r--tests/knot/semantic_check_data/nsec_wrong_bitmap_01.signed73
-rw-r--r--tests/knot/semantic_check_data/nsec_wrong_bitmap_02.signed73
-rw-r--r--tests/knot/semantic_check_data/rrsig_rdata_ttl.signed52
-rw-r--r--tests/knot/semantic_check_data/rrsig_signed.signed62
-rw-r--r--tests/knot/semantic_check_data/rrsig_ttl.signed52
-rw-r--r--tests/knot/test_acl.c314
-rw-r--r--tests/knot/test_changeset.c166
-rw-r--r--tests/knot/test_conf.c274
-rw-r--r--tests/knot/test_conf.h50
-rw-r--r--tests/knot/test_conf_tools.c74
-rw-r--r--tests/knot/test_confdb.c489
-rw-r--r--tests/knot/test_confio.c1100
-rw-r--r--tests/knot/test_digest.c474
-rw-r--r--tests/knot/test_dthreads.c148
-rw-r--r--tests/knot/test_fdset.c150
-rw-r--r--tests/knot/test_journal.c880
-rw-r--r--tests/knot/test_kasp_db.c233
-rw-r--r--tests/knot/test_node.c128
-rw-r--r--tests/knot/test_process_query.c201
-rw-r--r--tests/knot/test_query_module.c87
-rw-r--r--tests/knot/test_requestor.c188
-rw-r--r--tests/knot/test_semantic_check.in169
-rw-r--r--tests/knot/test_server.c72
-rw-r--r--tests/knot/test_server.h100
-rw-r--r--tests/knot/test_unreachable.c59
-rw-r--r--tests/knot/test_worker_pool.c152
-rw-r--r--tests/knot/test_worker_queue.c57
-rw-r--r--tests/knot/test_zone-tree.c135
-rw-r--r--tests/knot/test_zone-update.c337
-rw-r--r--tests/knot/test_zone_events.c99
-rw-r--r--tests/knot/test_zone_serial.c159
-rw-r--r--tests/knot/test_zone_timers.c110
-rw-r--r--tests/knot/test_zonedb.c115
86 files changed, 10024 insertions, 0 deletions
diff --git a/tests/knot/semantic_check_data/cdnskey.cds b/tests/knot/semantic_check_data/cdnskey.cds
new file mode 100644
index 0000000..6ce5610
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.cds
@@ -0,0 +1,123 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144147 25752 example.com.
+ dEDk41MHSAAoc2eboWOXxGQHYFj1gXuD/gfX
+ Qz6HEq44narP0IHuOWt4ni9HUhYDBuanPp7S
+ j/8nYnZc6gdpMg== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144147 25752 example.com.
+ 1HFpOHudUJp7hvrsTmdX6qt+X0I4K9RYo/Uy
+ gpWbJBNhNsPVENVrw8AabhnPaETJGbreS/4T
+ slgbxM1Ks/erzA== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144147 25752 example.com.
+ EA9rtC9Ub4LPDwS6Q8wE4g9nGddbVrg9ivHN
+ oHQzUjTFlxtn8gFPaJkUfHwqwg3PsSVGagyx
+ Bjsool21k/TG7A== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144147 25752 example.com.
+ YLQPkC55O9bpQI/Hg/Ih91UkieeM3wtQvJMT
+ ro3QJ2eDImSyeoIbWsF+ghtoQ+6IUulXLu3k
+ PtDViOe2tfaL/Q== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ 1J1lDp/FQFgAGv7EFeDTAru7rUIcUCc7bkYj
+ 8OlczfdQjo9IfS5MFg6MqIrE/KPC18CDX1Ki
+ DzaCFaMGDlavjQ==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 25752
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ hRcbHnvrTqCb215+XsIn96tvHacV5d15lcnS
+ h91pg8Htes3H0vOoG98C5oWXoj7RM4V/tDoH
+ /0ahiLyRzRnvBA==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 20197
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144147 20197 example.com.
+ JLKC5uLW1+JPkOyVcc8D6B6lCC/0FOlak/Qd
+ Na6Nb33hi9io1HMFI1eYiG7u7lxWmXsKnBo9
+ ONROz+WYGds++Q== )
+ 3600 CDS 53851 8 2 (
+ 6F8129D687EC387C948E6F4B0AC9AA01481C
+ CEBF7570AFEC582897E7725122D6 )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144147 20197 example.com.
+ pgi1+O/TWU6WCmLLYEibCYj+RzbcOuodnF1i
+ wlBQxDZLTcGYG+1KEC0spZTN1nQncEfdeEKc
+ jnYQUa0izPQRnA== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144147 25752 example.com.
+ MaFyQcB908WIXS+RiLeLXiKdjOo/R6tl9AM/
+ 6xokhcvRqQzuyQeoH4snUvcht0m5ghz09Km7
+ MPN0uzJcXIGg0Q== )
+ 3600 CDNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144147 20197 example.com.
+ Vdo7aYGIByxiC85dyqLKrrNAYYDFBnKXm8uE
+ rYSXBMWiQoFHwzvlavyqhUWlEABfvYD0pUrX
+ PZ27Hz8rPFCSLQ== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144147 25752 example.com.
+ 9Llt7e4nm8uMLqliT2NZJINmAmLmKDYqjloj
+ Q3/wNI4K+J0RUmWpg3f6xODVkKjjuVnwpxkK
+ eWV9zqY4jUTAGg== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144147 25752 example.com.
+ lZSHyLdXGFvoL9fhk26y70ifFwui2A5bpdir
+ Su7VhfsnNdLgNuCceRXbYwxQaUyODCl7dcJ9
+ UkRzq2eDs0evKQ== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144147 25752 example.com.
+ dDE1XApt4lZ9u20Z/vXwhJxE27AZJQzKwLkk
+ jpwEDVJo6/SdV2smB7s7+qmGnSKhIehVpUFX
+ wv3/3YaFxSTifQ== )
diff --git a/tests/knot/semantic_check_data/cdnskey.delete.both b/tests/knot/semantic_check_data/cdnskey.delete.both
new file mode 100644
index 0000000..b3b840b
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.delete.both
@@ -0,0 +1,113 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144234 36859 example.com.
+ uHjgn9WEMdw/d//q2ZhGF1GAQItK9UPyByET
+ VDuZgER/JBHuFd1/MMEkkFmCRneXuVudSnki
+ aXiza0GLV0ujfw== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144234 36859 example.com.
+ 39YAhtx1qe9sbJ/6N1fS7F4QLS9iqagdbQN4
+ w6VRyMRrseRY16G2n3Th9yw1+R9aXOazb6iP
+ BL6azQJiUCZJ5g== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144234 36859 example.com.
+ EXv3vV7Njpz59INdubRpDsGANROKfEhqBzQ8
+ zSL1vujpUOdaZWqmS3uoKusxHCghJacCFeUA
+ KQNrWNuZHT2S8g== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144234 36859 example.com.
+ LgXpsIgBZBO03iU6D2nqsbmal6AK51ev21Cj
+ PQFfFBLQ+ARqyE3k7mlTK4A+/UfIpWgpkKnz
+ St4SbtL3r6GK+g== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ l/Uak3BSxeoEO8n42GtZkS1aTdEV590rAuwS
+ Jvt8Gzyj1S5Aqx5Tytm+nb93ZtO3eSL2OpJg
+ p7tdmPjtHKxYpg==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 36859
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ jNkK9sXUo8jTJ2snaD+3Mao2q0m5UjyZ7ykD
+ 6yQqTJ2xgldvTCyuu/YlSCoR9gli8pOGz+KT
+ 3YA9HjG46ob8ug==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 65430
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144234 65430 example.com.
+ id6EVGBrg2vZm6vIIGNhSukuI2Uv6/MzZiJk
+ C1N9k5P3zAP6Es9aLp9m4cR8qGIdUu3DZ3AU
+ ngKndEZvk5YUUg== )
+ 3600 CDS 0 0 0 (
+ 00 )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144234 36859 example.com.
+ mDmiCviPRxQ1BiinR2+/lQ/KabHgIu/LSKZ2
+ yZFsgiF8YF4IT8mJc/qiKVtaCWLK4Sszxk/F
+ P8kMTmTKORT40Q== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144234 65430 example.com.
+ O1KH8u+VPLnd5TwGPRbv7VpMss+Mjwr+nIOE
+ UxSS7unksPUldU0e9qXby0fydlN5LTf/L0sD
+ daMwGOA2fuD/dA== )
+ 3600 CDNSKEY 0 3 0 (
+ AA==
+ ) ; ZSK; alg = 0 ; key id = 768
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144234 36859 example.com.
+ Hj8WJNT51BdqA6szAI7sn8gZftHY6/1/Y7qQ
+ DRsunh1J1cNRuqHtLBnRKpVdteZ4znNKnavb
+ uoC6kzSzbRiJzQ== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144234 65430 example.com.
+ 7YGVqSgaiHXwY+GdMkUJXZyqkGvkfA8LliB6
+ 6Nn4AvuETs4lX080MNq3dWmjI/tHSg5ptQz7
+ Hukvd6cYWNgtBQ== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144234 36859 example.com.
+ SVatJA8FhwAotw625XttyhgD8Rcp4ukcidii
+ By06YX9e5rCgOHOvjsHwA57kBBzcZg0ZXAbF
+ SOhDdUQibKaRSg== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144234 36859 example.com.
+ D+r82Tvm8eGuYrJKVCUMw1Gz+tevXwE2IGoG
+ 7pXErKbDv13p/eFAPsRdUKtdmsOq4mHSxQuZ
+ GVGAULfJjcs3pQ== )
diff --git a/tests/knot/semantic_check_data/cdnskey.delete.invalid.cdnskey b/tests/knot/semantic_check_data/cdnskey.delete.invalid.cdnskey
new file mode 100644
index 0000000..366edaf
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.delete.invalid.cdnskey
@@ -0,0 +1,113 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144623 39533 example.com.
+ wXvCukXPMbON0oD2nKINzyauQRgeYE/kIYKZ
+ pYaMwV5Z6yZ9SKSSy7oRBn7t1+rOmGI69NSx
+ 3WHXaRiLjcH1Sg== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144623 39533 example.com.
+ XNdl4tiEhUPOpEgwGO2njssc8QMB8IeP5QDM
+ 9/LZJUPZ0hZ76F7fX9C3X3edgysEoDFR1HAE
+ JdTxkJ5Oqv7Xig== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144623 39533 example.com.
+ Or2a9ZLl2FnBmNM1KbUcgAjgLKRS6O9H4XmK
+ VAGM3QxutaTZuF1sjsz+kNh6yrT38eLm5B8M
+ PLCxUmkTSUmgeA== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144623 39533 example.com.
+ 5SBXb1HpSfhPinO3hadK7E0lhRHwyUAsjZpy
+ /7jTO7/uUNXD6asY9V6kvOJmRgMpSeXFJKFw
+ +Vsyx0jifistyg== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ TQSEqjdF8egQ1YjZPdVXrX+pngPHTdCgwJFR
+ AefWVHOLsMADS3/LL5G+pZTSldB3j3Xo4Na/
+ 1tsuCgNmV+58xA==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 39533
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ VARBBNSEYzAbBYxgdQi/epYgWFaGnL49509p
+ CeZWg4LO4jhjVT7uyhsSQny2wyahP2Y37YeO
+ d+sY503BNpqzMQ==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 59324
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144623 59324 example.com.
+ YRhAwruTjWmu6drb4+iJ/QOwQg8dnGur8LH7
+ bsn1ZCHQYNDHiIai8JqikqzkhEYKIK8HIqT8
+ F2RY/LqFxKebjg== )
+ 3600 CDS 0 0 0 (
+ 00 )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144623 39533 example.com.
+ cHTGBug23nTe/aS09JaakuG4wa9EEbWxL3gu
+ LQpCK8HV/JMsNSGqh1FsUlX92y4tSIvJn+Lx
+ vvdN+Qzh+zASHg== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144623 59324 example.com.
+ GU9Q/CipUscofDL6uhT2ZmhQoyApLX9zbyfN
+ dG5XW6sXYaB94hVSiT2DSyt19fyQwYoKK2Br
+ fJwy4pI890kKoQ== )
+ 3600 CDNSKEY 0 3 0 (
+ BA==
+ ) ; ZSK; alg = 0 ; key id = 1792
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144623 39533 example.com.
+ CXeUfFxa7aT2tivKLovVQ2CA0HYZxxlUrbm1
+ voABTNkU7lb5W9Z7GQ/VDugd8QeKNK8YWOaQ
+ Tdl79jkL1rQKXw== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144623 59324 example.com.
+ sd+fzJmLLIoFIcbKCJ+rHE+tOs0PwHjjY9ml
+ Dsbel1k5sANI4xR8iMv6YAEhcpvb0S+8Nd7h
+ 7BT45SkKVtyFsQ== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144623 39533 example.com.
+ VGa9LkgVATBLHOwMBNc6g74iXCCSXnWWNs8O
+ ndoXk4ZMMRRkmaxSWXH2pBdJLZPL5f26aEVl
+ 4toVcsE722LoFA== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144623 39533 example.com.
+ i+94RvIQBBEOza7Y963huNEWYrqt/VT/eE1E
+ Gqx5kngvZgZ7wO8tcOsaE7ctb69SvgZwRR9c
+ RBgb2N6ezo9OxA== )
diff --git a/tests/knot/semantic_check_data/cdnskey.delete.invalid.cds b/tests/knot/semantic_check_data/cdnskey.delete.invalid.cds
new file mode 100644
index 0000000..9d63eb9
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.delete.invalid.cds
@@ -0,0 +1,113 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144646 56106 example.com.
+ 1CRyeUic9BIwBWcjk95VQJktQng6f3dLQm64
+ JwGGqivUM3Hgp7URguNIx0BsCvfo67NIpk7N
+ mMIFwMkMGOHmgg== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144646 56106 example.com.
+ pB4+Z3ltuzY+/NkAeCb9LOS7Zlh7QLfHKimR
+ JPtvdOuIhd8vB0NZLzcYX0lIkrqyP3LadbrS
+ u8r9BMIlu4cKpg== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144646 56106 example.com.
+ x8XhP7r3/glI7AenoSLVmfqhZXQfj6YllgxA
+ jkVxExiM9OJZOPdyeDTuRyUD1PFiBOEsP7Wu
+ vNgWA9eyQFOslA== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144646 56106 example.com.
+ TCn7V7sHR2TNY5ywyEpbYZMegZwTX+I/TPeO
+ 76D3WORu9pN0kJWjGPAebwTvL/a7p8xS8B9U
+ X9ivUVFORG+mJA== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ cOjtacSzGkoh6bO4clqYPM2y+g5ezQUtCNdx
+ iRqickHCvQnL9OM/h7V8txqEsSulG5ZCeW+O
+ LDhDQDUchpNv7A==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 56106
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ pB2mCNXFJ8e+UaMeMmy1LSCv6TJ92Fs3kFxY
+ I8NyZPyGvfePpMlzWZr7Bw7wS6G6Jhayhj94
+ MMJ4lM/5+ZzVJw==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 45911
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144646 45911 example.com.
+ uOAPEzDkPNI9Uo2N+iiRkIb2p1Y0VhgqwUom
+ +Dssd6X0CEdQEmD8YQ43Cuq9ZNwk8Bm+lgm3
+ X+ImdIKeE4MvNQ== )
+ 3600 CDS 0 0 0 (
+ 01 )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144646 45911 example.com.
+ IN5tLpm7OKjIL4VpucR1ero1Gv5UEyVqjzB9
+ rRJefwUtlZFKNaTbU0oQD33vQXEjUiIMr66b
+ zIC3Ju/YtYFDLg== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144646 56106 example.com.
+ f8VJa9GRwSWNmg0AR4nA3OD4X8im7BriZjME
+ 2ypYUOJkdIafolyb0LDz7XWTaVsFHQWO0z+J
+ 14g0CgCroTm3pQ== )
+ 3600 CDNSKEY 0 3 0 (
+ AA==
+ ) ; ZSK; alg = 0 ; key id = 768
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144646 45911 example.com.
+ 89oeIQuH82i2RYIj/fnX/71s8kspDHcI8lIa
+ R02OZZ9bF37bi6LbGkypdXpmxN9/rEjk4ThF
+ IHRX2USEPtl+wQ== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144646 56106 example.com.
+ Hgf4SgtoV0IHsF6feSP8YqeibPTtwZelLpLs
+ hux/D94MFKtYa6OseyzT3qIDdixav+mlI2ud
+ 0JyflYZ6MCBlxg== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144646 56106 example.com.
+ XdhVQ3Na3LsvdtT2HwdsM3ItiD3UH0HO6TZD
+ W6/jy8r0NA6fTN4b4oVr6wSqHAQIQVYUbWER
+ 7pav2Ek03LDa0Q== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144646 56106 example.com.
+ dVTxTNAfZy5sa0SW8eme+KMx3hByBnPIrRlF
+ zGDsGN1Xzw3OBhsTmuOwhbnZSnnvdBrhBOJw
+ 8eU/6zpcZypyFQ== )
diff --git a/tests/knot/semantic_check_data/cdnskey.invalid b/tests/knot/semantic_check_data/cdnskey.invalid
new file mode 100644
index 0000000..6937db5
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.invalid
@@ -0,0 +1,123 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144725 7800 example.com.
+ fIUb0+hjrELDVphcGgDZemNVpq1TBgyTt184
+ 9YnzaAhADynsscEd5iZRjuA5r7mlI/M9fFtU
+ l6wpEmqAs7sG5w== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144725 7800 example.com.
+ 86HnJEU3jP+bL9JmnY+2TGwna7DGtUVvgdhu
+ slzGQWN3EHb51vx1fHQGGfQlJ4P4ch5US3TE
+ 1rd/OKNUBE+p7w== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144725 7800 example.com.
+ 33SrrSRr8KwasK7qfxYAPxP//dj8Y9i95oza
+ 2Fwvt23QxfZS3TBLqMyMA6G/nmXyavUxsye8
+ C+mks7QsS7HJCA== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144725 7800 example.com.
+ WRb17ehBEEjIVl//Zw8vtDmbnTY6eLWe2KQ2
+ +E+pCMEK0QE1qXwcethJ9PkM+gKFmN9RscXH
+ DjrmWIAfgndjsA== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ VxRHPS89GaMJvJ1xL8/HulwW75tDXUZ6nYlI
+ 8VCFOMB7vU+SoZhaaoZu4YcCZqzjzfZLl8Lt
+ SEaXZPQbnpkhyA==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 7800
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ MWndPmlRdffYHO8Z2quMkXq80Nm3PNmWpTix
+ xJLJ71Oph+ta4XaTuiza6AQgVkCSzrfwoTuJ
+ UKHL13s4/IrRGg==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 46605
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144725 46605 example.com.
+ GRVgc202uXoxu8f36V/Tc4r9BzCKK07SCmS6
+ MCJ+mXO7PCv4RIzN9Dp8t6sVuDb5smLe6cV6
+ 5lgyPYJwr1TVJA== )
+ 3600 CDS 53851 8 2 (
+ 668159D684EC387C948E6F4B0AC9AA01481C
+ CEBF7570AFEC582897E7725122D6 )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144725 7800 example.com.
+ r+OpHWsZ0enCPKtUIZFXSb/8YbLdfYb3Ihpt
+ n/5kAWbOkkkVzAJX2/sCrVExMCVcP/nFSIIf
+ hACGKBjTvuLFLA== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144725 46605 example.com.
+ buNL2/GqYvtwcXMPSiOeaEB5L6r5InyVxzaJ
+ 1PaaJigmJHbdNKGFl8ijDiH7WBdQECb8M3oU
+ zeuWGebSLuy0AQ== )
+ 3600 CDNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144725 7800 example.com.
+ wYB3zuX5/bt3Pg2nz9F0j6MK1bkY19QvDcRb
+ pk/0rHXLbSjTepbIwy8O0KbJndHy+a70fN5p
+ 3dBGN5J56KymFg== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144725 46605 example.com.
+ pXWJCUC0kKqWpjZetDhGJLNPpXGqc8sJZ9wY
+ HKs4Sd734p+Gr45vnJ94pGYjjtZi9bwPo2nF
+ DmFP5K3NLACG+Q== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144725 7800 example.com.
+ Khv6ptUd4l4SgJI/H+L6Ls/gQHnmmQJcg0fB
+ xv7zECmQfQFguVIJ1bmoz4jP26ejsNH1pG+o
+ Wz9U7I5oWsDzYg== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144725 7800 example.com.
+ z8omQAty9S0cNyFATnM8DZ+RbMly/7staAmc
+ RF+PmOp/E7FtdKOZe5+ega/+aQV9VpePYXMA
+ UwmIeeYYU2pAJQ== )
diff --git a/tests/knot/semantic_check_data/cdnskey.invalid.param b/tests/knot/semantic_check_data/cdnskey.invalid.param
new file mode 100644
index 0000000..2814ddd
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.invalid.param
@@ -0,0 +1,123 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144756 33730 example.com.
+ tBomI7xR670RBUw9IjNL2A5eMVKtYqDUdhiq
+ XJI3CFdb4j6plfdUF75SfaiCP70aLX8Atzxm
+ 2RAzpR6M2Q3gbQ== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144756 33730 example.com.
+ 8mHEeq/7fnXpM/CaOFsIqTKyTrixQVZr8V+P
+ Lwn641YbbKniEP+KacrJ7Ul2jt2jCT2cnxC0
+ b9XicHENmd0phA== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144756 33730 example.com.
+ f8ZdC3vD/oIltQLyL4zBmwo9rRyijN183BGw
+ L6iZ6DnH4BASlUyrGa0IceRH4yD5pP+gnhCc
+ lBzWFgvtEIyPPQ== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144756 33730 example.com.
+ UK+oQx75Gdn82LKBzht8KxrtwPE5JCBhEMcR
+ hRhHTeMqRUjbbeEOSWRdjg/36329yNYrxC60
+ l7bBcqolo9dDmw== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ kr0M2egbhUXhH0i6fYiSl+zRH1pU7XhamCdO
+ nPhMEgFa3CsGp61kCuZFulpY0ODh8WrAPZcO
+ qC0tCj5Bz7nWZQ==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 33730
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ 7fs6TMYYlkkxI1PCunVT9dxcxWVGXu1N7xVv
+ 2EUyVYMXSn/Z04URNTaxXcoWuDafy99G8rcT
+ oPycl2oOhc+s0w==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 60664
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144756 60664 example.com.
+ WpjHrB8ZfAhOSjq79gAaPEiQgSxvEatTi8nC
+ AYYpGs4dc1n54iYZ4IjCfMW/etlkZsMzXbVE
+ s6t+Dj/gJ3JKZg== )
+ 3600 CDS 53851 4 2 (
+ 6F8129D687EC387C948E6F4B0AC9AA01481C
+ CEBF7570AFEC582897E7725122D6 )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144756 33730 example.com.
+ IAgBYDhTIYQvmF2vUy72TWoRlPJQGyGErJuT
+ 0xxZDStaSfoAVM3Hr6VEqIq7R3B+Xel/urDM
+ WYUbIAinEnvpOw== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144756 60664 example.com.
+ IpzPg5fx+O1HUqjN0lR1Bbo6Zx/Lq1wrrJvv
+ Y518ooGelg8Q2wH7NgScsyhLY342+MHk0fKX
+ RcxRzfaFohiEZg== )
+ 3600 CDNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144756 33730 example.com.
+ WMqSVG8Tcq7e5E2y8oHThr6Ip7ASu/35m10m
+ TzsEANrlFf0e1Z6XG5ca/6//NSolXoTu6jBx
+ 2kvnsX2bA222PA== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144756 60664 example.com.
+ LLGAWxuAhlKM/3i9+FFGngy6Zqo6NsxdXScR
+ wgVe3Ilw+3vU/Nih70uRE/xUjZpfFBOlMEk6
+ EBSf/DJr6awY/A== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144756 33730 example.com.
+ mpcGxsR9c/K6wuaJCeFds1kg0af6Xj8K24o6
+ FHzqn60w7HXXNnDjxS0jPTHpaVUkWhuKUcCR
+ 9EcvMW7uwVfULQ== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144756 33730 example.com.
+ gLwhcu1t0qloiWb5/XHuv0PAQZ+ChmDdMuMS
+ qS3hi0VPk9cscMjd7ZH7shJBH+9KKMI6YbMz
+ VGU4MSCj5/kT0A== )
diff --git a/tests/knot/semantic_check_data/cdnskey.nocdnskey b/tests/knot/semantic_check_data/cdnskey.nocdnskey
new file mode 100644
index 0000000..a7bac63
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.nocdnskey
@@ -0,0 +1,101 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144854 39620 example.com.
+ 0JDLQ/bZj4SSmqvLPAzt1v/UUb8mfJQnuLC9
+ B1CL4oRD45Hw00KgmbE7xgJVflYZJxfx7KIw
+ ydsB0/1/dMJzbA== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144854 39620 example.com.
+ Mnk/oSM7sdAhGYbWUMLpYFR1ahcvULo/8z42
+ giRwzAX8HiqvxxkqRCFbvzYeRkZLLw0fYTeR
+ Mqit0zQuWuc0ow== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144854 39620 example.com.
+ qPQblbJyzHdmhqYhYx4wfUHWe3SYGUA65hZR
+ UFYcx99Vhs1CXUobjCk9NBedRbBHR04kQ5Bo
+ /72fhuCPJFIC1Q== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144854 39620 example.com.
+ H5So5m0YdxOBU3k0+pi6KOgPNF2V4hU+GLxa
+ c0JdGnALP4Wz6lWCdMRPXIaMjImb3TK9vFti
+ 89lB/2MMDe4dTw== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ 6R8b9KzH06NQ/4AUqrmp8rFmY0AmHpbW/vhj
+ xLul6ON720xvdeKBzi0nLSeTdUO8/gK8s8jh
+ RmJ8Fw279eXXZQ==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 39620
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ hfwsa6JnfqjMRma2PlO+gt8qqLytVIygLZHB
+ 5APAuz2cheZCMD8A2kyt5NziCCj6szmCK4oZ
+ fColPGaDgYtpmA==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 6821
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144854 6821 example.com.
+ UbEQQoX5j1FVOqpkQBqckaG4WnCd7+4dBJax
+ 5sgjHQnfSSwKGfJx0zxd3ZbPCEKj+Ymrhpsm
+ nqfPzVRZhUPKuQ== )
+ 3600 CDS 53851 8 2 (
+ 6F8129D687EC387C948E6F4B0AC9AA01481C
+ CEBF7570AFEC582897E7725122D6 )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144854 6821 example.com.
+ Sc/K9xI1C9rzujnllO5o7sKoJiEKFUEfPxt8
+ gsxs3sb9Q1s0/uSocrPc2OcaLgEzuFGS5FzA
+ fg7HcgZN63I5TA== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144854 39620 example.com.
+ ykGu61Yjp24MJjp0wIYV20LSQ9ovRHT0zqp2
+ CSvlROIVpbUGlNjAAKJdWwYJAqNUD571gJ7E
+ TkhrLEIX02ySqw== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144854 39620 example.com.
+ ye5pM/p8OWbdRNhLfbfWsY6lG8lr0Ae80LKv
+ rVOCMhAowrtKmDL6hUByovCV7MjCIYwGM26C
+ Vl9CRmrWwJEULw== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144854 39620 example.com.
+ JHP3TuxCuZ+N0lWtRI7Xl0qIcHSrn/X+WDUr
+ 0cVBfQTsFrAZs14bJhvw0zMGgONAgnFsXlxg
+ QmAqIPmpRvKtnA== )
diff --git a/tests/knot/semantic_check_data/cdnskey.nocds b/tests/knot/semantic_check_data/cdnskey.nocds
new file mode 100644
index 0000000..ecb3188
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.nocds
@@ -0,0 +1,110 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144849 42608 example.com.
+ GDfM/H4m+FRVp3M/KsOv//eMFaL1LnyrIi8O
+ pUSht1KyYDRoVqSL72XTy1aAJJ49Sd0uq+4U
+ acekI3Xi9OpvXg== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144849 42608 example.com.
+ ICtOUMZr415dJb22HWsrjbYfW7q6hh6gxD2i
+ EikMQAkPncdBHHd7dCrjy1/4CPhixn/BnDfV
+ ZwF87k2Sa7EV8w== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144849 42608 example.com.
+ IokJy9LCiCaOPsluuBKYnwkesiPwsU/KZdA9
+ jK25UmdfD1uU8AA63OOciTZQSv9NI+Q4nzl3
+ LyqkRWFKToMz9A== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144849 42608 example.com.
+ kuhtgHhoeIwJ8IG08x+Tp5M7kQ+LzWoH/hTs
+ V17ZSyPD06YvMEmv9vdB+ATLd+j3uNYnMd4n
+ HW7Jh/ocOWg6+Q== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ p9BANIrBFV9hX2qwbzydeiubQkm9qstpzvUe
+ OFMDOEyyQxI+8s2nfHI76KmRliHuM7fOM9B5
+ e8wNmEeVd9JJmQ==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 42608
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ 5sv4MetMS4KWSgyzvn658Prs0A8tLaWFhRJD
+ E9IznhGY2ogp8Z/uSIqh8QWzf1kQvfDUQiav
+ kOx4CNa3dSx/ZA==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 8616
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144849 8616 example.com.
+ DeZBLj99QbyGhalCZ4UOmBJO/RLNgrPsAdaW
+ swYSg18lvE7jmLn9vxkUVZu0G6z43tulSb+a
+ lQT8m+U+PlusNA== )
+ 3600 CDNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144849 8616 example.com.
+ IlysaALuak04Zbh0+104PHAuQgnYDBTLpvz+
+ BgirzX9Vp+pg4yZVelAXsaDbcj2ZrXrwBjpo
+ +DHj53HmZygj4g== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144849 42608 example.com.
+ dJhB1Xmd3G1ueRVnFU+M4yc379LH0UrpBcNS
+ xHzjVd+vWtpNGPq03Wi3sczA9UUkXE0F5n22
+ 6ZNR5XAswf+SYw== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144849 42608 example.com.
+ 3DTwpPojzX4r9ZWeKo+zmJw+2L/uqrtoAZEv
+ ncPJG0AGB9QVzjLFiRg0BV4GiDZCl2Hh4onl
+ OShOi5Nt0GXp5Q== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144849 42608 example.com.
+ 1m2PpD3S6/5x3Kkes+1JgbHtsm0xlnKrNCmF
+ xeBvCl55D98zSvs0DjfRjFowAg22nWJkvsWo
+ 3N1vnfFZpzmPPA== )
diff --git a/tests/knot/semantic_check_data/cdnskey.nodnskey b/tests/knot/semantic_check_data/cdnskey.nodnskey
new file mode 100644
index 0000000..461e05a
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.nodnskey
@@ -0,0 +1,111 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144347 19649 example.com.
+ Tng1e4Zs8LvGZJqp75aBSX9Ci9bsncY+w8+K
+ rfYdoVe/Smq0I+Hgtygcq0Twc7llW0rwtZ8R
+ jQpbXbp+XNDi3g== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144347 19649 example.com.
+ OcKfgxtnriGsC/9wV9yI71wIVzR+71j3sZ3+
+ ZGVqAo2bWR8QRULa5g5lQpIxlayN7w6xi6vV
+ IVWY3vauy59pPQ== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144347 19649 example.com.
+ CtZFcGvbco6ZreotcmfSYl8SlRdN/JiSuoOG
+ KtdauRz9+a+xkT2k1Wy6dADfLpwHwXL8yElg
+ /LdNXKEWK96HcQ== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144347 19649 example.com.
+ 6GVUlXemDUb6W9IID4qK+PPDSizeURGJEJlN
+ Hoof218/H/k8/BLNphFIGpdhCC2jHnAx2Nxd
+ Af65dTLtt7OBjQ== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ LiJCYpav6haPA3M3GhTZ/L6wtSqS7e9mwKsU
+ TdBkZ71RS8qmXsITLz5bFHMSy7K8mCuQIdTT
+ J3cGkbguNBqgJg==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 19649
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ j18Cd+0frtc1WPeWn8bwdxYd9iTe7XsqTwnO
+ W46ZpPJPGBq/n31+7/N9TRAtXulE2r+rJDRF
+ mMooK5qrWOtqvw==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 24385
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144347 24385 example.com.
+ 8O0L6xxTnGMccrMSjaG2/MtljkSOls/BIwoX
+ eUmB9nJvDQNd8jg9XtNYUGG79dmysetBrNQl
+ TohQ1BEVGTJwig== )
+ 3600 CDS 53851 8 2 (
+ 6F8129D687EC387C948E6F4B0AC9AA01481C
+ CEBF7570AFEC582897E7725122D6 )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144347 19649 example.com.
+ CLjvJJOAZVToWUQQX06ySDkKo4QO4YcN2vhl
+ JZZ2a1hA2ranrzpeE8cslGKme5lxHKr8Y1ev
+ ffWfrz8KoQVW+A== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144347 24385 example.com.
+ TaPgzUzL+fPwEUNyusjCb6OZOF3DtlMNh3eY
+ ZTvogl2eRq84NA+mfzPmh0NXqVDbsVHGHq1B
+ mJoxuMtIt4G5Rg== )
+ 3600 CDNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144347 19649 example.com.
+ 5sY/Q/1tP9qPMAHyQVMtbFQ0gO24rofCLg/D
+ /BaXTvjp5bnWhGuv1wFbSCyEreYr072Va08t
+ JdntIC8Prt/1MQ== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144347 24385 example.com.
+ UlLhm8Nb6g0jUIs1ldjW4OedzzLXDjCllRSm
+ +6WQuBK1uA7vboyqYVvLxxyFZCxgz6xV02iK
+ eawtsKsOnlfGCg== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144347 19649 example.com.
+ ZRDwnV+YyfKPI58ASagzoCo+qWTscYZZa6j+
+ wr4axJ7jtIO6Firy4R1GlO6NXmN5vcjHAj90
+ NZ26ezRgCMCFQQ== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144347 19649 example.com.
+ c5ILb+AR9BIinFp6mCogN+jwR8067Fm9LT9Y
+ AWaR3pqUC4d+Qdo4pkODLkmhAaSQLJCyPyYB
+ TQ7OFkQCC49MtA== )
diff --git a/tests/knot/semantic_check_data/cdnskey.orphan.cdnskey b/tests/knot/semantic_check_data/cdnskey.orphan.cdnskey
new file mode 100644
index 0000000..70241ab
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.orphan.cdnskey
@@ -0,0 +1,135 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144945 39996 example.com.
+ pdj652v0OfPO/McP8sNpxoE+adY+Qim5je8m
+ TQPcudU3gm7I2L+YqU/ujX1NUOyhUAhzRng7
+ m6nfrudJebq15g== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144945 39996 example.com.
+ 7/X57I7FmbSlgxxeaE3Xgoot7KxN6nxtDb0E
+ mEEZNwdLCpjgaftaXXXM3NaZ1W2sdoECCrlz
+ R4/75kqrmNpYPw== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144945 39996 example.com.
+ 0tcHIXXPEKy1tpc+Of6s2hTdQ5dGh1IoIoxY
+ se9paUUfhoF2oH5Pb8HP3rNyWLiTqXh4/lxV
+ vFLi4rR5zojxLA== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144945 39996 example.com.
+ kbImDj5vgk5VG9MI+4HJ4FtwnJ4ykSbk8vNY
+ e49ibkZChGsTtIzLwdcNAmOk7w/em67FkGBi
+ oxqCj6b3G0C45w== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ R4pG7HF8CbXgbo4N6UqdSnE8CaClNUw6v/di
+ aScNknRS0eLPOKmpANe0tyiwBV1bRQyjpmxq
+ fgZ9Oxac7plIJw==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 39996
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ cJdrUmmcxe9JKHwHHAkJ8mO1J63Cm6Qoln56
+ CUya+eWuF1A3u9L3wumvY2rAXvzBpplLXeUN
+ GIN0GgLHejH6QQ==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 56026
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144945 56026 example.com.
+ srEjUMAQ4Z/yc22bas+P0ly30IVbZaIIlli9
+ H7avBz013fn90vDRDLiLuHAMvW++xdDJypcg
+ Sr+9I9+nv6jzRA== )
+ 3600 CDS 53851 8 2 (
+ 6F8129D687EC387C948E6F4B0AC9AA01481C
+ CEBF7570AFEC582897E7725122D6 )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144945 39996 example.com.
+ inhdpEZ+2W4EM1HSiVZdJa4xT5S319D0x3b5
+ eJpskw/EV/Rx1X87FCr8FP18iBOszsWJjQQq
+ Z66eAxIhpBcb7A== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144945 56026 example.com.
+ TA7UxWd+j6bOXKPxo3XuKlIy87/HvIPGoELS
+ WQyrON5IURgGw/2YWD0M5xw852jl27USezzo
+ pai940D3+VGeOQ== )
+ 3600 CDNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 CDNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144945 39996 example.com.
+ CSk6oHNIsj3XQgXpPtFOhf4dTv/Wu/vnJfJs
+ Lpc3IoApBMxrpSIzfM/c72JtjSVzjJcdo6kL
+ n71WM21CsMcQ4A== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144945 56026 example.com.
+ hsml4IaJtzvMdvaMTR3MzeCT5fMHJ46rCY0y
+ 8DTAvK7/Z6LHbF4G7yRh9ozwcyZbB006cMdc
+ 4XUFDtEPK62DGw== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144945 39996 example.com.
+ 1cNj6TJEHFxLXFYVt3RU3wC8Wz/F5bfjy8/W
+ jEJdrnVzo1ihmJWoY48e9MlvsGXnGe4+GUrl
+ HSS+2bsGOS7DyA== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144945 39996 example.com.
+ 5mtXYcvidkSnG12dZof3xSEaH2eOsV2fuBvb
+ 8Eb6XEuPfD9v5g2mweyZYrBtowEsTA9IOsly
+ 6AWT5PfZbNAe+Q== )
diff --git a/tests/knot/semantic_check_data/cdnskey.orphan.cds b/tests/knot/semantic_check_data/cdnskey.orphan.cds
new file mode 100644
index 0000000..54732de
--- /dev/null
+++ b/tests/knot/semantic_check_data/cdnskey.orphan.cds
@@ -0,0 +1,138 @@
+example.com. 3600 IN SOA dns2.example.com. hostmaster.example.com. (
+ 2010135808 ; serial
+ 10800 ; refresh (3 hours)
+ 3600 ; retry (1 hour)
+ 1209600 ; expire (2 weeks)
+ 7200 ; minimum (2 hours)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201012144942 8996 example.com.
+ ThTlvNtautK64IeJRxNCr5acLrRu8jXkTR3N
+ y5TlXrei2DIagbPja++4vLjhUJAcKTGndD+x
+ wgMrDpCY6pMAYQ== )
+ 3600 NS dns2.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201012144942 8996 example.com.
+ 3OJiG3v9Nq9OHkyysT3A6PNPRVn9sYTQkHNS
+ 6JL5BzLCQ+uYKJBCu0ZPxDlYpbYnO0HKQ7Ta
+ iZYCjm7vzqtvwA== )
+ 3600 MX 10 mail.example.com.
+ 3600 RRSIG MX 13 2 3600 (
+ 20601231235959 20201012144942 8996 example.com.
+ 9vi3n2cVyr+ghB0ql4Wc8vhpLfAuclopapXw
+ BQV328nEwftj0okcPz4Z7Iye9by4X6NDd13x
+ vzWXDKjZCSxLJg== )
+ 7200 NSEC dns2.example.com. NS SOA MX RRSIG NSEC DNSKEY CDS CDNSKEY
+ 7200 RRSIG NSEC 13 2 7200 (
+ 20601231235959 20201012144942 8996 example.com.
+ HP8iIlUO+EKFRgoHUrQWLcaX8oSGEb/tldEP
+ GcJKM+rGMeJvxXOJnjSskUm7AyRK1TKK4RqE
+ xaOHTgIz1uUkzw== )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVw
+ YkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH
+ 1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6
+ jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEe
+ CUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
+ ) ; ZSK; alg = RSASHA256 ; key id = 48849
+ 3600 DNSKEY 256 3 13 (
+ bkP3kBcYNsUB6jpKA764AJeNBzGJjNIRPxDl
+ 2wK1O7I/bvZDILscWSMUsSRmxZuPWGLjevpp
+ Tve1UMe+dP9VIA==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 8996
+ 3600 DNSKEY 257 3 8 (
+ AwEAAaulfU2biYVBiUsGwAyCXbA+gm0yWgH2
+ Z71S16R2YNERlb0he9Od28DcFd0HbaKdFnw/
+ CtX7Z2UWs6/IRu8QmHGn6SKDsLzZ5StdPsJD
+ KilfvSlEcQeqrRAncug1SnA5BogNQSD0/02Y
+ w5KDGn7ALCSYlNgOgy7l+D/urlkuxgsPWvqY
+ XnlxaIcKt96fndwmkfZ5eF+WAqxguaNcvm14
+ 6NA53wRrWx8BQbcHk1R+WcQGqFcVOlifCs9z
+ V+87QJy2H660QKqOVDgt8PF8QmRRJqzOKpu2
+ 9T+Vd1dM3zjBJ7deLaNH2E5p7Bbp1eeOCeOt
+ WpCG6XfaRmZIF3ZWVM6Ways=
+ ) ; KSK; alg = RSASHA256 ; key id = 56474
+ 3600 DNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 DNSKEY 257 3 8 (
+ AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKf
+ jqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4
+ IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la
+ 7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU8
+ 0AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbm
+ LIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpM
+ CLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRn
+ dpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs
+ 9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n
+ /4lgdSiBtvByLCXoWEYIGRs=
+ ) ; KSK; alg = RSASHA256 ; key id = 19420
+ 3600 DNSKEY 257 3 13 (
+ 1OgEqruDg7pI2dTIRMdP9ihhdl3wFngZW9bP
+ E4jMg4ByKKoKM/C1QN4Q+BQiQDkcprwE9vLf
+ D/cLgFNspjcBgQ==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 63865
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201012144942 63865 example.com.
+ 9d2q8pWH1AftoDmPq3DNblta3oPV+6ROZmVR
+ BvjHj7xJjI27aY514C0qNkQVhioe2mhQjikO
+ gyxvkWwBV/owPg== )
+ 3600 CDS 53851 8 2 (
+ 6F8129D687EC387C948E6F4B0AC9AA01481C
+ CEBF7570AFEC582897E7725122D6 )
+ 3600 CDS 56474 8 2 (
+ 260E7ADB07D1ECC40DEE79EFF6527CF7119C
+ 0AFC1CFA5DAC1ADFE342568CF32D )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144942 8996 example.com.
+ E7iVsJZjRyGbjMUADsi9Chz74+t1W75zTPmm
+ MYVD77dkRHiEpN41MJB6Z7Fn1lNOE6f8q2B5
+ iL/3UXULB1vpwA== )
+ 3600 RRSIG CDS 13 2 3600 (
+ 20601231235959 20201012144942 63865 example.com.
+ fsMqYcBDcTBtaDEqDTYrHHivnuQKb629drhm
+ 77RFfBxFJAxlq176PzaddA++zHfWsBgIlJzy
+ VHFy3S3huuyfaQ== )
+ 3600 CDNSKEY 257 3 8 (
+ AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYT
+ oARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM
+ 2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5W
+ mnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Ta
+ x7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCN
+ bGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/
+ mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4N
+ odQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5
+ tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQ
+ EHYAd/AP8YgaovS8N1fJyh0=
+ ) ; KSK; alg = RSASHA256 ; key id = 53851
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144942 8996 example.com.
+ hhpJcQ4cMcq9fLNtZrTEVAMGB2bjMwcDvv4C
+ Sss9wWDBNxIVOsi4x3j/08PZTqbfmYePWtK8
+ k2R5GOOK1lpVlw== )
+ 3600 RRSIG CDNSKEY 13 2 3600 (
+ 20601231235959 20201012144942 63865 example.com.
+ xU82j/dJf8oBd1Ti2lHH0YoxBvgCQo2MOdwJ
+ yOc6fDrT/c39rCMT//VoDmmKj3SavQ92ABBt
+ 18JqxCXK7+tnYQ== )
+dns2.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201012144942 8996 example.com.
+ D3O6XOYrOT1tlCieJJvw7zys0ClqXcCvs5+D
+ qSEpKcE6RNNeJG2d3SJg95fbO+eTkw30MROF
+ ajnNh5xJ+8xsMQ== )
+ 7200 NSEC example.com. A RRSIG NSEC
+ 7200 RRSIG NSEC 13 3 7200 (
+ 20601231235959 20201012144942 8996 example.com.
+ sGBFze6wRGj8n0B8izUNHO2ufA72sR55U3OQ
+ RLYTx2XqBRvdmapMKK6QDu/6lmwqgYMbjiBJ
+ XqDLv/1RP4DisQ== )
diff --git a/tests/knot/semantic_check_data/cname_extra_01.zone b/tests/knot/semantic_check_data/cname_extra_01.zone
new file mode 100644
index 0000000..ae3f27a
--- /dev/null
+++ b/tests/knot/semantic_check_data/cname_extra_01.zone
@@ -0,0 +1,18 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111218 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+ NS dns1
+ MX 10 mail
+
+dns1 A 192.0.2.1
+
+; error CNAME, node contains other records
+email CNAME mail
+ A 192.0.2.2
diff --git a/tests/knot/semantic_check_data/cname_extra_02.signed b/tests/knot/semantic_check_data/cname_extra_02.signed
new file mode 100644
index 0000000..724a8da
--- /dev/null
+++ b/tests/knot/semantic_check_data/cname_extra_02.signed
@@ -0,0 +1,76 @@
+email.example.com. 3600 IN CNAME mail.example.com.
+ 3600 RRSIG CNAME 7 3 3600 (
+ 20840201000000 20160224073150 29600 example.com.
+ IxkF8oqOEzhlZDSRBIi4448EGvQwxm0QDFE3
+ JExA4Byx2QaJvXo8LoCeyQxS/f9E6bXpXQk2
+ 4dgQxUrRZqnKEA== )
+ 86400 NSEC example.com. CNAME RRSIG NSEC A
+ 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224073150 29600 example.com.
+ iKA+5qsYA7A7JN7Df99aJnToYESjqordQgVj
+ yMS/1RVBYEGE4y3ggehzAxvc8bsNYnUwGeGt
+ vse5dMVKCcIaPA== )
+; CNAME extra record A
+email.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224073150 29600 example.com.
+ DummySignatureDEADBEEFToYESjqordQgVj
+ yMS/1RVBYEGE4y3ggehzAxvc8bsNYnUwGeGt
+ vse5dMVKCcIaPA== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160224073150 29600 example.com.
+ MT+QgXcsDzkrFgncNwFyH8lwXiOTpj1rnPgs
+ OUIOfIhyJyzT1hpozAHt+IWOPHUkKjBN1C5y
+ SwyTnlqwJtG0yw== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160224073150 29600 example.com.
+ Mr0Gu7PUu9PsUBflhd8tMhcQ9+ve+z561/ml
+ kP6PL0MHgLg7V8KVmL2tc7+JAhSOVSpJ4BGQ
+ c9HKD15lFDFEgw== )
+ 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+ 86400 RRSIG NSEC 7 2 86400 (
+ 20840201000000 20160224073150 29600 example.com.
+ oEMpoEhi86OM/SdyobPEh90zF3c3FhOgv68j
+ paD5BLUsAntf3qU+KoIMb9iVglp+VTGrg0Ol
+ XdJ2D/xSMA+XHA== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224073150 29600 example.com.
+ WOtx+LBKbS2MOahlpDJMqgeH1TI5dZoQitmA
+ SOkDRlJgfPsiKeiaGMrnWN9xnPZOVr9MsInE
+ sKYjh6EZM1nuBQ== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224073150 31323 example.com.
+ nL4eJLv62C56wexu10DMPHqXCXSE/3vRe4es
+ 4e0e1CkY9bdj+LgLfgs7CH7UDNXFX2CxKxHd
+ mL4sp5AtaA8fnQ== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224073150 29600 example.com.
+ nn2dG+ORbcNQWHT87ijfOddx0SKCSE+8hAxt
+ SiQQpxAzPw13CZmnbYas8uvFFtth6U689V3h
+ rMzzZcxQEA1z8w== )
+ 86400 NSEC email.example.com. A RRSIG NSEC
+ 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224073150 29600 example.com.
+ BFz1Z7dbBNgHXDOaufuCoIzGHbwyLUrA+Wad
+ QBPD9xCYkXHoHfvVOhtEeMR19Rz+fi6ottJI
+ 4AWItiobBC/DAQ== )
diff --git a/tests/knot/semantic_check_data/cname_multiple.zone b/tests/knot/semantic_check_data/cname_multiple.zone
new file mode 100644
index 0000000..971c34f
--- /dev/null
+++ b/tests/knot/semantic_check_data/cname_multiple.zone
@@ -0,0 +1,15 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111214 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+ NS dns1
+
+dns1 A 192.0.2.1
+
+email CNAME mail
+email CNAME mail2
diff --git a/tests/knot/semantic_check_data/delegation.signed b/tests/knot/semantic_check_data/delegation.signed
new file mode 100644
index 0000000..2007216
--- /dev/null
+++ b/tests/knot/semantic_check_data/delegation.signed
@@ -0,0 +1,43 @@
+; Delegation NS and glue signed despite mustn't.
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 NS dns1.example.com.
+ 0 NSEC3PARAM 1 0 10 -
+
+example.com. 3600 DNSKEY 257 3 13 Yk8KOmyVzOij3x+Zs+eT4J2Up9+ipwXEKOhL9fTYY/DU10yIQt+zYm02UFZJX2oVTdHBCajpBFsZLH2X4ho1yw==
+example.com. 3600 DNSKEY 256 3 13 tCoteOM+A4o/A9uxgLyDg3HOg2DClU+3d+1XPQRtTfuaEFOGIpyH6qiFUv2b4DYuvmMyTkL99nxvyhA8yo0Cgg==
+example.com. 3600 RRSIG DNSKEY 13 2 3600 20400406103150 20210205090150 25674 example.com. 4tMK6g2B0ITXf2haSSuH45nO53GlpZQ97ofC5Pd/S38oeNzWmhfxIBaGtb597qxRA2NC7rYtGsscLrCa0sthMA==
+example.com. 3600 RRSIG NS 13 2 3600 20400406102301 20210205085301 61806 example.com. TrCJZgu1hVoUK532mmhQpZcEcPdw4FezPCymtUuQH9XjZNBn3DP/OhM8NvAbtailiOIX/djosTC2cNDlqSoVCQ==
+example.com. 3600 RRSIG SOA 13 2 3600 20400406102301 20210205085301 61806 example.com. h/+XG/WWQsoAuzOM2wiulY8TOslYTj4MyP7Rjj3VXx8frlheIN84yH7NL6Xgt3ibQJpJl7rujkDuoTBH+snnCw==
+example.com. 0 RRSIG NSEC3PARAM 13 2 0 20400406102301 20210205085301 61806 example.com. TYk9hqD6hWA8YH/G3VeggrUHb7CwX3ut5GGiAOcl9o8I0gdMIOu8E1uUukexvJsZAt1Fbcjc7ZIbsUmvgs2MVg==
+deleg.example.com. 3600 RRSIG NS 13 3 3600 20400406102301 20210205085301 61806 example.com. /Xg/3viyTMyd88hcByGifSMHGo3up83exBQQt4FC6qexZffRyNiLrHOfnoz/2LqFMg/oDVCsvqaEomiMM6FlZw==
+dns1.example.com. 3600 RRSIG A 13 3 3600 20400406102301 20210205085301 61806 example.com. zc6VOVGfgoB9C8/0WPHOVrdikBzK6xh25UtrdIYuSzcPWbFlWSsV3+xS1q20MBDb2dj635jcyBWRep+287rDLA==
+deleg.example.com. 3600 RRSIG A 13 3 3600 20400406103429 20210205090429 61806 example.com. 8hcIsHOARI1XXMcPXwtlmQC071+FBH+I0a6CufDbE7nPa38brBKomqTjiYF26K1KZ4IQASw5vvF0lFg3eEOZog==
+
+deleg.example.com. 3600 NS deleg.example.com.
+deleg.example.com. 3600 A 192.0.2.1
+dns1.example.com. 3600 A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201008173641 61552 example.com.
+ URGzLYXySdeOtXWW5ph64pNedd7/cq0WYcbd
+ nArHBIN2S08knOfV/OHOMDaR7WufUbIF8bPQ
+ FxDkURlAhZbH9A== )
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 3600 IN NSEC3 1 0 10 - (
+ MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938
+ A RRSIG )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 3600 IN NSEC3 1 0 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ NS RRSIG )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 3600 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+
+20g1gol477ro51rk9a9nfd54tfqal7iq.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406102301 20210205085301 61806 example.com. LUBULY9667EsrOHecNjp2QkW9JJW1fOSyTmleWul7vGFwuNC1mKVUQu3H3V5ndtwzU1YD69oa6eI2DOERmiJXg==
+mjv836rjqej5ubghvksq7n44rso3q938.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406105733 20210205092733 61806 example.com. zYuSttG565eDv3FPeKfZs4FNuJHD204/8nv8cNx+9iqbxMdh5s1XJx4nolWyiOJcBq+G8CmtiuJK6plUs7x67w==
+utqvuhu2blk3dhmrr5t1hd9vteohqt0a.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406102301 20210205085301 61806 example.com. aMivM0YOs4Il/WRWqf3SRzh21nZXau7VIJOpX2NK46qxBCW41N/+J7rXaeAT15ayWNjCHP1YoDwyuC/lVZtCqg==
diff --git a/tests/knot/semantic_check_data/different_signer_name.signed b/tests/knot/semantic_check_data/different_signer_name.signed
new file mode 100644
index 0000000..ff92f7b
--- /dev/null
+++ b/tests/knot/semantic_check_data/different_signer_name.signed
@@ -0,0 +1,52 @@
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201008164859 49259 example.com.
+ UH4IJhLwxWI9g2vycAuGAHm5XzsW5LKr6xeI
+ aoaiMeb1pepw9vAWEUO1Byimg7FfhvYpt7+J
+ IhYCvpBb6u3ucA== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201008164859 49259 example.com.
+ ou6B0AgSUxs7//b+c+Gm3XjC83TpgGvRwj9d
+ F48TEZCMRpdvtVNc1hDnNKa8oXA16TafbkqN
+ Z0ekrEo2LlN+hw== )
+ 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+ 86400 RRSIG NSEC 13 2 86400 (
+ 20601231235959 20201008164859 49259 example.com.
+ uCzqU8DU8ZMt3t/h0jwZjdVgSj33HhwtGwhE
+ ZglZ0gUVDVLndP5Q+psqlz2jBmiXIN16s/+b
+ di0crJ9LULq0NA== )
+ 3600 DNSKEY 256 3 13 (
+ qWpA6ejmc17FHZTN/YoYX4WdNN32LC2IlBmm
+ n2Yoi16OQ1e2ztEusvQaSwzEMbN2pIzfTIlF
+ YQQ1gzLQAhWIpg==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 49259
+ 3600 DNSKEY 257 3 13 (
+ rHQi5BOkLnSsZh1v9saRZ38MkzYLL0oGbAK2
+ Dp86tH3lpDqPoR7LM98gyBLZgp81m0YHAYnf
+ 2yK617XStIPw+A==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 3753
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201008164859 3753 example.com.
+ 81C/yn0gxkwOMUWNZPszGow4UyDuDn1V4WQJ
+ NXJfNiTvT6edQ0rQakhJPGgVyH4LIwWJV8Uk
+ fOubCv7BBgu0wg== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201008164859 49259 example.com.
+ x6z2ftS2deCBR9HJeIazQNrDdzw0lEE04UYp
+ npUe2zkIx6aH7MvvgZIjcFTwPOVsI00u7gaU
+ AzuxODSma50TXQ== )
+ 86400 NSEC example.com. A RRSIG NSEC
+; different signer name in RRSIG
+ 86400 RRSIG NSEC 13 3 86400 (
+ 20601231235959 20201008164859 49259 different.com.
+ K/URrUmli54Noy0E3REXBo/g0LZ/8gneyVfa
+ FrGXLB0kvQydPyceL+BFIoJP6d/Gs/0qkUjT
+ vMQfvF0x3bFS3w== )
diff --git a/tests/knot/semantic_check_data/dname_apex_nsec3.signed b/tests/knot/semantic_check_data/dname_apex_nsec3.signed
new file mode 100644
index 0000000..b083ce9
--- /dev/null
+++ b/tests/knot/semantic_check_data/dname_apex_nsec3.signed
@@ -0,0 +1,25 @@
+; Zone without any semantic error
+
+;; Zone dump (Knot DNS 2.6.0)
+example.com. 3600 SOA dns1.com. hostmaster.com. 2010111217 21600 3600 604800 86400
+example.com. 3600 NS dns1.com.
+example.com. 3600 DNAME bar.example.com.
+example.com. 0 CDNSKEY 257 3 13 Yk8KOmyVzOij3x+Zs+eT4J2Up9+ipwXEKOhL9fTYY/DU10yIQt+zYm02UFZJX2oVTdHBCajpBFsZLH2X4ho1yw==
+example.com. 0 CDS 25674 13 2 2EC05563A3537BD32EA3EB92C44794C644F249EE440785CF28207B903E35322D
+example.com. 3600 DNSKEY 256 3 13 tCoteOM+A4o/A9uxgLyDg3HOg2DClU+3d+1XPQRtTfuaEFOGIpyH6qiFUv2b4DYuvmMyTkL99nxvyhA8yo0Cgg==
+example.com. 3600 DNSKEY 257 3 13 Yk8KOmyVzOij3x+Zs+eT4J2Up9+ipwXEKOhL9fTYY/DU10yIQt+zYm02UFZJX2oVTdHBCajpBFsZLH2X4ho1yw==
+example.com. 0 NSEC3PARAM 1 0 10 151E9F1094FE188F
+;; DNSSEC signatures
+example.com. 3600 RRSIG NS 13 2 3600 20400406111136 20210205094136 61806 example.com. WIlxYlV/hn9mfojITrVbIV+Giy9b5pAKofkw62Yli+jIspQ3dC/WWLrM5Y4HcQwTfNp7yuhIS0jPzkuy0xuAxg==
+example.com. 3600 RRSIG SOA 13 2 3600 20400406111136 20210205094136 61806 example.com. z71ipK0zBRKKokzXdoZdtkxGC75MJbwmICNjSfd+IX/hneIGvFE7mTose1Zbb0WGgKRdUMEoii7hLZLrx7waqg==
+example.com. 3600 RRSIG DNAME 13 2 3600 20400406111136 20210205094136 61806 example.com. 5tIYeBwbwpVF0X5ZLoSpHeB8IYLU5/2fFYXqvctZYqTO24T0EBfu+++j66VSERAI38xf2Z0KkYcwx1XeIeivBQ==
+example.com. 3600 RRSIG DNSKEY 13 2 3600 20400406111136 20210205094136 25674 example.com. X3n5YVkjpSpK+IOCkhv/wFmF5WIPHUR2LXkNME84i5S4efvQiRRq/jgqos2f7OgfSi/9Q2Q2x6BiMQ1vx/R+Pw==
+example.com. 0 RRSIG NSEC3PARAM 13 2 0 20400406111136 20210205094136 61806 example.com. gogp8pZycFopDodl4IOfpaKCbLqXw2v+5DcV2YwmHr/pMwrc28bClQxw4HVGcYQ13HpC9kKmzmcrn3dEumTb3A==
+example.com. 0 RRSIG CDS 13 2 0 20400406111136 20210205094136 25674 example.com. zRQEFycg2sNVVB4TOZO8QcMwRwSA7tHJqkc1l9V+WtEdJY8UvYpYPPgAn9FjWMzzhvRMlws89TBSsQzqCemHiQ==
+example.com. 0 RRSIG CDNSKEY 13 2 0 20400406111136 20210205094136 25674 example.com. hLOpPxmKXU//dmQoE5OdCqzWkkJsuBHa8QITWB/A3Tc2CXQTaqFKqTspZvTLOAYKNaSVu6BOLWM7Fi2Bq3I0mQ==
+;; DNSSEC NSEC3 chain
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 NSEC3 1 1 10 151E9F1094FE188F ple28jlp3q5anh045ssk9f3u7ltd4qlc NS SOA DNAME RRSIG DNSKEY NSEC3PARAM CDS CDNSKEY
+;; DNSSEC NSEC3 signatures
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406111136 20210205094136 61806 example.com. C3JeKvcKdQO3zTJqg5Z114jTd36tgF7PIL2kCs7X6VnCaVe7E5NtwUuLMLFIw/gUqaLDbE7vQwHMK3Psl536aA==
+;; Written 17 records
+;; Time 2017-10-06 15:58:57 CEST
diff --git a/tests/knot/semantic_check_data/dname_children.zone b/tests/knot/semantic_check_data/dname_children.zone
new file mode 100644
index 0000000..5758833
--- /dev/null
+++ b/tests/knot/semantic_check_data/dname_children.zone
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111214 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+ NS dns1
+
+dns1 A 192.0.2.1
+ AAAA 2001:DB8::1
+
+foo DNAME bar
+bar.foo A 192.0.0.1
diff --git a/tests/knot/semantic_check_data/dname_extra_ns.zone b/tests/knot/semantic_check_data/dname_extra_ns.zone
new file mode 100644
index 0000000..e188742
--- /dev/null
+++ b/tests/knot/semantic_check_data/dname_extra_ns.zone
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111214 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+ NS dns1
+
+dns1 A 192.0.2.1
+ AAAA 2001:DB8::1
+
+foo DNAME bar
+foo NS dns1
diff --git a/tests/knot/semantic_check_data/dname_multiple.zone b/tests/knot/semantic_check_data/dname_multiple.zone
new file mode 100644
index 0000000..2a6c0a2
--- /dev/null
+++ b/tests/knot/semantic_check_data/dname_multiple.zone
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111214 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+ NS dns1
+
+dns1 A 192.0.2.1
+ AAAA 2001:DB8::1
+
+foo DNAME bar1
+foo DNAME bar2
diff --git a/tests/knot/semantic_check_data/dnskey_param_error.signed b/tests/knot/semantic_check_data/dnskey_param_error.signed
new file mode 100644
index 0000000..1a2e936
--- /dev/null
+++ b/tests/knot/semantic_check_data/dnskey_param_error.signed
@@ -0,0 +1,70 @@
+; Zone without any semantic error
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ W9EprjaR4loSnNW96h4rLsquPDw3LHYvD05k
+ djkQofHSkMNZAJ7Q+eA3Fs2ik5fnJFM7wi5C
+ MtFsV2TfqMJFmg== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ I9Je1S7XhZIW9C0fWE8NwFLC2rhHklddNYBO
+ dxVKL/lxENU4jPPBwZBGrcYn2WVHgkIzjG0n
+ EOHONAgRFPi3Xw== )
+ 3600 DNSKEY 1 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 5 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ vO2UQiTN/CNUZOmSEg8kJlR/UqiAZHc4qMwj
+ 9u31sbPmOMuni+ZGuVCFFoEMtZerIkkQowkB
+ sXJFkvCP5oF2rA== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160229083110 31323 example.com.
+ Z+aaLu4rmzekfhlj6A0ClREloRi8MloRHf/3
+ Dlw/RYY1hrOCfcZKEY6AXeVdUwESEsSkSOco
+ CbhyGHH10dKAAg== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160229083110 29600 example.com.
+ d69kc52VdALI8fbdbflsVsltc1m7bI6QsJ5U
+ IDE9fy5VqcufZecZMKuozPDuF2vBA8ADFIRU
+ OfYgKs6YNIOLWg== )
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 1 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ A RRSIG )
+ 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229083110 29600 example.com.
+ D24JCtCcNzwsY1FXVliAjxMm+x95N2eUTXn0
+ M8NK5glSk1yLtnAUKzHxpRExAJLGUiaG4yPu
+ 2yGZuqwNvJztzw== )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+ 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229083110 29600 example.com.
+ F7y+xW/C7iICgmZeYrF4e7Yx4kWZAZPAMzlu
+ PtWVuf37ySg1VfEWcQcDP04vF2rXVUqSMEcj
+ bqUVN5W8Hoazxw== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ MoYrL/lToC4AHo6KCZRiBRmCMWHUAx2Xt32A
+ P4lDpwA+wiBWkCZSfVTh60AosS/BIGtBb2BK
+ mszMx8CLBvkjRg== )
diff --git a/tests/knot/semantic_check_data/duplicate.signature b/tests/knot/semantic_check_data/duplicate.signature
new file mode 100644
index 0000000..77bf21f
--- /dev/null
+++ b/tests/knot/semantic_check_data/duplicate.signature
@@ -0,0 +1,19 @@
+;; Zone dump (Knot DNS 2.5.0-dev)
+example.com. 3600 SOA dns1.example.com. hostmaster.example.com. 2010112269 10800 3600 1209600 7200
+example.com. 3600 NS dns1.example.com.
+example.com. 3600 DNSKEY 256 3 7 AwEAAd0e6EjJ0PgChDpbjB9QtvJ0ZqwKC/j7wlEOOB9owqefH/taZ37w6QR8Ysvvv2058AflDcCP3qlaOXp+ogq7AhayA+K4kc/UQyTPCe2jXKlX9IB0KAsr8nO9UEXzjYuyBw80Ry86Xxmj7OGYRu8eRm3ruOjVJy8hCrEQ7680an303Iu3Ixnmo8lPTPPMg4dbFXZ/RW6Sanrr/Sy6fre87XY58yywqX9lZOh5eqBeZG9WvU/HycrDkx5AcwD5etVk98tVTnofShY34ePZWDmRHEtvBpMzNObdomgM5we+DawC6P+Z8PFeGz+OgN7WVzkjm+MmYAk1aIeLQyNIE8SyMts=
+example.com. 3600 DNSKEY 257 3 7 AwEAAea81n0wL09ZMejh806rJ0Km3MYC+ySPWnOmV70nEmONbnduRPpXWjYSqFmH5kldfNdCH403kI/YCMYDYBAPFPbhxuZuVBaJJqOQVsI4rpwj+XiANfGFAq9pZ0oA8iH7gSoNUCf6+g2hcP0ajYoqCjUZ7ZZQNytV/x6foW5t5PbyPNeAU1AEKxk2VSg1TMfkccZqTIx1ofS0N102Z4tOBn26judPqLc0tXMCJc7wgekqG04IGe7UWfk9xWtwo2SbtX9diErF8DJ93C17OWkb04n1xCm3i8/XZadA/HrBjfX/NvlHF8qnUQzzxN7UGrvBD4hE12R9ICj4YNFZViOTdvs=
+dns1.example.com. 3600 A 192.0.2.1
+;; DNSSEC signatures
+example.com. 3600 RRSIG NS 7 2 3600 20170403124401 20170403124311 40703 example.com. ltKNDw2O/sIwQUsv3UCKqOtZYvWNJ0mHo2xDxpzZXfAiMbgR4k7jBIkpSEpcBiBlH7EvWom7CYVigPu8Y+j/Jq4uv+wmVF47OVY3YZvuzfprWj+iOQwPlfDJfUPx+U+73SSsZ21B5/+auB5cada730B4gQKmldleVGg5aov4H2+BpEyrsSs2o79qiXNBzLPqrZEmT0nfUAvQC8xhFV/71I8Q5qtfa3vO6DLSOBmBUtAlGKqfpWoZ2w+QDdA6rtOe0haizTZUtghL2ut47bdTR253brhUccL6nnLc5//jTUBToIhmG/p698xLnU9BYnuHIi74xsb3hVr5b46W5gAGKw==
+example.com. 3600 RRSIG SOA 7 2 3600 20170403124401 20170403124311 40703 example.com. E9a+I8HDh6ycTVkFgOWkzbH7PWds7ewp1M5lUci13ZzMVWsJeFW7t1tLnnOtvz2H8pq5/BevPB8iZBA7rHH7GxoQ5P8xrxAO6HvuRZT8O4kYAWRZ0QHhMIvY8f6VqTyoOmzgIGt0nJ3BL/XJgxIiFrsiLyih6+dkckEu62F22+FFvlv49ufKkCo+EUQPCzo7ZYODc8xKWo97SmaADzjfz7Hq9UPHraUgLhNkfBDbI9YPCGKaJaAiqCBy/6ih3SyHxVPLcIz95okeo5AJVszFIS+8pNPZssJBpWsLKYyAGzs2dsliRwS9z+a3wkHXJIfbLX+r3kGhcG4lQMYDz9SrFA==
+example.com. 7200 RRSIG NSEC 7 2 7200 20170403124401 20170403124311 40703 example.com. poh0BT+nUD3sM05axVGC+k7jj1r3YVNcx4bn/0cviNxzCqLY9RGgImPWsmkTgbJpmCox9SHzpTqL8acIQDNZaciNH9WeYKvn7wkap3z6jtCuQRezM3nUx7E37fzbnNC8MUoWkV37y3FSmtiza9l1isrE5dGkNMOsBcPvIp5wrbQ+dH4cMdcgQuW+NDjee6czIeeYtyarBWhq30S2lxroh8VXlrFDTcbiIY4UoGzJDfevvsonNFQXc+p7qq2fU1fyU1e3Ugty9I23g6fLhLcrmflVbYpcgE8/02K4asu5D7x/dOq21OU/jJfeudk66l6CVw7c3Qh/N63jRn8SsCj0Sg==
+example.com. 3600 RRSIG DNSKEY 7 2 3600 20170403124401 20170403124311 5154 example.com. RmAPllqg+CEX+vj5KKmXGYsF8vqbqLoXSYqSOSWbvgWRazKaQU98fpJWdrmqylkR6Xa1fnbvliP4N/0MGremNejsNPvMsJ4GvpyM75Mb4BEf5mwwikW6xov9V/n1AN9grWofj/r5evsZYcxIR7naM9oxV6qJvy8fFIjthG805MO18bYk1/Och2x9TgUf6DTqKNBHQjk1AfrhVvpuLjdNnNT16Ak3izrCLOm2tuNTaflkYkD0n06ZIAsz1krJWztpncA2csnKQmdybSL95wZnFeb6nkmq+P5vk3PuTENIMURYMCNfzBHogLfbVG5HpDhaHkcM2zSe1qATbp9xRZujLw==
+dns1.example.com. 3600 RRSIG A 7 3 3600 20170403124401 20170403124311 40703 example.com. iYfVT+HPDqMyH9f8aLrzNK6sOCoo38tlRJ5tjiko0DOpsWp20LLgVQLvKsTs3SfdC0gYzMVQCgzfDMbAgrEvmm4ZEQT/NSUhcO2t08f6pABn6GSdoswFupi0LGdQmgj/MbOET02OTALh9I6g3Ir1+bF+C10GS/8CYqffO/52IEJylc6AzDCwAjfkI/55hsuv2H8Wp5cqEG5yAlL4fK+U2zQWEuAGOtGbEuzeKcEDV6iiAuFge7ClW+CbB3gQxEhDdx5TQNNAcpzHmum5yfsfcFkIezZqIzEvOQWg1nJVcLvYnuBqyMWv/uGbG4CxTDy49U9JB/6QfilMk38VVcitZA==
+dns1.example.com. 7200 RRSIG NSEC 7 3 7200 20170403124401 20170403124311 40703 example.com. gtRE8TafAp50tzk3rAub93X69pp4J7uPzXPM0UAAp97oVMqcqvuZh80fICLmKl7xShvBx+AYfV+2CoeMW66CXVHTP8CyIjLyi32EGgL75Y2xs55/lEOaMl8hREgxniopCWGX/5vjmY0SBdGWVQVyeQeb0DbTXFWQNw/1LUPueoM1zqGcHFKFt5Y1GidboUEDsNeCmG3ZzGV9/v9sVUezzDK53uaHm8Ojz6E4N7kg6qXDF32ZAxs0dDjh46bsaTNvMLCEXqO2imHx9Omc2wYyCt/roMoeYiulXQ7yHYt0yQuCYwqxxMqJ4z9jvLNdLxH3YZYV0CVUrNgNC/5vtUILsQ==
+dns1.example.com. 3600 RRSIG A 7 3 3600 20170216152943 20170216152853 45258 example.com. j7H3N22L+tqfwuSd4GhIwMyjrFSY3+kypIcOvg0Ipbj4pAHsJOJTiW454Ueq54G/0ntoHxgmGLv3d/EV9prMPPQz8eqtRcYFip2NuEF9bJsIG3SMy+0HolPK+8D7B0MOGFA2TExKNknS7sJy/Jn/yQrf7BHubC61zWnqB+vN7MNlJASXEvy3008oi4FScSsrAVIrZK+z7utY4exkCVfELC7flGenoyPDFR12y8WpN/Tk6q1H37x+EKaQgFj361Bm6f/InPKW8Npn/SNCIJ2DvSWAnj6+2n1mse0sC+rKhRIDMDopu7JzTjpVs9U/p9BY5dtH/3YvST4Vz3syqd1unA==
+;; DNSSEC NSEC chain
+example.com. 7200 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+dns1.example.com. 7200 NSEC example.com. A RRSIG NSEC
+;; Written 13 records
+;; Time 2017-04-03 14:43:12 CEST
diff --git a/tests/knot/semantic_check_data/glue_apex_both.missing b/tests/knot/semantic_check_data/glue_apex_both.missing
new file mode 100644
index 0000000..74e37f6
--- /dev/null
+++ b/tests/knot/semantic_check_data/glue_apex_both.missing
@@ -0,0 +1,14 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111217 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+ NS dns1
+ NS dns2
+
+; missing glue for dns1 and dns2
diff --git a/tests/knot/semantic_check_data/glue_apex_one.missing b/tests/knot/semantic_check_data/glue_apex_one.missing
new file mode 100644
index 0000000..47ee797
--- /dev/null
+++ b/tests/knot/semantic_check_data/glue_apex_one.missing
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111217 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+ NS dns1
+ NS dns2
+
+dns1 A 192.0.2.1
+
+; missing glue for dns2
diff --git a/tests/knot/semantic_check_data/glue_besides.missing b/tests/knot/semantic_check_data/glue_besides.missing
new file mode 100644
index 0000000..38ad890
--- /dev/null
+++ b/tests/knot/semantic_check_data/glue_besides.missing
@@ -0,0 +1,17 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111217 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+ NS dns1
+
+dns1 A 192.0.2.1
+
+deleg NS dns2
+
+; missing glue for dns2
diff --git a/tests/knot/semantic_check_data/glue_deleg.missing b/tests/knot/semantic_check_data/glue_deleg.missing
new file mode 100644
index 0000000..291b450
--- /dev/null
+++ b/tests/knot/semantic_check_data/glue_deleg.missing
@@ -0,0 +1,17 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111217 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+ NS dns1
+
+dns1 A 192.0.2.1
+
+deleg NS ns1.deleg
+
+; missing glue for ns1.deleg
diff --git a/tests/knot/semantic_check_data/glue_in_apex.missing b/tests/knot/semantic_check_data/glue_in_apex.missing
new file mode 100644
index 0000000..a02f6bf
--- /dev/null
+++ b/tests/knot/semantic_check_data/glue_in_apex.missing
@@ -0,0 +1,13 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111217 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+ NS @
+
+; missing glue for @
diff --git a/tests/knot/semantic_check_data/glue_in_deleg.valid b/tests/knot/semantic_check_data/glue_in_deleg.valid
new file mode 100644
index 0000000..42adf6b
--- /dev/null
+++ b/tests/knot/semantic_check_data/glue_in_deleg.valid
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111217 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+ NS ns2.d
+
+d NS ns1.d
+ns1.d A 1.2.3.4
+
+; glue below another delegation is not mandatory
diff --git a/tests/knot/semantic_check_data/glue_no_foreign.valid b/tests/knot/semantic_check_data/glue_no_foreign.valid
new file mode 100644
index 0000000..4cdcbe0
--- /dev/null
+++ b/tests/knot/semantic_check_data/glue_no_foreign.valid
@@ -0,0 +1,13 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111217 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+ NS foreign.
+
+; glue for foreign. is not mandatory
diff --git a/tests/knot/semantic_check_data/glue_wildcard.valid b/tests/knot/semantic_check_data/glue_wildcard.valid
new file mode 100644
index 0000000..9e36b5e
--- /dev/null
+++ b/tests/knot/semantic_check_data/glue_wildcard.valid
@@ -0,0 +1,22 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111217 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+ NS dns1
+
+dns1 A 1.2.3.4
+
+abc NS a.ns.abc
+deleg1 NS a.ns.abc
+deleg2 NS a.ns.ns.ns.ns.xyz
+
+; wildcard glue
+
+*.ns.abc AAAA ::1
+*.ns.xyz AAAA ::2
diff --git a/tests/knot/semantic_check_data/invalid_ds.signed b/tests/knot/semantic_check_data/invalid_ds.signed
new file mode 100644
index 0000000..2435014
--- /dev/null
+++ b/tests/knot/semantic_check_data/invalid_ds.signed
@@ -0,0 +1,106 @@
+
+
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+ 3600 IN DS 60485 5 3 ( 2BB183AF5F22588179A53B0A
+ 98631FAD1A292118 )
+ 3600 IN DS 60485 5 7 ( 2BB183AF5F22588179A53B0A
+ 98631FAD1A292118 )
+
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 0 10 - (
+ 6DFJITU5VML86QNKU9FO2LJDDQQTQPVT
+ A RRSIG )
+6DFJITU5VML86QNKU9FO2LJDDQQTQPVT.example.com. 86400 IN NSEC3 1 1 10 - (
+ UI312KQOP1NG8IQEIEFNPSLA94KB5Q92
+ A RRSIG )
+UI312KQOP1NG8IQEIEFNPSLA94KB5Q92.example.com. 86400 IN NSEC3 1 0 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ A RRSIG)
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+
+UI312KQOP1NG8IQEIEFNPSLA94KB5Q92.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignature4ey0Qcln
+ uquQZT+z2HIdCE9HeslAkTlu/Xt78vF4+3db
+ t2Vno21DkteA+w== )
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignature4ey0Qcln
+ uquQZT+z2HIdCE9HeslAkTlu/Xt78vF4+3db
+ t2Vno21DkteA+w== )
+6DFJITU5VML86QNKU9FO2LJDDQQTQPVT.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ KElp8dLKBKFzgEFV8r5aP9pCyYUD+Z8rLBA9
+ KkCDm1y82x5T/Cu5UXuZJwhvDGDzwPqoY5Dr
+ Qbiek52n6umbEw== )
+
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DPwNyH7r/4wIBfTGxikNv4pY7omY6IqpQS6Q
+ jtTNuStA+5gk98dvcgRjluxqo/+ZlZz4V53f
+ 1y506ytGbX/q4Q== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ bGk1vLxVuJpcEy7n0gPvQVzfanbvINLJLcbD
+ eeie4sXZZAOwu6oQZy6kd8tvKtV4mL0OJzpH
+ XCO6BdZkmk/aQA== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ roe4aBp4G3TqQ4x5eRxbVIjApIh17gXDjfOY
+ zvRFLOkrwqKz3eX9WrRiCk3bYNn8s1fuenaQ
+ OSV1D5SL7utX5w== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ c1yhXb8wRGYndpVqG61+lHAAbZg+JcVYGPX3
+ Fw0jYigN4G+P0+VUCqPLkC4yfJylzuefyGfk
+ TUmriM3ihfXxIg== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160302125715 31323 example.com.
+ mZiLLTzbdaj7EJ8uj3TwvcvAfaMxYjyavlGT
+ qpa+cElfvBDm7R6MF4MaEQ9aZ2ylMt1lppjq
+ YyYRaaQC6yhm4g== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160302125715 29600 example.com.
+ K3PkVYZZV8QvZFtDsz9+ZfiM9wDkFu/eO2S5
+ tAtCXd1fktcW44TLWL0qADfFEEcMotvzLqv1
+ YJrD7TvrFDot8Q== )
+
+
+
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ vlzRtVFa44pRtdD8XZcgDa6021uA9A3TnNEw
+ 5jRnor4aoftUuVQNAanQMCgrWk63d14XZ2d0
+ lqhxunAbh08dsQ== )
+
+www.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ NWFuYaSEg3z3K4l/fHu/X9dK+rDZ177BbCNN
+ ZeFTPCAdOnX0nw1CQys629k7Vzdv1pHaanmy
+ 0Ru0tX9R65NlKw== )
+
+
diff --git a/tests/knot/semantic_check_data/missing.signed b/tests/knot/semantic_check_data/missing.signed
new file mode 100644
index 0000000..75c7d22
--- /dev/null
+++ b/tests/knot/semantic_check_data/missing.signed
@@ -0,0 +1,20 @@
+;; Zone dump (Knot DNS 2.5.0-dev)
+example.com. 3600 SOA dns1.example.com. hostmaster.example.com. 1081539379 3600 300 3600000 3600
+example.com. 3600 NS dns1.example.com.
+example.com. 3600 DNSKEY 256 3 7 AwEAAaBgc4O+4UWd7mzSyelnPb/le/x0q/E90B/xnlf56kgEFMvEGz++o6CMRXr5JfgyxDDsahxTwFoWu30KJry4MjgcwlETM63DFpIYtyDBsi8TlQFEp5NDrlYUWlPGiPfywZBVkHGFMcFct+5/ZalTzYIP39tDytZcPZ/IgQRQZA9qeHYIw51YX9IlNMalHFCtJyrpzCdo22FY/vwBwSbdCa+vzkH1Uu8JkIqyAvAGkuwVisgpMpzWhvJNi5WSAnQfwOcsYCftINAHdRXtuqyG+uU/RDcZ2psx+woi+mYzEPeYV9MEqWpDyIz7jS7e1hK/1o05+qY8Eu2gt4enRj9BQr0=
+example.com. 3600 DNSKEY 256 3 7 AwEAAfcfJSUnim+cR3YEc4VfdJ5W65GNlK0LQaAh6vAejH7uol8VYmXdlyz+wlhad+DyRM5Jl+XJVFMMyFUqWx+Q63DPRtl+TlN/2pWU2gsNHUoovFhFpdX1cQMVoxr2QLgsm1ASTeqvZV8Dn0xAlNRihNv877sTySjveaH0JpuVCMpe5DB1zVbAzLgDqFKAvwJCumdycp7RzMi9PqS1XtsEInKi+X/zZteTJbDO7l+tFt9/NgFxiaLgNo8Gz2oVBTQvAbjCDEi2mPA/YJrpOGZWNkB2L9HFSfzZih8BbgUI3Fh4lhS8XCVrfVV7K9YR2F5NBVi7h0Mk15hzNsSS7tRK1FM=
+example.com. 3600 DNSKEY 257 3 7 AwEAAcjdwuJkjM8G5rk967z1cJqF88BqpvN2GN/6Tj1XA5AbIx+33qy5JI6K43ehlT/neLizOCk/JyXaw8gcjQaDKcIy0vKysXvI6yK4PNgHTdzQunBqGTfvPDlXKCle550R/DJF2OZH/T7jgX2GhQlem6UB3A23n24YP50IzAmXK9RYdE/dMFXU5jEz+CjcHNkB8ZCb2VrKE9RDjY88vr6lyM2kPbvBtx4UaUSEzwlDMRc3Wf+dBWKm6mKWAPsHZM/cux+S2mca/cxEA1ngCgBBbm7824WjTXgDs14QWuwruMTqLPDujUYND5kbsiuhQsfEFGVq2UyhGEZG/NoIEEg7qLc=
+dns1.example.com. 3600 AAAA 2001:db8::3
+;; DNSSEC signatures
+example.com. 3600 RRSIG NS 7 2 3600 20840201000000 20160302125715 7242 example.com. B/6k7YAQGkiz6IkssLZblExgMZBE+Flkhv/leVgvM4RLPPpQ2znouYyrSbVCcU5irA7PFLbee5Mn1aWj2S57L8yGJjHBuamQSIO0GcvGcmXi1CrdaYXSofo3PtnKpM8/mG3+8RCUL5YhoxhTK4Y5gJrYGPkRPKsBTw2Qd2TUJFebtYgCuGN8Q3UwbeYPw89rNbqC3a7zsGwJoZKgDnm3NwCWcv6NRTcQA/H5v6T0/QvYbZpBMrjl3EiAWOccdUlQnALngGSzbJ2GnmK933VXYhuAoSKEN6thauOBSLkdCh9afkUzo/t7xhTJszo0F1uuavs8PYf3HjmdnMwdPMkUuQ==
+example.com. 3600 RRSIG SOA 7 2 3600 20840201000000 20160302125715 7242 example.com. dHmPqRl9snHFavwkkAFZqHDmvUrI3+e+dmEexqgW9txr30fbrkeGAp6ApdZlqJiDTJ/2q0UoyQxSYe/BzgV4gEBgTTgfmC7m9eHVLTD70KMlNuvwC4jkh1vWT1Zn6IFUsQtJ+54XfRTe/2VHyeK7saqsA/ARRZGOzk6To8CWxNCApUdLZMQO9UTX7uVcXKkPvfMvlhx1fmn4OE8ntwbY1oPosQb987N8V8x9Rb2hINr4DCkXNDydDZAh4vsZO0DHPlmyfkyNguQDmdgnDz1CVbJzguy8tqeMGT7CrwU8AmX3JADQTHoxjnWEidLLUa/gNDRFcRc5YMcdZyImHqdNZQ==
+example.com. 3600 RRSIG NSEC 7 2 3600 20840201000000 20160302125715 7242 example.com. bjw2G/BwF2xTP/QSkKqdr7byUS+nqMvfppuhZmH0VcysAKN2oqsV51bn7gWej6dnx0svtX7nCOlwdDFSCMJld5BGZFnAfhS+XVc/wTeZGMi1BkeJxlT3UbGLhf2DuLLyL969HPltL527vSysjBEmi7OsTlH+wXD6SW35ZClajNSRLjxrRpVHTGpA5uyyysHRYNXAKS3+SSc1N/Fovjgzi68exWD0BKTGia7Nf9Fn+bqvhbYh+pMHA7djPFJIsER3OCBx7H1KMxl6rap7Q3rC0I289xnnsOqRh/GnzSVgvobKWozOOs9XXNg+w9ioSos+kbzTxxSEvLKqNBgCbLjUHg==
+example.com. 3600 RRSIG DNSKEY 7 2 3600 20840201000000 20160302125715 37855 example.com. EHXazcQ27b5Cjqd1T8TAui2PrUqEq7cBxk45OA8BfBDmOuH2vXFVL+juCM2gCvQ+0oZmcJmpkjMCxUqQekXgxRy21PlEzJfR3VHRDSYCSogR9cCLw9T9OiFXugZAtYcLVXVHddKu0+t5yeQqdStgLBiz9EmeuPFYd/h/BxKI8FGx/TjHNzd06SKgxlZAT/vCGhEswgSIpxJm4Ju561vT2/Hh+NmD4jIKVf0OUSkfRVRbxpzMs0HaZx6s0T2mcL8so/rEXjSIORkw56Q7x3EmYQDxNJjoNo4nHKT0/pciCey+vHj9pxxaiave8wLBG96JpgJgSV7BG8TTbE2q62wX1Q==
+dns1.example.com. 3600 RRSIG AAAA 7 3 3600 20840201000000 20160302125715 7242 example.com. h0oZ7ghuhANB27zD+M1m0NyVUHND7g2qI1IfEKDjMzZ34wyqM0xWLm/Izln86ol4naDvJU3a7hsJS/95DdvW/s711Oi2nKhX/Hkjvnzu8WVcf5DvEKYQe/fyZ676hnwviKqFzwmfTAKgIuSvt2uZzJkpcyL8ZE6O/GdPrcR6rTuuDI30F4zXIWPmuMNLR2qJv59DwM0tZScLdmRGKGnZNpdxDvtbCsZrXBUPrOE5XpAw+fe8+oL3UEeKQZq8qFhVvegl4TAuk1a8CS+zG4E1ABQKp86J1h0G4l/ajmWqq2T59lHsBAOuX0IbKHEHIJzwRd9EV7LM59EtJVacx8ZCkw==
+dns1.example.com. 3600 RRSIG NSEC 7 3 3600 20840201000000 20160302125715 7242 example.com. Pq6F6akEhyIqch7vwWJ5C53FW1UW/Y8vseFqB6tzql5bnIYjEwikgiWR85uvSUNGvsjHbadBYiVh2i68k80ws/2LecQCvguSH+rMkqqY9go+pBh3pdiNlJaJZp3zJQ6+E35xOA+p0G5t84Et3satJl3OcpVthrdBKuotpDg4P+nOpfLHkI3FO5vehxs71HmESQli5JllhPNMH6WZfWsP74D4DgRjUpIK9hGznCeuZxJT5+S5wL4fzqb+P20W30bsQqMbo9GNdPy5AdbwZoEKJVoN3HC/sv03ScQzWUxjamHCQOeZFys25fFlh7+JU1xYSb3V/fPhUUuf7OsBVvn7+g==
+mail.example.com. 7200 RRSIG NSEC 7 3 7200 20840201000000 20160302125715 19578 example.com. gjNXoKVddN+Z3MmHXxs0v4Gv/3zaTAg0mBSLkSp8Ion6qKj/aR2y50QhNfZGVEZSmyerDiaVpfPMN+q9mwx+6xmv4/G97DkadXBYt5IXGR1fXhMCF+RLJb5ePYjQKSk2TfRMJAlk1Mowfvlp8rXFrT576y2F+IXKbpiJOdRt/13Wo5IUbw6LLFDOeZ3fUiZtBmoWTTjBnrGWYdb+ePcSXID+qM5TmRXqIOFceJvt/RhGZ5LYAchgM2sZDf4Asacxg6Z6vS2cA1opTLMAIu+cuEmq61cSJxWHblfXIpPMXFG+4i+nkCxEFxWyxt9edlAeHS/l2AiHQl5QeuzwEjFI2g==
+;; DNSSEC NSEC chain
+example.com. 3600 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+dns1.example.com. 3600 NSEC example.com. AAAA RRSIG NSEC
+;; Written 14 records
+;; Time 2017-03-31 15:38:20 CEST
diff --git a/tests/knot/semantic_check_data/no_error_delegation_bitmap.signed b/tests/knot/semantic_check_data/no_error_delegation_bitmap.signed
new file mode 100644
index 0000000..abbf088
--- /dev/null
+++ b/tests/knot/semantic_check_data/no_error_delegation_bitmap.signed
@@ -0,0 +1,61 @@
+; Zone without any semantic error
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201008173446 32411 example.com.
+ /R/djqaZWRo1zCmz7B58/93D8ZxJoZAAKEbH
+ xuCsAJ5dm2ubvtgvqmhNXMqdVBvpb2OPdBX8
+ VF1j9RsjuE7ORQ== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201008173446 32411 example.com.
+ AmyqpqMfMEztA9S1Urv6yEtKd5yc6kkSedRU
+ uLp7velyCkipFzWgpzRVDqn+wp2ZaHig0Fod
+ kryw3j4yHOLlHA== )
+ 86400 NSEC deleg.example.com. NS SOA RRSIG NSEC DNSKEY
+ 86400 RRSIG NSEC 13 2 86400 (
+ 20601231235959 20201008173446 32411 example.com.
+ 9tR3kL4pVEYsHzt888pbP0TtS/npeApAEUfZ
+ L5rXQE0WqBLQGtyEPYxujFuaruvxH0SgLl6r
+ n6MKCEB07DjhTA== )
+ 3600 DNSKEY 256 3 13 (
+ C7v6eelCoXgBoUjHe/gKdsnWNw04GH7PpYMo
+ 2hF5jaeq1zkLSXkF2xS/04MgBTFFYuDU+LGt
+ 8kMKNc8o2wH2jQ==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 32411
+ 3600 DNSKEY 257 3 13 (
+ m6KdGBizfDaUhcW+nIHuRdufZFcSYlZ5Xoky
+ +GcH23OxZtPzPwKwpg5rTx+RCRPlVpmwyiW3
+ aC69n0Q8mr8NpA==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 60051
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201008173446 60051 example.com.
+ SD4149dui/vuky4G6wiJQLUw5b8XpG+Cy/cf
+ +9CSbuKWHRcC1K0wVEw6xyEah6eD/7Sh0eFA
+ EECgej5etJbL3A== )
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+ 86400 NSEC dns1.example.com. NS RRSIG NSEC
+ 86400 RRSIG NSEC 13 3 86400 (
+ 20601231235959 20201008173446 32411 example.com.
+ HFA1XBdjaUvb8lbyhXVDYxTUn8Nr2HNC5ktc
+ kPBW2AGMQiVUtyR3vPxUIiusxsQn+uyRL2QC
+ NBG3ANo5exT8ug== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201008173446 32411 example.com.
+ 4NLhmO0Sa3yk1ZikWSRYEX0FpHK0NkTGk++h
+ RHJO3E9M6Og1am/PiPf67DAe/2n4ANItC/SH
+ u/1WSvYQV7OZqg== )
+ 86400 NSEC example.com. A RRSIG NSEC
+ 86400 RRSIG NSEC 13 3 86400 (
+ 20601231235959 20201008173446 32411 example.com.
+ pQgr7WzGpL8gbbAcbeYEIYBLq8lCAuE9NaUf
+ itYKBFh7Cbg4YrLOoeAV6v6V4tfZPpmNpd2U
+ 9VUrY9es4QfX6Q== )
diff --git a/tests/knot/semantic_check_data/no_error_nsec3_optout.signed b/tests/knot/semantic_check_data/no_error_nsec3_optout.signed
new file mode 100644
index 0000000..a03f4ea
--- /dev/null
+++ b/tests/knot/semantic_check_data/no_error_nsec3_optout.signed
@@ -0,0 +1,29 @@
+; Zone without any semantic error
+
+;; Zone dump (Knot DNS 3.1.dev.1612270066.d215637a6)
+example.com. 3600 SOA dns1.example.com. hostmaster.example.com. 2010111222 21600 3600 604800 86400
+example.com. 3600 NS dns1.example.com.
+example.com. 0 CDNSKEY 257 3 13 Yk8KOmyVzOij3x+Zs+eT4J2Up9+ipwXEKOhL9fTYY/DU10yIQt+zYm02UFZJX2oVTdHBCajpBFsZLH2X4ho1yw==
+example.com. 0 CDS 25674 13 2 2EC05563A3537BD32EA3EB92C44794C644F249EE440785CF28207B903E35322D
+example.com. 3600 DNSKEY 256 3 13 tCoteOM+A4o/A9uxgLyDg3HOg2DClU+3d+1XPQRtTfuaEFOGIpyH6qiFUv2b4DYuvmMyTkL99nxvyhA8yo0Cgg==
+example.com. 3600 DNSKEY 257 3 13 Yk8KOmyVzOij3x+Zs+eT4J2Up9+ipwXEKOhL9fTYY/DU10yIQt+zYm02UFZJX2oVTdHBCajpBFsZLH2X4ho1yw==
+example.com. 0 NSEC3PARAM 1 0 10 151E9F1094FE188F
+deleg.example.com. 3600 NS deleg.example.com.
+deleg.example.com. 3600 A 192.0.2.1
+dns1.example.com. 3600 A 192.0.2.1
+;; DNSSEC signatures
+example.com. 3600 RRSIG NS 13 2 3600 20400406110811 20210205093811 61806 example.com. VD3IclxLUSi1tgv4+FJ+9e3EWiRny6de1y4jUFn1Ama8+Cl2vZO2Jc34Q9MKY/S9m4id7Xe8MtkkrKThQcaaXw==
+example.com. 3600 RRSIG SOA 13 2 3600 20400406110811 20210205093811 61806 example.com. BniH53lEM1hYGcorTmqF7At3+neZkifPT1sM15nGlQUQ6RfkPxh7Uy8Pj3PxLL5v7WDTyFGbLVThEFWZUh/h6w==
+example.com. 3600 RRSIG DNSKEY 13 2 3600 20400406110811 20210205093811 25674 example.com. 3FSDEJ9f54++FX/EHWXXnbHW8iJPaDG4kc7qf772y62dtqTfAvb22lq2yKzCOaRFFwpPKEdcS4OEkhx0IbC27w==
+example.com. 0 RRSIG NSEC3PARAM 13 2 0 20400406110811 20210205093811 61806 example.com. BTT+7Gj8V2pATxogxJ8xEO5eiVHoVIDxdK60zDS3MWNcbUc/n9vJR8NrCECel9egQUWrejawikO4DkyQxLZpkw==
+example.com. 0 RRSIG CDS 13 2 0 20400406110811 20210205093811 25674 example.com. h43kZiM1EFETWQEtMM8Xls/RFDsAkLIpLf+DUnJ+zzxv37xpGvtf/s//3ew9qEhouBnGh/1FWtNr8vjhzh0tsg==
+example.com. 0 RRSIG CDNSKEY 13 2 0 20400406110811 20210205093811 25674 example.com. 4mf7C/zyWoFRllUEaLHpdxJdlbEQXIRKNH6JOH3sTKSQMGj1SMmkWm9qlO9tVaUm1ggB6r8TPWgrAUBG+4A9gQ==
+dns1.example.com. 3600 RRSIG A 13 3 3600 20400406110811 20210205093811 61806 example.com. lMj63MgZYiCl6Fdf0Q5C4/K99AAXTqCI9HSBQcrc7qiZDjRpZXzBUO8yv7+5JSMIo/A3tJtQL/12VFPGZ9NQ5w==
+;; DNSSEC NSEC3 chain
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 NSEC3 1 1 10 151E9F1094FE188F rvcd9h11kcnenarqcmtmrhusdmb24rm4 NS SOA RRSIG DNSKEY NSEC3PARAM CDS CDNSKEY
+rvcd9h11kcnenarqcmtmrhusdmb24rm4.example.com. 3600 NSEC3 1 1 10 151E9F1094FE188F ple28jlp3q5anh045ssk9f3u7ltd4qlc A RRSIG
+;; DNSSEC NSEC3 signatures
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406110811 20210205093811 61806 example.com. 7AdxaQLQ16ORwtf3t9lNQrzOP1BKu0TOIiKfx8/7o0JKoVtDYjqTC+ilWSD/Mbfb6PI6ND3NQKsIbnApOa2SUA==
+rvcd9h11kcnenarqcmtmrhusdmb24rm4.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406110811 20210205093811 61806 example.com. bOUzqzuIhV/SPyXiFOgsJbnS77dijFWcLDY/0X3r9aNiAo3/vSE4OTT0f6CkcBQDka+LjIoRaE7NIaTMl24fdg==
+;; Written 21 records
+;; Time 2021-02-05 12:08:11 CET
diff --git a/tests/knot/semantic_check_data/no_rrsig.signed b/tests/knot/semantic_check_data/no_rrsig.signed
new file mode 100644
index 0000000..6a3161b
--- /dev/null
+++ b/tests/knot/semantic_check_data/no_rrsig.signed
@@ -0,0 +1,48 @@
+dns1.example.com. 3600 IN A 192.0.2.1
+ 86400 NSEC example.com. A NSEC
+; missing RRSIGs
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160224081310 29600 example.com.
+ ieEKhIV69ywg+YFSqdz0t17eE+PLl1eR4kpv
+ Mq6Q6TfjC7V5/PcFW6KRoP50RFp4m4cD0E7T
+ GpmpnPF++QV1Vw== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160224081310 29600 example.com.
+ kYbAbCGzyWPBEfc0TH1calUiKsZi12MH3TNV
+ 7vtjOvIYEqeNmuJkrw899a7nOPNoahB6h7o/
+ DXuRlFqYYCC16Q== )
+ 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+ 86400 RRSIG NSEC 7 2 86400 (
+ 20840201000000 20160224081310 29600 example.com.
+ PchT9RWRkLCMxWAQ3ut6LZlh4MYT4CkAPThQ
+ cnIn0ORi/fVgGzlifQ88xfEdEr1ZoXk9PlhT
+ 5b+wocBOl2HhGg== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224081310 29600 example.com.
+ JLcSyR8KgSicUou0c7Zs7Ol1DYiaQ8Lfyort
+ 8a+5OP3em3r3NH1nJkiVfs8+xdvUcGlGkbib
+ RKlfRWiIcOEalQ== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224081310 31323 example.com.
+ EQMX5DPXhwa+blMRkzl+swUW3BtzpGJ5tGEU
+ hkH7bJfM51gIAO5qnUO/mMPnEA8b4dc20nnZ
+ 8j8lETDjqBLgDQ== )
diff --git a/tests/knot/semantic_check_data/no_rrsig_with_delegation.signed b/tests/knot/semantic_check_data/no_rrsig_with_delegation.signed
new file mode 100644
index 0000000..2c36b9b
--- /dev/null
+++ b/tests/knot/semantic_check_data/no_rrsig_with_delegation.signed
@@ -0,0 +1,61 @@
+ns.deleg.example.com. 3600 IN A 192.168.0.2
+deleg.example.com. 3600 IN NS ns.deleg.example.com.
+ 86400 NSEC dns1.example.com. NS NSEC
+; missing RRSIG for NSEC record
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160224081610 29600 example.com.
+ HhnlCtlIaZFVklpzVUnzm6AzFd65CSc4WCJL
+ f2o7Gkevu+HTnkiPN6gqtERC/BKJz1EKd2fC
+ KDyLxXw6KeTRAw== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160224081610 29600 example.com.
+ rcHuZd9wTYykzis+9Z8uyqD8V9h22szf2bmE
+ GYNyJBlHZO0sOmys31xnvDfQ9sdk9hf1TUfB
+ 9ACGIF5lDHBEog== )
+ 86400 NSEC deleg.example.com. NS SOA RRSIG NSEC DNSKEY
+ 86400 RRSIG NSEC 7 2 86400 (
+ 20840201000000 20160224081610 29600 example.com.
+ YGSe1OINjOY3I8BY1EoxcOJsDZ/DjGCT5nqY
+ J6BBjTcbT5S1W61SN50xc2sGB4Q8F2KTotAe
+ arzn4DGDt9mOMw== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224081610 29600 example.com.
+ rdmqHOUXqhwrJusNt/7FTV+AtO/v6Md3LXzj
+ /QzR/pCADNC6ZA+FvqaOycnUxoryKk7PY3pM
+ 5ispCMuEx/1OGA== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224081610 31323 example.com.
+ jELyXsaJx+G4heZJ96dyE12hSyTNFazwWDkq
+ 1Mkja9/bTTdYAd+t8fhf/c35bUiTVJWMivJe
+ +YcCwqGf2U+2zw== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224081610 29600 example.com.
+ ln2xuvghOWBDOfyk19Wwtv3oc8+1go3WQuMf
+ vel5x/uHVx6voNA25cpFIQ6nPlCo8pmd5R3w
+ paMxgoQtBkzBcA== )
+ 86400 NSEC example.com. A RRSIG NSEC
+ 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224081610 29600 example.com.
+ EEKcIegUeyn/1FIgxHV+gSX3b/ygQPAcjD8g
+ aCt1yiO0B1xmVm09RJNxzCLaTKxQENhxIoUZ
+ 2l7250pBQnrlAQ== )
diff --git a/tests/knot/semantic_check_data/ns_apex.missing b/tests/knot/semantic_check_data/ns_apex.missing
new file mode 100644
index 0000000..fd7b7be
--- /dev/null
+++ b/tests/knot/semantic_check_data/ns_apex.missing
@@ -0,0 +1,11 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@ IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111214 ; serial
+ 6h ; refresh
+ 1h ; retry
+ 1w ; expire
+ 1d ) ; minimum
+
+; missing NS in apex
diff --git a/tests/knot/semantic_check_data/nsec3_chain_01.signed b/tests/knot/semantic_check_data/nsec3_chain_01.signed
new file mode 100644
index 0000000..cd90b9f
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_chain_01.signed
@@ -0,0 +1,80 @@
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 0 10 - (
+ MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938
+ A RRSIG )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ ; wrong next record
+ NS )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+; RRSIGs for NSEC3s
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229140652 29600 example.com.
+ PjEM7Bxxb7w67366fKCLkR9BVFAL0RI8RJCZ
+ 5aqoMVuy+ui7MLKxKT2LfeTHgBw1Cww1bbJw
+ Ip2zu0/ZGPfKzA== )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229140652 29600 example.com.
+ DUMMYDUMMYDUMMYgc7Jx/FgAlruRjwsS/YJa
+ sZRspDGZhSqK2daV5K0lmK+XL8BoOtp7aXtq
+ VER5XcWLOebCdw== )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229140652 29600 example.com.
+ XsJa0IUE2ddTohJmiuNVd/Po1ZOK0PDCuU7/
+ CS0/wiZ5ZlxPdVUAYXuC7HhGH+ZPsqwZ4oUU
+ ToDbFqfdzmC1XQ== )
+
+; other zone data without error
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160229140652 29600 example.com.
+ u5QMvOSkZBUM5tLiEAq3A+x4Ha17ZsNUYqeI
+ SuYA1+NbaBDxAtT6scB9aeA4lOTQ0TZvpGFE
+ YF/XxGtqvwdZ8g== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160229140652 29600 example.com.
+ ELZOh4iS9DpAafa8NTaI/eNL3Qwy+lsmgrzF
+ 7jaoR5yOURl/RZSJY+m9Peaq4ALcROdGJ0O4
+ miSpdTIZsBSGZg== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160229140652 29600 example.com.
+ sjxCP/grgOR+4vmXw7HU/hGSx5dS5QxM00IA
+ gZNJ6Lqf+4OSL3TEa1/qqRSFTl5uv3rqh5W4
+ 8p2JoT1ZkcJj6w== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160229140652 31323 example.com.
+ jrH48r1iPFRfbyIZWcARQrejVgrE9v8qqt4R
+ uPHjz5t7PYmZYH544SI9HtaWGkIJ9jzlxr5l
+ ikCWo1we50y9Lg== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160229140652 29600 example.com.
+ yIXzhQw8c/c/in+doXX5JmqoGiqoYD2Hhw6d
+ /aGXc5QLQqxyATXln02vkwt1d7DK/ha1vkfx
+ bvGdduXDQ7YZ+g== )
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160229140652 29600 example.com.
+ aMRzV/1+m9wQHWezSiwkmDEbnS85wB9dA5x/
+ u2P7NPsgwMnRdfpVIMfaVhSJH88i5OlLTvL1
+ sSK+RADpuoqnLA== )
diff --git a/tests/knot/semantic_check_data/nsec3_chain_02.signed b/tests/knot/semantic_check_data/nsec3_chain_02.signed
new file mode 100644
index 0000000..ca70cfa
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_chain_02.signed
@@ -0,0 +1,94 @@
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 0 10 - (
+ 6DFJITU5VML86QNKU9FO2LJDDQQTQPVT
+ A RRSIG )
+6DFJITU5VML86QNKU9FO2LJDDQQTQPVT.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ ; wrong next
+ A RRSIG )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 86400 IN NSEC3 1 0 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ NS )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 1 0 10 - (
+ MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938 ; wrong next
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ oErbN3Xw+0zAqkz5KC5nOsINblBc4ey0Qcln
+ uquQZT+z2HIdCE9HeslAkTlu/Xt78vF4+3db
+ t2Vno21DkteA+w== )
+6DFJITU5VML86QNKU9FO2LJDDQQTQPVT.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignature+Z8rLBA9
+ KkCDm1y82x5T/Cu5UXuZJwhvDGDzwPqoY5Dr
+ Qbiek52n6umbEw== )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ ep1TVqEISn2ZOiBtizK2eyuuhsYyD37X9Bw2
+ 9JOkecZnmzCwBqfMCBvRYmNRpMd512+ZnW/I
+ 1vIViE7CGwkHyA== )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySginature6IqpQS6Q
+ jtTNuStA+5gk98dvcgRjluxqo/+ZlZz4V53f
+ 1y506ytGbX/q4Q== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ bGk1vLxVuJpcEy7n0gPvQVzfanbvINLJLcbD
+ eeie4sXZZAOwu6oQZy6kd8tvKtV4mL0OJzpH
+ XCO6BdZkmk/aQA== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ roe4aBp4G3TqQ4x5eRxbVIjApIh17gXDjfOY
+ zvRFLOkrwqKz3eX9WrRiCk3bYNn8s1fuenaQ
+ OSV1D5SL7utX5w== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ c1yhXb8wRGYndpVqG61+lHAAbZg+JcVYGPX3
+ Fw0jYigN4G+P0+VUCqPLkC4yfJylzuefyGfk
+ TUmriM3ihfXxIg== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160302125715 31323 example.com.
+ mZiLLTzbdaj7EJ8uj3TwvcvAfaMxYjyavlGT
+ qpa+cElfvBDm7R6MF4MaEQ9aZ2ylMt1lppjq
+ YyYRaaQC6yhm4g== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160302125715 29600 example.com.
+ K3PkVYZZV8QvZFtDsz9+ZfiM9wDkFu/eO2S5
+ tAtCXd1fktcW44TLWL0qADfFEEcMotvzLqv1
+ YJrD7TvrFDot8Q== )
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ vlzRtVFa44pRtdD8XZcgDa6021uA9A3TnNEw
+ 5jRnor4aoftUuVQNAanQMCgrWk63d14XZ2d0
+ lqhxunAbh08dsQ== )
+
+www.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ NWFuYaSEg3z3K4l/fHu/X9dK+rDZ177BbCNN
+ ZeFTPCAdOnX0nw1CQys629k7Vzdv1pHaanmy
+ 0Ru0tX9R65NlKw== )
diff --git a/tests/knot/semantic_check_data/nsec3_chain_03.signed b/tests/knot/semantic_check_data/nsec3_chain_03.signed
new file mode 100644
index 0000000..80112f8
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_chain_03.signed
@@ -0,0 +1,94 @@
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 0 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A ; wrong next
+ A RRSIG )
+6DFJITU5VML86QNKU9FO2LJDDQQTQPVT.example.com. 86400 IN NSEC3 1 0 10 - (
+ MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938
+ A RRSIG )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 86400 IN NSEC3 1 0 10 - (
+ 6DFJITU5VML86QNKU9FO2LJDDQQTQPVT ; wrong next
+ NS )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignature4ey0Qcln
+ uquQZT+z2HIdCE9HeslAkTlu/Xt78vF4+3db
+ t2Vno21DkteA+w== )
+6DFJITU5VML86QNKU9FO2LJDDQQTQPVT.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ KElp8dLKBKFzgEFV8r5aP9pCyYUD+Z8rLBA9
+ KkCDm1y82x5T/Cu5UXuZJwhvDGDzwPqoY5Dr
+ Qbiek52n6umbEw== )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignatureD37X9Bw2
+ 9JOkecZnmzCwBqfMCBvRYmNRpMd512+ZnW/I
+ 1vIViE7CGwkHyA== )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DPwNyH7r/4wIBfTGxikNv4pY7omY6IqpQS6Q
+ jtTNuStA+5gk98dvcgRjluxqo/+ZlZz4V53f
+ 1y506ytGbX/q4Q== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ bGk1vLxVuJpcEy7n0gPvQVzfanbvINLJLcbD
+ eeie4sXZZAOwu6oQZy6kd8tvKtV4mL0OJzpH
+ XCO6BdZkmk/aQA== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ roe4aBp4G3TqQ4x5eRxbVIjApIh17gXDjfOY
+ zvRFLOkrwqKz3eX9WrRiCk3bYNn8s1fuenaQ
+ OSV1D5SL7utX5w== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ c1yhXb8wRGYndpVqG61+lHAAbZg+JcVYGPX3
+ Fw0jYigN4G+P0+VUCqPLkC4yfJylzuefyGfk
+ TUmriM3ihfXxIg== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160302125715 31323 example.com.
+ mZiLLTzbdaj7EJ8uj3TwvcvAfaMxYjyavlGT
+ qpa+cElfvBDm7R6MF4MaEQ9aZ2ylMt1lppjq
+ YyYRaaQC6yhm4g== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160302125715 29600 example.com.
+ K3PkVYZZV8QvZFtDsz9+ZfiM9wDkFu/eO2S5
+ tAtCXd1fktcW44TLWL0qADfFEEcMotvzLqv1
+ YJrD7TvrFDot8Q== )
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ vlzRtVFa44pRtdD8XZcgDa6021uA9A3TnNEw
+ 5jRnor4aoftUuVQNAanQMCgrWk63d14XZ2d0
+ lqhxunAbh08dsQ== )
+
+www.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ NWFuYaSEg3z3K4l/fHu/X9dK+rDZ177BbCNN
+ ZeFTPCAdOnX0nw1CQys629k7Vzdv1pHaanmy
+ 0Ru0tX9R65NlKw== )
diff --git a/tests/knot/semantic_check_data/nsec3_ds.signed b/tests/knot/semantic_check_data/nsec3_ds.signed
new file mode 100644
index 0000000..ad5da7c
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_ds.signed
@@ -0,0 +1,57 @@
+
+
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+ 3600 IN DS 60485 5 2 ( 4EFB4310DB01A42E7882E102
+ 7A73CC28E2E0FE938F2D5888
+ A0DA0005B99E7FF8 )
+deleg.example.com. 3600 IN RRSIG DS 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignature4ey0Qcln
+ uquQZT+z2HIdCE9HeslAkTlu/Xt78vF4+3db
+ t2Vno21DkteA+w== )
+
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 3600 IN NSEC3 1 0 10 - (
+ 6DFJITU5VML86QNKU9FO2LJDDQQTQPVT
+ A RRSIG )
+6DFJITU5VML86QNKU9FO2LJDDQQTQPVT.example.com. 3600 IN NSEC3 1 1 10 - (
+ UI312KQOP1NG8IQEIEFNPSLA94KB5Q92
+ A RRSIG )
+UI312KQOP1NG8IQEIEFNPSLA94KB5Q92.example.com. 3600 IN NSEC3 1 0 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ A RRSIG)
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 3600 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+
+20g1gol477ro51rk9a9nfd54tfqal7iq.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406101515 20210205084515 61806 example.com. k2hYD9qbLM8cRuN1fcLar/GsSufK/5oQYxRnE9bUDiKvC1WhCDF3pee6MSqybb3LoNkQUeOgGV4jdzvslzDlhQ==
+6dfjitu5vml86qnku9fo2ljddqqtqpvt.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406101515 20210205084515 61806 example.com. fGQRezo0T9Hd1tGJqhCXPyLONKSxOPmX1Kl7MjD1OVDLg9l5Ei9DmhrpCFxahXMBGIA4yy1J7mSK3PqelPMyFw==
+ui312kqop1ng8iqeiefnpsla94kb5q92.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406101515 20210205084515 61806 example.com. 6AmfjUgzO4Ew9FmW6koVhQ+98Vd7xI7kpFXwj8wb4ObmuM8uFu6tpvcT/jDcUduFuUb//DS5fS9fXraLNL8JUQ==
+utqvuhu2blk3dhmrr5t1hd9vteohqt0a.example.com. 3600 RRSIG NSEC3 13 3 3600 20400406101515 20210205084515 61806 example.com. WMvFzIf9Ekvr0UVRzbZpxUAjT2Sf2KgsXek6iG786Iw6nZ/rzPVNlfNLhWvdqQmi5LEDp03UExshDlPz3JgOkQ==
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 NS dns1.example.com.
+ 0 NSEC3PARAM 1 0 10 -
+dns1.example.com. 3600 IN A 192.0.2.1
+www.example.com. 3600 IN A 192.0.2.1
+
+example.com. 3600 DNSKEY 257 3 13 Yk8KOmyVzOij3x+Zs+eT4J2Up9+ipwXEKOhL9fTYY/DU10yIQt+zYm02UFZJX2oVTdHBCajpBFsZLH2X4ho1yw==
+example.com. 3600 DNSKEY 256 3 13 tCoteOM+A4o/A9uxgLyDg3HOg2DClU+3d+1XPQRtTfuaEFOGIpyH6qiFUv2b4DYuvmMyTkL99nxvyhA8yo0Cgg==
+example.com. 3600 RRSIG DNSKEY 13 2 3600 20400405162736 20210204145736 25674 example.com. 5nIsRsT30KNhPS/i8rNhT/C3uPli0jb+7fLYL+eHKggTHk5UK69Z5EHA/ISKnbEOMIQA3QJ98XNreLJk+sTZ4w==
+
+example.com. 3600 RRSIG NS 13 2 3600 20400405162736 20210204145736 61806 example.com. nzKbYNX9cbrf3zNMSRK4ftG/p4DLn/uB3BM29txIj0nyKxL1cmK0wsTltGmwLzJTegBy/LV1VtMudDLWEFU3sQ==
+example.com. 3600 RRSIG SOA 13 2 3600 20400405162736 20210204145736 61806 example.com. HvtxfzCSLHjFSHuAyO+KKymy/vxOGLS8T1DuhfAoUtweHv1zVeYfbFOfCdcfs15PKO31ldqwWRvFWAhM+3hnrA==
+example.com. 0 RRSIG NSEC3PARAM 13 2 0 20400405162736 20210204145736 61806 example.com. 8uDKYTVd+XuYFyzf/aNm6kMjZhbI8r+22v1AuuYYqgP5aH6/ZFXusczSGkPdcauVIgKLV1I7dBBQkQm2LNIqAA==
+deleg.example.com. 3600 RRSIG A 13 3 3600 20400405162736 20210204145736 61806 example.com. beD3O8cnCQ+8HWZpn35gFrR2tLkb9tGpe143BfUA0aOkAr2PdK9CUBs47uSyWAATYoa11gtxxdFUzW6coa7l/w==
+deleg.example.com. 3600 RRSIG NS 13 3 3600 20400405162736 20210204145736 61806 example.com. HJCAXBevueFA2BOP6eOnsbP1X+2VUQRGXRcYI2SDqqq4U2DQHWQMOfI+pKVpkfdc8D6qDYnFZSg6II/dDJQ0AQ==
+deleg.example.com. 3600 RRSIG DS 13 3 3600 20400405162736 20210204145736 61806 example.com. DhZsh6wiPACEUz7GY4WpvcIrMOF+sU27kJAGKaCcpxv9jQBY7Jpf/otRf+yn+Bmm32RZUr5swSXMXAvDtCj6qA==
+dns1.example.com. 3600 RRSIG A 13 3 3600 20400405162736 20210204145736 61806 example.com. z/pEp4EcGkmy+niefZRLgRo1LraBlJABdgpSo94cYEqJM3GBMHsPZeAKmqnMAYA5Nz0hQtTplqS3rsJHJJdQ7w==
+www.example.com. 3600 RRSIG A 13 3 3600 20400405162736 20210204145736 61806 example.com. FpOwodJYlk3NxEEjGvY75r8Ptef13P4Um9N74NxV1QWQlqtBhg+1bndvaY376uBFVDFGsEiDFEgIoFL0Ao+PeA==
+
+
diff --git a/tests/knot/semantic_check_data/nsec3_missing.signed b/tests/knot/semantic_check_data/nsec3_missing.signed
new file mode 100644
index 0000000..4974956
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_missing.signed
@@ -0,0 +1,120 @@
+
+; extra record without corresponding NSEC3
+extra.example.com. 3600 IN A 1.2.3.4
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignature12345678
+ 123456789123456789123456789123456789
+ lqhxunAbh08dsQ== )
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 0 10 - (
+ 6DFJITU5VML86QNKU9FO2LJDDQQTQPVT
+ A RRSIG )
+6DFJITU5VML86QNKU9FO2LJDDQQTQPVT.example.com. 86400 IN NSEC3 1 0 10 - (
+ MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938
+ A RRSIG )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 86400 IN NSEC3 1 0 10 - (
+ UI312KQOP1NG8IQEIEFNPSLA94KB5Q92
+ NS )
+UI312KQOP1NG8IQEIEFNPSLA94KB5Q92.example.com. 86400 IN NSEC3 1 0 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ A RRSIG)
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN A 1.2.3.4
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 RRSIG A 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DPwNyH7r/4wIBfTGxikNv4pY7omY6IqpQS6Q
+ jtTNuStA+5gk98dvcgRjluxqo/+ZlZz4V53f
+ 1y506ytGbX/q4Q== )
+
+
+UI312KQOP1NG8IQEIEFNPSLA94KB5Q92.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignature4ey0Qcln
+ uquQZT+z2HIdCE9HeslAkTlu/Xt78vF4+3db
+ t2Vno21DkteA+w== )
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignature4ey0Qcln
+ uquQZT+z2HIdCE9HeslAkTlu/Xt78vF4+3db
+ t2Vno21DkteA+w== )
+6DFJITU5VML86QNKU9FO2LJDDQQTQPVT.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ KElp8dLKBKFzgEFV8r5aP9pCyYUD+Z8rLBA9
+ KkCDm1y82x5T/Cu5UXuZJwhvDGDzwPqoY5Dr
+ Qbiek52n6umbEw== )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DummySignatureDummySignatureD37X9Bw2
+ 9JOkecZnmzCwBqfMCBvRYmNRpMd512+ZnW/I
+ 1vIViE7CGwkHyA== )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160302125715 29600 example.com.
+ DPwNyH7r/4wIBfTGxikNv4pY7omY6IqpQS6Q
+ jtTNuStA+5gk98dvcgRjluxqo/+ZlZz4V53f
+ 1y506ytGbX/q4Q== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ bGk1vLxVuJpcEy7n0gPvQVzfanbvINLJLcbD
+ eeie4sXZZAOwu6oQZy6kd8tvKtV4mL0OJzpH
+ XCO6BdZkmk/aQA== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ roe4aBp4G3TqQ4x5eRxbVIjApIh17gXDjfOY
+ zvRFLOkrwqKz3eX9WrRiCk3bYNn8s1fuenaQ
+ OSV1D5SL7utX5w== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ c1yhXb8wRGYndpVqG61+lHAAbZg+JcVYGPX3
+ Fw0jYigN4G+P0+VUCqPLkC4yfJylzuefyGfk
+ TUmriM3ihfXxIg== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160302125715 31323 example.com.
+ mZiLLTzbdaj7EJ8uj3TwvcvAfaMxYjyavlGT
+ qpa+cElfvBDm7R6MF4MaEQ9aZ2ylMt1lppjq
+ YyYRaaQC6yhm4g== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160302125715 29600 example.com.
+ K3PkVYZZV8QvZFtDsz9+ZfiM9wDkFu/eO2S5
+ tAtCXd1fktcW44TLWL0qADfFEEcMotvzLqv1
+ YJrD7TvrFDot8Q== )
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ vlzRtVFa44pRtdD8XZcgDa6021uA9A3TnNEw
+ 5jRnor4aoftUuVQNAanQMCgrWk63d14XZ2d0
+ lqhxunAbh08dsQ== )
+
+www.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160302125715 29600 example.com.
+ NWFuYaSEg3z3K4l/fHu/X9dK+rDZ177BbCNN
+ ZeFTPCAdOnX0nw1CQys629k7Vzdv1pHaanmy
+ 0Ru0tX9R65NlKw== )
+
+
diff --git a/tests/knot/semantic_check_data/nsec3_optout.signed b/tests/knot/semantic_check_data/nsec3_optout.signed
new file mode 100644
index 0000000..c9caa5d
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_optout.signed
@@ -0,0 +1,81 @@
+
+; insecure delegation, not covered by NSEC3 or opt-out
+zzz.example.com. 3600 IN NS zzz.example.com.
+ 3600 A 192.0.2.1
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ W9EprjaR4loSnNW96h4rLsquPDw3LHYvD05k
+ djkQofHSkMNZAJ7Q+eA3Fs2ik5fnJFM7wi5C
+ MtFsV2TfqMJFmg== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ I9Je1S7XhZIW9C0fWE8NwFLC2rhHklddNYBO
+ dxVKL/lxENU4jPPBwZBGrcYn2WVHgkIzjG0n
+ EOHONAgRFPi3Xw== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ vO2UQiTN/CNUZOmSEg8kJlR/UqiAZHc4qMwj
+ 9u31sbPmOMuni+ZGuVCFFoEMtZerIkkQowkB
+ sXJFkvCP5oF2rA== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160229083110 31323 example.com.
+ Z+aaLu4rmzekfhlj6A0ClREloRi8MloRHf/3
+ Dlw/RYY1hrOCfcZKEY6AXeVdUwESEsSkSOco
+ CbhyGHH10dKAAg== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160229083110 29600 example.com.
+ d69kc52VdALI8fbdbflsVsltc1m7bI6QsJ5U
+ IDE9fy5VqcufZecZMKuozPDuF2vBA8ADFIRU
+ OfYgKs6YNIOLWg== )
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 0 10 - (
+ MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938
+ A RRSIG )
+ 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229083110 29600 example.com.
+ D24JCtCcNzwsY1FXVliAjxMm+x95N2eUTXn0
+ M8NK5glSk1yLtnAUKzHxpRExAJLGUiaG4yPu
+ 2yGZuqwNvJztzw== )
+MJV836RJQEJ5UBGHVKSQ7N44RSO3Q938.example.com. 86400 IN NSEC3 1 0 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ NS )
+ 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229083110 29600 example.com.
+ jRNMrWLfS4yzRHQOBxs6/GKWIzx6AZV5lyCm
+ 7bYTV9wS3owDJSQhJ7lft0WbBmUMtV3tP9Xr
+ Yc+yW48p2Vr+QQ== )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+ 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229083110 29600 example.com.
+ F7y+xW/C7iICgmZeYrF4e7Yx4kWZAZPAMzlu
+ PtWVuf37ySg1VfEWcQcDP04vF2rXVUqSMEcj
+ bqUVN5W8Hoazxw== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ MoYrL/lToC4AHo6KCZRiBRmCMWHUAx2Xt32A
+ P4lDpwA+wiBWkCZSfVTh60AosS/BIGtBb2BK
+ mszMx8CLBvkjRg== )
diff --git a/tests/knot/semantic_check_data/nsec3_optout_ent.all b/tests/knot/semantic_check_data/nsec3_optout_ent.all
new file mode 100644
index 0000000..5ebd917
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_optout_ent.all
@@ -0,0 +1,15 @@
+example.com. 3600 SOA dns1.com. hostmaster.com. 2010111217 21600 3600 604800 86400
+example.com. 3600 NS dns1.com.
+example.com. 3600 DNSKEY 256 3 13 tCoteOM+A4o/A9uxgLyDg3HOg2DClU+3d+1XPQRtTfuaEFOGIpyH6qiFUv2b4DYuvmMyTkL99nxvyhA8yo0Cgg==
+example.com. 3600 DNSKEY 257 3 13 Yk8KOmyVzOij3x+Zs+eT4J2Up9+ipwXEKOhL9fTYY/DU10yIQt+zYm02UFZJX2oVTdHBCajpBFsZLH2X4ho1yw==
+example.com. 0 NSEC3PARAM 1 0 10 151E9F1094FE188F
+deleg1.ent.example.com. 3600 NS glue.outofzone.net.
+deleg2.ent.example.com. 3600 NS glue.outofzone.net.
+
+example.com. 3600 RRSIG NS 13 2 3600 20400410173442 20210209160442 61806 example.com. laxHzto10anAyWXb/IqVEoBsybVmb/aCMb4SdxEC3YiJFj1IX9rxChVnuXrQ5zgr1f6YaRyc/DDTP8NFvwyTWg==
+example.com. 3600 RRSIG SOA 13 2 3600 20400410173442 20210209160442 61806 example.com. /eNl2bkB/SJ6qBX+Jpm5KTXIs5Xi978JWRN2jtbEh5Z9udy7liS73oMkBLlJ33amKc7Gwfqi2+SgdHHud4j0Ug==
+example.com. 3600 RRSIG DNSKEY 13 2 3600 20400410173442 20210209160442 25674 example.com. TpePckJM7GcsE72vbfSf49LzEM1chUFIiKBN0VyCHdB3YFpRH5d8Qx+XWh8Vs9AuLoKMWTQ0UD4kZK8yF70N4A==
+example.com. 0 RRSIG NSEC3PARAM 13 2 0 20400410173442 20210209160442 61806 example.com. RfPCpoA94H+dm7fqxhZ+GIf4fQwzN19yJVbhmEOtx6if9U/H6mJalvoy4d5UD/L2bferTBbie4I/TzAIXgVETQ==
+
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 NSEC3 1 1 10 151E9F1094FE188F ple28jlp3q5anh045ssk9f3u7ltd4qlc NS SOA RRSIG DNSKEY NSEC3PARAM
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 RRSIG NSEC3 13 3 3600 20400410181548 20210209164548 61806 example.com. EBPlHXYdARm1T0TaYadx0ETwC6w0g5J1yPR6LB3ur9IItcEWRONhqDrNwUbYGbW5c4nWep/hnJYdmMFq1bTfiw==
diff --git a/tests/knot/semantic_check_data/nsec3_optout_ent.invalid b/tests/knot/semantic_check_data/nsec3_optout_ent.invalid
new file mode 100644
index 0000000..114d5d7
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_optout_ent.invalid
@@ -0,0 +1,18 @@
+example.com. 3600 SOA dns1.com. hostmaster.com. 2010111217 21600 3600 604800 86400
+example.com. 3600 NS dns1.com.
+example.com. 3600 DNSKEY 256 3 13 tCoteOM+A4o/A9uxgLyDg3HOg2DClU+3d+1XPQRtTfuaEFOGIpyH6qiFUv2b4DYuvmMyTkL99nxvyhA8yo0Cgg==
+example.com. 3600 DNSKEY 257 3 13 Yk8KOmyVzOij3x+Zs+eT4J2Up9+ipwXEKOhL9fTYY/DU10yIQt+zYm02UFZJX2oVTdHBCajpBFsZLH2X4ho1yw==
+example.com. 0 NSEC3PARAM 1 0 10 151E9F1094FE188F
+deleg1.ent.example.com. 3600 NS glue.outofzone.net.
+deleg2.ent.example.com. 3600 NS glue.outofzone.net.
+
+example.com. 3600 RRSIG NS 13 2 3600 20400410173442 20210209160442 61806 example.com. laxHzto10anAyWXb/IqVEoBsybVmb/aCMb4SdxEC3YiJFj1IX9rxChVnuXrQ5zgr1f6YaRyc/DDTP8NFvwyTWg==
+example.com. 3600 RRSIG SOA 13 2 3600 20400410173442 20210209160442 61806 example.com. /eNl2bkB/SJ6qBX+Jpm5KTXIs5Xi978JWRN2jtbEh5Z9udy7liS73oMkBLlJ33amKc7Gwfqi2+SgdHHud4j0Ug==
+example.com. 3600 RRSIG DNSKEY 13 2 3600 20400410173442 20210209160442 25674 example.com. TpePckJM7GcsE72vbfSf49LzEM1chUFIiKBN0VyCHdB3YFpRH5d8Qx+XWh8Vs9AuLoKMWTQ0UD4kZK8yF70N4A==
+example.com. 0 RRSIG NSEC3PARAM 13 2 0 20400410173442 20210209160442 61806 example.com. RfPCpoA94H+dm7fqxhZ+GIf4fQwzN19yJVbhmEOtx6if9U/H6mJalvoy4d5UD/L2bferTBbie4I/TzAIXgVETQ==
+
+gtr2v0c3d7eqh7ob8rbad7ta90tq8lci.example.com. 3600 NSEC3 1 1 10 151E9F1094FE188F ple28jlp3q5anh045ssk9f3u7ltd4qlc NS
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 NSEC3 1 1 10 151E9F1094FE188F gtr2v0c3d7eqh7ob8rbad7ta90tq8lci NS SOA RRSIG DNSKEY NSEC3PARAM
+
+gtr2v0c3d7eqh7ob8rbad7ta90tq8lci.example.com. 3600 RRSIG NSEC3 13 3 3600 20400410173442 20210209160442 61806 example.com. gb3uKByt54iwCsd284xzOVnnpN97r7ARz6UacMdm2Xs4M8t6Ao9bRG7jvbNpFCALfaU/xDQF7K3v31iKBeVwjw==
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 RRSIG NSEC3 13 3 3600 20400410173442 20210209160442 61806 example.com. kpuFRuzOhsG5zy0Sdql0AB44IDUtf9ccTwJXdULoIqUNKeRqvgWJ7ekEhBKvntVHlBQZPescgPMvvq7PLcA2Dw==
diff --git a/tests/knot/semantic_check_data/nsec3_optout_ent.valid b/tests/knot/semantic_check_data/nsec3_optout_ent.valid
new file mode 100644
index 0000000..c9fe657
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_optout_ent.valid
@@ -0,0 +1,20 @@
+example.com. 3600 SOA dns1.com. hostmaster.com. 2010111217 21600 3600 604800 86400
+example.com. 3600 NS dns1.com.
+example.com. 3600 DNSKEY 256 3 13 tCoteOM+A4o/A9uxgLyDg3HOg2DClU+3d+1XPQRtTfuaEFOGIpyH6qiFUv2b4DYuvmMyTkL99nxvyhA8yo0Cgg==
+example.com. 3600 DNSKEY 257 3 13 Yk8KOmyVzOij3x+Zs+eT4J2Up9+ipwXEKOhL9fTYY/DU10yIQt+zYm02UFZJX2oVTdHBCajpBFsZLH2X4ho1yw==
+example.com. 0 NSEC3PARAM 1 0 10 151E9F1094FE188F
+deleg1.ent.example.com. 3600 NS glue.outofzone.net.
+deleg2.ent.example.com. 3600 NS glue.outofzone.net.
+
+example.com. 3600 RRSIG NS 13 2 3600 20400410173236 20210209160236 61806 example.com. C4ierSNpy03xjH5rQEfb01wCj4SVIzX9b15FVEMIbn3lmDo5jXO6stOrW8Z7OjoVuCaRi1Qj997TeCYqOxNXSQ==
+example.com. 3600 RRSIG SOA 13 2 3600 20400410173236 20210209160236 61806 example.com. NNyQzYOcPbfEsqv61I78MuMguN/KIFi/wSJc940pj7rv+riA3J+XVzpaHSSh//q8CmrvpBAk2g8KsQG/6kOXmg==
+example.com. 3600 RRSIG DNSKEY 13 2 3600 20400410173236 20210209160236 25674 example.com. ZY3nxZJeOfSOEhs02mfhQgt6N1EgZubtPp3HuV69gStFSu4aCLi8a2aseQGilOFW64dOAYNm3LL/WqhPi7MZ1Q==
+example.com. 0 RRSIG NSEC3PARAM 13 2 0 20400410173236 20210209160236 61806 example.com. JITs/EH8nLaFRidlkT6+mcTwEpjgp2TMjb9fU5TBIlKn94og8YtOWFbNmzdEYBKlGLlkg8LwY2ortrSoRHS6Hw==
+
+ej69a9a2k2j0ntktmdvihrv5ao8fl1jt.example.com. 3600 NSEC3 1 1 10 151E9F1094FE188F gtr2v0c3d7eqh7ob8rbad7ta90tq8lci
+gtr2v0c3d7eqh7ob8rbad7ta90tq8lci.example.com. 3600 NSEC3 1 1 10 151E9F1094FE188F ple28jlp3q5anh045ssk9f3u7ltd4qlc NS
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 NSEC3 1 1 10 151E9F1094FE188F ej69a9a2k2j0ntktmdvihrv5ao8fl1jt NS SOA RRSIG DNSKEY NSEC3PARAM
+
+ej69a9a2k2j0ntktmdvihrv5ao8fl1jt.example.com. 3600 RRSIG NSEC3 13 3 3600 20400410173236 20210209160236 61806 example.com. yatL/lbFSUyN4UyRtMXymxsiqhOXHp+N+pTI/zNOc0NXCdaaLceh+tZHlc+E4napRfP53XXEhuGavjShTIJ/+g==
+gtr2v0c3d7eqh7ob8rbad7ta90tq8lci.example.com. 3600 RRSIG NSEC3 13 3 3600 20400410173236 20210209160236 61806 example.com. 20XNZrfJ4l/JIDjCbsba3mUOrNyOxJ2VuCju/yLc0XbdzqMcKJR87g3u967GEnoYY5f5+rJt/IHsuJWHcLApCQ==
+ple28jlp3q5anh045ssk9f3u7ltd4qlc.example.com. 3600 RRSIG NSEC3 13 3 3600 20400410173236 20210209160236 61806 example.com. eLRo9y8Rxf157qcciWM/LSUbtjYks2zLO5xQ9Ff5bidHc9m2XEqjWxqdPZz5gurEf+uPnM8mnix36X4YH4ZXwg==
diff --git a/tests/knot/semantic_check_data/nsec3_param_invalid.signed b/tests/knot/semantic_check_data/nsec3_param_invalid.signed
new file mode 100644
index 0000000..c7d8d6d
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_param_invalid.signed
@@ -0,0 +1,70 @@
+; Zone without any semantic error
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ W9EprjaR4loSnNW96h4rLsquPDw3LHYvD05k
+ djkQofHSkMNZAJ7Q+eA3Fs2ik5fnJFM7wi5C
+ MtFsV2TfqMJFmg== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ I9Je1S7XhZIW9C0fWE8NwFLC2rhHklddNYBO
+ dxVKL/lxENU4jPPBwZBGrcYn2WVHgkIzjG0n
+ EOHONAgRFPi3Xw== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ vO2UQiTN/CNUZOmSEg8kJlR/UqiAZHc4qMwj
+ 9u31sbPmOMuni+ZGuVCFFoEMtZerIkkQowkB
+ sXJFkvCP5oF2rA== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160229083110 31323 example.com.
+ Z+aaLu4rmzekfhlj6A0ClREloRi8MloRHf/3
+ Dlw/RYY1hrOCfcZKEY6AXeVdUwESEsSkSOco
+ CbhyGHH10dKAAg== )
+ 0 NSEC3PARAM 1 4 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160229083110 29600 example.com.
+ d69kc52VdALI8fbdbflsVsltc1m7bI6QsJ5U
+ IDE9fy5VqcufZecZMKuozPDuF2vBA8ADFIRU
+ OfYgKs6YNIOLWg== )
+deleg.example.com. 3600 IN NS deleg.example.com.
+ 3600 A 192.0.2.1
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 1 15 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ A RRSIG )
+ 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229083110 29600 example.com.
+ D24JCtCcNzwsY1FXVliAjxMm+x95N2eUTXn0
+ M8NK5glSk1yLtnAUKzHxpRExAJLGUiaG4yPu
+ 2yGZuqwNvJztzw== )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 4 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+ 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160229083110 29600 example.com.
+ F7y+xW/C7iICgmZeYrF4e7Yx4kWZAZPAMzlu
+ PtWVuf37ySg1VfEWcQcDP04vF2rXVUqSMEcj
+ bqUVN5W8Hoazxw== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160229083110 29600 example.com.
+ MoYrL/lToC4AHo6KCZRiBRmCMWHUAx2Xt32A
+ P4lDpwA+wiBWkCZSfVTh60AosS/BIGtBb2BK
+ mszMx8CLBvkjRg== )
diff --git a/tests/knot/semantic_check_data/nsec3_wrong_bitmap_01.signed b/tests/knot/semantic_check_data/nsec3_wrong_bitmap_01.signed
new file mode 100644
index 0000000..a3024d8
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_wrong_bitmap_01.signed
@@ -0,0 +1,70 @@
+; example.com -- missing DNSKEY in type bitmap
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG NSEC3PARAM )
+; dns1.example.com
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 0 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ A RRSIG )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160225083237 29600 example.com.
+ li23VC44fumpMHhKwWug2J1C2fwCMiwgofYO
+ DKydNYsJyYTlyi8ezLJ2KoBlCtOc4Fp0NbqS
+ aN8CKWh7fQVnkQ== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160225083237 29600 example.com.
+ Y8olY2OClZgC+QHnOhY52LONVOcctOnl8jNY
+ /c7sCHZO4TdPPDHDhpbVntQD+Vc4fUTx+cXY
+ GrF5sLbhddBJXg== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160225083237 29600 example.com.
+ fx2rZzhyYrp1b4tNH1SmM852VbGEeZdKrD+f
+ ZoInny1m8sovb1J9ORtVbGkOYOnInDMLWMCX
+ fghHC2MafuFV+Q== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160225083237 31323 example.com.
+ TcNU6AlrYhJLrNlkfOPJzO6A77j6C39IPoP4
+ OfmY2ClA5Vx2JO0vQ4bIHR7GIW8fiMe6M6tt
+ ZwQImhVWdG414A== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160225083237 29600 example.com.
+ iY0WB0dN1hQXoctaMwvvXzn7paQt5xUyucT3
+ xwo6HAI8Y+OJlecUfOpkkQ9lqIfsqPTXmgbY
+ RieoZGrWR6ZvaQ== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160225083237 29600 example.com.
+ QptUkTNS7umNQ5V6Z9DyGl6z+rG7G3TFmHG8
+ p9HGaKifSxjwSFW0nZ9/s86XHQ8ql5+bQmPa
+ xw39ntBmQLVxfg== )
+
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160225083237 29600 example.com.
+ CPx6000z5m1zUUpVhki1u9U7P/WMr7PUJAk3
+ G0w3v+/Lw56mDzYzNuTpPzS0noe0LKuecqRu
+ m99KpLyLOx+9QA== )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160225083237 29600 example.com.
+ m2z+hx+8hTA7Phu6QzGJrq+o4MiURpda3fYm
+ 0wTDmXtfPKsHmojGr3kBlvUMg16s2gpvNyCL
+ MSlnJ+7KCkI+Mw== )
diff --git a/tests/knot/semantic_check_data/nsec3_wrong_bitmap_02.signed b/tests/knot/semantic_check_data/nsec3_wrong_bitmap_02.signed
new file mode 100644
index 0000000..e3e4940
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec3_wrong_bitmap_02.signed
@@ -0,0 +1,70 @@
+; example.com
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 IN NSEC3 1 0 10 - (
+ 20G1GOL477RO51RK9A9NFD54TFQAL7IQ
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+; dns1.example.com -- extra type in bitmap - NSEC
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 IN NSEC3 1 0 10 - (
+ UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A
+ A RRSIG NSEC)
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160225083237 29600 example.com.
+ li23VC44fumpMHhKwWug2J1C2fwCMiwgofYO
+ DKydNYsJyYTlyi8ezLJ2KoBlCtOc4Fp0NbqS
+ aN8CKWh7fQVnkQ== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160225083237 29600 example.com.
+ Y8olY2OClZgC+QHnOhY52LONVOcctOnl8jNY
+ /c7sCHZO4TdPPDHDhpbVntQD+Vc4fUTx+cXY
+ GrF5sLbhddBJXg== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160225083237 29600 example.com.
+ fx2rZzhyYrp1b4tNH1SmM852VbGEeZdKrD+f
+ ZoInny1m8sovb1J9ORtVbGkOYOnInDMLWMCX
+ fghHC2MafuFV+Q== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160225083237 31323 example.com.
+ TcNU6AlrYhJLrNlkfOPJzO6A77j6C39IPoP4
+ OfmY2ClA5Vx2JO0vQ4bIHR7GIW8fiMe6M6tt
+ ZwQImhVWdG414A== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 2 0 (
+ 20840201000000 20160225083237 29600 example.com.
+ iY0WB0dN1hQXoctaMwvvXzn7paQt5xUyucT3
+ xwo6HAI8Y+OJlecUfOpkkQ9lqIfsqPTXmgbY
+ RieoZGrWR6ZvaQ== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160225083237 29600 example.com.
+ QptUkTNS7umNQ5V6Z9DyGl6z+rG7G3TFmHG8
+ p9HGaKifSxjwSFW0nZ9/s86XHQ8ql5+bQmPa
+ xw39ntBmQLVxfg== )
+
+20G1GOL477RO51RK9A9NFD54TFQAL7IQ.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160225083237 29600 example.com.
+ CPx6000z5m1zUUpVhki1u9U7P/WMr7PUJAk3
+ G0w3v+/Lw56mDzYzNuTpPzS0noe0LKuecqRu
+ m99KpLyLOx+9QA== )
+UTQVUHU2BLK3DHMRR5T1HD9VTEOHQT0A.example.com. 86400 RRSIG NSEC3 7 3 86400 (
+ 20840201000000 20160225083237 29600 example.com.
+ m2z+hx+8hTA7Phu6QzGJrq+o4MiURpda3fYm
+ 0wTDmXtfPKsHmojGr3kBlvUMg16s2gpvNyCL
+ MSlnJ+7KCkI+Mw== )
diff --git a/tests/knot/semantic_check_data/nsec_broken_chain_01.signed b/tests/knot/semantic_check_data/nsec_broken_chain_01.signed
new file mode 100644
index 0000000..cb41dce
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec_broken_chain_01.signed
@@ -0,0 +1,72 @@
+; not coherent NSEC chain
+example.com. 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+dns1.example.com. 86400 NSEC example.com. A RRSIG NSEC
+www.example.com. 86400 NSEC example.com. A RRSIG NSEC
+
+; signatures for NSECs
+example.com. 86400 RRSIG NSEC 7 2 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ FHLUUQTvnVboNzGoQVLpwQAcB+fUEF5xQqMQ
+ oKhE86sdvlQUiEfUpv2PJ9y3YfXHeYxJUtvm
+ cY14UkYqsdP3fA== )
+dns1.example.com. 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ FDPJTLixRBZtMFLqk5wfYTSLnLMZiLtN7uTA
+ COEqyphK33oW+7XJzfG6ADvwGewY4hTCPQkk
+ cEg+DBI7qZ88NA== )
+www.example.com. 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ FDPJTLixRBZtMFLqk5wfYTSLnLMZiLtN7uTA
+ COEqyphK33oW+7XJzfG6ADvwGewY4hTCPQkk
+ cEg+DBI7qZ88NA== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ xJIoENJ4d24FIVd9ZSGpQlcWN4zuriU90r/H
+ +ufcM2qtWcOGR1M1LVNIAWEVJEcD2dBGA2w1
+ B7Cx+BILQRev8w== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ vBffD+/kBuxUHfeXKYBVYxeMIbuW5f8BstRM
+ XJnC1GTGfdNvb8NknHuv5fEytBmnnpH6f9pC
+ iWLeZzFR1+aJBA== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ LMyY8+vWsFB7CziWt8rnR5jfg4Loe/xzy4TQ
+ /ITEDbz5pkoadG+0mqTHQ0F5XCe6ZJPamcyr
+ kcMw0GqUzOVb9w== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224082919 31323 example.com.
+ tpHcGRuIkul47hHXVpNAOL48c5YYMsaIJkFE
+ rlQi9wU4TCiukdJkLuPk7ykk9XrxbiCB/FwD
+ o63Vcqyy3gZfvA== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ HlfZThngg+1xglDUh8kjDtzVn5D5a9T3emMt
+ Uxfryu9va7bj+xoK4gLADGau69GCZxJNSvwK
+ TAGEqGRYFSY9Ew== )
+www.example.com. 3600 IN A 192.0.2.2
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ FLR8e2k6u7dhQA1xZ3YMxkvuktoydXC+ZNwl
+ xzW9hLpF3oKoqqY/V+kw7m2OMgnOEu2jWN4Q
+ EETdmMeQzkiuNw== )
diff --git a/tests/knot/semantic_check_data/nsec_broken_chain_02.signed b/tests/knot/semantic_check_data/nsec_broken_chain_02.signed
new file mode 100644
index 0000000..5c5f004
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec_broken_chain_02.signed
@@ -0,0 +1,65 @@
+; not coherent NSEC chain
+example.com. 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+dns1.example.com. 86400 NSEC www.example.com. A RRSIG NSEC
+www.example.com. 86400 NSEC www.example.com. A RRSIG NSEC
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201008171141 31772 example.com.
+ Qwf3qgLbSvE4PmUVU8rpIASe0v1T1K0ie3Lw
+ g+6o3tpBS8vWcmHMUiKns/6rAvoum7vHQRmO
+ dH7X3Pp1/X3xCw== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201008171141 31772 example.com.
+ 92/D4j7CUCKkykxMzdjfJoaNrMwO93OQtZlB
+ APsfcEyYl+W0sSnow/2RgYvKfX+kdcmp5VXD
+ vQxTGC0VqdMwCQ== )
+ 86400 RRSIG NSEC 13 2 86400 (
+ 20601231235959 20201008171141 31772 example.com.
+ shdsucYBfD8/zV1h1QgUBiC7VgYdFxFEcF1k
+ FQfY+UHkfD/AyOkiFPQxysimgzqJn2/z5Q+v
+ GT1CzzzemgzoXw== )
+ 3600 DNSKEY 256 3 13 (
+ /4RnFpCmaYIIrL/zP1T6LvfhXdpun0ZyYDKL
+ ho0zuUD+RMDe31IQCzr9AuSn1BAIQWIunxFs
+ EaTSlvpiUd+CAg==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 31772
+ 3600 DNSKEY 257 3 13 (
+ /KEwa6qUWHdkpEMGX55UaIvl7do5l2IADCDq
+ iNnawoCLu7Tm4MU6ylzYS1htz1mTd8Zcuzl0
+ gkRe4FXwOmOzvQ==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 14119
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201008171141 14119 example.com.
+ FPftK2atu4GMOspSR24p5iIvmq2VKgPJMUTu
+ 5RiwflEf8UgD7s2WFe7A6/JLurwEhqa/313T
+ eEURk7m313h4jQ== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201008171141 31772 example.com.
+ +Xvcx4bZ536B8DtNwzurqmPPoDVdtS5nlRhQ
+ pMZ+OLsHECDnFaI50dSw4F1/c3DERz1ktM0+
+ QCC96MZ7QdAYQw== )
+ 86400 RRSIG NSEC 13 3 86400 (
+ 20601231235959 20201008171141 31772 example.com.
+ 64MPHHZG8wrbAtk+LY/5ISicI1vU7V19q9lF
+ wOm0mcpvoBERyDwadgZpmHsvin1sRt/LZYDr
+ iBKxcnaviHfULg== )
+www.example.com. 3600 IN A 192.0.2.2
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201008171141 31772 example.com.
+ +/+14BFYf5Iq9IIeX1Oz5XqxsaPaw3T6PTPH
+ neJz6N9QhnI6aKkGZFYBuqY0Zhmcr52zbhPi
+ 1yZAUTP7OvouhA== )
+ 86400 RRSIG NSEC 13 3 86400 (
+ 20601231235959 20201008171141 31772 example.com.
+ fPqL9hFml35JLmfX3MA32hMnMhh9UA1Mc2OZ
+ nY+0j4wTtVR0PVMWHOv9UaULzTCM+5mlpFXm
+ nRUMj8sMTGzFzw== )
diff --git a/tests/knot/semantic_check_data/nsec_missing.signed b/tests/knot/semantic_check_data/nsec_missing.signed
new file mode 100644
index 0000000..e901607
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec_missing.signed
@@ -0,0 +1,67 @@
+example.com. 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+dns1.example.com. 86400 NSEC example.com. A RRSIG NSEC
+; missing NSEC for www.example.com.
+
+; signatures for NSECs
+example.com. 86400 RRSIG NSEC 7 2 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ FHLUUQTvnVboNzGoQVLpwQAcB+fUEF5xQqMQ
+ oKhE86sdvlQUiEfUpv2PJ9y3YfXHeYxJUtvm
+ cY14UkYqsdP3fA== )
+dns1.example.com. 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ GF3mqBf6Ny481XSbEor1uTzQZtT2DSA/3jU2
+ ZcLXXhlmHG3nI/PB49lG+17O83rDrbhcYc8G
+ cHEbLIGNr/6+Mw== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ xJIoENJ4d24FIVd9ZSGpQlcWN4zuriU90r/H
+ +ufcM2qtWcOGR1M1LVNIAWEVJEcD2dBGA2w1
+ B7Cx+BILQRev8w== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ vBffD+/kBuxUHfeXKYBVYxeMIbuW5f8BstRM
+ XJnC1GTGfdNvb8NknHuv5fEytBmnnpH6f9pC
+ iWLeZzFR1+aJBA== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ LMyY8+vWsFB7CziWt8rnR5jfg4Loe/xzy4TQ
+ /ITEDbz5pkoadG+0mqTHQ0F5XCe6ZJPamcyr
+ kcMw0GqUzOVb9w== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224082919 31323 example.com.
+ tpHcGRuIkul47hHXVpNAOL48c5YYMsaIJkFE
+ rlQi9wU4TCiukdJkLuPk7ykk9XrxbiCB/FwD
+ o63Vcqyy3gZfvA== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ HlfZThngg+1xglDUh8kjDtzVn5D5a9T3emMt
+ Uxfryu9va7bj+xoK4gLADGau69GCZxJNSvwK
+ TAGEqGRYFSY9Ew== )
+
+www.example.com. 3600 IN A 192.0.2.2
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ FLR8e2k6u7dhQA1xZ3YMxkvuktoydXC+ZNwl
+ xzW9hLpF3oKoqqY/V+kw7m2OMgnOEu2jWN4Q
+ EETdmMeQzkiuNw== )
diff --git a/tests/knot/semantic_check_data/nsec_multiple.signed b/tests/knot/semantic_check_data/nsec_multiple.signed
new file mode 100644
index 0000000..0cd6aec
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec_multiple.signed
@@ -0,0 +1,66 @@
+; not coherent NSEC chain
+example.com. 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+dns1.example.com. 86400 NSEC www.example.com. A RRSIG NSEC
+www.example.com. 86400 NSEC example.com. A RRSIG NSEC
+www.example.com. 86400 NSEC www.example.com. A RRSIG NSEC
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201008170543 19445 example.com.
+ dEcgYVtA8cRE8ErOZGO/aaMat99+KuJdKoDc
+ 0+8fauQ3dcTUHVg2I+v4hdizjlmAJzGXJN+7
+ 6ssZgcvXCnWOsQ== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201008170543 19445 example.com.
+ 2OEk6Lpt+1c58vnCEHBrV7//7gyoo1bGJSHo
+ k+oWaF9Uh07XVkVWznq6mmCErqukUPLnW1Bn
+ rysjk4i5Yflqkg== )
+ 86400 RRSIG NSEC 13 2 86400 (
+ 20601231235959 20201008170543 19445 example.com.
+ icB72dzHg9d9klcTL/mW53mGIX6KzF0GLWUt
+ DKLCcu2Ailyp3kdM64dyJxRYTr7F7KfxyHi4
+ 3KJtphYNEA6ZWA== )
+ 3600 DNSKEY 256 3 13 (
+ H1roLYze5AZ+ouWMduBJtoJ8N5BPFdF3n6Pv
+ +Nfw5bNHUtCzgvMhmtX2gcRlmZ70Ycv1C/U+
+ mCvLWVdfJm08lA==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 19445
+ 3600 DNSKEY 257 3 13 (
+ MSWkrHjEr7zi143oQdRthBBzl70MXeILunB7
+ 8j55a5a9+Q39YKaIiRM4zyCV6WTXpm9H6eOS
+ RRgdQqGNL1gsKQ==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 23836
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201008170543 23836 example.com.
+ ejlk2L0CVBWuAxr1g+qivdvyIXqzp3+9U0tu
+ a2geLUtaVx8ErYnIvUug15S54g75+lZoZ1uK
+ l2WFWuy751kIsw== )
+www.example.com. 3600 IN A 192.0.2.2
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201008170543 19445 example.com.
+ 8k4wk4+kCs1kO3+8sL6zZdpkHw0U58oua/Ur
+ C8CHo6TjlLx/jRrLdQKcFy5H7gBMcJY76SDs
+ mT91HuWH+BpwNA== )
+ 86400 RRSIG NSEC 13 3 86400 (
+ 20601231235959 20201008170543 19445 example.com.
+ 3XbwYx32/Y8sLtQ+dW1lg+s1eaOSZlmkdJeO
+ IsLOAF6U9kq/2zrUTYCtFBMfqs5yYDEISK6X
+ W5UfBBdFRdYzgw== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 13 3 3600 (
+ 20601231235959 20201008170543 19445 example.com.
+ DDTolVJ5Mxfm8srRVi/SRu0+5y3OBTQCVFuQ
+ ywdv4IahQoE11pjXRCBUXvroTeDgoHrmD7PD
+ b1aIBxHLiC/2pg== )
+ 86400 RRSIG NSEC 13 3 86400 (
+ 20601231235959 20201008170543 19445 example.com.
+ DDhuGYMEij4vbJZlscX3os8qj/wgq55w63jc
+ 8mPr/LquDr6o6lrEYdcnZl4Rz22snnF2+po1
+ 3SEjRSJ0ROmTbw== )
diff --git a/tests/knot/semantic_check_data/nsec_wrong_bitmap_01.signed b/tests/knot/semantic_check_data/nsec_wrong_bitmap_01.signed
new file mode 100644
index 0000000..058a0a3
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec_wrong_bitmap_01.signed
@@ -0,0 +1,73 @@
+example.com. 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+dns1.example.com. 86400 NSEC www.example.com. A RRSIG NSEC
+
+; extra AAAA type in NSEC bitmap
+www.example.com. 86400 NSEC example.com. A RRSIG NSEC AAAA
+www.example.com. 3600 IN A 192.0.2.2
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ FLR8e2k6u7dhQA1xZ3YMxkvuktoydXC+ZNwl
+ xzW9hLpF3oKoqqY/V+kw7m2OMgnOEu2jWN4Q
+ EETdmMeQzkiuNw== )
+
+; signatures for NSECs
+example.com. 86400 RRSIG NSEC 7 2 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ FHLUUQTvnVboNzGoQVLpwQAcB+fUEF5xQqMQ
+ oKhE86sdvlQUiEfUpv2PJ9y3YfXHeYxJUtvm
+ cY14UkYqsdP3fA== )
+dns1.example.com. 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ GF3mqBf6Ny481XSbEor1uTzQZtT2DSA/3jU2
+ ZcLXXhlmHG3nI/PB49lG+17O83rDrbhcYc8G
+ cHEbLIGNr/6+Mw== )
+www.example.com. 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ FDPJTLixRBZtMFLqk5wfYTSLnLMZiLtN7uTA
+ COEqyphK33oW+7XJzfG6ADvwGewY4hTCPQkk
+ cEg+DBI7qZ88NA== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ xJIoENJ4d24FIVd9ZSGpQlcWN4zuriU90r/H
+ +ufcM2qtWcOGR1M1LVNIAWEVJEcD2dBGA2w1
+ B7Cx+BILQRev8w== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ vBffD+/kBuxUHfeXKYBVYxeMIbuW5f8BstRM
+ XJnC1GTGfdNvb8NknHuv5fEytBmnnpH6f9pC
+ iWLeZzFR1+aJBA== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ LMyY8+vWsFB7CziWt8rnR5jfg4Loe/xzy4TQ
+ /ITEDbz5pkoadG+0mqTHQ0F5XCe6ZJPamcyr
+ kcMw0GqUzOVb9w== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224082919 31323 example.com.
+ tpHcGRuIkul47hHXVpNAOL48c5YYMsaIJkFE
+ rlQi9wU4TCiukdJkLuPk7ykk9XrxbiCB/FwD
+ o63Vcqyy3gZfvA== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ HlfZThngg+1xglDUh8kjDtzVn5D5a9T3emMt
+ Uxfryu9va7bj+xoK4gLADGau69GCZxJNSvwK
+ TAGEqGRYFSY9Ew== )
diff --git a/tests/knot/semantic_check_data/nsec_wrong_bitmap_02.signed b/tests/knot/semantic_check_data/nsec_wrong_bitmap_02.signed
new file mode 100644
index 0000000..dafdc92
--- /dev/null
+++ b/tests/knot/semantic_check_data/nsec_wrong_bitmap_02.signed
@@ -0,0 +1,73 @@
+example.com. 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+dns1.example.com. 86400 NSEC www.example.com. A RRSIG NSEC
+
+; missing A type in NSEC bitmap
+www.example.com. 86400 NSEC example.com. RRSIG NSEC
+www.example.com. 3600 IN A 192.0.2.2
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ FLR8e2k6u7dhQA1xZ3YMxkvuktoydXC+ZNwl
+ xzW9hLpF3oKoqqY/V+kw7m2OMgnOEu2jWN4Q
+ EETdmMeQzkiuNw== )
+
+; signatures for NSECs
+example.com. 86400 RRSIG NSEC 7 2 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ FHLUUQTvnVboNzGoQVLpwQAcB+fUEF5xQqMQ
+ oKhE86sdvlQUiEfUpv2PJ9y3YfXHeYxJUtvm
+ cY14UkYqsdP3fA== )
+dns1.example.com. 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ GF3mqBf6Ny481XSbEor1uTzQZtT2DSA/3jU2
+ ZcLXXhlmHG3nI/PB49lG+17O83rDrbhcYc8G
+ cHEbLIGNr/6+Mw== )
+www.example.com. 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160224082919 29600 example.com.
+ FDPJTLixRBZtMFLqk5wfYTSLnLMZiLtN7uTA
+ COEqyphK33oW+7XJzfG6ADvwGewY4hTCPQkk
+ cEg+DBI7qZ88NA== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ xJIoENJ4d24FIVd9ZSGpQlcWN4zuriU90r/H
+ +ufcM2qtWcOGR1M1LVNIAWEVJEcD2dBGA2w1
+ B7Cx+BILQRev8w== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ vBffD+/kBuxUHfeXKYBVYxeMIbuW5f8BstRM
+ XJnC1GTGfdNvb8NknHuv5fEytBmnnpH6f9pC
+ iWLeZzFR1+aJBA== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ LMyY8+vWsFB7CziWt8rnR5jfg4Loe/xzy4TQ
+ /ITEDbz5pkoadG+0mqTHQ0F5XCe6ZJPamcyr
+ kcMw0GqUzOVb9w== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160224082919 31323 example.com.
+ tpHcGRuIkul47hHXVpNAOL48c5YYMsaIJkFE
+ rlQi9wU4TCiukdJkLuPk7ykk9XrxbiCB/FwD
+ o63Vcqyy3gZfvA== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160224082919 29600 example.com.
+ HlfZThngg+1xglDUh8kjDtzVn5D5a9T3emMt
+ Uxfryu9va7bj+xoK4gLADGau69GCZxJNSvwK
+ TAGEqGRYFSY9Ew== )
diff --git a/tests/knot/semantic_check_data/rrsig_rdata_ttl.signed b/tests/knot/semantic_check_data/rrsig_rdata_ttl.signed
new file mode 100644
index 0000000..28b118c
--- /dev/null
+++ b/tests/knot/semantic_check_data/rrsig_rdata_ttl.signed
@@ -0,0 +1,52 @@
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201008172615 16105 example.com.
+ UkbSKt1soIfnM7ZkNAfOcS4D3eHBzMQOef1d
+ bFK+ne+MtJsKEGM9brUD23v0f0CdvteVkeNS
+ 2oRrfrb3avZ08A== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201008172615 16105 example.com.
+ Mu/BsXIC10V5uRFUGR42/ntmT5eYt4192AQe
+ a5zdWnLo7A3GYHlPcOcZRMdqvsa3SAPOK2Br
+ UmFkHsWTawhWJQ== )
+ 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+ 86400 RRSIG NSEC 13 2 86400 (
+ 20601231235959 20201008172615 16105 example.com.
+ IexJzu8x2GxGzGrWlceYZmUbry2D+E67py6B
+ /7j2K5IPjNQVGKbItfvqjQTUm+eVrdcwFbyK
+ iiEuVeU7qG5hIw== )
+ 3600 DNSKEY 256 3 13 (
+ tGxruia7b3JYm32MDdFLYX1M1e44DQJmXpVM
+ EWDjcNulSNY5sWR/zgDzhqiQSKEKCFolwhB/
+ MFVIF71WNjE65Q==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 16105
+ 3600 DNSKEY 257 3 13 (
+ 24gAMJg6uXIBEdWkrAXmwP6znng79lTelLDg
+ WxeHbXriSxVPLSTYxrp7SO1FUi2N03v1RXcn
+ 5jONJdQYlxLtSg==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 17031
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201008172615 17031 example.com.
+ Tm4MkXCDkavltvRYnEp/enJzzjyjX3EgI8yY
+ OF2VuJY8uQHD0/uzZF3JTmXj7pkGShAUpFKI
+ Uzn5e3jrGqtMGA== )
+dns1.example.com. 3600 IN A 192.0.2.1
+; wrong RRSIG original-ttl
+ 3600 RRSIG A 13 3 600 (
+ 20601231235959 20201008172615 16105 example.com.
+ 7J01Zyly+ky0F94kfaDtERQDVyxhHexzqETa
+ qgsemJkH0pP9FKsEY/dTkeZUwCY4EFZeps7C
+ AOKyGTKdqR5N7Q== )
+ 86400 NSEC example.com. A RRSIG NSEC
+ 86400 RRSIG NSEC 13 3 86400 (
+ 20601231235959 20201008172615 16105 example.com.
+ 0evb+3+rXrrx0f8Za//w6q2acUZPvYbW+Ezj
+ BoJFvwBYHrhyiiVHlfUzmr/jJh9cTEdxPnL3
+ ow6ZUsfF0HJ4hg== )
diff --git a/tests/knot/semantic_check_data/rrsig_signed.signed b/tests/knot/semantic_check_data/rrsig_signed.signed
new file mode 100644
index 0000000..2798026
--- /dev/null
+++ b/tests/knot/semantic_check_data/rrsig_signed.signed
@@ -0,0 +1,62 @@
+dns1.example.com. 86400 RRSIG RRSIG 7 3 86400 (
+ 20840201000000 20160201000000 29600 example.com.
+ DummySignatureDEADBEEF8ijooV1IMfEtki
+ kLbaIvFcgZbPvTnXXHyesHO2OPiRsc7zF576
+ Z6prBT8CkMM7bw== )
+
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 7 2 3600 (
+ 20840201000000 20160201000000 29600 example.com.
+ kINKkWiBvb9Dpb0vghlLhXyObSzsYYNsOqe9
+ pWJN4lI4F2O3T6biPTQPsq3mYMR+6x9gPr6v
+ ysEPHlGtLdTLag== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 7 2 3600 (
+ 20840201000000 20160201000000 29600 example.com.
+ LkagMndC+wJGlQycPDvNmCZ0/QuBB7Zo4UVZ
+ He5jzQrE3Hnq8tn+/QfJ/yn62qCZ87DETwTT
+ rGaLqOTYRb1isg== )
+ 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+ 86400 RRSIG NSEC 7 2 86400 (
+ 20840201000000 20160201000000 29600 example.com.
+ YDJ1tQvNlv8Y7cGioq8nkbaETx7wmyJKqa0B
+ 8hDLClYA4nf9UtyVXqZCISa2PlgRdBc5GEEh
+ U5BuLr4wYXqEFA== )
+ 3600 DNSKEY 256 3 7 (
+ AwEAAcvvW/oJAjcRdntRC8J52baXoNFVWOFz
+ oVFe3Vgl8aBBiGh3gnbuNt7xKmy9z2qc2/35
+ MFwieWYfDdgUnPxyKMM=
+ ) ; ZSK; alg = NSEC3RSASHA1; key id = 29600
+ 3600 DNSKEY 257 3 7 (
+ AwEAAeXCF7sHLcFiaCwCFH4xh2CJcCp55i04
+ exG41EtzILS2waabEM5byhRkoylbv91q6HY+
+ JH9YXitS21LMD0Hqp1s=
+ ) ; KSK; alg = NSEC3RSASHA1; key id = 31323
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160201000000 29600 example.com.
+ FPOm8y3e09jh0fv0ZaOecWbdIXDAoERVKdjz
+ qsg1Etop1n6nDhO/lW3pwOUe02Zq2vretu2W
+ DozlDr5E6ZoqPA== )
+ 3600 RRSIG DNSKEY 7 2 3600 (
+ 20840201000000 20160201000000 31323 example.com.
+ cZTevjvA8UO9Tqet/pbsN0Peep6aN8heyxMK
+ XP/Twsj4u0DeClKeIN7pd7Gi7Aac/UV2dev/
+ x/90SM22VQVpeQ== )
+dns1.example.com. 3600 IN A 192.0.2.1
+ 3600 RRSIG A 7 3 3600 (
+ 20840201000000 20160201000000 29600 example.com.
+ f24sVhH1P/0mEMYTMbFLrWmJtl6kqZF6yzaS
+ TcyK6JhVM4sDT//YnjizJGsTVGSCelz3FxMj
+ LdiUm9AD05uY6A== )
+ 86400 NSEC example.com. A RRSIG NSEC
+ 86400 RRSIG NSEC 7 3 86400 (
+ 20840201000000 20160201000000 29600 example.com.
+ FgQ4VD1yDeA+uvJ+o8e1F28ijooV1IMfEtki
+ kLbaIvFcgZbPvTnXXHyesHO2OPiRsc7zF576
+ Z6prBT8CkMM7bw== )
diff --git a/tests/knot/semantic_check_data/rrsig_ttl.signed b/tests/knot/semantic_check_data/rrsig_ttl.signed
new file mode 100644
index 0000000..1aeef78
--- /dev/null
+++ b/tests/knot/semantic_check_data/rrsig_ttl.signed
@@ -0,0 +1,52 @@
+example.com. 3600 IN SOA dns1.example.com. hostmaster.example.com. (
+ 2010111220 ; serial
+ 21600 ; refresh (6 hours)
+ 3600 ; retry (1 hour)
+ 604800 ; expire (1 week)
+ 86400 ; minimum (1 day)
+ )
+ 3600 RRSIG SOA 13 2 3600 (
+ 20601231235959 20201008165912 34876 example.com.
+ NaUbzn4tb3bsVI4O2YgrefFtZPJSYlLKbVKB
+ HyIqwfQjwdkbIKZ5tqH/IGJagvj8oxeStwF/
+ vEoG9c/o/MNs4g== )
+ 3600 NS dns1.example.com.
+ 3600 RRSIG NS 13 2 3600 (
+ 20601231235959 20201008165912 34876 example.com.
+ YZqxQKpj3kxfRHxoQda1z9JD9nmX8uNJTBGV
+ qdMMU3cPOVamTzOqymseQYjBPaaeoxL1kyqk
+ K2w/ixOUCFp8qg== )
+ 86400 NSEC dns1.example.com. NS SOA RRSIG NSEC DNSKEY
+ 86400 RRSIG NSEC 13 2 86400 (
+ 20601231235959 20201008165912 34876 example.com.
+ 88QLNDpFWd2FIag2vcKGvY1HQFVeOaRIiMU5
+ 2VZfLFOPBmuTniTcnPvCt76i5ObPVsWdwJhM
+ /7NVMxoRPfMC1w== )
+ 3600 DNSKEY 256 3 13 (
+ 9+7buhxES5wZQZ54+O1qQGuRcKz3P3URZwws
+ 30CacknPsdcWAy7RN1yYmUjP80geUrxJVQt3
+ boo1BwFW4Rnnsg==
+ ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 34876
+ 3600 DNSKEY 257 3 13 (
+ eYNrBYFUn5JIhTlS3N0i2aFj1YE8127h3tlb
+ VJP9JAfMMxQT+Mg6lwDpUa0oQkNFbEoHhqrD
+ 0pcMvp4VeMgJ7g==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 36952
+ 3600 RRSIG DNSKEY 13 2 3600 (
+ 20601231235959 20201008165912 36952 example.com.
+ AVF7u7FzDx2ORApl74nP2hcJd4Szs1o1LXH5
+ OWe6JULh80kITEb9zogpCryQu41bYSZYuxMk
+ yeblfo1OEI2DZg== )
+dns1.example.com. 3600 IN A 192.0.2.1
+; TTL of RRSIG differs from original-ttl
+ 600 RRSIG A 13 3 3600 (
+ 20601231235959 20201008165912 34876 example.com.
+ +PPg6tDZVS2mbxWXOtVEYTQtjK+CkwRk/WFZ
+ dWgX3rzHPQ9AIexC9vKbXdont3s0xdHpcV/8
+ +Sf+N2h44ZTwMQ== )
+ 86400 NSEC example.com. A RRSIG NSEC
+ 86400 RRSIG NSEC 13 3 86400 (
+ 20601231235959 20201008165912 34876 example.com.
+ OCjWQ/5e4SUIWgR84IJLlghKyuowctiZ+b0q
+ eXB0o2qpcWoX6wfxzMlYxGtpgyq3OWKF+R8H
+ UBVCdT+qBt5VOA== )
diff --git a/tests/knot/test_acl.c b/tests/knot/test_acl.c
new file mode 100644
index 0000000..6a66404
--- /dev/null
+++ b/tests/knot/test_acl.c
@@ -0,0 +1,314 @@
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <tap/basic.h>
+
+#include "test_conf.h"
+#include "libknot/libknot.h"
+#include "knot/updates/acl.h"
+#include "contrib/sockaddr.h"
+
+#define ZONE "example.zone"
+#define ZONE2 "example2.zone"
+#define KEY1 "key1_md5"
+#define KEY2 "key2_md5"
+#define KEY3 "key3_sha256"
+
+static void check_sockaddr_set(struct sockaddr_storage *ss, int family,
+ const char *straddr, int port)
+{
+ int ret = sockaddr_set(ss, family, straddr, port);
+ ok(ret == 0, "set address '%s'", straddr);
+}
+
+void check_update(conf_t *conf, knot_rrset_t *authority, knot_tsig_key_t *key,
+ knot_dname_t *zone_name, bool allowed, const char *desc)
+{
+ struct sockaddr_storage addr;
+ check_sockaddr_set(&addr, AF_INET, "1.2.3.4", 0);
+
+ knot_pkt_t *query = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
+ assert(query);
+ knot_pkt_begin(query, KNOT_AUTHORITY);
+ knot_pkt_put(query, 0, authority, 0);
+
+ knot_pkt_t *parsed = knot_pkt_new(query->wire, query->size, NULL);
+ ok(knot_pkt_parse(parsed, 0) == KNOT_EOK, "Parse update packet");
+
+ conf_val_t acl = conf_zone_get(conf, C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+
+ bool ret = acl_allowed(conf, &acl, ACL_ACTION_UPDATE, &addr, key,
+ zone_name, parsed);
+ ok(ret == allowed, "%s", desc);
+
+ knot_pkt_free(parsed);
+ knot_pkt_free(query);
+}
+
+static void test_acl_allowed(void)
+{
+ int ret;
+ conf_val_t acl;
+ struct sockaddr_storage addr = { 0 };
+
+ knot_dname_t *zone_name = knot_dname_from_str_alloc(ZONE);
+ ok(zone_name != NULL, "create zone dname");
+ knot_dname_t *zone2_name = knot_dname_from_str_alloc(ZONE2);
+ ok(zone2_name != NULL, "create zone2 dname");
+ knot_dname_t *key1_name = knot_dname_from_str_alloc(KEY1);
+ ok(key1_name != NULL, "create "KEY1);
+ knot_dname_t *key2_name = knot_dname_from_str_alloc(KEY2);
+ ok(key2_name != NULL, "create "KEY2);
+ knot_dname_t *key3_name = knot_dname_from_str_alloc(KEY3);
+ ok(key3_name != NULL, "create "KEY3);
+
+ knot_tsig_key_t key0 = { 0 };
+ knot_tsig_key_t key1 = { DNSSEC_TSIG_HMAC_MD5, key1_name };
+ knot_tsig_key_t key2 = { DNSSEC_TSIG_HMAC_MD5, key2_name };
+ knot_tsig_key_t key3 = { DNSSEC_TSIG_HMAC_SHA256, key3_name };
+
+ const char *conf_str =
+ "key:\n"
+ " - id: "KEY1"\n"
+ " algorithm: hmac-md5\n"
+ " secret: Zm9v\n"
+ " - id: "KEY2"\n"
+ " algorithm: hmac-md5\n"
+ " secret: Zm9v\n"
+ " - id: "KEY3"\n"
+ " algorithm: hmac-sha256\n"
+ " secret: Zm8=\n"
+ "\n"
+ "remote:\n"
+ " - id: remote_v6_ko\n"
+ " address: [ 2009::1 ]\n"
+ " key: key1_md5\n"
+ " - id: remote_v6_ok\n"
+ " address: [ 127.0.0.1, 2001::1 ]\n"
+ " key: key1_md5\n"
+ "\n"
+ "acl:\n"
+ " - id: acl_key_addr\n"
+ " remote: [ remote_v6_ko, remote_v6_ok ]\n"
+ " action: [ transfer ]\n"
+ " - id: acl_deny\n"
+ " address: [ 240.0.0.2 ]\n"
+ " action: [ notify ]\n"
+ " deny: on\n"
+ " - id: acl_no_action_deny\n"
+ " address: [ 240.0.0.3 ]\n"
+ " deny: on\n"
+ " - id: acl_multi_addr\n"
+ " address: [ 192.168.1.1, 240.0.0.0/24 ]\n"
+ " action: [ notify, update ]\n"
+ " - id: acl_multi_key\n"
+ " key: [ key2_md5, key3_sha256 ]\n"
+ " action: [ notify, update ]\n"
+ " - id: acl_range_addr\n"
+ " address: [ 100.0.0.0-100.0.0.5, ::0-::5 ]\n"
+ " action: [ transfer ]\n"
+ " - id: acl_deny_no_action_no_key\n"
+ " address: [ 240.0.0.4 ]\n"
+ " deny: on\n"
+ " - id: acl_notify_key\n"
+ " address: [ 240.0.0.0/24 ]\n"
+ " key: "KEY1"\n"
+ " action: [ notify ]\n"
+ " - id: acl_update_key\n"
+ " key: "KEY1"\n"
+ " update-owner: key\n"
+ " update-type: [ AAAA, A ]\n"
+ " action: [ update ]\n"
+ " - id: acl_update_name\n"
+ " key: "KEY2"\n"
+ " update-owner: name\n"
+ " update-owner-name: [ a, b."KEY2". ]\n"
+ " update-owner-match: equal\n"
+ " action: [ update ]\n"
+ "\n"
+ "zone:\n"
+ " - domain: "ZONE"\n"
+ " acl: [ acl_key_addr, acl_deny, acl_no_action_deny ]\n"
+ " acl: [ acl_multi_addr, acl_multi_key ]\n"
+ " acl: [ acl_range_addr ]\n"
+ " - domain: "ZONE2"\n"
+ " acl: [ acl_deny_no_action_no_key, acl_notify_key ]\n"
+ " - domain: "KEY1"\n"
+ " acl: acl_update_key\n"
+ " - domain: "KEY2"\n"
+ " acl: acl_update_name";
+
+ ret = test_conf(conf_str, NULL);
+ is_int(KNOT_EOK, ret, "Prepare configuration");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET6, "2001::1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_QUERY, &addr, &key1, zone_name, NULL);
+ ok(ret == true, "Address, key, empty action");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET6, "2001::1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_TRANSFER, &addr, &key1, zone_name, NULL);
+ ok(ret == true, "Address, key, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET6, "2001::2", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_TRANSFER, &addr, &key1, zone_name, NULL);
+ ok(ret == false, "Address not match, key, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET6, "2001::1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_TRANSFER, &addr, &key0, zone_name, NULL);
+ ok(ret == false, "Address match, no key, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET6, "2001::1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_TRANSFER, &addr, &key2, zone_name, NULL);
+ ok(ret == false, "Address match, key not match, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET6, "2001::1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_NOTIFY, &addr, &key1, zone_name, NULL);
+ ok(ret == false, "Address, key match, action not match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET, "240.0.0.1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_NOTIFY, &addr, &key0, zone_name, NULL);
+ ok(ret == true, "Second address match, no key, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET, "240.0.0.1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_NOTIFY, &addr, &key1, zone_name, NULL);
+ ok(ret == false, "Second address match, extra key, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET, "240.0.0.2", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_NOTIFY, &addr, &key0, zone_name, NULL);
+ ok(ret == false, "Denied address match, no key, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET, "240.0.0.2", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_UPDATE, &addr, &key0, zone_name, NULL);
+ ok(ret == true, "Denied address match, no key, action not match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET, "240.0.0.3", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_UPDATE, &addr, &key0, zone_name, NULL);
+ ok(ret == false, "Denied address match, no key, no action");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET, "1.1.1.1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_UPDATE, &addr, &key3, zone_name, NULL);
+ ok(ret == true, "Arbitrary address, second key, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET, "100.0.0.1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_TRANSFER, &addr, &key0, zone_name, NULL);
+ ok(ret == true, "IPv4 address from range, no key, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone_name);
+ ok(acl.code == KNOT_EOK, "Get zone ACL");
+ check_sockaddr_set(&addr, AF_INET6, "::1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_TRANSFER, &addr, &key0, zone_name, NULL);
+ ok(ret == true, "IPv6 address from range, no key, action match");
+
+ acl = conf_zone_get(conf(), C_ACL, zone2_name);
+ ok(acl.code == KNOT_EOK, "Get zone2 ACL");
+ check_sockaddr_set(&addr, AF_INET, "240.0.0.4", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_NOTIFY, &addr, &key1, zone2_name, NULL);
+ ok(ret == false, "Address, key, action, denied");
+
+ acl = conf_zone_get(conf(), C_ACL, zone2_name);
+ ok(acl.code == KNOT_EOK, "Get zone2 ACL");
+ check_sockaddr_set(&addr, AF_INET, "240.0.0.1", 0);
+ ret = acl_allowed(conf(), &acl, ACL_ACTION_NOTIFY, &addr, &key1, zone2_name, NULL);
+ ok(ret == true, "Address, key, action, match");
+
+ knot_rrset_t A;
+ knot_rrset_init(&A, key1_name, KNOT_RRTYPE_A, KNOT_CLASS_IN, 3600);
+ knot_rrset_add_rdata(&A, (uint8_t *)"\x00\x00\x00\x00", 4, NULL);
+ check_update(conf(), &A, &key1, key1_name, true, "Update, tsig, type");
+
+ check_update(conf(), &A, &key2, key2_name, false, "Update, tsig, bad name");
+ knot_rdataset_clear(&A.rrs, NULL);
+
+ knot_rrset_t MX;
+ knot_rrset_init(&MX, key1_name, KNOT_RRTYPE_MX, KNOT_CLASS_IN, 3600);
+ knot_rrset_add_rdata(&MX, (uint8_t *)"\x00\x00\x00", 3, NULL);
+ check_update(conf(), &MX, &key1, key1_name, false, "Update, tsig, bad type");
+ knot_rdataset_clear(&MX.rrs, NULL);
+
+ knot_rrset_t aA;
+ knot_dname_t *a_key2_name = knot_dname_from_str_alloc("a."KEY2".");
+ ok(a_key2_name != NULL, "create a."KEY2".");
+ knot_rrset_init(&aA, a_key2_name, KNOT_RRTYPE_A, KNOT_CLASS_IN, 3600);
+ knot_rrset_add_rdata(&aA, (uint8_t *)"\x00\x00\x00\x00", 4, NULL);
+ check_update(conf(), &aA, &key2, key2_name, true, "Update, tsig, relative name");
+ knot_dname_free(a_key2_name, NULL);
+ knot_rdataset_clear(&aA.rrs, NULL);
+
+ knot_rrset_t bA;
+ knot_dname_t *b_key2_name = knot_dname_from_str_alloc("b."KEY2".");
+ ok(b_key2_name != NULL, "create b."KEY2".");
+ knot_rrset_init(&bA, b_key2_name, KNOT_RRTYPE_A, KNOT_CLASS_IN, 3600);
+ knot_rrset_add_rdata(&bA, (uint8_t *)"\x00\x00\x00\x00", 4, NULL);
+ check_update(conf(), &bA, &key2, key2_name, true, "Update, tsig, absolute name");
+ knot_dname_free(b_key2_name, NULL);
+ knot_rdataset_clear(&bA.rrs, NULL);
+
+ knot_rrset_t aaA;
+ knot_dname_t *aa_key2_name = knot_dname_from_str_alloc("a.a."KEY2);
+ ok(aa_key2_name != NULL, "create a.a."KEY2);
+ knot_rrset_init(&aaA, aa_key2_name, KNOT_RRTYPE_A, KNOT_CLASS_IN, 3600);
+ knot_rrset_add_rdata(&aaA, (uint8_t *)"\x00\x00\x00\x00", 4, NULL);
+ check_update(conf(), &aaA, &key2, key2_name, false, "Update, tsig, bad name");
+ knot_dname_free(aa_key2_name, NULL);
+ knot_rdataset_clear(&aaA.rrs, NULL);
+
+ conf_free(conf());
+ knot_dname_free(zone_name, NULL);
+ knot_dname_free(zone2_name, NULL);
+ knot_dname_free(key1_name, NULL);
+ knot_dname_free(key2_name, NULL);
+ knot_dname_free(key3_name, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ diag("acl_allowed");
+ test_acl_allowed();
+
+ return 0;
+}
diff --git a/tests/knot/test_changeset.c b/tests/knot/test_changeset.c
new file mode 100644
index 0000000..6775b76
--- /dev/null
+++ b/tests/knot/test_changeset.c
@@ -0,0 +1,166 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <assert.h>
+#include <tap/basic.h>
+
+#include "libknot/errcode.h"
+#include "libknot/error.h"
+#include "knot/updates/changesets.h"
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ // Test with NULL changeset
+ ok(changeset_size(NULL) == 0, "changeset: NULL size");
+ ok(changeset_empty(NULL), "changeset: NULL empty");
+
+ // Test creation.
+ knot_dname_t *d = knot_dname_from_str_alloc("test.");
+ assert(d);
+ changeset_t *ch = changeset_new(d);
+ knot_dname_free(d, NULL);
+ ok(ch != NULL, "changeset: new");
+ if (!ch) {
+ return 1;
+ }
+ ok(changeset_empty(ch), "changeset: empty");
+ ch->soa_to = (knot_rrset_t *)0xdeadbeef;
+ ok(!changeset_empty(ch), "changeset: empty SOA");
+ ch->soa_to = NULL;
+ ok(changeset_size(ch) == 0, "changeset: empty size");
+
+ // Test additions.
+ d = knot_dname_from_str_alloc("non.terminals.test.");
+ assert(d);
+ knot_rrset_t *apex_txt_rr = knot_rrset_new(d, KNOT_RRTYPE_TXT, KNOT_CLASS_IN, 3600, NULL);
+ assert(apex_txt_rr);
+ uint8_t data[8] = "\7teststr";
+ knot_rrset_add_rdata(apex_txt_rr, data, sizeof(data), NULL);
+
+ int ret = changeset_add_addition(ch, apex_txt_rr, CHANGESET_CHECK);
+ is_int(KNOT_EOK, ret, "changeset: add RRSet");
+ ok(changeset_size(ch) == 1, "changeset: size add");
+ ret = changeset_add_removal(ch, apex_txt_rr, CHANGESET_CHECK);
+ is_int(KNOT_EOK, ret, "changeset: rem RRSet");
+ ok(changeset_size(ch) == 0, "changeset: size remove");
+ ok(changeset_empty(ch), "changeset: empty");
+ changeset_add_addition(ch, apex_txt_rr, CHANGESET_CHECK);
+
+ // Add another RR to node.
+ knot_rrset_t *apex_spf_rr = knot_rrset_new(d, KNOT_RRTYPE_SPF, KNOT_CLASS_IN, 3600, NULL);
+ assert(apex_spf_rr);
+ knot_rrset_add_rdata(apex_spf_rr, data, sizeof(data), NULL);
+ ret = changeset_add_addition(ch, apex_spf_rr, CHANGESET_CHECK);
+ is_int(KNOT_EOK, ret, "changeset: add multiple");
+
+ // Add another node.
+ knot_dname_free(d, NULL);
+ d = knot_dname_from_str_alloc("here.come.more.non.terminals.test");
+ assert(d);
+ knot_rrset_t *other_rr = knot_rrset_new(d, KNOT_RRTYPE_TXT, KNOT_CLASS_IN, 3600, NULL);
+ assert(other_rr);
+ knot_rrset_add_rdata(other_rr, data, sizeof(data), NULL);
+ ret = changeset_add_addition(ch, other_rr, CHANGESET_CHECK);
+ is_int(KNOT_EOK, ret, "changeset: remove multiple");
+
+ // Test add traversal.
+ changeset_iter_t it;
+ ret = changeset_iter_add(&it, ch);
+ is_int(KNOT_EOK, ret, "changeset: create iter add");
+ // Order: non.terminals.test. TXT, SPF, here.come.more.non.terminals.test. TXT.
+ knot_rrset_t iter = changeset_iter_next(&it);
+ bool trav_ok = knot_rrset_equal(&iter, apex_txt_rr, true);
+ iter = changeset_iter_next(&it);
+ trav_ok = trav_ok && knot_rrset_equal(&iter, apex_spf_rr, true);
+ iter = changeset_iter_next(&it);
+ trav_ok = trav_ok && knot_rrset_equal(&iter, other_rr, true);
+
+ ok(trav_ok, "changeset: add traversal");
+
+ iter = changeset_iter_next(&it);
+ changeset_iter_clear(&it);
+ ok(knot_rrset_empty(&iter), "changeset: traversal: skip non-terminals");
+
+ changeset_add_removal(ch, apex_txt_rr, CHANGESET_CHECK);
+ changeset_add_removal(ch, apex_txt_rr, CHANGESET_CHECK);
+
+ // Test remove traversal.
+ ret = changeset_iter_rem(&it, ch);
+ is_int(KNOT_EOK, ret, "changeset: create iter rem");
+ iter = changeset_iter_next(&it);
+ ok(knot_rrset_equal(&iter, apex_txt_rr, true),
+ "changeset: rem traversal");
+ changeset_iter_clear(&it);
+
+ // Test all traversal - just count.
+ ret = changeset_iter_all(&it, ch);
+ is_int(KNOT_EOK, ret, "changeset: create iter all");
+ size_t size = 0;
+ iter = changeset_iter_next(&it);
+ while (!knot_rrset_empty(&iter)) {
+ ++size;
+ iter = changeset_iter_next(&it);
+ }
+ changeset_iter_clear(&it);
+ ok(size == 3, "changeset: iter all");
+
+ // Create new changeset.
+ knot_dname_free(d, NULL);
+ d = knot_dname_from_str_alloc("test.");
+ assert(d);
+ changeset_t *ch2 = changeset_new(d);
+ knot_dname_free(d, NULL);
+ assert(ch2);
+ // Add something to add section.
+ knot_dname_free(apex_txt_rr->owner, NULL);
+ apex_txt_rr->owner = knot_dname_from_str_alloc("something.test.");
+ assert(apex_txt_rr->owner);
+ ret = changeset_add_addition(ch2, apex_txt_rr, CHANGESET_CHECK);
+ assert(ret == KNOT_EOK);
+
+ // Add something to remove section.
+ knot_dname_free(apex_txt_rr->owner, NULL);
+ apex_txt_rr->owner =
+ knot_dname_from_str_alloc("and.now.for.something.completely.different.test.");
+ assert(apex_txt_rr->owner);
+ ret = changeset_add_removal(ch2, apex_txt_rr, CHANGESET_CHECK);
+ assert(ret == KNOT_EOK);
+
+ // Test merge.
+ ret = changeset_merge(ch, ch2, 0);
+ ok(ret == KNOT_EOK && changeset_size(ch) == 5, "changeset: merge");
+
+ // Test cleanup.
+ changeset_clear(ch);
+ ok(changeset_empty(ch), "changeset: clear");
+ free(ch);
+
+ list_t chgs;
+ init_list(&chgs);
+ add_head(&chgs, &ch2->n);
+ changesets_clear(&chgs);
+ ok(changeset_empty(ch2), "changeset: clear list");
+ free(ch2);
+
+ knot_rrset_free(apex_txt_rr, NULL);
+ knot_rrset_free(apex_spf_rr, NULL);
+ knot_rrset_free(other_rr, NULL);
+
+ return 0;
+}
diff --git a/tests/knot/test_conf.c b/tests/knot/test_conf.c
new file mode 100644
index 0000000..cc625ed
--- /dev/null
+++ b/tests/knot/test_conf.c
@@ -0,0 +1,274 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#define CONFIG_DIR "/tmp"
+
+#include <tap/basic.h>
+
+#include "knot/conf/conf.c"
+#include "test_conf.h"
+
+#define ZONE_ARPA "0/25.2.0.192.in-addr.arpa."
+#define ZONE_ROOT "."
+#define ZONE_1LABEL "x."
+#define ZONE_3LABEL "abc.ab.a."
+#define ZONE_UNKNOWN "unknown."
+
+static void check_name(const char *zone, const char *name, const char *ref)
+{
+ knot_dname_t *z = knot_dname_from_str_alloc(zone);
+
+ char *file = get_filename(conf(), NULL, z, name);
+ ok(file != NULL, "Get zonefile path for %s", zone);
+ if (file != NULL) {
+ ok(strcmp(file, ref) == 0, "Zonefile path compare %s", name);
+ free(file);
+ }
+
+ knot_dname_free(z, NULL);
+}
+
+static void check_name_err(const char *zone, const char *name)
+{
+ knot_dname_t *z = knot_dname_from_str_alloc(zone);
+
+ char *filename = get_filename(conf(), NULL, z, name);
+ ok(filename == NULL, "Invalid name %s", name);
+ free(filename);
+
+ knot_dname_free(z, NULL);
+}
+
+static void test_get_filename(void)
+{
+ int ret = test_conf("", NULL);
+ is_int(KNOT_EOK, ret, "Prepare empty configuration");
+
+ // Name formatter.
+ char *zone = "abc";
+ check_name(zone, "/%s", "/abc");
+
+ zone = ".";
+ check_name(zone, "/%s", "/");
+
+ // Char formatter.
+ zone = "abc.def.g";
+ check_name(zone, "/%c[0]", "/a");
+ check_name(zone, "/%c[3]", "/.");
+ check_name(zone, "/%c[8]", "/g");
+ check_name(zone, "/%c[9]", "/.");
+ check_name(zone, "/%c[10]", "/");
+ check_name(zone, "/%c[255]", "/");
+ check_name(zone, "/%c[0-1]", "/ab");
+ check_name(zone, "/%c[1-1]", "/b");
+ check_name(zone, "/%c[1-3]", "/bc.");
+ check_name(zone, "/%c[1-4]", "/bc.d");
+ check_name(zone, "/%c[254-255]", "/");
+ check_name_err(zone, "/%c");
+ check_name_err(zone, "/%cx");
+ check_name_err(zone, "/%c[a]");
+ check_name_err(zone, "/%c[:]");
+ check_name_err(zone, "/%c[/]");
+ check_name_err(zone, "/%c[-1]");
+ check_name_err(zone, "/%c[256]");
+ check_name_err(zone, "/%c[");
+ check_name_err(zone, "/%c[1");
+ check_name_err(zone, "/%c[1-");
+ check_name_err(zone, "/%c[1-2");
+ check_name_err(zone, "/%c[1-b]");
+ check_name_err(zone, "/%c[8-0]");
+
+ zone = "abcd";
+ check_name(zone, "/%c[2-9]", "/cd.");
+ check_name(zone, "/%c[3]", "/d");
+ check_name(zone, "/%c[4]", "/.");
+
+ zone = ".";
+ check_name(zone, "/%c[0]", "/.");
+ check_name(zone, "/%c[1]", "/");
+
+ // Label formatter.
+ zone = "abc.def.gh";
+ check_name(zone, "/%l[0]", "/gh");
+ check_name(zone, "/%l[1]", "/def");
+ check_name(zone, "/%l[2]", "/abc");
+ check_name(zone, "/%l[3]", "/");
+ check_name(zone, "/%l[255]", "/");
+ check_name(zone, "/%l[0]-%l[1]-%l[2]", "/gh-def-abc");
+ check_name_err(zone, "/%l[0-1]");
+ check_name_err(zone, "/%l[-1]");
+ check_name_err(zone, "/%l[256]");
+
+ zone = ".";
+ check_name(zone, "/%l[0]", "/");
+ check_name(zone, "/%l[1]", "/");
+
+ test_conf_free();
+}
+
+static void test_conf_zonefile(void)
+{
+ int ret;
+ char *file;
+
+ knot_dname_t *zone_arpa = knot_dname_from_str_alloc(ZONE_ARPA);
+ ok(zone_arpa != NULL, "create dname "ZONE_ARPA);
+ knot_dname_t *zone_root = knot_dname_from_str_alloc(ZONE_ROOT);
+ ok(zone_root != NULL, "create dname "ZONE_ROOT);
+ knot_dname_t *zone_1label = knot_dname_from_str_alloc(ZONE_1LABEL);
+ ok(zone_1label != NULL, "create dname "ZONE_1LABEL);
+ knot_dname_t *zone_3label = knot_dname_from_str_alloc(ZONE_3LABEL);
+ ok(zone_3label != NULL, "create dname "ZONE_3LABEL);
+ knot_dname_t *zone_unknown = knot_dname_from_str_alloc(ZONE_UNKNOWN);
+ ok(zone_unknown != NULL, "create dname "ZONE_UNKNOWN);
+
+ const char *conf_str =
+ "template:\n"
+ " - id: default\n"
+ " storage: /tmp\n"
+ "\n"
+ "zone:\n"
+ " - domain: "ZONE_ARPA"\n"
+ " file: dir/a%%b/%s.suffix/%a\n"
+ " - domain: "ZONE_ROOT"\n"
+ " file: /%s\n"
+ " - domain: "ZONE_1LABEL"\n"
+ " file: /%s\n"
+ " - domain: "ZONE_3LABEL"\n";
+
+ ret = test_conf(conf_str, NULL);
+ is_int(KNOT_EOK, ret, "Prepare configuration");
+
+ // Relative path with formatters.
+ file = conf_zonefile(conf(), zone_arpa);
+ ok(file != NULL, "Get zonefile path for "ZONE_ARPA);
+ if (file != NULL) {
+ ok(strcmp(file, "/tmp/dir/a%b/0_25.2.0.192.in-addr.arpa.suffix/") == 0,
+ "Zonefile path compare for "ZONE_ARPA);
+ free(file);
+ }
+
+ // Absolute path without formatters - root zone.
+ file = conf_zonefile(conf(), zone_root);
+ ok(file != NULL, "Get zonefile path for "ZONE_ROOT);
+ if (file != NULL) {
+ ok(strcmp(file, "/") == 0,
+ "Zonefile path compare for "ZONE_ROOT);
+ free(file);
+ }
+
+ // Absolute path without formatters - non-root zone.
+ file = conf_zonefile(conf(), zone_1label);
+ ok(file != NULL, "Get zonefile path for "ZONE_1LABEL);
+ if (file != NULL) {
+ ok(strcmp(file, "/x") == 0,
+ "Zonefile path compare for "ZONE_1LABEL);
+ free(file);
+ }
+
+ // Default zonefile path.
+ file = conf_zonefile(conf(), zone_3label);
+ ok(file != NULL, "Get zonefile path for "ZONE_3LABEL);
+ if (file != NULL) {
+ ok(strcmp(file, "/tmp/abc.ab.a.zone") == 0,
+ "Zonefile path compare for "ZONE_3LABEL);
+ free(file);
+ }
+
+ // Unknown zone zonefile path.
+ file = conf_zonefile(conf(), zone_unknown);
+ ok(file != NULL, "Get zonefile path for "ZONE_UNKNOWN);
+ if (file != NULL) {
+ ok(strcmp(file, "/tmp/unknown.zone") == 0,
+ "Zonefile path compare for "ZONE_UNKNOWN);
+ free(file);
+ }
+
+ test_conf_free();
+ knot_dname_free(zone_arpa, NULL);
+ knot_dname_free(zone_root, NULL);
+ knot_dname_free(zone_1label, NULL);
+ knot_dname_free(zone_3label, NULL);
+ knot_dname_free(zone_unknown, NULL);
+}
+
+static void test_mix_ref(void)
+{
+ const char *conf_string =
+ "remote:\n"
+ " - id: r1\n"
+ " address: ::1\n"
+ " - id: r2\n"
+ " address: ::2\n"
+ " - id: r3\n"
+ " address: ::3\n"
+ " - id: r4\n"
+ " address: ::4\n"
+ " - id: r5\n"
+ " address: ::5\n"
+ "remotes:\n"
+ " - id: rs2\n"
+ " remote: [r2]\n"
+ " - id: rs45\n"
+ " remote: [r4, r5]\n"
+ "\n"
+ "submission:\n"
+ " - id: t1\n"
+ " parent: [r1, rs2, r3, rs45]\n"
+ " - id: t2\n"
+ " parent: [rs45, r2, r1]\n";
+
+ int ret = test_conf(conf_string, NULL);
+ is_int(KNOT_EOK, ret, "Prepare configuration");
+
+ size_t cnt1 = 0;
+ conf_val_t test1 = conf_rawid_get(conf(), C_SBM, C_PARENT, (const uint8_t *)"t1", 3);
+ conf_mix_iter_t iter1;
+ conf_mix_iter_init(conf(), &test1, &iter1);
+ while (iter1.id->code == KNOT_EOK) {
+ cnt1++;
+ conf_mix_iter_next(&iter1);
+ }
+ is_int(5, cnt1, "number of mixed references 1");
+
+ size_t cnt2 = 0;
+ conf_val_t test2 = conf_rawid_get(conf(), C_SBM, C_PARENT, (const uint8_t *)"t2", 3);
+ conf_mix_iter_t iter2;
+ conf_mix_iter_init(conf(), &test2, &iter2);
+ while (iter2.id->code == KNOT_EOK) {
+ cnt2++;
+ conf_mix_iter_next(&iter2);
+ }
+ is_int(4, cnt2, "number of mixed references 2");
+
+ test_conf_free();
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ diag("get_filename");
+ test_get_filename();
+
+ diag("conf_zonefile");
+ test_conf_zonefile();
+
+ diag("mixed references");
+ test_mix_ref();
+
+ return 0;
+}
diff --git a/tests/knot/test_conf.h b/tests/knot/test_conf.h
new file mode 100644
index 0000000..1297ec0
--- /dev/null
+++ b/tests/knot/test_conf.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/conf/conf.h"
+#include "libknot/errcode.h"
+
+/* Prepare server configuration. */
+static inline int test_conf(const char *conf_str, const yp_item_t *schema)
+{
+ // Use default schema if not specified.
+ if (schema == NULL) {
+ schema = conf_schema;
+ }
+
+ conf_t *new_conf = NULL;
+ int ret = conf_new(&new_conf, schema, NULL, 2 * 1024 * 1024, CONF_FNONE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = conf_import(new_conf, conf_str, false, false);
+ if (ret != KNOT_EOK) {
+ conf_free(new_conf);
+ return ret;
+ }
+
+ conf_update(new_conf, CONF_UPD_FNONE);
+
+ return KNOT_EOK;
+}
+
+static inline void test_conf_free(void)
+{
+ conf_update(NULL, CONF_UPD_FNONE);
+}
diff --git a/tests/knot/test_conf_tools.c b/tests/knot/test_conf_tools.c
new file mode 100644
index 0000000..dc83a06
--- /dev/null
+++ b/tests/knot/test_conf_tools.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <tap/basic.h>
+
+#include "libknot/yparser/yptrafo.h"
+#include "knot/conf/tools.h"
+#include "libknot/libknot.h"
+
+static void mod_id_test(const char *txt, const char *val)
+{
+ int ret;
+ uint8_t b[64];
+ size_t b_len = sizeof(b);
+ char t[64];
+ size_t t_len = sizeof(t);
+ yp_item_t i = { NULL, YP_TDATA, YP_VDATA = { 0, NULL,
+ mod_id_to_bin,
+ mod_id_to_txt } };
+
+ diag("module id \"%s\":", txt);
+ ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
+ is_int(KNOT_EOK, ret, "txt to bin");
+ ok(memcmp(b, val, b_len) == 0, "compare");
+ ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
+ is_int(KNOT_EOK, ret, "bin to txt");
+ ok(strlen(t) == t_len, "txt ret length");
+ ok(strlen(txt) == t_len, "txt length");
+ ok(memcmp(txt, t, t_len) == 0, "compare");
+}
+
+static void mod_id_bad_test(const char *txt, int code)
+{
+ int ret;
+ uint8_t b[64];
+ size_t b_len = sizeof(b);
+ yp_item_t i = { NULL, YP_TDATA, YP_VDATA = { 0, NULL,
+ mod_id_to_bin,
+ mod_id_to_txt } };
+
+ diag("module id \"%s\":", txt);
+ ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
+ ok(ret == code, "invalid txt to bin");
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ /* Module id tests. */
+ mod_id_test("module/id", "\x06moduleid");
+ mod_id_test("module", "\x06module");
+ mod_id_bad_test("module/", KNOT_EINVAL);
+ mod_id_bad_test("/", KNOT_EINVAL);
+ mod_id_bad_test("/id", KNOT_EINVAL);
+
+ return 0;
+}
diff --git a/tests/knot/test_confdb.c b/tests/knot/test_confdb.c
new file mode 100644
index 0000000..e149f8d
--- /dev/null
+++ b/tests/knot/test_confdb.c
@@ -0,0 +1,489 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+
+#include "test_conf.h"
+#include "knot/conf/confdb.c"
+
+static void check_db_content(conf_t *conf, knot_db_txn_t *txn, int count)
+{
+ ok(db_check_version(conf, txn) == KNOT_EOK, "Version check");
+ if (count >= 0) {
+ ok(conf->api->count(txn) == 1 + count, "Check DB entries count");
+ }
+}
+
+static void check_code(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ uint8_t section_code,
+ const yp_name_t *name,
+ db_action_t action,
+ int ret,
+ uint8_t ref_code)
+{
+ uint8_t code = 0;
+ ok(db_code(conf, txn, section_code, name, action, &code) == ret,
+ "Compare DB code return");
+
+ if (ret != KNOT_EOK) {
+ return;
+ }
+
+ uint8_t k[64] = { section_code, 0 };
+ memcpy(k + 2, name + 1, name[0]);
+ knot_db_val_t key = { .data = k, .len = 2 + name[0] };
+ knot_db_val_t val;
+
+ ret = conf->api->find(txn, &key, &val, 0);
+ switch (action) {
+ case DB_GET:
+ case DB_SET:
+ ok(code == ref_code, "Compare DB code");
+ is_int(KNOT_EOK, ret, "Find DB code");
+ ok(val.len == 1, "Compare DB code length");
+ ok(((uint8_t *)val.data)[0] == code, "Compare DB code value");
+ break;
+ case DB_DEL:
+ is_int(KNOT_ENOENT, ret, "Find item code");
+ break;
+ }
+}
+
+static void test_db_code(conf_t *conf, knot_db_txn_t *txn)
+{
+ // Add codes.
+ check_code(conf, txn, 0, C_SERVER, DB_SET, KNOT_EOK, KEY1_FIRST);
+ check_db_content(conf, txn, 1);
+ check_code(conf, txn, 0, C_LOG, DB_SET, KNOT_EOK, KEY1_FIRST + 1);
+ check_db_content(conf, txn, 2);
+ check_code(conf, txn, 2, C_IDENT, DB_SET, KNOT_EOK, KEY1_FIRST);
+ check_db_content(conf, txn, 3);
+ check_code(conf, txn, 0, C_ZONE, DB_SET, KNOT_EOK, KEY1_FIRST + 2);
+ check_db_content(conf, txn, 4);
+ check_code(conf, txn, 2, C_VERSION, DB_SET, KNOT_EOK, KEY1_FIRST + 1);
+ check_db_content(conf, txn, 5);
+
+ // Add existing code (no change).
+ check_code(conf, txn, 0, C_SERVER, DB_SET, KNOT_EOK, KEY1_FIRST);
+ check_db_content(conf, txn, 5);
+
+ // Get codes.
+ check_code(conf, txn, 0, C_SERVER, DB_GET, KNOT_EOK, KEY1_FIRST);
+ check_db_content(conf, txn, 5);
+ check_code(conf, txn, 0, C_RMT, DB_GET, KNOT_ENOENT, 0);
+ check_db_content(conf, txn, 5);
+
+ // Delete not existing code.
+ check_code(conf, txn, 0, C_COMMENT, DB_DEL, KNOT_ENOENT, 0);
+ check_db_content(conf, txn, 5);
+
+ // Delete codes.
+ check_code(conf, txn, 0, C_SERVER, DB_DEL, KNOT_EOK, 0);
+ check_db_content(conf, txn, 4);
+ check_code(conf, txn, 2, C_IDENT, DB_DEL, KNOT_EOK, 0);
+ check_db_content(conf, txn, 3);
+
+ // Reuse deleted codes.
+ check_code(conf, txn, 0, C_ACL, DB_SET, KNOT_EOK, KEY1_FIRST);
+ check_db_content(conf, txn, 4);
+ check_code(conf, txn, 2, C_NSID, DB_SET, KNOT_EOK, KEY1_FIRST);
+ check_db_content(conf, txn, 5);
+}
+
+static void check_set(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ int ret,
+ const uint8_t *data,
+ size_t data_len,
+ const uint8_t *exp_data,
+ size_t exp_data_len)
+{
+ ok(conf_db_set(conf, txn, key0, key1, id, id_len, data, data_len) == ret,
+ "Check set return");
+
+ if (ret != KNOT_EOK || (key1 == NULL && id == NULL)) {
+ return;
+ }
+
+ uint8_t section_code, item_code;
+ section_code = 0, item_code = 0; // prevents Wuninitialized
+ ok(db_code(conf, txn, KEY0_ROOT, key0, DB_GET, &section_code) == KNOT_EOK,
+ "Get DB section code");
+ if (key1 != NULL) {
+ ok(db_code(conf, txn, section_code, key1, DB_GET, &item_code) == KNOT_EOK,
+ "Get DB item code");
+ } else {
+ item_code = KEY1_ID;
+ }
+
+ uint8_t k[64] = { section_code, item_code };
+ if (id != NULL) {
+ memcpy(k + 2, id, id_len);
+ }
+ knot_db_val_t key = { .data = k, .len = 2 + id_len };
+ knot_db_val_t val;
+
+ ok(conf->api->find(txn, &key, &val, 0) == KNOT_EOK, "Get inserted data");
+ ok(val.len == exp_data_len, "Compare data length");
+ ok(memcmp(val.data, exp_data, exp_data_len) == 0, "Compare data");
+
+ check_db_content(conf, txn, -1);
+}
+
+static void test_conf_db_set(conf_t *conf, knot_db_txn_t *txn)
+{
+ // Set section without item - noop.
+ check_set(conf, txn, C_INCL, NULL, NULL, 0, KNOT_EOK, NULL, 0, NULL, 0);
+
+ // Set singlevalued item.
+ check_set(conf, txn, C_SERVER, C_RUNDIR, NULL, 0, KNOT_EOK,
+ (uint8_t *)"\0", 1, (uint8_t *)"\0", 1);
+ check_set(conf, txn, C_SERVER, C_RUNDIR, NULL, 0, KNOT_EOK,
+ (uint8_t *)"a b\0", 4, (uint8_t *)"a b\0", 4);
+
+ // Set multivalued item.
+ check_set(conf, txn, C_SERVER, C_LISTEN, NULL, 0, KNOT_EOK,
+ (uint8_t *)"\0", 1, (uint8_t *)"\x00\x01""\0", 3);
+ check_set(conf, txn, C_SERVER, C_LISTEN, NULL, 0, KNOT_EOK,
+ (uint8_t *)"a\0", 2, (uint8_t *)"\x00\x01""\0""\x00\x02""a\0", 7);
+ check_set(conf, txn, C_SERVER, C_LISTEN, NULL, 0, KNOT_EOK,
+ (uint8_t *)"b\0", 2, (uint8_t *)"\x00\x01""\0""\x00\x02""a\0""\x00\x02""b\0", 11);
+
+ // Set group id.
+ check_set(conf, txn, C_ZONE, NULL, (uint8_t *)"id", 2, KNOT_EOK,
+ NULL, 0, (uint8_t *)"", 0);
+
+ // Set singlevalued item with id.
+ check_set(conf, txn, C_ZONE, C_FILE, (uint8_t *)"id", 2, KNOT_EOK,
+ (uint8_t *)"\0", 1, (uint8_t *)"\0", 1);
+ check_set(conf, txn, C_ZONE, C_FILE, (uint8_t *)"id", 2, KNOT_EOK,
+ (uint8_t *)"a b\0", 4, (uint8_t *)"a b\0", 4);
+
+ // Set multivalued item with id.
+ check_set(conf, txn, C_ZONE, C_MASTER, (uint8_t *)"id", 2, KNOT_EOK,
+ (uint8_t *)"\0", 1, (uint8_t *)"\x00\x01""\0", 3);
+ check_set(conf, txn, C_ZONE, C_MASTER, (uint8_t *)"id", 2, KNOT_EOK,
+ (uint8_t *)"a\0", 2, (uint8_t *)"\x00\x01""\0""\x00\x02""a\0", 7);
+ check_set(conf, txn, C_ZONE, C_MASTER, (uint8_t *)"id", 2, KNOT_EOK,
+ (uint8_t *)"b\0", 2, (uint8_t *)"\x00\x01""\0""\x00\x02""a\0""\x00\x02""b\0", 11);
+
+ // ERR set invalid section.
+ check_set(conf, txn, C_MASTER, NULL, NULL, 0, KNOT_YP_EINVAL_ITEM,
+ NULL, 0, NULL, 0);
+
+ // ERR set invalid item.
+ check_set(conf, txn, C_SERVER, C_DOMAIN, NULL, 0, KNOT_YP_EINVAL_ITEM,
+ NULL, 0, NULL, 0);
+
+ // ERR redefine section id.
+ check_set(conf, txn, C_ZONE, NULL, (uint8_t *)"id", 2, KNOT_CONF_EREDEFINE,
+ NULL, 0, NULL, 0);
+
+ // ERR set singlevalued item with non-existing id.
+ check_set(conf, txn, C_ZONE, C_FILE, (uint8_t *)"idx", 3, KNOT_YP_EINVAL_ID,
+ NULL, 0, NULL, 0);
+}
+
+static void check_get(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ int ret,
+ const uint8_t *exp_data,
+ size_t exp_data_len)
+{
+ conf_val_t val;
+ ok(conf_db_get(conf, txn, key0, key1, id, id_len, &val) == ret,
+ "Check get return");
+
+ if (ret != KNOT_EOK) {
+ return;
+ }
+
+ ok(val.blob_len == exp_data_len, "Compare data length");
+ ok(val.blob != NULL && memcmp(val.blob, exp_data, exp_data_len) == 0,
+ "Compare data");
+
+ check_db_content(conf, txn, -1);
+}
+
+static void test_conf_db_get(conf_t *conf, knot_db_txn_t *txn)
+{
+ // Get singlevalued item.
+ check_get(conf, txn, C_SERVER, C_RUNDIR, NULL, 0, KNOT_EOK,
+ (uint8_t *)"a b\0", 4);
+
+ // Get multivalued item.
+ check_get(conf, txn, C_SERVER, C_LISTEN, NULL, 0, KNOT_EOK,
+ (uint8_t *)"\x00\x01""\0""\x00\x02""a\0""\x00\x02""b\0", 11);
+
+ // Get group id.
+ check_get(conf, txn, C_ZONE, NULL, (uint8_t *)"id", 2, KNOT_EOK,
+ (uint8_t *)"", 0);
+
+ // Get singlevalued item with id.
+ check_get(conf, txn, C_ZONE, C_FILE, (uint8_t *)"id", 2, KNOT_EOK,
+ (uint8_t *)"a b\0", 4);
+
+ // Get multivalued item with id.
+ check_get(conf, txn, C_ZONE, C_MASTER, (uint8_t *)"id", 2, KNOT_EOK,
+ (uint8_t *)"\x00\x01""\0""\x00\x02""a\0""\x00\x02""b\0", 11);
+
+ // ERR get section without item.
+ check_get(conf, txn, C_INCL, NULL, NULL, 0, KNOT_EINVAL, NULL, 0);
+
+ // ERR get invalid section.
+ check_get(conf, txn, C_MASTER, NULL, NULL, 0, KNOT_YP_EINVAL_ITEM,
+ NULL, 0);
+
+ // ERR get invalid item.
+ check_get(conf, txn, C_SERVER, C_DOMAIN, NULL, 0, KNOT_YP_EINVAL_ITEM,
+ NULL, 0);
+
+ // ERR get singlevalued item with non-existing id.
+ check_get(conf, txn, C_ZONE, C_FILE, (uint8_t *)"idx", 3, KNOT_YP_EINVAL_ID,
+ NULL, 0);
+}
+
+static void check_unset(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ int ret,
+ const uint8_t *data,
+ size_t data_len,
+ const uint8_t *exp_data,
+ size_t exp_data_len)
+{
+ ok(conf_db_unset(conf, txn, key0, key1, id, id_len, data, data_len, false) == ret,
+ "Check unset return");
+
+ if (ret != KNOT_EOK) {
+ return;
+ }
+
+ uint8_t section_code, item_code;
+ ok(db_code(conf, txn, KEY0_ROOT, key0, DB_GET, &section_code) == KNOT_EOK,
+ "Get DB section code");
+ if (key1 != NULL) {
+ ok(db_code(conf, txn, section_code, key1, DB_GET, &item_code) == KNOT_EOK,
+ "Get DB item code");
+ } else {
+ item_code = KEY1_ID;
+ }
+
+ uint8_t k[64] = { section_code, item_code };
+ if (id != NULL) {
+ memcpy(k + 2, id, id_len);
+ }
+ knot_db_val_t key = { .data = k, .len = 2 + id_len };
+ knot_db_val_t val;
+
+ ret = conf->api->find(txn, &key, &val, 0);
+ if (exp_data != NULL) {
+ is_int(KNOT_EOK, ret, "Get deleted data");
+ ok(val.len == exp_data_len, "Compare data length");
+ ok(memcmp(val.data, exp_data, exp_data_len) == 0, "Compare data");
+ } else {
+ is_int(KNOT_ENOENT, ret, "Get deleted data");
+ }
+
+ check_db_content(conf, txn, -1);
+}
+
+static void check_unset_key(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ int ret)
+{
+ ok(conf_db_unset(conf, txn, key0, key1, id, id_len, NULL, 0, true) == ret,
+ "Check unset return");
+
+ if (ret != KNOT_EOK) {
+ return;
+ }
+
+ uint8_t section_code, item_code;
+ ret = db_code(conf, txn, KEY0_ROOT, key0, DB_GET, &section_code);
+ if (key1 == NULL && id_len == 0) {
+ is_int(KNOT_ENOENT, ret, "Get DB section code");
+ } else {
+ is_int(KNOT_EOK, ret, "Get DB section code");
+ ret = db_code(conf, txn, section_code, key1, DB_GET, &item_code);
+ is_int(KNOT_ENOENT, ret, "Get DB item code");
+ }
+
+ check_db_content(conf, txn, -1);
+}
+
+static void test_conf_db_unset(conf_t *conf, knot_db_txn_t *txn)
+{
+ // ERR unset section without item.
+ check_unset(conf, txn, C_INCL, NULL, NULL, 0, KNOT_ENOENT,
+ NULL, 0, NULL, 0);
+
+ // ERR unset invalid section.
+ check_unset(conf, txn, C_MASTER, NULL, NULL, 0, KNOT_YP_EINVAL_ITEM,
+ NULL, 0, NULL, 0);
+
+ // ERR unset invalid item.
+ check_unset(conf, txn, C_SERVER, C_DOMAIN, NULL, 0, KNOT_YP_EINVAL_ITEM,
+ NULL, 0, NULL, 0);
+
+ // ERR unset singlevalued item with non-existing id.
+ check_unset(conf, txn, C_ZONE, C_FILE, (uint8_t *)"idx", 3, KNOT_YP_EINVAL_ID,
+ NULL, 0, NULL, 0);
+
+ // ERR unset singlevalued item invalid value.
+ check_unset(conf, txn, C_SERVER, C_RUNDIR, NULL, 0, KNOT_ENOENT,
+ (uint8_t *)"x\0", 2, NULL, 0);
+
+ // Unset singlevalued item data.
+ check_unset(conf, txn, C_SERVER, C_RUNDIR, NULL, 0, KNOT_EOK,
+ (uint8_t *)"a b\0", 4, NULL, 0);
+ // Unset item.
+ check_unset_key(conf, txn, C_SERVER, C_RUNDIR, NULL, 0, KNOT_EOK);
+
+ // Unset multivalued item.
+ check_unset(conf, txn, C_SERVER, C_LISTEN, NULL, 0, KNOT_EOK,
+ (uint8_t *)"a", 2, (uint8_t *)"\x00\x01""\0""\x00\x02""b\0", 7);
+ check_unset(conf, txn, C_SERVER, C_LISTEN, NULL, 0, KNOT_EOK,
+ (uint8_t *)"", 1, (uint8_t *)"\x00\x02""b\0", 4);
+ check_unset(conf, txn, C_SERVER, C_LISTEN, NULL, 0, KNOT_EOK,
+ (uint8_t *)"b", 2, NULL, 0);
+ // Unset item.
+ check_unset_key(conf, txn, C_SERVER, C_LISTEN, NULL, 0, KNOT_EOK);
+ // Unset section.
+ check_unset_key(conf, txn, C_SERVER, NULL, NULL, 0, KNOT_EOK);
+
+ // Unset singlevalued item with id - all data at one step.
+ check_unset(conf, txn, C_ZONE, C_FILE, (uint8_t *)"id", 2, KNOT_EOK,
+ NULL, 0, NULL, 0);
+
+ // Unset multivalued item with id - all data at one step (non-null data!).
+ check_unset(conf, txn, C_ZONE, C_MASTER, (uint8_t *)"id", 2, KNOT_EOK,
+ NULL + 1, 0, NULL, 0);
+
+ // Unset group id.
+ check_unset(conf, txn, C_ZONE, NULL, (uint8_t *)"id", 2, KNOT_EOK,
+ NULL, 0, NULL, 0);
+}
+
+static void test_conf_db_iter(conf_t *conf, knot_db_txn_t *txn)
+{
+ const size_t total = 4;
+ char names[][10] = { "alfa", "beta", "delta", "epsilon" };
+
+ // Prepare identifiers to iterate through.
+ for (size_t i = 0; i < total; i++) {
+ check_set(conf, txn, C_RMT, NULL, (uint8_t *)names[i],
+ strlen(names[i]), KNOT_EOK, NULL, 0, (uint8_t *)"", 0);
+ }
+
+ // Create section iterator.
+ conf_iter_t iter;
+ int ret = conf_db_iter_begin(conf, txn, C_RMT, &iter);
+ is_int(KNOT_EOK, ret, "Create iterator");
+
+ // Iterate through the section.
+ size_t count = 0;
+ while (ret == KNOT_EOK) {
+ const uint8_t *id;
+ size_t id_len;
+ id = NULL, id_len = 0; // prevents Wuninitialized
+ ret = conf_db_iter_id(conf, &iter, &id, &id_len);
+ is_int(KNOT_EOK, ret, "Get iteration id");
+ ok(id_len == strlen(names[count]), "Compare iteration id length");
+ ok(memcmp(id, names[count], id_len) == 0, "Compare iteration id");
+
+ ok(conf_db_iter_del(conf, &iter) == KNOT_EOK, "Delete iteration key");
+
+ count++;
+ ret = conf_db_iter_next(conf, &iter);
+ }
+ is_int(KNOT_EOF, ret, "Finished iteration");
+ ok(count == total, "Check iteration count");
+
+ // Check empty section.
+ ret = conf_db_iter_begin(conf, txn, C_RMT, &iter);
+ is_int(KNOT_ENOENT, ret, "Create iterator");
+
+ // ERR non-iterable section.
+ ok(conf_db_iter_begin(conf, txn, C_SERVER, &iter) == KNOT_ENOTSUP, "Create iterator");
+
+ // ERR empty section.
+ ok(conf_db_iter_begin(conf, txn, C_ZONE, &iter) == KNOT_ENOENT, "Create iterator");
+
+ // ERR section with no code.
+ ok(conf_db_iter_begin(conf, txn, C_LOG, &iter) == KNOT_ENOENT, "Create iterator");
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ ok(test_conf("", NULL) == KNOT_EOK, "Prepare configuration");
+ check_db_content(conf(), &conf()->read_txn, 0);
+
+ knot_db_txn_t txn;
+ ok(conf()->api->txn_begin(conf()->db, &txn, 0) == KNOT_EOK, "Begin transaction");
+
+ diag("db_code");
+ test_db_code(conf(), &txn);
+
+ conf()->api->txn_abort(&txn);
+
+ ok(conf()->api->txn_begin(conf()->db, &txn, 0) == KNOT_EOK, "Begin transaction");
+
+ diag("conf_db_set");
+ test_conf_db_set(conf(), &txn);
+
+ diag("conf_db_get");
+ test_conf_db_get(conf(), &txn);
+
+ diag("conf_db_unset");
+ test_conf_db_unset(conf(), &txn);
+
+ conf()->api->txn_abort(&txn);
+
+ ok(conf()->api->txn_begin(conf()->db, &txn, 0) == KNOT_EOK, "Begin transaction");
+
+ diag("conf_db_iter");
+ test_conf_db_iter(conf(), &txn);
+
+ conf()->api->txn_abort(&txn);
+
+ conf_free(conf());
+
+ return 0;
+}
diff --git a/tests/knot/test_confio.c b/tests/knot/test_confio.c
new file mode 100644
index 0000000..f5d3c94
--- /dev/null
+++ b/tests/knot/test_confio.c
@@ -0,0 +1,1100 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+
+#include "test_conf.h"
+#include "knot/conf/confio.h"
+#include "knot/conf/tools.h"
+#include "libknot/yparser/yptrafo.h"
+#include "contrib/string.h"
+#include "contrib/openbsd/strlcat.h"
+
+#define SKIP_OPENBSD skip("Nested transactions are not supported on OpenBSD");
+#define OUT_LEN 1024
+#define ZONE1 "zone1"
+#define ZONE2 "zone2"
+#define ZONE3 "zone3"
+
+char *format_key(conf_io_t *io)
+{
+ knot_dname_txt_storage_t id;
+ size_t id_len = sizeof(id);
+
+ // Get the textual item id.
+ if (io->id_len > 0 && !io->id_as_data) {
+ if (yp_item_to_txt(io->key0->var.g.id, io->id, io->id_len, id,
+ &id_len, YP_SNOQUOTE) != KNOT_EOK) {
+ return NULL;
+ }
+ }
+
+ // Get the item prefix.
+ const char *prefix = "";
+ switch (io->type) {
+ case NEW: prefix = "+"; break;
+ case OLD: prefix = "-"; break;
+ default: break;
+ }
+
+ // Format the item key.
+ return sprintf_alloc(
+ "%s%.*s%s%.*s%s%s%.*s",
+ prefix, (int)io->key0->name[0], io->key0->name + 1,
+ (io->id_len > 0 && !io->id_as_data ? "[" : ""),
+ (io->id_len > 0 && !io->id_as_data ? (int)id_len : 0), id,
+ (io->id_len > 0 && !io->id_as_data ? "]" : ""),
+ (io->key1 != NULL ? "." : ""),
+ (io->key1 != NULL ? (int)io->key1->name[0] : 0),
+ (io->key1 != NULL ? io->key1->name + 1 : ""));
+}
+
+static int append_data(const yp_item_t *item, const uint8_t *bin, size_t bin_len,
+ char *out, size_t out_len)
+{
+ char buf[YP_MAX_TXT_DATA_LEN + 1] = "\0";
+ size_t buf_len = sizeof(buf);
+
+ int ret = yp_item_to_txt(item, bin, bin_len, buf, &buf_len, YP_SNONE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (strlcat(out, buf, out_len) >= out_len) {
+ return KNOT_ESPACE;
+ }
+
+ return KNOT_EOK;
+}
+
+char *format_data(conf_io_t *io)
+{
+ char out[YP_MAX_TXT_DATA_LEN + 1] = "\0";
+
+ // Return the item identifier as the item data.
+ if (io->id_as_data) {
+ if (append_data(io->key0->var.g.id, io->id, io->id_len, out,
+ sizeof(out)) != KNOT_EOK) {
+ return NULL;
+ }
+
+ return strdup(out);
+ }
+
+ // Check for no data.
+ if (io->data.val == NULL && io->data.bin == NULL) {
+ return NULL;
+ }
+
+ const yp_item_t *item = (io->key1 != NULL) ? io->key1 : io->key0;
+
+ // Format explicit binary data value.
+ if (io->data.bin != NULL) {
+ if (append_data(item, io->data.bin, io->data.bin_len, out,
+ sizeof(out)) != KNOT_EOK) {
+ return NULL;
+ }
+ // Format multivalued item data.
+ } else if (item->flags & YP_FMULTI) {
+ size_t values = conf_val_count(io->data.val);
+ for (size_t i = 0; i < values; i++) {
+ // Skip other values if known index (counted from 1).
+ if (io->data.index > 0 &&
+ io->data.index != i + 1) {
+ conf_val_next(io->data.val);
+ continue;
+ }
+
+ if (i > 0) {
+ if (strlcat(out, " ", sizeof(out)) >= sizeof(out)) {
+ return NULL;
+ }
+ }
+
+ conf_val(io->data.val);
+ if (append_data(item, io->data.val->data, io->data.val->len,
+ out, sizeof(out)) != KNOT_EOK) {
+ return NULL;
+ }
+
+ conf_val_next(io->data.val);
+ }
+ // Format singlevalued item data.
+ } else {
+ conf_val(io->data.val);
+ if (append_data(item, io->data.val->data, io->data.val->len, out,
+ sizeof(out)) != KNOT_EOK) {
+ return NULL;
+ }
+ }
+
+ return strdup(out);
+}
+
+static int format_item(conf_io_t *io)
+{
+ char *out = (char *)io->misc;
+
+ // Get the item key and data strings.
+ char *key = format_key(io);
+ char *data = format_data(io);
+
+ // Format the item.
+ char *item = sprintf_alloc(
+ "%s%s%s%s",
+ (*out != '\0' ? "\n" : ""),
+ (key != NULL ? key : ""),
+ (data != NULL ? " = " : ""),
+ (data != NULL ? data : ""));
+ free(key);
+ free(data);
+ if (item == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Append the item.
+ if (strlcat(out, item, OUT_LEN) >= OUT_LEN) {
+ free(item);
+ return KNOT_ESPACE;
+ }
+
+ free(item);
+
+ return KNOT_EOK;
+}
+
+static void test_conf_io_begin(void)
+{
+ ok(conf_io_begin(true) == KNOT_TXN_ENOTEXISTS, "begin child txn with no parent");
+ ok(conf()->io.txn == NULL, "check txn depth");
+
+#if defined(__OpenBSD__)
+ SKIP_OPENBSD
+#else
+ ok(conf_io_begin(false) == KNOT_EOK, "begin parent txn");
+ ok(conf()->io.txn == &(conf()->io.txn_stack[0]), "check txn depth");
+
+ ok(conf_io_begin(false) == KNOT_TXN_EEXISTS, "begin another parent txn");
+ ok(conf()->io.txn == &(conf()->io.txn_stack[0]), "check txn depth");
+
+ for (int i = 1; i < CONF_MAX_TXN_DEPTH; i++) {
+ ok(conf_io_begin(true) == KNOT_EOK, "begin child txn");
+ ok(conf()->io.txn == &(conf()->io.txn_stack[i]), "check txn depth");
+ }
+ ok(conf_io_begin(true) == KNOT_TXN_EEXISTS, "begin another child txn");
+ ok(conf()->io.txn == &(conf()->io.txn_stack[CONF_MAX_TXN_DEPTH - 1]),
+ "check txn depth");
+
+ conf_io_abort(false);
+ ok(conf()->io.txn == NULL, "check txn depth");
+#endif
+}
+
+static void test_conf_io_abort(void)
+{
+#if defined(__OpenBSD__)
+ SKIP_OPENBSD
+#else
+ // Test child persistence after subchild abort.
+ {
+ char idx[2] = { '0' };
+ ok(conf_io_begin(false) == KNOT_EOK, "begin parent txn");
+ ok(conf_io_set("server", "version", NULL, idx) ==
+ KNOT_EOK, "set single value '%s'", idx);
+ }
+
+ for (int i = 1; i < CONF_MAX_TXN_DEPTH; i++) {
+ char idx[2] = { '0' + i };
+ ok(conf_io_begin(true) == KNOT_EOK, "begin child txn %s", idx);
+ ok(conf_io_set("server", "version", NULL, idx) ==
+ KNOT_EOK, "set single value '%s'", idx);
+ }
+
+ for (int i = CONF_MAX_TXN_DEPTH - 1; i > 0; i--) {
+ char idx[2] = { '0' + i };
+ conf_io_abort(true);
+ conf_val_t val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_EOK, "check entry");
+ const char *data = conf_str(&val);
+ ok(*data == (idx[0] - 1), "compare txn data '%s'", data);
+ }
+
+ conf_io_abort(false);
+ ok(conf()->io.txn == NULL, "check txn depth");
+
+ // Test child abort with committed subchild.
+ ok(conf_io_begin(false) == KNOT_EOK, "begin new parent txn");
+ ok(conf_io_begin(true) == KNOT_EOK, "begin child txn");
+ ok(conf_io_begin(true) == KNOT_EOK, "begin subchild txn");
+ ok(conf_io_set("server", "version", NULL, "text") ==
+ KNOT_EOK, "set single value");
+ ok(conf_io_commit(true) == KNOT_EOK, "commit subchild txn");
+ conf_val_t val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_EOK, "check entry");
+ const char *data = conf_str(&val);
+ ok(strcmp(data, "text") == 0, "compare subchild txn data '%s'", data);
+ conf_io_abort(true);
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_ENOENT, "check entry");
+ conf_io_abort(false);
+
+ // Test unchanged read_txn.
+ val = conf_get_txn(conf(), &conf()->read_txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_ENOENT, "check entry");
+#endif
+}
+
+static void test_conf_io_commit(void)
+{
+ ok(conf_io_commit(false) == KNOT_TXN_ENOTEXISTS, "commit no txt txn");
+ ok(conf_io_commit(true) == KNOT_TXN_ENOTEXISTS, "commit no txt txn");
+
+#if defined(__OpenBSD__)
+ SKIP_OPENBSD
+#else
+ // Test subchild persistence after commit.
+ {
+ char idx[2] = { '0' };
+ ok(conf_io_begin(false) == KNOT_EOK, "begin parent txn");
+ ok(conf_io_set("server", "version", NULL, idx) ==
+ KNOT_EOK, "set single value '%s'", idx);
+ }
+
+ for (int i = 1; i < CONF_MAX_TXN_DEPTH; i++) {
+ char idx[2] = { '0' + i };
+ ok(conf_io_begin(true) == KNOT_EOK, "begin child txn %s", idx);
+ ok(conf_io_set("server", "version", NULL, idx) ==
+ KNOT_EOK, "set single value '%s'", idx);
+ }
+
+ for (int i = CONF_MAX_TXN_DEPTH - 1; i > 0; i--) {
+ char idx[2] = { '0' + i };
+ ok(conf_io_commit(true) == KNOT_EOK, "commit child txn %s", idx);
+ conf_val_t val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_EOK, "check entry");
+ const char *data = conf_str(&val);
+ ok(*data == ('0' + CONF_MAX_TXN_DEPTH - 1), "compare txn data '%s'", data);
+ }
+
+ ok(conf_io_commit(false) == KNOT_EOK, "commit parent txn");
+ ok(conf()->io.txn == NULL, "check txn depth");
+
+ // Test child persistence after parent commit.
+ ok(conf_io_begin(false) == KNOT_EOK, "begin new parent txn");
+ conf_val_t val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_EOK, "check entry");
+ char idx[2] = { '0' + CONF_MAX_TXN_DEPTH - 1 };
+ const char *data = conf_str(&val);
+ ok(strcmp(data, idx) == 0, "compare final data '%s'", data);
+ conf_io_abort(false);
+
+ // Test unchanged read_txn.
+ val = conf_get_txn(conf(), &conf()->read_txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_ENOENT, "check entry");
+#endif
+}
+
+static void test_conf_io_check(void)
+{
+ conf_io_t io = { NULL };
+
+ // ERR no txn.
+ ok(conf_io_check(&io) ==
+ KNOT_TXN_ENOTEXISTS, "check without active txn");
+
+ ok(conf_io_begin(false) == KNOT_EOK, "begin txn");
+
+ // Section check.
+ ok(conf_io_set("remote", "id", NULL, "remote1") ==
+ KNOT_EOK, "set remote id");
+ ok(conf_io_check(&io) ==
+ KNOT_EINVAL, "check missing remote address");
+ ok(io.error.code == KNOT_EINVAL, "compare error code");
+
+ ok(conf_io_set("remote", "address", "remote1", "1.1.1.1") ==
+ KNOT_EOK, "set remote address");
+ ok(conf_io_check(&io) ==
+ KNOT_EOK, "check remote address");
+ ok(io.error.code == KNOT_EOK, "compare error code");
+
+ // Item check.
+ ok(conf_io_set("zone", "domain", NULL, ZONE1) ==
+ KNOT_EOK, "set zone domain "ZONE1);
+ ok(conf_io_set("zone", "master", ZONE1, "remote1") ==
+ KNOT_EOK, "set zone master");
+
+ ok(conf_io_check(&io) ==
+ KNOT_EOK, "check all");
+
+ ok(conf_io_unset("remote", NULL, NULL, NULL) ==
+ KNOT_EOK, "unset remotes");
+
+ ok(conf_io_check(&io) ==
+ KNOT_ENOENT, "check missing master remote");
+ ok(io.error.code == KNOT_ENOENT, "compare error code");
+
+ conf_io_abort(false);
+}
+
+static void test_conf_io_set(void)
+{
+ // ERR no txn.
+ ok(conf_io_set("server", "version", NULL, "text") ==
+ KNOT_TXN_ENOTEXISTS, "set without active txn");
+
+ ok(conf_io_begin(false) == KNOT_EOK, "begin txn");
+
+ // ERR.
+ ok(conf_io_set(NULL, NULL, NULL, NULL) ==
+ KNOT_EINVAL, "set NULL key0");
+ ok(conf_io_set("", NULL, NULL, NULL) ==
+ KNOT_YP_EINVAL_ITEM, "set empty key0");
+ ok(conf_io_set("unknown", NULL, NULL, NULL) ==
+ KNOT_YP_EINVAL_ITEM, "set unknown key0");
+ ok(conf_io_set("server", "unknown", NULL, NULL) ==
+ KNOT_YP_EINVAL_ITEM, "set unknown key1");
+ ok(conf_io_set("include", NULL, NULL, NULL) ==
+ KNOT_YP_ENODATA, "set non-group without data");
+ ok(conf_io_set("server", "background-workers", NULL, "x") ==
+ KNOT_EINVAL, "set invalid data");
+
+ // ERR callback
+ ok(conf_io_set("include", NULL, NULL, "invalid") ==
+ KNOT_EFILE, "set invalid callback value");
+
+ // Single group, no item, no value.
+ ok(conf_io_set("server", NULL, NULL, NULL) ==
+ KNOT_ENOTSUP, "set group no value");
+ // Single group, no item, value.
+ ok(conf_io_set("server", NULL, NULL, "text") ==
+ KNOT_YP_ENOTSUP_DATA, "set group value");
+ // Single group, item, no value.
+ ok(conf_io_set("server", "version", NULL, NULL) ==
+ KNOT_YP_ENODATA, "set group item no value");
+
+ // Single group, single value.
+ ok(conf_io_set("server", "version", NULL, "text") ==
+ KNOT_EOK, "set single value");
+ conf_val_t val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_EOK, "check entry");
+ ok(strcmp(conf_str(&val), "text") == 0, "check entry value");
+
+ // Single group, multi value.
+ ok(conf_io_set("server", "listen", NULL, "1.1.1.1") ==
+ KNOT_EOK, "set multivalue 1");
+ ok(conf_io_set("server", "listen", NULL, "1.1.1.2") ==
+ KNOT_EOK, "set multivalue 2");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_LISTEN);
+ ok(val.code == KNOT_EOK, "check entry");
+ ok(conf_val_count(&val) == 2, "check entry value count");
+
+ // Prepare dnames.
+ knot_dname_t *zone1 = knot_dname_from_str_alloc(ZONE1);
+ ok(zone1 != NULL, "create dname "ZONE1);
+ knot_dname_t *zone2 = knot_dname_from_str_alloc(ZONE2);
+ ok(zone2 != NULL, "create dname "ZONE2);
+ knot_dname_t *zone3 = knot_dname_from_str_alloc(ZONE3);
+ ok(zone3 != NULL, "create dname "ZONE3);
+
+ // Multi group no id.
+ ok(conf_io_set("zone", "domain", NULL, NULL) ==
+ KNOT_YP_ENOID, "set zone empty domain");
+
+ // Multi group ids.
+ ok(conf_io_set("zone", "domain", NULL, ZONE1) ==
+ KNOT_EOK, "set zone domain "ZONE1);
+ ok(conf_io_set("zone", NULL, ZONE2, NULL) ==
+ KNOT_EOK, "set zone domain "ZONE2);
+
+ // Multi group, single value.
+ ok(conf_io_set("zone", "file", ZONE1, "name") ==
+ KNOT_EOK, "set zone file");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_FILE, zone1);
+ ok(val.code == KNOT_EOK, "check entry");
+ ok(strcmp(conf_str(&val), "name") == 0, "check entry value");
+
+ // Multi group, single value, bad id.
+ ok(conf_io_set("zone", "file", ZONE3, "name") ==
+ KNOT_YP_EINVAL_ID, "set zone file");
+
+ // Multi group, single value, all ids.
+ ok(conf_io_set("zone", "comment", NULL, "abc") ==
+ KNOT_EOK, "set zones comment");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone1);
+ ok(val.code == KNOT_EOK, "check entry");
+ ok(strcmp(conf_str(&val), "abc") == 0, "check entry value");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone2);
+ ok(val.code == KNOT_EOK, "check entry");
+ ok(strcmp(conf_str(&val), "abc") == 0, "check entry value");
+
+ // Prepare different comment.
+ ok(conf_io_set("zone", "domain", NULL, ZONE3) ==
+ KNOT_EOK, "set zone domain "ZONE3);
+ ok(conf_io_set("zone", "comment", ZONE3, "xyz") ==
+ KNOT_EOK, "set zone comment");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone3);
+ ok(val.code == KNOT_EOK, "check entry");
+ ok(strcmp(conf_str(&val), "xyz") == 0, "check entry value");
+
+ knot_dname_free(zone1, NULL);
+ knot_dname_free(zone2, NULL);
+ knot_dname_free(zone3, NULL);
+
+ ok(conf_io_commit(false) == KNOT_EOK, "commit txn");
+
+ // Update read-only transaction.
+ ok(conf_refresh_txn(conf()) == KNOT_EOK, "update read-only txn");
+}
+
+static void test_conf_io_unset(void)
+{
+ // ERR no txn.
+ ok(conf_io_unset("server", "version", NULL, "text") ==
+ KNOT_TXN_ENOTEXISTS, "unset without active txn");
+
+ ok(conf_io_begin(false) == KNOT_EOK, "begin txn");
+
+ // ERR.
+ ok(conf_io_unset("", NULL, NULL, NULL) ==
+ KNOT_YP_EINVAL_ITEM, "unset unknown key0");
+ ok(conf_io_unset("unknown", NULL, NULL, NULL) ==
+ KNOT_YP_EINVAL_ITEM, "unset unknown key0");
+ ok(conf_io_unset("server", "unknown", NULL, NULL) ==
+ KNOT_YP_EINVAL_ITEM, "unset unknown key1");
+ ok(conf_io_unset("include", NULL, NULL, "file") ==
+ KNOT_ENOTSUP, "unset non-group item");
+ ok(conf_io_unset("server", "background-workers", NULL, "x") ==
+ KNOT_EINVAL, "unset invalid data");
+
+ // Single group, single value.
+ ok(conf_io_unset("server", "version", NULL, "") ==
+ KNOT_ENOENT, "unset zero length text value");
+ conf_val_t val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_EOK, "check entry");
+
+ ok(conf_io_unset("server", "version", NULL, "bad text") ==
+ KNOT_ENOENT, "unset bad value");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_EOK, "check entry");
+
+ ok(conf_io_unset("server", "version", NULL, "text") ==
+ KNOT_EOK, "unset explicit value");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_ENOENT, "check entry");
+
+ // Restart transaction.
+ conf_io_abort(false);
+ ok(conf_io_begin(false) == KNOT_EOK, "restart txn");
+
+ ok(conf_io_unset("server", "version", NULL, NULL) ==
+ KNOT_EOK, "unset value");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_ENOENT, "check entry");
+
+ // Single group, multi value.
+ ok(conf_io_unset("server", "listen", NULL, "9.9.9.9") ==
+ KNOT_ENOENT, "unset bad value");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_LISTEN);
+ ok(val.code == KNOT_EOK, "check entry");
+
+ ok(conf_io_unset("server", "listen", NULL, "1.1.1.1") ==
+ KNOT_EOK, "unset explicit value");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_LISTEN);
+ ok(val.code == KNOT_EOK, "check entry");
+ ok(conf_val_count(&val) == 1, "check entry value count");
+
+ ok(conf_io_unset("server", "listen", NULL, NULL) ==
+ KNOT_EOK, "unset value");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_LISTEN);
+ ok(val.code == KNOT_ENOENT, "check entry");
+
+ // Restart transaction.
+ conf_io_abort(false);
+ ok(conf_io_begin(false) == KNOT_EOK, "restart txn");
+
+ // Whole section items.
+ ok(conf_io_unset("server", NULL, NULL, NULL) ==
+ KNOT_EOK, "unset section");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_ENOENT, "check entry");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_LISTEN);
+ ok(val.code == KNOT_ENOENT, "check entry");
+
+ // Restart transaction.
+ conf_io_abort(false);
+ ok(conf_io_begin(false) == KNOT_EOK, "restart txn");
+
+ // Prepare dnames.
+ knot_dname_t *zone1 = knot_dname_from_str_alloc(ZONE1);
+ ok(zone1 != NULL, "create dname "ZONE1);
+ knot_dname_t *zone2 = knot_dname_from_str_alloc(ZONE2);
+ ok(zone2 != NULL, "create dname "ZONE2);
+ knot_dname_t *zone3 = knot_dname_from_str_alloc(ZONE3);
+ ok(zone3 != NULL, "create dname "ZONE3);
+
+ // Multi group, single value.
+ ok(conf_io_unset("zone", "file", ZONE1, "name") ==
+ KNOT_EOK, "unset zone file");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_FILE, zone1);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+
+ // Multi group, single bad value, all ids.
+ ok(conf_io_unset("zone", "comment", NULL, "other") ==
+ KNOT_EOK, "unset zones comment");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone1);
+ ok(val.code == KNOT_EOK, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone2);
+ ok(val.code == KNOT_EOK, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone3);
+ ok(val.code == KNOT_EOK, "check entry");
+
+ // Restart transaction.
+ conf_io_abort(false);
+ ok(conf_io_begin(false) == KNOT_EOK, "restart txn");
+
+ // Multi group, single value (not all match), all ids.
+ ok(conf_io_unset("zone", "comment", NULL, "abc") ==
+ KNOT_EOK, "unset some zones comment");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone1);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone2);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone3);
+ ok(val.code == KNOT_EOK, "check entry");
+
+ // Restart transaction.
+ conf_io_abort(false);
+ ok(conf_io_begin(false) == KNOT_EOK, "restart txn");
+
+ // Multi group, single value (all match), all ids.
+ ok(conf_io_unset("zone", "comment", NULL, NULL) ==
+ KNOT_EOK, "unset all zones comment");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone1);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone2);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone3);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+
+ // Restart transaction.
+ conf_io_abort(false);
+ ok(conf_io_begin(false) == KNOT_EOK, "restart txn");
+
+ // Multi group, all items, specific id.
+ ok(conf_io_unset("zone", NULL, ZONE1, NULL) ==
+ KNOT_EOK, "unset zone items");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_FILE, zone1);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone1);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone2);
+ ok(val.code == KNOT_EOK, "check entry");
+
+ // Restart transaction.
+ conf_io_abort(false);
+ ok(conf_io_begin(false) == KNOT_EOK, "restart txn");
+
+ // Multi group, all items, all ids.
+ ok(conf_io_unset("zone", NULL, NULL, NULL) ==
+ KNOT_EOK, "unset zone items");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_FILE, zone1);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone1);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone2);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+
+ // Restart transaction.
+ conf_io_abort(false);
+ ok(conf_io_begin(false) == KNOT_EOK, "restart txn");
+
+ // All groups.
+ ok(conf_io_unset(NULL, NULL, NULL, NULL) ==
+ KNOT_EOK, "unset all");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_VERSION);
+ ok(val.code == KNOT_ENOENT, "check entry");
+ val = conf_get_txn(conf(), conf()->io.txn, C_SERVER, C_LISTEN);
+ ok(val.code == KNOT_ENOENT, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_FILE, zone1);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone1);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+ val = conf_zone_get_txn(conf(), conf()->io.txn, C_COMMENT, zone2);
+ ok(val.code == KNOT_YP_EINVAL_ID, "check entry");
+
+ knot_dname_free(zone1, NULL);
+ knot_dname_free(zone2, NULL);
+ knot_dname_free(zone3, NULL);
+
+ conf_io_abort(false);
+}
+
+static void test_conf_io_get(void)
+{
+ const char *ref;
+ char out[OUT_LEN];
+
+ conf_io_t io = {
+ .fcn = format_item,
+ .misc = out
+ };
+
+ // ERR no txn.
+ ok(conf_io_get("server", "version", NULL, false, &io) ==
+ KNOT_TXN_ENOTEXISTS, "get without active txn");
+
+ // Get current, no active txn.
+ *out = '\0';
+ ok(conf_io_get("server", "version", NULL, true, &io) ==
+ KNOT_EOK, "get current without active txn");
+ ref = "server.version = \"text\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ ok(conf_io_begin(false) == KNOT_EOK, "begin txn");
+
+ // ERR.
+ ok(conf_io_get("", NULL, NULL, true, &io) ==
+ KNOT_YP_EINVAL_ITEM, "get empty key0");
+ ok(conf_io_get("unknown", NULL, NULL, true, &io) ==
+ KNOT_YP_EINVAL_ITEM, "get unknown key0");
+ ok(conf_io_get("server", "unknown", NULL, true, &io) ==
+ KNOT_YP_EINVAL_ITEM, "get unknown key1");
+ ok(conf_io_get("include", NULL, NULL, true, &io) ==
+ KNOT_ENOTSUP, "get non-group item");
+
+ // Update item in the active txn.
+ ok(conf_io_set("server", "version", NULL, "new text") ==
+ KNOT_EOK, "set single value");
+
+ // Get new, active txn.
+ *out = '\0';
+ ok(conf_io_get("server", "version", NULL, false, &io) ==
+ KNOT_EOK, "get with active txn");
+ ref = "server.version = \"new text\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Get current, active txn.
+ *out = '\0';
+ ok(conf_io_get("server", "version", NULL, true, &io) ==
+ KNOT_EOK, "get with active txn");
+ ref = "server.version = \"text\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Multi value.
+ *out = '\0';
+ ok(conf_io_get("server", "listen", NULL, true, &io) ==
+ KNOT_EOK, "get with active txn");
+ ref = "server.listen = \"1.1.1.1\" \"1.1.1.2\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Single group.
+ *out = '\0';
+ ok(conf_io_get("server", NULL, NULL, true, &io) ==
+ KNOT_EOK, "get with active txn");
+ ref = "server.version = \"text\"\n"
+ "server.listen = \"1.1.1.1\" \"1.1.1.2\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Prepare dnames.
+ knot_dname_t *zone1 = knot_dname_from_str_alloc(ZONE1);
+ ok(zone1 != NULL, "create dname "ZONE1);
+
+ // Multi group, all values, all ids.
+ *out = '\0';
+ ok(conf_io_get("zone", NULL, NULL, true, &io) ==
+ KNOT_EOK, "get with active txn");
+ ref = "zone.domain = \"zone1.\"\n"
+ "zone[zone1.].file = \"name\"\n"
+ "zone[zone1.].comment = \"abc\"\n"
+ "zone.domain = \"zone2.\"\n"
+ "zone[zone2.].comment = \"abc\"\n"
+ "zone.domain = \"zone3.\"\n"
+ "zone[zone3.].comment = \"xyz\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Multi group ids.
+ *out = '\0';
+ ok(conf_io_get("zone", "domain", NULL, true, &io) ==
+ KNOT_EOK, "get with active txn");
+ ref = "zone.domain = \"zone1.\"\n"
+ "zone.domain = \"zone2.\"\n"
+ "zone.domain = \"zone3.\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Multi group, all values, single id.
+ *out = '\0';
+ ok(conf_io_get("zone", NULL, ZONE1, true, &io) ==
+ KNOT_EOK, "get with active txn");
+ ref = "zone.domain = \"zone1.\"\n"
+ "zone[zone1.].file = \"name\"\n"
+ "zone[zone1.].comment = \"abc\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Multi group, single value, single id.
+ *out = '\0';
+ ok(conf_io_get("zone", "file", ZONE1, true, &io) ==
+ KNOT_EOK, "get with active txn");
+ ref = "zone[zone1.].file = \"name\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // All groups.
+ *out = '\0';
+ ok(conf_io_get(NULL, NULL, NULL, true, &io) ==
+ KNOT_EOK, "get with active txn");
+ ref = "server.version = \"text\"\n"
+ "server.listen = \"1.1.1.1\" \"1.1.1.2\"\n"
+ "zone.domain = \"zone1.\"\n"
+ "zone[zone1.].file = \"name\"\n"
+ "zone[zone1.].comment = \"abc\"\n"
+ "zone.domain = \"zone2.\"\n"
+ "zone[zone2.].comment = \"abc\"\n"
+ "zone.domain = \"zone3.\"\n"
+ "zone[zone3.].comment = \"xyz\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ knot_dname_free(zone1, NULL);
+
+ conf_io_abort(false);
+}
+
+static void test_conf_io_diff(void)
+{
+ const char *ref;
+ char out[OUT_LEN];
+
+ conf_io_t io = {
+ .fcn = format_item,
+ .misc = out
+ };
+
+ // ERR no txn.
+ ok(conf_io_diff("server", "version", NULL, &io) ==
+ KNOT_TXN_ENOTEXISTS, "diff without active txn");
+
+ ok(conf_io_begin(false) == KNOT_EOK, "begin txn");
+
+ // ERR.
+ ok(conf_io_diff("", NULL, NULL, &io) ==
+ KNOT_YP_EINVAL_ITEM, "diff empty key0");
+ ok(conf_io_diff("unknown", NULL, NULL, &io) ==
+ KNOT_YP_EINVAL_ITEM, "diff unknown key0");
+ ok(conf_io_diff("server", "unknown", NULL, &io) ==
+ KNOT_YP_EINVAL_ITEM, "diff unknown key1");
+ ok(conf_io_diff("include", NULL, NULL, &io) ==
+ KNOT_ENOTSUP, "diff non-group item");
+
+ *out = '\0';
+ ok(conf_io_diff(NULL, NULL, NULL, &io) == KNOT_EOK, "diff no change");
+ ref = "";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Update singlevalued item.
+ ok(conf_io_set("server", "version", NULL, "new text") ==
+ KNOT_EOK, "set single value");
+
+ *out = '\0';
+ ok(conf_io_diff("server", "version", NULL, &io) == KNOT_EOK, "diff single item");
+ ref = "-server.version = \"text\"\n"
+ "+server.version = \"new text\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Update multivalued item.
+ ok(conf_io_unset("server", "listen", NULL, "1.1.1.1") ==
+ KNOT_EOK, "unset multivalue");
+ ok(conf_io_set("server", "listen", NULL, "1.1.1.3") ==
+ KNOT_EOK, "set multivalue");
+
+ *out = '\0';
+ ok(conf_io_diff("server", "listen", NULL, &io) == KNOT_EOK, "diff multi item");
+ ref = "-server.listen = \"1.1.1.1\" \"1.1.1.2\"\n"
+ "+server.listen = \"1.1.1.2\" \"1.1.1.3\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Unset single item.
+ ok(conf_io_unset("zone", "comment", ZONE3, NULL) ==
+ KNOT_EOK, "unset multivalue");
+
+ *out = '\0';
+ ok(conf_io_diff("zone", NULL, ZONE3, &io) == KNOT_EOK, "diff section");
+ ref = "-zone[zone3.].comment = \"xyz\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Unset id.
+ ok(conf_io_unset("zone", NULL, ZONE1, NULL) ==
+ KNOT_EOK, "unset id");
+ ok(conf_io_unset("zone", NULL, ZONE2, NULL) ==
+ KNOT_EOK, "unset id");
+
+ *out = '\0';
+ ok(conf_io_diff("zone", NULL, ZONE2, &io) == KNOT_EOK, "diff id section");
+ ref = "-zone.domain = \"zone2.\"\n"
+ "-zone[zone2.].comment = \"abc\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ *out = '\0';
+ ok(conf_io_diff("zone", "domain", NULL, &io) == KNOT_EOK, "diff id");
+ ref = "-zone.domain = \"zone1.\"\n"
+ "-zone.domain = \"zone2.\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ *out = '\0';
+ ok(conf_io_diff(NULL, NULL, NULL, &io) == KNOT_EOK, "diff whole change");
+ ref = "-server.version = \"text\"\n"
+ "+server.version = \"new text\"\n"
+ "-server.listen = \"1.1.1.1\" \"1.1.1.2\"\n"
+ "+server.listen = \"1.1.1.2\" \"1.1.1.3\"\n"
+ "-zone.domain = \"zone1.\"\n"
+ "-zone[zone1.].file = \"name\"\n"
+ "-zone[zone1.].comment = \"abc\"\n"
+ "-zone.domain = \"zone2.\"\n"
+ "-zone[zone2.].comment = \"abc\"\n"
+ "-zone[zone3.].comment = \"xyz\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ conf_io_abort(false);
+}
+
+static void test_conf_io_list(void)
+{
+ const char *ref;
+ char out[OUT_LEN];
+
+ conf_io_t io = {
+ .fcn = format_item,
+ .misc = out
+ };
+
+ // ERR.
+ ok(conf_io_list("", NULL, NULL, false, true, &io) ==
+ KNOT_YP_EINVAL_ITEM, "list empty key0");
+ ok(conf_io_list("unknown", NULL, NULL, false, true, &io) ==
+ KNOT_YP_EINVAL_ITEM, "list unknown key0");
+ ok(conf_io_list("include", NULL, NULL, false, true, &io) ==
+ KNOT_EOK, "list non-group item");
+ ok(conf_io_list("template", NULL, NULL, false, false, &io) ==
+ KNOT_TXN_ENOTEXISTS, "no active txn");
+
+ // Desc schema.
+ *out = '\0';
+ ok(conf_io_list(NULL, NULL, NULL, true, true, &io) ==
+ KNOT_EOK, "list schema");
+ ref = "server\n"
+ "xdp\n"
+ "control\n"
+ "remote\n"
+ "template\n"
+ "zone\n"
+ "include";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // Desc group.
+ *out = '\0';
+ ok(conf_io_list("server", NULL, NULL, true, true, &io) ==
+ KNOT_EOK, "list group");
+ ref = "server.version\n"
+ "server.listen\n"
+ "server.tcp-idle-timeout\n"
+ "server.tcp-io-timeout\n"
+ "server.tcp-remote-io-timeout\n"
+ "server.tcp-max-clients\n"
+ "server.tcp-reuseport\n"
+ "server.tcp-fastopen\n"
+ "server.quic-max-clients\n"
+ "server.quic-idle-close-timeout\n"
+ "server.quic-outbuf-max-size\n"
+ "server.socket-affinity\n"
+ "server.udp-workers\n"
+ "server.tcp-workers\n"
+ "server.background-workers\n"
+ "server.udp-max-payload\n"
+ "server.udp-max-payload-ipv4\n"
+ "server.udp-max-payload-ipv6\n"
+ "server.edns-client-subnet\n"
+ "server.answer-rotation\n"
+ "server.automatic-acl\n"
+ "server.dbus-event";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // List item options.
+ *out = '\0';
+ ok(conf_io_list("zone", "zonefile-load", NULL, true, true, &io) ==
+ KNOT_EOK, "list item options");
+ ref = "zone.zonefile-load = \"opt1\"\n"
+ "zone.zonefile-load = \"opt2\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // List zone identifiers 1.
+ *out = '\0';
+ ok(conf_io_list("zone", NULL, NULL, false, true, &io) ==
+ KNOT_EOK, "list zone identifiers 1");
+ ref = "zone[zone1.]\n"
+ "zone[zone2.]\n"
+ "zone[zone3.]";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // List zone identifiers 2.
+ *out = '\0';
+ ok(conf_io_list("zone", "domain", NULL, false, true, &io) ==
+ KNOT_EOK, "list zone identifiers 2");
+ ref = "zone = \"zone1.\"\n"
+ "zone = \"zone2.\"\n"
+ "zone = \"zone3.\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // List item values.
+ *out = '\0';
+ ok(conf_io_list("server", "listen", NULL, false, true, &io) ==
+ KNOT_EOK, "list item values");
+ ref = "server.listen = \"1.1.1.1\" \"1.1.1.2\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+
+ // List multi-group item values.
+ *out = '\0';
+ ok(conf_io_list("zone", "file", "zone1", false, true, &io) ==
+ KNOT_EOK, "list multi-group item values");
+ ref = "zone[zone1.].file = \"name\"";
+ ok(strcmp(ref, out) == 0, "compare result");
+}
+
+static const yp_item_t desc_server[] = {
+ { C_VERSION, YP_TSTR, YP_VNONE },
+ { C_LISTEN, YP_TADDR, YP_VNONE, YP_FMULTI },
+ // Required config cache items - assert fix.
+ { C_TCP_IDLE_TIMEOUT, YP_TINT, YP_VNONE },
+ { C_TCP_IO_TIMEOUT, YP_TINT, YP_VNONE },
+ { C_TCP_RMT_IO_TIMEOUT, YP_TINT, YP_VNONE },
+ { C_TCP_MAX_CLIENTS, YP_TINT, YP_VNONE },
+ { C_TCP_REUSEPORT, YP_TBOOL, YP_VNONE },
+ { C_TCP_FASTOPEN, YP_TBOOL, YP_VNONE },
+ { C_QUIC_MAX_CLIENTS, YP_TINT, YP_VNONE },
+ { C_QUIC_IDLE_CLOSE, YP_TINT, YP_VNONE },
+ { C_QUIC_OUTBUF_MAX_SIZE, YP_TINT, YP_VNONE },
+ { C_SOCKET_AFFINITY, YP_TBOOL, YP_VNONE },
+ { C_UDP_WORKERS, YP_TINT, YP_VNONE },
+ { C_TCP_WORKERS, YP_TINT, YP_VNONE },
+ { C_BG_WORKERS, YP_TINT, YP_VNONE },
+ { C_UDP_MAX_PAYLOAD, YP_TINT, YP_VNONE },
+ { C_UDP_MAX_PAYLOAD_IPV4, YP_TINT, YP_VNONE },
+ { C_UDP_MAX_PAYLOAD_IPV6, YP_TINT, YP_VNONE },
+ { C_ECS, YP_TBOOL, YP_VNONE },
+ { C_ANS_ROTATION, YP_TBOOL, YP_VNONE },
+ { C_AUTO_ACL, YP_TBOOL, YP_VNONE },
+ { C_DBUS_EVENT, YP_TOPT, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_xdp[] = {
+ { C_UDP, YP_TBOOL, YP_VNONE },
+ { C_TCP, YP_TBOOL, YP_VNONE },
+ { C_QUIC, YP_TBOOL, YP_VNONE },
+ { C_TCP_MAX_CLIENTS, YP_TINT, YP_VNONE },
+ { C_TCP_INBUF_MAX_SIZE, YP_TINT, YP_VNONE },
+ { C_TCP_OUTBUF_MAX_SIZE,YP_TINT, YP_VNONE },
+ { C_TCP_IDLE_CLOSE, YP_TINT, YP_VNONE },
+ { C_TCP_IDLE_RESET, YP_TINT, YP_VNONE },
+ { C_TCP_RESEND, YP_TINT, YP_VNONE },
+ { C_ROUTE_CHECK, YP_TBOOL, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_control[] = {
+ { C_TIMEOUT, YP_TINT, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_remote[] = {
+ { C_ID, YP_TSTR, YP_VNONE },
+ { C_ADDR, YP_TADDR, YP_VNONE, YP_FMULTI },
+ { NULL }
+};
+
+static const knot_lookup_t opts[] = {
+ { 1, "opt1" },
+ { 2, "opt2" },
+ { 0, NULL }
+};
+
+#define ZONE_ITEMS \
+ { C_FILE, YP_TSTR, YP_VNONE }, \
+ { C_MASTER, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } }, \
+ { C_ZONEFILE_LOAD, YP_TOPT, YP_VOPT = { opts, 0 } }, \
+ { C_JOURNAL_CONTENT, YP_TOPT, YP_VOPT = { opts, 0 } }, \
+ { C_DNSSEC_SIGNING, YP_TBOOL, YP_VNONE }, \
+ { C_DNSSEC_VALIDATION, YP_TBOOL, YP_VNONE }, \
+ { C_CATALOG_ROLE, YP_TOPT, YP_VOPT = { opts, 0 } }, \
+ { C_CATALOG_TPL, YP_TREF, YP_VREF = { C_RMT } }, \
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+
+static const yp_item_t desc_template[] = {
+ { C_ID, YP_TSTR, YP_VNONE },
+ ZONE_ITEMS
+ { NULL }
+};
+
+static const yp_item_t desc_zone[] = {
+ { C_DOMAIN, YP_TDNAME, YP_VNONE },
+ ZONE_ITEMS
+ { NULL }
+};
+
+const yp_item_t test_schema[] = {
+ { C_SRV, YP_TGRP, YP_VGRP = { desc_server } },
+ { C_XDP, YP_TGRP, YP_VGRP = { desc_xdp } },
+ { C_CTL, YP_TGRP, YP_VGRP = { desc_control } },
+ { C_RMT, YP_TGRP, YP_VGRP = { desc_remote }, YP_FMULTI, { check_remote } },
+ { C_TPL, YP_TGRP, YP_VGRP = { desc_template }, YP_FMULTI, { check_template } },
+ { C_ZONE, YP_TGRP, YP_VGRP = { desc_zone }, YP_FMULTI, { check_zone } },
+ { C_INCL, YP_TSTR, YP_VNONE, YP_FNONE, { include_file } },
+ { NULL }
+};
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ ok(test_conf("", test_schema) == KNOT_EOK, "Prepare configuration");
+
+ diag("conf_io_begin");
+ test_conf_io_begin();
+
+ diag("conf_io_abort");
+ test_conf_io_abort();
+
+ diag("conf_io_commit");
+ test_conf_io_commit();
+
+ diag("conf_io_check");
+ test_conf_io_check();
+
+ diag("conf_io_set");
+ test_conf_io_set();
+
+ diag("conf_io_unset");
+ test_conf_io_unset();
+
+ diag("conf_io_get");
+ test_conf_io_get();
+
+ diag("conf_io_diff");
+ test_conf_io_diff();
+
+ diag("conf_io_list");
+ test_conf_io_list();
+
+ conf_free(conf());
+
+ return 0;
+}
diff --git a/tests/knot/test_digest.c b/tests/knot/test_digest.c
new file mode 100644
index 0000000..a694e49
--- /dev/null
+++ b/tests/knot/test_digest.c
@@ -0,0 +1,474 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "knot/zone/digest.h"
+
+#include <string.h>
+#include <tap/basic.h>
+
+#include "knot/zone/zonefile.h"
+#include "libzscanner/scanner.h"
+
+// copy-pasted from knot/zone/zonefile.c
+static void process_data(zs_scanner_t *scanner)
+{
+ zcreator_t *zc = scanner->process.data;
+ if (zc->ret != KNOT_EOK) {
+ scanner->state = ZS_STATE_STOP;
+ return;
+ }
+
+ knot_dname_t *owner = knot_dname_copy(scanner->r_owner, NULL);
+ if (owner == NULL) {
+ zc->ret = KNOT_ENOMEM;
+ return;
+ }
+
+ knot_rrset_t rr;
+ knot_rrset_init(&rr, owner, scanner->r_type, scanner->r_class, scanner->r_ttl);
+
+ int ret = knot_rrset_add_rdata(&rr, scanner->r_data, scanner->r_data_length, NULL);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&rr, NULL);
+ zc->ret = ret;
+ return;
+ }
+
+ ret = knot_rrset_rr_to_canonical(&rr);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&rr, NULL);
+ zc->ret = ret;
+ return;
+ }
+
+ zc->ret = zcreator_step(zc, &rr);
+ knot_rrset_clear(&rr, NULL);
+}
+
+static void process_error(zs_scanner_t *s)
+{
+ (void)s;
+ assert(0);
+}
+
+static zone_contents_t *str2contents(const char *zone_str)
+{
+ knot_dname_txt_storage_t origin_str;
+ sscanf(zone_str, "%s", origin_str); // NOTE assuming that first token in zone_str is origin name!
+
+ knot_dname_t *origin = knot_dname_from_str_alloc(origin_str);
+ assert(origin != NULL);
+
+ zone_contents_t *cont = zone_contents_new(origin, false);
+ assert(cont != NULL);
+ knot_dname_free(origin, NULL);
+
+ zcreator_t zc = { cont, true, KNOT_EOK };
+
+ zs_scanner_t sc;
+ ok(zs_init(&sc, origin_str, KNOT_CLASS_IN, 3600) == 0 &&
+ zs_set_input_string(&sc, zone_str, strlen(zone_str)) == 0 &&
+ zs_set_processing(&sc, process_data, process_error, &zc) == 0 &&
+ zs_parse_all(&sc) == 0, "zscanner initialization");
+ zs_deinit(&sc);
+
+ return cont;
+}
+
+static int check_contents(const char *zone_str)
+{
+ zone_contents_t *cont = str2contents(zone_str);
+ int ret = zone_contents_digest_verify(cont);
+ zone_contents_deep_free(cont);
+ return ret;
+}
+
+const char *simple_zone = "\
+example. 86400 IN SOA ns1 admin 2018031900 ( \n\
+ 1800 900 604800 86400 ) \n\
+ 86400 IN NS ns1 \n\
+ 86400 IN NS ns2 \n\
+ 86400 IN ZONEMD 2018031900 1 1 ( \n\
+ c68090d90a7aed71 \n\
+ 6bc459f9340e3d7c \n\
+ 1370d4d24b7e2fc3 \n\
+ a1ddc0b9a87153b9 \n\
+ a9713b3c9ae5cc27 \n\
+ 777f98b8e730044c ) \n\
+ns1 3600 IN A 203.0.113.63 \n\
+ns2 3600 IN AAAA 2001:db8::63";
+
+const char *complex_zone = "\
+example. 86400 IN SOA ns1 admin 2018031900 ( \n\
+ 1800 900 604800 86400 ) \n\
+ 86400 IN NS ns1 \n\
+ 86400 IN NS ns2 \n\
+ 86400 IN ZONEMD 2018031900 1 1 ( \n\
+ a3b69bad980a3504 \n\
+ e1cffcb0fd6397f9 \n\
+ 3848071c93151f55 \n\
+ 2ae2f6b1711d4bd2 \n\
+ d8b39808226d7b9d \n\
+ b71e34b72077f8fe ) \n\
+ns1 3600 IN A 203.0.113.63 \n\
+NS2 3600 IN AAAA 2001:db8::63 \n\
+occluded.sub 7200 IN TXT \"I'm occluded but must be digested\" \n\
+sub 7200 IN NS ns1 \n\
+duplicate 300 IN TXT \"I must be digested just once\" \n\
+duplicate 300 IN TXT \"I must be digested just once\" \n\
+foo.test. 555 IN TXT \"out-of-zone data must be excluded\" \n\
+UPPERCASE 3600 IN TXT \"canonicalize uppercase owner names\" \n\
+* 777 IN PTR dont-forget-about-wildcards \n\
+mail 3600 IN MX 20 MAIL1 \n\
+mail 3600 IN MX 10 Mail2.Example. \n\
+sortme 3600 IN AAAA 2001:db8::5:61 \n\
+sortme 3600 IN AAAA 2001:db8::3:62 \n\
+sortme 3600 IN AAAA 2001:db8::4:63 \n\
+sortme 3600 IN AAAA 2001:db8::1:65 \n\
+sortme 3600 IN AAAA 2001:db8::2:64 \n\
+non-apex 900 IN ZONEMD 2018031900 1 1 ( \n\
+ 616c6c6f77656420 \n\
+ 6275742069676e6f \n\
+ 7265642e20616c6c \n\
+ 6f77656420627574 \n\
+ 2069676e6f726564 \n\
+ 2e20616c6c6f7765 )";
+
+const char *multiple_digests = "\
+example. 86400 IN SOA ns1 admin 2018031900 ( \n\
+ 1800 900 604800 86400 ) \n\
+example. 86400 IN NS ns1.example. \n\
+example. 86400 IN NS ns2.example. \n\
+example. 86400 IN ZONEMD 2018031900 1 1 ( \n\
+ 62e6cf51b02e54b9 \n\
+ b5f967d547ce4313 \n\
+ 6792901f9f88e637 \n\
+ 493daaf401c92c27 \n\
+ 9dd10f0edb1c56f8 \n\
+ 080211f8480ee306 ) \n\
+example. 86400 IN ZONEMD 2018031900 1 2 ( \n\
+ 08cfa1115c7b948c \n\
+ 4163a901270395ea \n\
+ 226a930cd2cbcf2f \n\
+ a9a5e6eb85f37c8a \n\
+ 4e114d884e66f176 \n\
+ eab121cb02db7d65 \n\
+ 2e0cc4827e7a3204 \n\
+ f166b47e5613fd27 ) \n\
+example. 86400 IN ZONEMD 2018031900 1 240 ( \n\
+ e2d523f654b9422a \n\
+ 96c5a8f44607bbee ) \n\
+example. 86400 IN ZONEMD 2018031900 241 1 ( \n\
+ e1846540e33a9e41 \n\
+ 89792d18d5d131f6 \n\
+ 05fc283e ) \n\
+ns1.example. 3600 IN A 203.0.113.63 \n\
+ns2.example. 86400 IN TXT \"This example has multiple digests\" \n\
+NS2.EXAMPLE. 3600 IN AAAA 2001:db8::63";
+
+const char *signed_zone = "\
+uri.arpa. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2018100702 10800 3600 1209600 3600 \n\
+uri.arpa. 3600 IN RRSIG SOA 8 2 3600 20210217232440 20210120232440 37444 uri.arpa. GzQw+QzwLDJr13REPGVmpEChjD1D2XlX0ie1DnWHpgaEw1E/dhs3lCN3 +BmHd4Kx3tffTRgiyq65HxR6feQ5v7VmAifjyXUYB1DZur1eP5q0Ms2y gCB3byoeMgCNsFS1oKZ2LdzNBRpy3oace8xQn1SpmHGfyrsgg+WbHKCT 1dY= \n\
+uri.arpa. 86400 IN NS a.iana-servers.net. \n\
+uri.arpa. 86400 IN NS b.iana-servers.net. \n\
+uri.arpa. 86400 IN NS c.iana-servers.net. \n\
+uri.arpa. 86400 IN NS ns2.lacnic.net. \n\
+uri.arpa. 86400 IN NS sec3.apnic.net. \n\
+uri.arpa. 86400 IN RRSIG NS 8 2 86400 20210217232440 20210120232440 37444 uri.arpa. M+Iei2lcewWGaMtkPlrhM9FpUAHXFkCHTVpeyrjxjEONeNgKtHZor5e4 V4qJBOzNqo8go/qJpWlFBm+T5Hn3asaBZVstFIYky38/C8UeRLPKq1hT THARYUlFrexr5fMtSUAVOgOQPSBfH3xBq/BgSccTdRb9clD+HE7djpqr LS4= \n\
+uri.arpa. 600 IN MX 10 pechora.icann.org. \n\
+uri.arpa. 600 IN RRSIG MX 8 2 600 20210217232440 20210120232440 37444 uri.arpa. kQAJQivmv6A5hqYBK8h6Z13ESY69gmosXwKI6WE09I8RFetfrxr24ecd nYd0lpnDtgNNSoHkYRSOoB+C4+zuJsoyAAzGo9uoWMWj97/2xeGhf3PT C9meQ9Ohi6hul9By7OR76XYmGhdWX8PBi60RUmZ1guslFBfQ8izwPqzu phs= \n\
+uri.arpa. 3600 IN NSEC ftp.uri.arpa. NS SOA MX RRSIG NSEC DNSKEY ZONEMD \n\
+uri.arpa. 3600 IN RRSIG NSEC 8 2 3600 20210217232440 20210120232440 37444 uri.arpa. dU/rXLM/naWd1+1PiWiYVaNJyCkiuyZJSccr91pJI673T8r3685B4ODM YFafZRboVgwnl3ZrXddY6xOhZL3n9V9nxXZwjLJ2HJUojFoKcXTlpnUy YUYvVQ2kj4GHAo6fcGCEp5QFJ2KbCpeJoS+PhKGRRx28icCiNT4/uXQv O2E= \n\
+uri.arpa. 3600 IN DNSKEY 256 3 8 AwEAAbMxuFuLeVDuOwIMzYOTD/bTREjLflo7wOi6ieIJhqltEzgjNzmW Jf9kGwwDmzxU7kbthMEhBNBZNn84zmcyRSCMzuStWveL7xmqqUlE3swL 8kLOvdZvc75XnmpHrk3ndTyEb6eZM7slh2C63Oh6K8VR5VkiZAkEGg0u ZIT3NjsF \n\
+uri.arpa. 3600 IN DNSKEY 257 3 8 AwEAAdkTaWkZtZuRh7/OobBUFxM+ytTst+bCu0r9w+rEwXD7GbDs0pIM hMenrZzoAvmv1fQxw2MGs6Ri6yPKfNULcFOSt9l8i6BVBLI+SKTY6XXe DUQpSEmSaxohHeRPMQFzpysfjxINp/L2rGtZ7yPmxY/XRiFPSO0myqwG Ja9r06Zw9CHM5UDHKWV/E+zxPFq/I7CfPbrrzbUotBX7Z6Vh3Sarllbe 8cGUB2UFNaTRgwB0TwDBPRD5ER3w2Dzbry9NhbElTr7vVfhaGWeOGuqA UXwlXEg6CrNkmJXJ2F1Rzr9WHUzhp7uWxhAbmJREGfi2dEyPAbUAyCjB qhFaqglknvc= \n\
+uri.arpa. 3600 IN DNSKEY 257 3 8 AwEAAenQaBoFmDmvRT+/H5oNbm0Tr5FmNRNDEun0Jpj/ELkzeUrTWhNp QmZeIMC8I0kZ185tEvOnRvn8OvV39B17QIdrvvKGIh2HlgeDRCLolhao jfn2QM0DStjF/WWHpxJOmE6CIuvhqYEU37yoJscGAPpPVPzNvnL1HhYT aao1VRYWQ/maMrJ+bfHg+YX1N6M/8MnRjIKBif1FWjbCKvsn6dnuGGL9 oCWYUFJ3DwofXuhgPyZMkzPc88YkJj5EMvbMH4wtelbCwC+ivx732l0w /rXJn0ciQSOgoeVvDio8dIJmWQITWQAuP+q/ZHFEFHPlrP3gvQh5mcVS 48eLX71Bq7c= \n\
+uri.arpa. 3600 IN RRSIG DNSKEY 8 2 3600 20210217232440 20210120232440 12670 uri.arpa. DBE2gkKAoxJCfz47KKxzoImN/0AKArhIVHE7TyTwy0DdRPo44V5R+vL6 thUxlQ1CJi2Rw0jwAXymx5Y3Q873pOEllH+4bJoIT4dmoBmPXfYWW7Cl vw9UPKHRP0igKHmCVwIeBYDTU3gfLcMTbR4nEWPDN0GxlL1Mf7ITaC2I oabo79Ip3M/MR8I3Vx/xZ4ZKKPHtLn3xUuJluPNanqJrED2gTslL2xWZ 1tqjsAjJv7JnJo2HJ8XVRB5zBto0IaJ2oBlqcjdcQ/0VlyoM8uOy1pDw HQ2BJl7322gNMHBP9HSiUPIOaIDNUCwW8eUcW6DIUk+s9u3GN1uTqwWz sYB/rA== \n\
+uri.arpa. 3600 IN RRSIG DNSKEY 8 2 3600 20210217232440 20210120232440 30577 uri.arpa. Kx6HwP4UlkGc1UZ7SERXtQjPajOF4iUvkwDj7MEG1xbQFB1KoJiEb/ei W0qmSWdIhMDv8myhgauejRLyJxwxz8HDRV4xOeHWnRGfWBk4XGYwkejV zOHzoIArVdUVRbr2JKigcTOoyFN+uu52cNB7hRYu7dH5y1hlc6UbOnzR pMtGxcgVyKQ+/ARbIqGG3pegdEOvV49wTPWEiyY65P2urqhvnRg5ok/j zwAdMx4XGshiib7Ojq0sRVl2ZIzj4rFgY/qsSO8SEXEhMo2VuSkoJNio fVzYoqpxEeGnANkIT7Tx2xJL1BWyJxyc7E8Wr2QSgCcc+rYL6IkHDtJG Hy7TaQ== \n\
+uri.arpa. 3600 IN ZONEMD 2018100702 1 1 0DBC3C4DBFD75777C12CA19C337854B1577799901307C482E9D91D5D 15CD934D16319D98E30C4201CF25A1D5A0254960 \n\
+uri.arpa. 3600 IN RRSIG ZONEMD 8 2 3600 20210217232440 20210120232440 37444 uri.arpa. QDo4XZcL3HMyn8aAHyCUsu/Tqj4Gkth8xY1EqByOb8XOTwVtA4ZNQORE 1siqNqjtJUbeJPtJSbLNqCL7rCq0CzNNnBscv6IIf4gnqJZjlGtHO30o hXtKvEc4z7SU3IASsi6bB3nLmEAyERdYSeU6UBfx8vatQDIRhkgEnnWU Th4= \n\
+ftp.uri.arpa. 604800 IN NAPTR 0 0 \"\" \"\" \"!^ftp://([^:/?#]*).*$!\\\\1!i\" . \n\
+ftp.uri.arpa. 604800 IN RRSIG NAPTR 8 3 604800 20210217232440 20210120232440 37444 uri.arpa. EygekDgl+Lyyq4NMSEpPyOrOywYf9Y3FAB4v1DT44J3R5QGidaH8l7ZF jHoYFI8sY64iYOCV4sBnX/dh6C1L5NgpY+8l5065Xu3vvjyzbtuJ2k6Y YwJrrCbvl5DDn53zAhhO2hL9uLgyLraZGi9i7TFGd0sm3zNyUF/EVL0C cxU= \n\
+ftp.uri.arpa. 3600 IN NSEC http.uri.arpa. NAPTR RRSIG NSEC \n\
+ftp.uri.arpa. 3600 IN RRSIG NSEC 8 3 3600 20210217232440 20210120232440 37444 uri.arpa. pbP4KxevPXCu/bDqcvXiuBppXyFEmtHyiy0eAN5gS7mi6mp9Z9bWFjx/ LdH9+6oFGYa5vGmJ5itu/4EDMe8iQeZbI8yrpM4TquB7RR/MGfBnTd8S +sjyQtlRYG7yqEu77Vd78Fme22BKPJ+MVqjS0JHMUE/YUGomPkAjLJJw wGw= \n\
+http.uri.arpa. 604800 IN NAPTR 0 0 \"\" \"\" \"!^http://([^:/?#]*).*$!\\\\1!i\" . \n\
+http.uri.arpa. 604800 IN RRSIG NAPTR 8 3 604800 20210217232440 20210120232440 37444 uri.arpa. eTqbWvt1GvTeXozuvm4ebaAfkXFQKrtdu0cEiExto80sHIiCbO0WL8UD a/J3cDivtQca7LgUbOb6c17NESsrsVkc6zNPx5RK2tG7ZQYmhYmtqtfg 1oU5BRdHZ5TyqIXcHlw9Blo2pir1Y9IQgshhD7UOGkbkEmvB1Lrd0aHh AAg= \n\
+http.uri.arpa. 3600 IN NSEC mailto.uri.arpa. NAPTR RRSIG NSEC \n\
+http.uri.arpa. 3600 IN RRSIG NSEC 8 3 3600 20210217232440 20210120232440 37444 uri.arpa. R9rlNzw1CVz2N08q6DhULzcsuUm0UKcPaGAWEU40tr81jEDHsFHNM+kh CdOI8nDstzA42aee4rwCEgijxJpRCcY9hrO1Ysrrr2fdqNz60JikMdar vU5O0p0VXeaaJDfJQT44+o+YXaBwI7Qod3FTMx7aRib8i7istvPm1Rr7 ixA= \n\
+mailto.uri.arpa. 604800 IN NAPTR 0 0 \"\" \"\" \"!^mailto:(.*)@(.*)$!\\\\2!i\" . \n\
+mailto.uri.arpa. 604800 IN RRSIG NAPTR 8 3 604800 20210217232440 20210120232440 37444 uri.arpa. Ch2zTG2F1plEvQPyIH4Yd80XXLjXOPvMbiqDjpJBcnCJsV8QF7kr0wTL nUT3dB+asQudOjPyzaHGwFlMzmrrAsszN4XAMJ6htDtFJdsgTMP/NkHh YRSmVv6rLeAhd+mVfObY12M//b/GGVTjeUI/gJaLW0fLVZxr1Fp5U5CR jyw= \n\
+mailto.uri.arpa. 3600 IN NSEC urn.uri.arpa. NAPTR RRSIG NSEC \n\
+mailto.uri.arpa. 3600 IN RRSIG NSEC 8 3 3600 20210217232440 20210120232440 37444 uri.arpa. fQUbSIE6E7JDi2rosah4SpCOTrKufeszFyj5YEavbQuYlQ5cNFvtm8Ku E2xXMRgRI4RGvM2leVqcoDw5hS3m2pOJLxH8l2WE72YjYvWhvnwc5Rof e/8yB/vaSK9WCnqN8y2q6Vmy73AGP0fuiwmuBra7LlkOiqmyx3amSFiz wms= \n\
+urn.uri.arpa. 604800 IN NAPTR 0 0 \"\" \"\" \"/urn:([^:]+)/\\\\1/i\" . \n\
+urn.uri.arpa. 604800 IN RRSIG NAPTR 8 3 604800 20210217232440 20210120232440 37444 uri.arpa. CVt2Tgz0e5ZmaSXqRfNys/8OtVCk9nfP0zhezhN8Bo6MDt6yyKZ2kEEW JPjkN7PCYHjO8fGjnUn0AHZI2qBNv7PKHcpR42VY03q927q85a65weOO 1YE0vPYMzACpua9TOtfNnynM2Ws0uN9URxUyvYkXBdqOC81N3sx1dVEL cwc= \n\
+urn.uri.arpa. 3600 IN NSEC uri.arpa. NAPTR RRSIG NSEC \n\
+urn.uri.arpa. 3600 IN RRSIG NSEC 8 3 3600 20210217232440 20210120232440 37444 uri.arpa. JuKkMiC3/j9iM3V8/izcouXWAVGnSZjkOgEgFPhutMqoylQNRcSkbEZQ zFK8B/PIVdzZF0Y5xkO6zaKQjOzz6OkSaNPIo1a7Vyyl3wDY/uLCRRAH RJfpknuY7O+AUNXvVVIEYJqZggd4kl/Rjh1GTzPYZTRrVi5eQidI1LqC Oeg=";
+
+const char *nsec3_zone = "\
+arpa. 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2021051902 1800 900 604800 86400 \n\
+arpa. 518400 IN NS a.root-servers.net. \n\
+arpa. 518400 IN NS b.root-servers.net. \n\
+arpa. 518400 IN NS c.root-servers.net. \n\
+arpa. 518400 IN NS d.root-servers.net. \n\
+arpa. 518400 IN NS e.root-servers.net. \n\
+arpa. 518400 IN NS f.root-servers.net. \n\
+arpa. 518400 IN NS g.root-servers.net. \n\
+arpa. 518400 IN NS h.root-servers.net. \n\
+arpa. 518400 IN NS i.root-servers.net. \n\
+arpa. 518400 IN NS k.root-servers.net. \n\
+arpa. 518400 IN NS l.root-servers.net. \n\
+arpa. 518400 IN NS m.root-servers.net. \n\
+arpa. 518400 IN RRSIG NS 8 1 518400 20210616170429 20210519170429 29094 arpa. gyq/RdMYEGuTElq9QCbqmZSEUAF3aeBc+MGOMVK0hgmYKfVr8DDrh9UZJy4Ht+24+FHXGgAh8OkW4UbnmiIHQnsSflbQiyHljNYZGX3/H2fUs2FFWAjjAww2iPKuuPUkHgjZZQk0683FQuI9Ium0VK7dXGAvNKFh4Ay4LMjkQ6Y= \n\
+arpa. 86400 IN RRSIG SOA 8 1 86400 20210616170429 20210519170429 29094 arpa. BnSptCxxljkkYItDfsphqUzCz4fALNhOqWrLtYx5aDRWAydcG0N7owhGTqy56VBop+lTzYKmlHfO5/bb/fRCYAXkDhsmVEqS00cDYTqpygTJbVB8Xd+ia1tBeF8cqsbngRhigF4y0cts+bkn7Wrvw21j7nhs01KROimudGH08hs= \n\
+arpa. 86400 IN RRSIG DNSKEY 8 1 86400 20210616170429 20210519170429 18949 arpa. be6sPsu3+7kzDMkAHDsUM0FSoUhULtajWemX95PIVS4wpiEpVMsvF71YLIGRTzw+GfFI2NgsL/idFbUW2Fo7bZIBhbj8JXyZwvsoxt+cLfSfZtVGllKO1XQn5u7/PGU6U8YRSyzRA+ocpdjKqyohkMmOqiqkM7mOSvchDkcZDiw= \n\
+arpa. 3600 IN RRSIG NSEC3PARAM 8 1 3600 20210616170429 20210519170429 29094 arpa. CHmmYN1DJGWraPdMPurcXadDO7ODWoz6gv0B7ln0Gwz5L4Mwb5SEtGAinO5R0T2M4OxQEkN0xhy73VERrZb5FvsxyEGJu0M5S6icvyKkJ1Zq+US5b3FX6MI/bIKu2pI5x7/ubpzWKZJ9itNWBRONBiuBsGT9c3Tb2IreuQWziH0= \n\
+arpa. 86400 IN RRSIG TYPE63 8 1 86400 20210616170429 20210519170429 29094 arpa. Aqb9IQoNaga9euw67potZbiQYeyEAqd/zVYhDFxfLNfC4Qf6v7aPxW8Tyl+foNob91/KX5JGcS5tD4pq+G+IV+heLRH57s+moF3C0lsid8oZLqCbctmR/hr0YUQc5+dGQ/iy2erEPZq1W4eLsWX+YlUsQfajb5y4ggp7OMTmRuY= \n\
+arpa. 86400 IN DNSKEY 256 3 8 AwEAAdMaRW2okM0GrfInisiH9HWsqokdnmeXnJjKUwVQ8dy5sxm0DyCtzNapj54SF4ofgJxYufQCzYoe3Y3WsB6dKW15pTvu6ggqwuTTxvAnkMSHAlMGBE0sybRBIM38WswPcjAXmpITj7Zvgm8qh80dcusK5vwqJhb2CDWHRezUwiIB ;{id = 29094 (zsk), size = 1024b} \n\
+arpa. 86400 IN DNSKEY 257 3 8 AwEAAdQP1t2ookuQYFNUNGDmLHcoA6LFSImvULaUgChKiIO6Vv5yDyHB0Ng6ZkfHM0586cLcbXNBLj/9u5A4vqzOFj8phzW4WLZREZBLYMcuHhvQdqzuDJ0J5mxmLLis5eNaCwukVm6Zpf/otzCJsx9LyrhQBTyx6FF+h7dbSCvjh7tD ;{id = 18949 (ksk), size = 1024b} \n\
+arpa. 3600 IN NSEC3PARAM 1 0 1 - \n\
+arpa. 86400 IN TYPE63 \\# 54 7876cdfe01019a84145013e13e3de2328868888c65aa46b7381213990f83d496c642d2324029cc852e09bffa38afd8e9197977776591 \n\
+0js82oec35lbbc4hl35476cm5icacksf.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. PRVkH4+Nm17QlFgwFLnoqwaiIwWZ4pvscanHdMb6HOKkSxwtDoWAGhZubvYGt/Je735nQkGQPPXW2tkMkJa3D7e6RkX/8AoxcqqXOimC6BlG6LuSL4rSousDlbrulyh87qgIHXkUtrHyYUNAMZMKOjMHo7t5IxwjBO0SGADoglk= \n\
+0js82oec35lbbc4hl35476cm5icacksf.arpa. 86400 IN NSEC3 1 0 1 - 2UB8EN7BK0T6DENIGO3I729IVQVME3VE NS \n\
+2ub8en7bk0t6denigo3i729ivqvme3ve.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. JsSiqDiPs0juQxKEcCKTFvKXzUdvIvCILEzcN79+qAxaiQuulHUxTSMDvrsxm83m9juvoOUYtBlPyZdI9erAfiEkpF71ZIl8iP7AKGgqTeV1C4SHnf2KsFi69qimdLbWeIfFGYEq+54Vj5vF1SrRounvj63avhI/Zf0tTWz11+4= \n\
+2ub8en7bk0t6denigo3i729ivqvme3ve.arpa. 86400 IN NSEC3 1 0 1 - 3MKQ4F9MV3H6JSJNUJ6G31KRJLHKN9KJ NS DS RRSIG \n\
+3mkq4f9mv3h6jsjnuj6g31krjlhkn9kj.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. NAt7ul6uWzK19LyTcxbtfIt0SppVHyVjj4S/j0zxqcOH7gkJwf36+uIsb0lP7QzdYoB7dDeMFKnZfOCjBu+OkXTnOmfdwS5XA5OTM3dpi6g8plVRkcBDoWqz+UtQljD66A2XyuVl5vBmhP3OWe8TnlnA3jrHYO5zneEM/MdsoEE= \n\
+3mkq4f9mv3h6jsjnuj6g31krjlhkn9kj.arpa. 86400 IN NSEC3 1 0 1 - BA4462JFP3IQK2KT4COIMT6532KSV55K NS DS RRSIG \n\
+as112.arpa. 172800 IN NS a.iana-servers.net. \n\
+as112.arpa. 172800 IN NS b.iana-servers.net. \n\
+as112.arpa. 172800 IN NS c.iana-servers.net. \n\
+as112.arpa. 86400 IN DS 20236 8 1 1307e5595598b25fe2eb07bcef767c9d96c3ecdc \n\
+as112.arpa. 86400 IN DS 20236 8 2 72c9e5d15accc54a32c8c76fe5944bcbf3aabc2b13dc417609763e57bd89d515 \n\
+as112.arpa. 86400 IN DS 49400 8 1 0236339d6c1fb0fdf6069a9babe455b443fe2f95 \n\
+as112.arpa. 86400 IN DS 49400 8 2 f8e230e43e20e14200e46beb6e0a67ced274790c8c8c169df7fec5fb7dfa321f \n\
+as112.arpa. 86400 IN DS 53690 8 1 85d712965f3aa6556f40e11ba29c638565444acf \n\
+as112.arpa. 86400 IN DS 53690 8 2 354c6ef7b8b46a4c87ce6a21f3a9043898e68427ad64d029097ce2a38933b82e \n\
+as112.arpa. 86400 IN RRSIG DS 8 2 86400 20210616170429 20210519170429 29094 arpa. Hs6t8f1s8NCPO1yzQIqCWWpGADwHqTVLCRVJIxMkpiWpDPP8zXxQRFp2BHNQ8jAcsp5w5OwIfIR27+5N7O73/y5qjcjDe6Yyzeh7L/nut0fuOuqne47a6VkuXJHmdilGeNFitAFZ+1iP9KnFVxb3NxNLByemx8mO30jYDw14O4Y= \n\
+ba4462jfp3iqk2kt4coimt6532ksv55k.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. MrpAQuo8eH4CAA2jjsLHGiMJ8DexXMDI7LHzQbX7k5L4oUTtBNoTnKFdxqKdxZoEXvO39GB5s0nD0qgR8g5xFAFfj+pcF2y4GC+LqXqV5N6gXKa23zEEN5mfxSuwnQ/JXw95ct2IuQkuU80MIU0ZdE/FVhSyHnlJYMGE3uB2DyY= \n\
+ba4462jfp3iqk2kt4coimt6532ksv55k.arpa. 86400 IN NSEC3 1 0 1 - C26TIAI64HA5JPB4P8KII6P9JHH3TJFH NS DS RRSIG \n\
+c26tiai64ha5jpb4p8kii6p9jhh3tjfh.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. FSQuCmqKEUtYHqhkXDC8uikAIi5ZpMtS14jeaeWEn6Mip3uP1pFNuSQHgFhX9L20hdbeuOG3ribTqs3d4kz9VQ51g4KqD3uhHMVuQZyzpBJWq4Xwynt9cetvSK0f/kaf/wtAARo9HLkciJTBYiYUmYZVdmknIto4TqDNy2kkMrA= \n\
+c26tiai64ha5jpb4p8kii6p9jhh3tjfh.arpa. 86400 IN NSEC3 1 0 1 - DKAS8UE0E261D6338P2GMF52ALH64LA6 NS DS RRSIG \n\
+dkas8ue0e261d6338p2gmf52alh64la6.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. pPD9lqm6kAoLwagCrQwBWBq4McfrHywg4RkQ20ZjuVcnmopggO6UkjlmYUnBn53Si5eqRY9CwtSEvYjKztXcyXnkwbD1xWExAsYucRYVbUPZmOllulYezphTHi1Qp7fRrhEjb/TCYcBUXvLJfU+S9OeVqefruYnIw3VevMPp518= \n\
+dkas8ue0e261d6338p2gmf52alh64la6.arpa. 86400 IN NSEC3 1 0 1 - EARMJ48JEL1C2RDHIGD36N68U3V8Q1KV NS DS RRSIG \n\
+e164.arpa. 172800 IN NS ns3.lacnic.net. \n\
+e164.arpa. 172800 IN NS ns3.afrinic.net. \n\
+e164.arpa. 172800 IN NS ns4.apnic.net. \n\
+e164.arpa. 172800 IN NS pri.authdns.ripe.net. \n\
+e164.arpa. 172800 IN NS rirns.arin.net. \n\
+e164.arpa. 86400 IN DS 46334 8 2 550664875d1121c6edd01f9602577640fed5ad19a749ae1e3fd68476af454578 \n\
+e164.arpa. 86400 IN RRSIG DS 8 2 86400 20210616170429 20210519170429 29094 arpa. A07roaG8r7ns0YydNMhaURb741akipIL8UCgRRMAs3BzzneUtXW3EmS50C7vxb5ikH84a39FerXHOetifGTKETjVMtuQmdPw1F8ClHMkWfdRyR5a+lWwosV3fgnSItoekfbggUZop1dZxzie93pv4RM89Jf/SMlOW/3bYJ1p7Hk= \n\
+earmj48jel1c2rdhigd36n68u3v8q1kv.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. yNYXtZ4dGDdJW3VNoLRtktV93mZmQsQv3Tvy6+iBTGx+W7T0ipSCZq+l5yvblfqGKXXnWWzYf/xKktaLmXnAzvdsacWaKGtudvvtSwLkhlxNWlL018Eoe2md0tsSLd5tSiTbufahrd4p1lv09ne//sGoSw/amfvY5hsRvmnhNhA= \n\
+earmj48jel1c2rdhigd36n68u3v8q1kv.arpa. 86400 IN NSEC3 1 0 1 - H2D0RTQ108UOOUB5UDNN9D2PGQBVABC9 NS DS RRSIG \n\
+h2d0rtq108uooub5udnn9d2pgqbvabc9.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. isNpvWJ3TpDmEl66a9J9Q2GdlNqh9HculGjNFVIbiSfTb5aNgCITkgrKSoxjfZ8go3pDSeqwo5fhaBlbZQ4xGNGlc/T5U2qh2hJPGZpBwHYkR9a1YzMhzMx33oRXfMzsuC+6sasS8BLRHPmS4X89jPeA+lItEJPd1rQlHb1wt1I= \n\
+h2d0rtq108uooub5udnn9d2pgqbvabc9.arpa. 86400 IN NSEC3 1 0 1 - KSH70CK6POGI86ENT4ONT3I9UJ71QE8K NS SOA RRSIG DNSKEY NSEC3PARAM TYPE63 \n\
+home.arpa. 172800 IN NS blackhole-1.iana.org. \n\
+home.arpa. 172800 IN NS blackhole-2.iana.org. \n\
+in-addr.arpa. 172800 IN NS a.in-addr-servers.arpa. \n\
+in-addr.arpa. 172800 IN NS b.in-addr-servers.arpa. \n\
+in-addr.arpa. 172800 IN NS c.in-addr-servers.arpa. \n\
+in-addr.arpa. 172800 IN NS d.in-addr-servers.arpa. \n\
+in-addr.arpa. 172800 IN NS e.in-addr-servers.arpa. \n\
+in-addr.arpa. 172800 IN NS f.in-addr-servers.arpa. \n\
+in-addr.arpa. 86400 IN DS 47054 8 2 5cafccec201d1933b4c9f6a9c8f51e51f3b39979058ac21b8df1b1f281cbc6f2 \n\
+in-addr.arpa. 86400 IN DS 53696 8 2 13e5501c56b20394da921b51412d48b7089c5eb6957a7c58553c4d4d424f04df \n\
+in-addr.arpa. 86400 IN DS 63982 8 2 aaf4fb5d213ef25ae44679032ebe3514c487d7abd99d7f5fec3383d030733c73 \n\
+in-addr.arpa. 86400 IN RRSIG DS 8 2 86400 20210616170429 20210519170429 29094 arpa. lr32Q5rTcwVyBASuYq2Mc1t8XPCSSXJDNtK+MzisWifCZ0b0m/GARo34QKR2y3afqeFdqVXWrYrBVjAF2Rg21izsWqpMNyfLloesNNl63A9uQi4dFT3Zfz3OdQOGhWcy51ydn8KVtieIubRTBQAgExgZsDzyRC4PXjzh4Jj872g= \n\
+in-addr-servers.arpa. 172800 IN NS a.in-addr-servers.arpa. \n\
+in-addr-servers.arpa. 172800 IN NS b.in-addr-servers.arpa. \n\
+in-addr-servers.arpa. 172800 IN NS c.in-addr-servers.arpa. \n\
+in-addr-servers.arpa. 172800 IN NS d.in-addr-servers.arpa. \n\
+in-addr-servers.arpa. 172800 IN NS e.in-addr-servers.arpa. \n\
+in-addr-servers.arpa. 172800 IN NS f.in-addr-servers.arpa. \n\
+in-addr-servers.arpa. 86400 IN DS 1987 8 2 dacfdeb02a489a514c6408d0d54e0904fe6e09a6e111abc9eacb27f6552805e1 \n\
+in-addr-servers.arpa. 86400 IN DS 45104 8 2 50136f7a8d3ffe4f9887ad234ff8ce945cabd331feb12569b2f61f99ce40fdbf \n\
+in-addr-servers.arpa. 86400 IN DS 62996 8 2 836537710efc1e5570e3aeff7c0c80d3957a16ddf8005034bc9082898968dc81 \n\
+in-addr-servers.arpa. 86400 IN RRSIG DS 8 2 86400 20210616170429 20210519170429 29094 arpa. j+2AVMMc1xfd/ua7lHpNQUr95kUTcr8SIQJk6prTkYnPdDvMNZPIhhdVNw7WzFjIvGLF3iumbYY46I3KN3P1eZUKtn0OFvTZ/UG/tlbWaj473XNxWnbwp8sPuT46nuLH6P14gNEhbPGGrh2VE+hFPkM/4ZdfwlCbDC5vEsQNYko= \n\
+a.in-addr-servers.arpa. 172800 IN A 199.180.182.53 \n\
+a.in-addr-servers.arpa. 172800 IN AAAA 2620:37:e000::53 \n\
+b.in-addr-servers.arpa. 172800 IN A 199.253.183.183 \n\
+b.in-addr-servers.arpa. 172800 IN AAAA 2001:500:87::87 \n\
+c.in-addr-servers.arpa. 172800 IN A 196.216.169.10 \n\
+c.in-addr-servers.arpa. 172800 IN AAAA 2001:43f8:110::10 \n\
+d.in-addr-servers.arpa. 172800 IN A 200.10.60.53 \n\
+d.in-addr-servers.arpa. 172800 IN AAAA 2001:13c7:7010::53 \n\
+e.in-addr-servers.arpa. 172800 IN A 203.119.86.101 \n\
+e.in-addr-servers.arpa. 172800 IN AAAA 2001:dd8:6::101 \n\
+f.in-addr-servers.arpa. 172800 IN A 193.0.9.1 \n\
+f.in-addr-servers.arpa. 172800 IN AAAA 2001:67c:e0::1 \n\
+ip6.arpa. 172800 IN NS a.ip6-servers.arpa. \n\
+ip6.arpa. 172800 IN NS b.ip6-servers.arpa. \n\
+ip6.arpa. 172800 IN NS c.ip6-servers.arpa. \n\
+ip6.arpa. 172800 IN NS d.ip6-servers.arpa. \n\
+ip6.arpa. 172800 IN NS e.ip6-servers.arpa. \n\
+ip6.arpa. 172800 IN NS f.ip6-servers.arpa. \n\
+ip6.arpa. 86400 IN DS 13880 8 2 068554efcb5861f42af93ef8e79c442a86c16fc5652e6b6d2419ed527f344d17 \n\
+ip6.arpa. 86400 IN DS 45094 8 2 e6b54e0a20ce1edbfcb6879c02f5782059cecb043a31d804a04afa51af01d5fb \n\
+ip6.arpa. 86400 IN DS 64060 8 2 8a11501086330132be2c23f22dedf0634ad5ff668b4aa1988e172c6a2a4e5f7b \n\
+ip6.arpa. 86400 IN RRSIG DS 8 2 86400 20210616170429 20210519170429 29094 arpa. aNklM0l2ixPusry6KMt0PYGuKgLXqAJArq3KSZgG0QgMjGC0ChVwAO2+vq4wwR8QuqA6vAWHKKpw79l8MYV9I7+a50WPFyEOugl1s+konVjzkgMboPaOZbg52g47mPdQ7Q0N9MPLA8/FJx13cHauimQjZ+1FOiiWhveqgR2Jg8o= \n\
+ip6-servers.arpa. 172800 IN NS a.ip6-servers.arpa. \n\
+ip6-servers.arpa. 172800 IN NS b.ip6-servers.arpa. \n\
+ip6-servers.arpa. 172800 IN NS c.ip6-servers.arpa. \n\
+ip6-servers.arpa. 172800 IN NS d.ip6-servers.arpa. \n\
+ip6-servers.arpa. 172800 IN NS e.ip6-servers.arpa. \n\
+ip6-servers.arpa. 172800 IN NS f.ip6-servers.arpa. \n\
+ip6-servers.arpa. 86400 IN DS 16169 8 2 27fb5354c3c011c2851ee25ba32929b645d63262779ac101a6f28cd631991269 \n\
+ip6-servers.arpa. 86400 IN DS 19720 8 2 f154d00f5759c274de9cad621910cc0b87d720d35b7de4b0b566e135196c38e2 \n\
+ip6-servers.arpa. 86400 IN DS 54832 8 2 ff0d5f44a086a7a31b99c81cfd1135524b5896878e6de78f12b3f609bf7279dc \n\
+ip6-servers.arpa. 86400 IN RRSIG DS 8 2 86400 20210616170429 20210519170429 29094 arpa. fYShlxJWViKV2SbFCqyxUa64AKAedJ2udqcw/VtKNxg2T6i5IQzFc2aPB7V/+MtE64vHWwbrThgOvNC4Xmc7jVqKNsSc1X4Q8ZSQy+/CgmS5pBkI4XpLBb6kTUJMGorgAOI1ek1OMpl25mGmeJ6lE8e5PTNUisz/7ybIx5pBTz0= \n\
+a.ip6-servers.arpa. 172800 IN A 199.180.182.53 \n\
+a.ip6-servers.arpa. 172800 IN AAAA 2620:37:e000::53 \n\
+b.ip6-servers.arpa. 172800 IN A 199.253.182.182 \n\
+b.ip6-servers.arpa. 172800 IN AAAA 2001:500:86::86 \n\
+c.ip6-servers.arpa. 172800 IN A 196.216.169.11 \n\
+c.ip6-servers.arpa. 172800 IN AAAA 2001:43f8:110::11 \n\
+d.ip6-servers.arpa. 172800 IN A 200.7.86.53 \n\
+d.ip6-servers.arpa. 172800 IN AAAA 2001:13c7:7012::53 \n\
+e.ip6-servers.arpa. 172800 IN A 203.119.86.101 \n\
+e.ip6-servers.arpa. 172800 IN AAAA 2001:dd8:6::101 \n\
+f.ip6-servers.arpa. 172800 IN A 193.0.9.2 \n\
+f.ip6-servers.arpa. 172800 IN AAAA 2001:67c:e0::2 \n\
+ipv4only.arpa. 172800 IN NS a.iana-servers.net. \n\
+ipv4only.arpa. 172800 IN NS b.iana-servers.net. \n\
+ipv4only.arpa. 172800 IN NS c.iana-servers.net. \n\
+ipv4only.arpa. 172800 IN NS ns.icann.org. \n\
+iris.arpa. 172800 IN NS a.iana-servers.net. \n\
+iris.arpa. 172800 IN NS b.iana-servers.net. \n\
+iris.arpa. 172800 IN NS c.iana-servers.net. \n\
+iris.arpa. 172800 IN NS ns3.lacnic.net. \n\
+iris.arpa. 172800 IN NS ns4.apnic.net. \n\
+iris.arpa. 86400 IN DS 38534 8 2 163416c9dcaf8d1babfec16552ed109029607907ab80b195e1dab40f1792a59c \n\
+iris.arpa. 86400 IN DS 39464 8 2 1e09a2d6374800d54cfd0e52293906ccf7db7e923dcab7015e4bb697d76d9846 \n\
+iris.arpa. 86400 IN DS 44285 8 2 05cbf77375a8bf5702cf8e261ff947be8c8ab7a0b9485a0241edcfe2f155c7f3 \n\
+iris.arpa. 86400 IN RRSIG DS 8 2 86400 20210616170429 20210519170429 29094 arpa. oikOvs9AfaPv1Po/E76SZ7VBoYjqHqzZEzrA0N4gWXlemmsUKyXh9fiXqtusFIZD7QUBJMvOYkIpWnAOliWnk/oj4lmmwnYMqqLWDMWVoXiUAUtmwQHm89cAjyWc9nRuDVBweKtqH5GQKtEWxu4nkKPIbuUVNHBgxtKZP7Jbzic= \n\
+ksh70ck6pogi86ent4ont3i9uj71qe8k.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. YPnC0imYz+x2dNwUQwvp2CB1Ini1dEcn9Vur9T4KwzAMqVr+PPkheMRiIQcAbmkSLG1D1p/qVzaFEC7ixlaxuEFlvGwM+c5OvukbWek1QtdCDJpgtse3HBajoRTgBDGRwvj+DFej9ppygZpe+vlgSDmiC2fgPMhcG4Z6jMmVAec= \n\
+ksh70ck6pogi86ent4ont3i9uj71qe8k.arpa. 86400 IN NSEC3 1 0 1 - MKQDDR5C3MPRP6DRU5TO19BB27TDVCVT NS DS RRSIG \n\
+mkqddr5c3mprp6dru5to19bb27tdvcvt.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. sUTu2ijBQlhCmn/fNl8O+UofW4ERQ0tgmK0LY8ggHCnvY26k4RCrGieZ6YXl8lCereSyx1DEPuScBA7YRCUEw/FtrW8rCKMo+wQhb4Uon2UUZRl/mrjNNsYxtYwjIN7u/BzfDhBHq2/8vVCybAS8GhqqJhOYpEcDgsITuDKVFOE= \n\
+mkqddr5c3mprp6dru5to19bb27tdvcvt.arpa. 86400 IN NSEC3 1 0 1 - SRGGVLP1DI07IJT2IA31AGJRPFCNC616 NS DS RRSIG \n\
+srggvlp1di07ijt2ia31agjrpfcnc616.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. ep49bJfQ1c1dNMIlFO+EgeG4iW7pHyJvKbK6MJBBj/LJwVfhzwTa8ellqgHp3AH63j8tNPutowc1shlQwE7G/f3KfiVBUwPtAZHtqNYBFdNm0WdxoqRueJmyVR0h+vUfY+r1F4IYzwfjn+ldfj5lhKqQ+gX2HFR3M/FI6H97nHQ= \n\
+srggvlp1di07ijt2ia31agjrpfcnc616.arpa. 86400 IN NSEC3 1 0 1 - SSTSS4TF3ICJ43RCMUQTSJORRDDSRSRL NS \n\
+sstss4tf3icj43rcmuqtsjorrddsrsrl.arpa. 86400 IN RRSIG NSEC3 8 2 86400 20210616170429 20210519170429 29094 arpa. 0GVjQFd8YAYSXMh526fZ5Rx4WDHIf84MTzIsAYuLwM00H6uagrFxQv8mrGExWPummQ+Q+nHDuCBC5lEXjTF4/1qAu7MI627/mKtpcQevTvF3iE2ocf1/vfAFWVCzyLQ3AuFbGGuYQ6nlZzbOu2oRtma6/m4WpDhNszOhuONNlbY= \n\
+sstss4tf3icj43rcmuqtsjorrddsrsrl.arpa. 86400 IN NSEC3 1 0 1 - 0JS82OEC35LBBC4HL35476CM5ICACKSF NS DS RRSIG \n\
+uri.arpa. 172800 IN NS a.iana-servers.net. \n\
+uri.arpa. 172800 IN NS b.iana-servers.net. \n\
+uri.arpa. 172800 IN NS c.iana-servers.net. \n\
+uri.arpa. 172800 IN NS ns3.lacnic.net. \n\
+uri.arpa. 172800 IN NS ns4.apnic.net. \n\
+uri.arpa. 86400 IN DS 15796 8 2 7f8fa18fdd9a826eb08a4d4e9ce94dbba7a5b7b2b3ce1d74afd150242e9f572f \n\
+uri.arpa. 86400 IN DS 28547 8 2 deaefd0c163175350152da7b127dc7c4f9ec8bdf04ccc02829455df86c5ca035 \n\
+uri.arpa. 86400 IN DS 57851 8 2 8feda13f642ed9be2e4aaa3d50099dd422ca6081b6bf8188f804343b58d39cb7 \n\
+uri.arpa. 86400 IN RRSIG DS 8 2 86400 20210616170429 20210519170429 29094 arpa. jwQhmqBE2EWCE2yi14CqgjMfYWq4/W//IuL/EHSRZPJjyP7R7cnUgh/7rDO4JUcYebviO4s9hidjfpnLQWxpR2Jy2SH6aeNERLo76O28UW2Y28eused7aWMDWAnWW4HxURsQSBy2cyQbNwPCLGVLeQZaeZbKRBJUbWJ4MT4UpDE= \n\
+urn.arpa. 172800 IN NS a.iana-servers.net. \n\
+urn.arpa. 172800 IN NS b.iana-servers.net. \n\
+urn.arpa. 172800 IN NS c.iana-servers.net. \n\
+urn.arpa. 172800 IN NS ns3.lacnic.net. \n\
+urn.arpa. 172800 IN NS ns4.apnic.net. \n\
+urn.arpa. 86400 IN DS 28996 8 2 8e66d01a1e5864bcdb8e1f85579aec7c8c536c9d6fc7032ee708e869fd27f3d3 \n\
+urn.arpa. 86400 IN DS 34555 8 2 bd743967def1caf0812fe9eff2371d3adf29e27251db272145a5d523c92f7101 \n\
+urn.arpa. 86400 IN DS 45052 8 2 7685b675f93ada412cfe534820c8dcc55654b1711f677ba83a8564c12943f695 \n\
+urn.arpa. 86400 IN RRSIG DS 8 2 86400 20210616170429 20210519170429 29094 arpa. BHHa1YLYUOABgiloeQQRIMXRKxXNIwRken6E6ETFAWw3Js1ocu6H/X3bcPvBTjID/B+GRGgIyCnDnZ9iWeU41Tw1GnMNT9EM35DmnUgfzUU79shVzRtiYDV6JHF9Kidc90IxNrQOGAcUy0J9jhMa4KYEjfQab8sJSo0M+uJkNMw=";
+
+const char *no_zonemd = "\
+example. 86400 IN SOA ns1 admin 2018031900 ( \n\
+ 1800 900 604800 86400 ) \n\
+ 86400 IN NS ns1 \n\
+ 86400 IN NS ns2 \n\
+ns1 3600 IN A 203.0.113.63 \n\
+ns2 3600 IN AAAA 2001:db8::63";
+
+const char *wrong_soa = "\
+example. 86400 IN SOA ns1 admin 2018031900 ( \n\
+ 1800 900 604800 86400 ) \n\
+ 86400 IN NS ns1 \n\
+ 86400 IN NS ns2 \n\
+ 86400 IN ZONEMD 2018031901 1 1 ( \n\
+ c68090d90a7aed71 \n\
+ 6bc459f9340e3d7c \n\
+ 1370d4d24b7e2fc3 \n\
+ a1ddc0b9a87153b9 \n\
+ a9713b3c9ae5cc27 \n\
+ 777f98b8e730044c ) \n\
+ns1 3600 IN A 203.0.113.63 \n\
+ns2 3600 IN AAAA 2001:db8::63";
+
+const char *duplicate_schemalg = "\
+example. 86400 IN SOA ns1 admin 2018031900 ( \n\
+ 1800 900 604800 86400 ) \n\
+ 86400 IN NS ns1 \n\
+ 86400 IN NS ns2 \n\
+ 86400 IN ZONEMD 2018031900 1 1 ( \n\
+ c68090d90a7aed71 \n\
+ 6bc459f9340e3d7c \n\
+ 1370d4d24b7e2fc3 \n\
+ a1ddc0b9a87153b9 \n\
+ a9713b3c9ae5cc27 \n\
+ 777f98b8e730044c ) \n\
+ 86400 IN ZONEMD 2018031901 1 1 ( \n\
+ c68090d90a7aed71 \n\
+ 6bc459f9340e3d7c \n\
+ 1370d4d24b7e2fc3 \n\
+ a1ddc0b9a87153b9 \n\
+ a9713b3c9ae5cc27 \n\
+ 777f98b8e730044c ) \n\
+ns1 3600 IN A 203.0.113.63 \n\
+ns2 3600 IN AAAA 2001:db8::63";
+
+const char *wrong_hash = "\
+example. 86400 IN SOA ns1 admin 2018031900 ( \n\
+ 1800 900 604800 86400 ) \n\
+ 86400 IN NS ns1 \n\
+ 86400 IN NS ns2 \n\
+ 86400 IN ZONEMD 2018031900 1 1 ( \n\
+ c68090d90a7aed71 \n\
+ 6bc459f9340e3d7c \n\
+ 1370d4d24b7e2fc3 \n\
+ a1ddc0b9a87153b9 \n\
+ a9713b3c9ae5cc27 \n\
+ 777f98b8e730044d ) \n\
+ns1 3600 IN A 203.0.113.63 \n\
+ns2 3600 IN AAAA 2001:db8::63";
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ int ret = check_contents(simple_zone);
+ is_int(KNOT_EOK, ret, "simple zone");
+
+ ret = check_contents(complex_zone);
+ is_int(KNOT_EOK, ret, "complex zone");
+
+ ret = check_contents(multiple_digests);
+ is_int(KNOT_EOK, ret, "multiple digests");
+
+ ret = check_contents(signed_zone);
+ is_int(KNOT_EOK, ret, "signed zone");
+
+ ret = check_contents(nsec3_zone);
+ is_int(KNOT_EOK, ret, "nsec3 zone");
+
+ ret = check_contents(no_zonemd);
+ is_int(KNOT_ENOENT, ret, "no zonemd");
+
+ ret = check_contents(wrong_soa);
+ is_int(KNOT_ENOTSUP, ret, "wrong SOA serial");
+ // TODO tests for different scheme / algorithm ?
+
+ ret = check_contents(duplicate_schemalg);
+ is_int(KNOT_ESEMCHECK, ret, "duplicate scheme+algorithm pair");
+
+ ret = check_contents(wrong_hash);
+ is_int(KNOT_EMALF, ret, "wrong hash");
+
+ return 0;
+}
diff --git a/tests/knot/test_dthreads.c b/tests/knot/test_dthreads.c
new file mode 100644
index 0000000..3bdfa3a
--- /dev/null
+++ b/tests/knot/test_dthreads.c
@@ -0,0 +1,148 @@
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <tap/basic.h>
+
+#include "knot/server/dthreads.h"
+
+/* Unit runnable data. */
+static pthread_mutex_t _runnable_mx;
+static volatile int _runnable_i = 0;
+static const int _runnable_cycles = 10000;
+
+/*! \brief Unit runnable. */
+int runnable(struct dthread *thread)
+{
+ for (int i = 0; i < _runnable_cycles; ++i) {
+
+ // Increase counter
+ pthread_mutex_lock(&_runnable_mx);
+ ++_runnable_i;
+ pthread_mutex_unlock(&_runnable_mx);
+
+ // Cancellation point
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ // Yield
+ sched_yield();
+ }
+
+ return 0;
+}
+
+/* Destructor data. */
+static volatile int _destructor_data = 0;
+static pthread_mutex_t _destructor_mx;
+
+/*! \brief Thread destructor. */
+int destruct(struct dthread *thread)
+{
+ pthread_mutex_lock(&_destructor_mx);
+ _destructor_data += 1;
+ pthread_mutex_unlock(&_destructor_mx);
+
+ return 0;
+}
+
+// Signal handler
+static void interrupt_handle(int s)
+{
+}
+
+/*! API: run tests. */
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ int cpus = dt_online_cpus();
+ ok(cpus > 0, "dthread: online cpus is positive value");
+
+ // Register service and signal handler
+ struct sigaction sa;
+ sa.sa_handler = interrupt_handle;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, NULL); // Interrupt
+
+ /* Initialize */
+ srand(time(NULL));
+ pthread_mutex_init(&_runnable_mx, NULL);
+ pthread_mutex_init(&_destructor_mx, NULL);
+
+ /* Test 1: Create unit */
+ int size = 2;
+ dt_unit_t *unit = dt_create(size, &runnable, NULL, NULL);
+ ok(unit != NULL, "dthreads: create unit (size %d)", size);
+ if (unit == NULL) {
+ skip_block(7, "No dthreads unit");
+ goto skip_all;
+ }
+
+ /* Test 2: Start tasks. */
+ _runnable_i = 0;
+ ok(dt_start(unit) == 0, "dthreads: start single task");
+
+ /* Test 3: Wait for tasks. */
+ ok(dt_join(unit) == 0, "dthreads: join threads");
+
+ /* Test 4: Compare counter. */
+ int expected = _runnable_cycles * 2;
+ is_int(expected, _runnable_i, "dthreads: result ok");
+
+ /* Test 5: Deinitialize */
+ dt_delete(&unit);
+ ok(unit == NULL, "dthreads: delete unit");
+
+ /* Test 6: Wrong values. */
+ unit = dt_create(-1, NULL, NULL, NULL);
+ ok(unit == NULL, "dthreads: create with negative count");
+
+ /* Test 7: NULL operations crashing. */
+ int ret = 0;
+ ret += dt_activate(0);
+ ret += dt_cancel(0);
+ ret += dt_compact(0);
+ dt_delete(0);
+ ret += dt_is_cancelled(0);
+ ret += dt_join(0);
+ ret += dt_signalize(0, SIGALRM);
+ ret += dt_start(0);
+ ret += dt_stop(0);
+ ret += dt_unit_lock(0);
+ ret += dt_unit_unlock(0);
+ is_int(-198, ret, "dthreads: correct values when passed NULL context");
+
+ /* Test 8: Thread destructor. */
+ _destructor_data = 0;
+ unit = dt_create(2, 0, destruct, 0);
+ dt_start(unit);
+ dt_stop(unit);
+ dt_join(unit);
+ is_int(2, _destructor_data, "dthreads: destructor with dt_create_coherent()");
+ dt_delete(&unit);
+
+skip_all:
+
+ pthread_mutex_destroy(&_runnable_mx);
+ pthread_mutex_destroy(&_destructor_mx);
+ return 0;
+}
diff --git a/tests/knot/test_fdset.c b/tests/knot/test_fdset.c
new file mode 100644
index 0000000..d0282f0
--- /dev/null
+++ b/tests/knot/test_fdset.c
@@ -0,0 +1,150 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+#include <tap/basic.h>
+#include <unistd.h>
+
+#include "knot/common/fdset.h"
+#include "libknot/attribute.h"
+#include "contrib/time.h"
+
+#define PATTERN1 "0x45"
+#define PATTERN2 "0xED"
+
+#define TIMEOUT0 2000
+#define TIMEOUT1 10
+#define TIMEOUT2 400
+#define JITTER (TIMEOUT2 - TIMEOUT1 - 10)
+
+void *thr_action1(void *arg)
+{
+ usleep(1000 * TIMEOUT1);
+ _unused_ int ret = write(*((int *)arg), &PATTERN1, 1);
+ return NULL;
+}
+
+void *thr_action2(void *arg)
+{
+ usleep(1000 * TIMEOUT2);
+ _unused_ int ret = write(*((int *)arg), &PATTERN2, 1);
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ fdset_t fdset;
+ int ret = fdset_init(&fdset, 32);
+ ok(ret == KNOT_EOK, "fdset_init");
+
+ int fds0[2], fds1[2], fds2[2];
+
+ ret = pipe(fds0);
+ ok(ret >= 0, "create pipe 0");
+ ret = fdset_add(&fdset, fds0[0], FDSET_POLLIN, NULL);
+ ok(ret >= 0, "add pipe 0 to fdset");
+
+ ret = pipe(fds1);
+ ok(ret >= 0, "create pipe 1");
+ ret = fdset_add(&fdset, fds1[0], FDSET_POLLIN, NULL);
+ ok(ret >= 0, "add pipe 1 to fdset");
+
+ ret = pipe(fds2);
+ ok(ret >= 0, "create pipe 2");
+ ret = fdset_add(&fdset, fds2[0], FDSET_POLLIN, NULL);
+ ok(ret >= 0, "add pipe 2 to fdset");
+
+ ok(fdset_get_length(&fdset) == 3, "fdset size full");
+
+ struct timespec time0 = time_now();
+
+ pthread_t t1, t2;
+ ret = pthread_create(&t1, 0, thr_action1, &fds1[1]);
+ ok(ret == 0, "create thread 1");
+ ret = pthread_create(&t2, 0, thr_action2, &fds2[1]);
+ ok(ret == 0, "create thread 2");
+
+ fdset_it_t it;
+ ret = fdset_poll(&fdset, &it, 0, TIMEOUT0);
+ struct timespec time1 = time_now();
+ double diff1 = time_diff_ms(&time0, &time1);
+ ok(ret == 1, "fdset_poll return 1");
+ ok(diff1 >= TIMEOUT1 && diff1 < TIMEOUT1 + JITTER, "fdset_poll timeout 1 (%f)", diff1);
+ for(; !fdset_it_is_done(&it); fdset_it_next(&it)) {
+ ok(!fdset_it_is_error(&it), "fdset no error");
+ ok(fdset_it_is_pollin(&it), "fdset can read");
+
+ int fd = fdset_it_get_fd(&it);
+ ok(fd == fds1[0], "fdset_it fd check");
+
+ char buf = 0x00;
+ ret = read(fd, &buf, sizeof(buf));
+ ok(ret == 1 && buf == PATTERN1[0], "fdset_it value check");
+
+ fdset_it_remove(&it);
+ }
+ fdset_it_commit(&it);
+ ok(fdset_get_length(&fdset) == 2, "fdset size 2");
+ close(fds1[1]);
+
+ int fd2_dup = dup(fds2[0]);
+ ok(fd2_dup >= 0, "duplicate fd");
+
+ ret = fdset_poll(&fdset, &it, 0, TIMEOUT0);
+ struct timespec time2 = time_now();
+ double diff2 = time_diff_ms(&time0, &time2);
+ ok(ret == 1, "fdset_poll return 2");
+ ok(diff2 >= TIMEOUT2 && diff2 < TIMEOUT2 + JITTER, "fdset_poll timeout 2 (%f)", diff2);
+ for(; !fdset_it_is_done(&it); fdset_it_next(&it)) {
+ ok(!fdset_it_is_error(&it), "fdset no error");
+ ok(fdset_it_is_pollin(&it), "fdset can read");
+
+ int fd = fdset_it_get_fd(&it);
+ ok(fd == fds2[0], "fdset_it fd check");
+
+ char buf = 0x00;
+ ret = read(fd, &buf, sizeof(buf));
+ ok(ret == 1 && buf == PATTERN2[0], "fdset_it value check");
+
+ fdset_it_remove(&it);
+ }
+ fdset_it_commit(&it);
+ ok(fdset_get_length(&fdset) == 1, "fdset size 1");
+
+ pthread_join(t1, 0);
+ pthread_join(t2, 0);
+
+ ret = fdset_remove(&fdset, 0);
+ ok(ret == KNOT_EOK, "fdset remove");
+ close(fds0[1]);
+ ok(fdset_get_length(&fdset) == 0, "fdset size 0");
+
+ ret = write(fds2[1], &PATTERN2, 1);
+ ok(ret == 1, "write to removed fd");
+ ret = fdset_poll(&fdset, &it, 0, 100);
+ ok(ret == 0, "fdset_poll return 3");
+
+
+ close(fds2[1]);
+ if (fd2_dup >= 0) {
+ close(fd2_dup);
+ }
+ fdset_clear(&fdset);
+
+ return 0;
+}
diff --git a/tests/knot/test_journal.c b/tests/knot/test_journal.c
new file mode 100644
index 0000000..748ab02
--- /dev/null
+++ b/tests/knot/test_journal.c
@@ -0,0 +1,880 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <tap/basic.h>
+#include <tap/files.h>
+
+#include "knot/journal/journal_read.h"
+#include "knot/journal/journal_write.h"
+
+#include "libknot/attribute.h"
+#include "libknot/libknot.h"
+#include "knot/zone/zone.h"
+#include "knot/zone/zone-diff.h"
+#include "test_conf.h"
+
+#define RAND_RR_LABEL 16
+#define RAND_RR_PAYLOAD 64
+#define MIN_SOA_SIZE 22
+
+char *test_dir_name;
+
+knot_lmdb_db_t jdb;
+zone_journal_t jj;
+
+unsigned env_flag;
+
+static unsigned lmdb_page_size(knot_lmdb_db_t *db)
+{
+ knot_lmdb_txn_t txn = { 0 };
+ knot_lmdb_begin(db, &txn, false);
+ MDB_stat st = { 0 };
+ mdb_stat(txn.txn, txn.db->dbi, &st);
+ knot_lmdb_abort(&txn);
+ return st.ms_psize;
+}
+
+static void set_conf(int zonefile_sync, size_t journal_usage, const knot_dname_t *apex)
+{
+ (void)apex;
+ char conf_str[512];
+ snprintf(conf_str, sizeof(conf_str),
+ "template:\n"
+ " - id: default\n"
+ " zonefile-sync: %d\n"
+ " journal-max-usage: %zu\n"
+ " journal-max-depth: 1000\n",
+ zonefile_sync, journal_usage);
+ _unused_ int ret = test_conf(conf_str, NULL);
+ assert(ret == KNOT_EOK);
+ jj.conf = conf();
+}
+
+static void unset_conf(void)
+{
+ conf_update(NULL, CONF_UPD_FNONE);
+}
+
+/*! \brief Generate random string with given length. */
+static int randstr(char* dst, size_t len)
+{
+ for (int i = 0; i < len - 1; ++i) {
+ dst[i] = '0' + (int) (('Z'-'0') * (rand() / (RAND_MAX + 1.0)));
+ }
+ dst[len - 1] = '\0';
+
+ return 0;
+}
+
+/*! \brief Init RRSet with type SOA and given serial. */
+static void init_soa(knot_rrset_t *rr, const uint32_t serial, const knot_dname_t *apex)
+{
+ knot_rrset_init(rr, knot_dname_copy(apex, NULL), KNOT_RRTYPE_SOA, KNOT_CLASS_IN, 3600);
+
+ uint8_t soa_data[MIN_SOA_SIZE] = { 0 };
+ _unused_ int ret = knot_rrset_add_rdata(rr, soa_data, sizeof(soa_data), NULL);
+ knot_soa_serial_set(rr->rrs.rdata, serial);
+ assert(ret == KNOT_EOK);
+}
+
+/*! \brief Init RRSet with type TXT, random owner and random payload. */
+static void init_random_rr(knot_rrset_t *rr , const knot_dname_t *apex)
+{
+ /* Create random label. */
+ char owner[RAND_RR_LABEL + knot_dname_size(apex)];
+ owner[0] = RAND_RR_LABEL - 1;
+ randstr(owner + 1, RAND_RR_LABEL);
+
+ /* Append zone apex. */
+ memcpy(owner + RAND_RR_LABEL, apex, knot_dname_size(apex));
+ knot_rrset_init(rr, knot_dname_copy((knot_dname_t *)owner, NULL),
+ KNOT_RRTYPE_TXT, KNOT_CLASS_IN, 3600);
+
+ /* Create random RDATA. */
+ uint8_t txt[RAND_RR_PAYLOAD + 1];
+ txt[0] = RAND_RR_PAYLOAD - 1;
+ randstr((char *)(txt + 1), RAND_RR_PAYLOAD);
+
+ _unused_ int ret = knot_rrset_add_rdata(rr, txt, RAND_RR_PAYLOAD, NULL);
+ assert(ret == KNOT_EOK);
+}
+
+/*! \brief Init changeset with random changes. */
+static void init_random_changeset(changeset_t *ch, const uint32_t from, const uint32_t to,
+ const size_t size, const knot_dname_t *apex, bool is_bootstrap)
+{
+ // Add SOAs
+ knot_rrset_t soa;
+
+ if (is_bootstrap) {
+ ch->soa_from = NULL;
+ zone_contents_deep_free(ch->remove);
+ ch->remove = NULL;
+ } else {
+ init_soa(&soa, from, apex);
+ ch->soa_from = knot_rrset_copy(&soa, NULL);
+ assert(ch->soa_from);
+ knot_rrset_clear(&soa, NULL);
+ }
+
+ init_soa(&soa, to, apex);
+ ch->soa_to = knot_rrset_copy(&soa, NULL);
+ assert(ch->soa_to);
+ knot_rrset_clear(&soa, NULL);
+
+ // Add RRs to add section
+ for (size_t i = 0; i < size / 2; ++i) {
+ knot_rrset_t rr;
+ init_random_rr(&rr, apex);
+ _unused_ int ret = changeset_add_addition(ch, &rr, 0);
+ assert(ret == KNOT_EOK);
+ knot_rrset_clear(&rr, NULL);
+ }
+
+ // Add RRs to remove section
+ for (size_t i = 0; i < size / 2 && !is_bootstrap; ++i) {
+ knot_rrset_t rr;
+ init_random_rr(&rr, apex);
+ _unused_ int ret = changeset_add_removal(ch, &rr, 0);
+ assert(ret == KNOT_EOK);
+ knot_rrset_clear(&rr, NULL);
+ }
+}
+
+static void changeset_set_soa_serials(changeset_t *ch, uint32_t from, uint32_t to,
+ const knot_dname_t *apex)
+{
+ knot_rrset_t soa;
+
+ init_soa(&soa, from, apex);
+ knot_rrset_free(ch->soa_from, NULL);
+ ch->soa_from = knot_rrset_copy(&soa, NULL);
+ assert(ch->soa_from);
+ knot_rrset_clear(&soa, NULL);
+
+ init_soa(&soa, to, apex);
+ knot_rrset_free(ch->soa_to, NULL);
+ ch->soa_to = knot_rrset_copy(&soa, NULL);
+ assert(ch->soa_to);
+ knot_rrset_clear(&soa, NULL);
+}
+
+/*! \brief Compare two changesets for equality. */
+static bool changesets_eq(const changeset_t *ch1, changeset_t *ch2)
+{
+ bool bootstrap = (ch1->remove == NULL);
+
+ if (!bootstrap && changeset_size(ch1) != changeset_size(ch2)) {
+ return false;
+ }
+
+ if ((bootstrap && ch2->remove != NULL) ||
+ (!bootstrap && ch2->remove == NULL)) {
+ return false;
+ }
+
+ changeset_iter_t it1;
+ changeset_iter_t it2;
+ if (bootstrap) {
+ changeset_iter_add(&it1, ch1);
+ changeset_iter_add(&it2, ch2);
+ } else {
+ changeset_iter_all(&it1, ch1);
+ changeset_iter_all(&it2, ch2);
+ }
+
+ knot_rrset_t rr1 = changeset_iter_next(&it1);
+ knot_rrset_t rr2 = changeset_iter_next(&it2);
+ bool ret = true;
+ while (!knot_rrset_empty(&rr1)) {
+ if (!knot_rrset_equal(&rr1, &rr2, true)) {
+ ret = false;
+ break;
+ }
+ rr1 = changeset_iter_next(&it1);
+ rr2 = changeset_iter_next(&it2);
+ }
+
+ changeset_iter_clear(&it1);
+ changeset_iter_clear(&it2);
+
+ return ret;
+}
+
+static bool changesets_list_eq(list_t *l1, list_t *l2)
+{
+ node_t *n = NULL;
+ node_t *k = HEAD(*l2);
+ WALK_LIST(n, *l1) {
+ if (k == NULL) {
+ return false;
+ }
+
+ changeset_t *ch1 = (changeset_t *) n;
+ changeset_t *ch2 = (changeset_t *) k;
+ if (!changesets_eq(ch1, ch2)) {
+ return false;
+ }
+
+ k = k->next;
+ }
+
+ if (k->next != NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+/*! \brief Test a list of changesets for continuity. */
+static bool test_continuity(list_t *l)
+{
+ node_t *n = NULL;
+ uint32_t key1, key2;
+ WALK_LIST(n, *l) {
+ if (n == TAIL(*l)) {
+ break;
+ }
+ changeset_t *ch1 = (changeset_t *) n;
+ changeset_t *ch2 = (changeset_t *) n->next;
+ key1 = knot_soa_serial(ch1->soa_to->rrs.rdata);
+ key2 = knot_soa_serial(ch2->soa_from->rrs.rdata);
+ if (key1 != key2) {
+ return KNOT_EINVAL;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static void test_journal_db(void)
+{
+ env_flag = journal_env_flags(JOURNAL_MODE_ASYNC, false);
+ knot_lmdb_init(&jdb, test_dir_name, 2048 * 1024, env_flag, NULL);
+
+ int ret = knot_lmdb_open(&jdb);
+ is_int(KNOT_EOK, ret, "journal: open db (%s)", knot_strerror(ret));
+
+ ret = knot_lmdb_reconfigure(&jdb, test_dir_name, 4096 * 1024, env_flag);
+ is_int(KNOT_EOK, ret, "journal: re-open with bigger mapsize (%s)", knot_strerror(ret));
+
+ ret = knot_lmdb_reconfigure(&jdb, test_dir_name, 1024 * 1024, env_flag);
+ is_int(KNOT_EOK, ret, "journal: re-open with smaller mapsize (%s)", knot_strerror(ret));
+
+ knot_lmdb_deinit(&jdb);
+}
+
+static int load_j_list(zone_journal_t *zj, bool zij, uint32_t serial,
+ journal_read_t **read, list_t *list)
+{
+ changeset_t *ch;
+ init_list(list);
+ int ret = journal_read_begin(*zj, zij, serial, read);
+ if (ret == KNOT_EOK) {
+ while ((ch = calloc(1, sizeof(*ch))) != NULL &&
+ journal_read_changeset(*read, ch)) {
+ add_tail(list, &ch->n);
+ }
+ free(ch);
+ ret = journal_read_get_error(*read, KNOT_EOK);
+ }
+ return ret;
+}
+
+/*! \brief Test behavior with real changesets. */
+static void test_store_load(const knot_dname_t *apex)
+{
+ set_conf(1000, 512 * 1024, apex);
+
+ knot_lmdb_init(&jdb, test_dir_name, 1536 * 1024, env_flag, NULL);
+ assert(knot_lmdb_open(&jdb) == KNOT_EOK);
+
+ jj.db = &jdb;
+ jj.zone = apex;
+ list_t l, k;
+
+ changeset_t *m_ch = changeset_new(apex), r_ch, e_ch;
+ init_random_changeset(m_ch, 0, 1, 128, apex, false);
+ int ret = journal_insert(jj, m_ch, NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: store changeset (%s)", knot_strerror(ret));
+ ret = journal_sem_check(jj);
+ is_int(KNOT_EOK, ret, "journal: check after store changeset (%s)", knot_strerror(ret));
+ journal_read_t *read = NULL;
+
+ ret = load_j_list(&jj, false, changeset_from(m_ch), &read, &l);
+ is_int(KNOT_EOK, ret, "journal: read single changeset (%s)", knot_strerror(ret));
+ ok(1 == list_size(&l), "journal: read exactly one changeset");
+ ok(changesets_eq(m_ch, HEAD(l)), "journal: changeset equal after read");
+ changesets_free(&l);
+
+ journal_read_end(read);
+ ret = journal_set_flushed(jj);
+ is_int(KNOT_EOK, ret, "journal: first simple flush (%s)", knot_strerror(ret));
+
+ init_list(&k);
+ uint32_t serial = 1;
+ for (; ret == KNOT_EOK && serial < 40000; ++serial) {
+ changeset_t *m_ch2 = changeset_new(apex);
+ init_random_changeset(m_ch2, serial, serial + 1, 128, apex, false);
+ ret = journal_insert(jj, m_ch2, NULL, NULL);
+ if (ret != KNOT_EOK) {
+ changeset_free(m_ch2);
+ break;
+ }
+ add_tail(&k, &m_ch2->n);
+ }
+ is_int(KNOT_EBUSY, ret, "journal: overfill with changesets (%d inserted) (%d should= %d)",
+ serial, ret, KNOT_EBUSY);
+ ret = journal_sem_check(jj);
+ is_int(KNOT_EOK, ret, "journal check (%s)", knot_strerror(ret));
+
+ ret = load_j_list(&jj, false, 1, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: load list (%s)", knot_strerror(ret));
+ ok(changesets_list_eq(&l, &k), "journal: changeset lists equal after read");
+ ok(test_continuity(&l) == KNOT_EOK, "journal: changesets are in order");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ ret = load_j_list(&jj, false, 1, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: load list 2nd (%s)", knot_strerror(ret));
+ ok(changesets_list_eq(&l, &k), "journal: changeset lists equal after 2nd read");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ ret = journal_set_flushed(jj);
+ is_int(KNOT_EOK, ret, "journal: flush after overfill (%s)", knot_strerror(ret));
+ ret = journal_sem_check(jj);
+ is_int(KNOT_EOK, ret, "journal check (%s)", knot_strerror(ret));
+
+ ret = load_j_list(&jj, false, 1, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: load list (%s)", knot_strerror(ret));
+ ok(changesets_list_eq(&l, &k), "journal: changeset lists equal after flush");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ changesets_free(&k);
+
+ changeset_t ch;
+ ret = changeset_init(&ch, apex);
+ ok(ret == KNOT_EOK, "journal: changeset init (%d)", ret);
+ init_random_changeset(&ch, serial, serial + 1, 555, apex, false);
+ ret = journal_insert(jj, &ch, NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: store after flush (%d)", ret);
+ ret = journal_sem_check(jj);
+ is_int(KNOT_EOK, ret, "journal check (%s)", knot_strerror(ret));
+ ret = load_j_list(&jj, false, serial, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: load after store after flush after overfill (%s)", knot_strerror(ret));
+ is_int(1, list_size(&l), "journal: single changeset in list");
+ ok(changesets_eq(&ch, HEAD(l)), "journal: changeset not malformed after overfill");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ changeset_clear(&ch);
+
+ changeset_init(&ch, apex);
+ init_random_changeset(&ch, 2, 3, 100, apex, false);
+ ret = journal_insert(jj, &ch, NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: insert discontinuous changeset (%s)", knot_strerror(ret));
+ ret = journal_sem_check(jj);
+ is_int(KNOT_EOK, ret, "journal check (%s)", knot_strerror(ret));
+ ret = load_j_list(&jj, false, 2, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: read after discontinuity (%s)", knot_strerror(ret));
+ is_int(1, list_size(&l), "journal: discontinuity caused journal to drop");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ // Test for serial number collision handling. We insert changesets
+ // with valid serial sequence that overflows and then collides with itself.
+ // The sequence is 0 -> 1 -> 2 -> 2147483647 -> 4294967294 -> 1 which should
+ // remove changesets 0->1 and 1->2. *
+ uint32_t serials[6] = { 0, 1, 2, 2147483647, 4294967294, 1 };
+ for (int i = 0; i < 5; i++) {
+ changeset_clear(&ch);
+ changeset_init(&ch, apex);
+ init_random_changeset(&ch, serials[i], serials[i + 1], 100, apex, false);
+ ret = journal_insert(jj, &ch, NULL, NULL);
+ is_int(i == 4 ? KNOT_EBUSY : KNOT_EOK, ret, "journal: inserting cycle (%s)", knot_strerror(ret));
+ ret = journal_sem_check(jj);
+ is_int(KNOT_EOK, ret, "journal check (%s)", knot_strerror(ret));
+ }
+ ret = journal_set_flushed(jj);
+ is_int(KNOT_EOK, ret, "journal: flush in cycle (%s)", knot_strerror(ret));
+ ret = journal_insert(jj, &ch, NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: inserted cycle (%s)", knot_strerror(ret));
+ ret = journal_sem_check(jj);
+ is_int(KNOT_EOK, ret, "journal check (%s)", knot_strerror(ret));
+ ret = journal_read_begin(jj, false, 0, &read);
+ is_int(KNOT_ENOENT, ret, "journal: cycle removed first changeset (%d should= %d)", ret, KNOT_ENOENT);
+ ret = journal_read_begin(jj, false, 1, &read);
+ is_int(KNOT_ENOENT, ret, "journal: cycle removed second changeset (%d should= %d)", ret, KNOT_ENOENT);
+ ret = load_j_list(&jj, false, 4294967294, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: read after cycle (%s)", knot_strerror(ret));
+ ok(3 >= list_size(&l), "journal: cycle caused journal to partly drop");
+ ok(changesets_eq(&ch, HEAD(l)), "journal: changeset not malformed after cycle");
+ changesets_free(&l);
+ journal_read_end(read);
+ changeset_clear(&ch);
+ changeset_free(m_ch);
+
+ changeset_init(&e_ch, apex);
+ init_random_changeset(&e_ch, 0, 1, 200, apex, true);
+ zone_node_t *n = NULL;
+ zone_contents_add_rr(e_ch.add, e_ch.soa_to, &n);
+ ret = journal_insert_zone(jj, e_ch.add);
+ zone_contents_remove_rr(e_ch.add, e_ch.soa_to, &n);
+ is_int(KNOT_EOK, ret, "journal: insert zone-in-journal (%s)", knot_strerror(ret));
+ changeset_init(&r_ch, apex);
+ init_random_changeset(&r_ch, 1, 2, 200, apex, false);
+ ret = journal_insert(jj, &r_ch, NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: insert after zone-in-journal (%s)", knot_strerror(ret));
+ ret = load_j_list(&jj, true, 0, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: load zone-in-journal (%s)", knot_strerror(ret));
+ is_int(2, list_size(&l), "journal: read two changesets from zone-in-journal");
+ ok(changesets_eq(&e_ch, HEAD(l)), "journal: zone-in-journal not malformed");
+ ok(changesets_eq(&r_ch, TAIL(l)), "journal: after zone-in-journal not malformed");
+ changesets_free(&l);
+ journal_read_end(read);
+ changeset_clear(&e_ch);
+ changeset_clear(&r_ch);
+
+ ret = journal_scrape_with_md(jj, true);
+ is_int(KNOT_EOK, ret, "journal: scrape with md (%s)", knot_strerror(ret));
+
+ unset_conf();
+}
+
+static void test_size_control(const knot_dname_t *zone1, const knot_dname_t *zone2)
+{
+ set_conf(-1, 100 * 1024, zone1);
+
+ zone_journal_t jj2 = { &jdb, zone2, conf() };
+ changeset_t *small_ch2 = changeset_new(zone2);
+ init_random_changeset(small_ch2, 1, 2, 100, zone2, false);
+ int ret = journal_insert(jj2, small_ch2, NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: storing small changeset must be ok");
+
+ changeset_t *big_zij = changeset_new(zone1);
+ init_random_changeset(big_zij, 0, 1, 1200, zone1, true);
+ zone_node_t *n = NULL;
+ zone_contents_add_rr(big_zij->add, big_zij->soa_to, &n);
+ ret = journal_insert_zone(jj, big_zij->add);
+ is_int(KNOT_EOK, ret, "journal: store big zone-in-journal");
+
+ changeset_t *big_ch2 = changeset_new(zone2);
+ init_random_changeset(big_ch2, 2, 3, 750, zone2, false);
+ ret = journal_insert(jj2, big_ch2, NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: second zone is not affected by storing big zij of other zone");
+
+ journal_read_t *read = NULL;
+ list_t l;
+ init_list(&l);
+ changeset_t *medium_ch1 = changeset_new(zone1);
+ init_random_changeset(medium_ch1, 1, 2, 300, zone1, false);
+ ret = journal_insert(jj, medium_ch1, NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: storing medium changeset must be ok");
+ ret = load_j_list(&jj, true, 0, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: load zone-in-journal (%s)", knot_strerror(ret));
+ is_int(2, list_size(&l), "journal: read two changesets from journal");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ changeset_t *small_ch1 = changeset_new(zone1);
+ init_random_changeset(small_ch1, 2, 3, 100, zone1, false);
+ ret = journal_insert(jj, small_ch1, NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: storing small changeset must be ok");
+ ret = load_j_list(&jj, true, 0, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: load zone-in-journal (%s)", knot_strerror(ret));
+ is_int(2, list_size(&l), "journal: previous chs merged into zone-in-journal due to size limits");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ changeset_t *medium_ch1b = changeset_new(zone1);
+ init_random_changeset(medium_ch1b, 3, 4, 300, zone1, false);
+ ret = journal_insert(jj, medium_ch1b, NULL, NULL);
+ is_int(KNOT_ESPACE, ret, "journal: not able to free space for changeset by merging");
+
+ changeset_t *too_big_zij = changeset_new(zone1);
+ init_random_changeset(too_big_zij, 0, 1, 2200, zone1, true);
+ zone_contents_add_rr(too_big_zij->add, too_big_zij->soa_to, &n);
+ ret = journal_insert_zone(jj, too_big_zij->add);
+ is_int(KNOT_ESPACE, ret, "journal: store too big zone-in-journal");
+
+ changeset_free(big_ch2);
+ changeset_free(big_zij);
+ changeset_free(too_big_zij);
+ changeset_free(small_ch2);
+ changeset_free(small_ch1);
+ changeset_free(medium_ch1);
+ changeset_free(medium_ch1b);
+
+ unset_conf();
+}
+
+const uint8_t *rdA = (const uint8_t *) "\x01\x02\x03\x04";
+const uint8_t *rdB = (const uint8_t *) "\x01\x02\x03\x05";
+const uint8_t *rdC = (const uint8_t *) "\x01\x02\x03\x06";
+
+// frees owner
+static knot_rrset_t * tm_rrset(knot_dname_t * owner, const uint8_t * rdata)
+{
+ knot_rrset_t * rrs = knot_rrset_new(owner, KNOT_RRTYPE_A, KNOT_CLASS_IN, 3600, NULL);
+ knot_rrset_add_rdata(rrs, rdata, 4, NULL);
+ free(owner);
+ return rrs;
+}
+
+static knot_dname_t *tm_owner(const char *prefix, const knot_dname_t *apex)
+{
+ size_t prefix_len = strlen(prefix);
+ size_t apex_len = knot_dname_size(apex);
+
+ knot_dname_t *out = malloc(prefix_len + apex_len + 2);
+ out[0] = prefix_len;
+ memcpy(out + 1, prefix, prefix_len);
+ memcpy(out + 1 + prefix_len, apex, apex_len);
+ return out;
+}
+
+static knot_dname_t *tm_owner_int(int x, const knot_dname_t *apex)
+{
+ char buf[12] = { 0 };
+ (void)snprintf(buf, sizeof(buf), "i%d", x);
+ return tm_owner(buf, apex);
+}
+
+static knot_rrset_t * tm_rrs(const knot_dname_t * apex, int x)
+{
+ static knot_rrset_t * rrsA = NULL;
+ static knot_rrset_t * rrsB = NULL;
+ static knot_rrset_t * rrsC = NULL;
+
+ if (apex == NULL) {
+ knot_rrset_free(rrsA, NULL);
+ knot_rrset_free(rrsB, NULL);
+ knot_rrset_free(rrsC, NULL);
+ rrsA = rrsB = rrsC = NULL;
+ return NULL;
+ }
+
+ if (rrsA == NULL) rrsA = tm_rrset(tm_owner("aaaaaaaaaaaaaaaaa", apex), rdA);
+ if (rrsB == NULL) rrsB = tm_rrset(tm_owner("bbbbbbbbbbbbbbbbb", apex), rdB);
+ if (rrsC == NULL) rrsC = tm_rrset(tm_owner("ccccccccccccccccc", apex), rdC);
+ switch ((x % 3 + 3) % 3) {
+ case 0: return rrsA;
+ case 1: return rrsB;
+ case 2: return rrsC;
+ }
+ assert(0); return NULL;
+}
+
+#define TM_RRS_INT_MAX 1000
+
+static knot_rrset_t *tm_rrs_int(const knot_dname_t *apex, int x)
+{
+ assert(x < TM_RRS_INT_MAX);
+ static knot_rrset_t *stat_rrs[TM_RRS_INT_MAX] = { 0 };
+
+ if (apex == NULL) {
+ for (int i = 0; i < TM_RRS_INT_MAX; i++) {
+ knot_rrset_free(stat_rrs[i], NULL);
+ stat_rrs[i] = NULL;
+ }
+ return NULL;
+ }
+
+ if (stat_rrs[x] == NULL) {
+ stat_rrs[x] = tm_rrset(tm_owner_int(x, apex), rdA);
+ }
+ return stat_rrs[x];
+}
+
+int tm_rrcnt(const changeset_t * ch, int flg)
+{
+ changeset_iter_t it;
+ int i = 0;
+ if (flg >= 0) changeset_iter_add(&it, ch);
+ else changeset_iter_rem(&it, ch);
+
+ knot_rrset_t rri;
+ while (rri = changeset_iter_next(&it), !knot_rrset_empty(&rri)) i++;
+
+ changeset_iter_clear(&it);
+ return i;
+}
+
+static changeset_t * tm_chs(const knot_dname_t * apex, int x)
+{
+ static changeset_t * chsI = NULL, * chsX = NULL, * chsY = NULL;
+ static uint32_t serial = 0;
+ if (x < 0) {
+ serial = 0;
+ return NULL;
+ }
+
+ if (apex == NULL) {
+ changeset_free(chsI);
+ changeset_free(chsX);
+ changeset_free(chsY);
+ chsI = chsX = chsY = NULL;
+ return NULL;
+ }
+
+ if (chsI == NULL) {
+ chsI = changeset_new(apex);
+ assert(chsI != NULL);
+ changeset_add_addition(chsI, tm_rrs(apex, 0), 0);
+ changeset_add_addition(chsI, tm_rrs(apex, 1), 0);
+ }
+ if (chsX == NULL) {
+ chsX = changeset_new(apex);
+ assert(chsX != NULL);
+ changeset_add_removal(chsX, tm_rrs(apex, 1), 0);
+ changeset_add_addition(chsX, tm_rrs(apex, 2), 0);
+ }
+ if (chsY == NULL) {
+ chsY = changeset_new(apex);
+ assert(chsY != NULL);
+ changeset_add_removal(chsY, tm_rrs(apex, 2), 0);
+ changeset_add_addition(chsY, tm_rrs(apex, 1), 0);
+ }
+ assert(x >= 0);
+ changeset_t * ret;
+ if (x == 0) ret = chsI;
+ else if (x % 2 == 1) ret = chsX;
+ else ret = chsY;
+
+ changeset_set_soa_serials(ret, serial, serial + 1, apex);
+ serial++;
+
+ return ret;
+}
+
+static void tm2_add_all(zone_contents_t *toadd)
+{
+ assert(toadd != NULL);
+ for (int i = 1; i < TM_RRS_INT_MAX; i++) {
+ zone_node_t *unused = NULL;
+ _unused_ int ret = zone_contents_add_rr(toadd, tm_rrs_int(toadd->apex->owner, i), &unused);
+ assert(ret == KNOT_EOK);
+ }
+}
+
+static zone_contents_t *tm2_zone(const knot_dname_t *apex)
+{
+ zone_contents_t *z = zone_contents_new(apex, false);
+ if (z != NULL) {
+ knot_rrset_t soa;
+ zone_node_t *unused = NULL;
+ init_soa(&soa, 1, apex);
+ _unused_ int ret = zone_contents_add_rr(z, &soa, &unused);
+ knot_rrset_clear(&soa, NULL);
+ assert(ret == KNOT_EOK);
+ tm2_add_all(z);
+ }
+ return z;
+}
+
+static changeset_t *tm2_chs_unzone(const knot_dname_t *apex)
+{
+ changeset_t *ch = changeset_new(apex);
+ if (ch != NULL) {
+ changeset_set_soa_serials(ch, 1, 2, apex);
+ tm2_add_all(ch->remove);
+ _unused_ int ret = changeset_add_addition(ch, tm_rrs_int(apex, 0), 0);
+ assert(ret == KNOT_EOK);
+ }
+ return ch;
+}
+
+static int merged_present(void)
+{
+ bool exists, has_merged;
+ return journal_info(jj, &exists, NULL, NULL, NULL, &has_merged, NULL, NULL, NULL) == KNOT_EOK && exists && has_merged;
+}
+
+static void test_merge(const knot_dname_t *apex)
+{
+ int i, ret;
+ list_t l;
+
+ // allow merge
+ set_conf(-1, 400 * 1024, apex);
+ ok(!journal_allow_flush(jj), "journal: merge allowed");
+
+ ret = journal_scrape_with_md(jj, false);
+ is_int(KNOT_EOK, ret, "journal: journal_drop_changesets must be ok");
+
+ // insert stuff and check the merge
+ for (i = 0; !merged_present() && i < 40000; i++) {
+ ret = journal_insert(jj, tm_chs(apex, i), NULL, NULL);
+ assert(ret == KNOT_EOK);
+ }
+ ret = journal_sem_check(jj);
+ is_int(KNOT_EOK, ret, "journal: sem check (%s)", knot_strerror(ret));
+ journal_read_t *read = NULL;
+ ret = load_j_list(&jj, false, 0, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: journal_load_changesets must be ok");
+ assert(ret == KNOT_EOK);
+ ok(list_size(&l) == 2, "journal: read the merged and one following");
+ changeset_t * mch = (changeset_t *)HEAD(l);
+ ok(list_size(&l) >= 1 && tm_rrcnt(mch, 1) == 2, "journal: merged additions # = 2");
+ ok(list_size(&l) >= 1 && tm_rrcnt(mch, -1) == 0, "journal: merged removals # = 0");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ // insert one more and check the #s of results
+ ret = journal_insert(jj, tm_chs(apex, i), NULL, NULL);
+ is_int(KNOT_EOK, ret, "journal: insert one more (%s)", knot_strerror(ret));
+ ret = load_j_list(&jj, false, 0, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: journal_load_changesets2 must be ok");
+ ok(list_size(&l) == 3, "journal: read merged together with new changeset");
+ changesets_free(&l);
+ journal_read_end(read);
+ ret = load_j_list(&jj, false, i - 3, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: journal_load_changesets3 must be ok");
+ ok(list_size(&l) == 4, "journal: read short history of merged/unmerged changesets");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ // insert large zone-in-journal taking more than one chunk
+ zone_contents_t *bigz = tm2_zone(apex);
+ ret = journal_insert_zone(jj, bigz);
+ zone_contents_deep_free(bigz);
+ is_int(KNOT_EOK, ret, "journal: insert large zone-in-journal");
+
+ // insert changeset that will cancel it mostly out
+ changeset_t *bigz_cancelout = tm2_chs_unzone(apex);
+ ret = journal_insert(jj, bigz_cancelout, NULL, NULL);
+ changeset_free(bigz_cancelout);
+ is_int(KNOT_EOK, ret, "journal: insert cancel-out changeset");
+
+ // now fill up with dumy changesets to enforce merge
+ tm_chs(apex, -1);
+ while (changeset_to(tm_chs(apex, 0)) != 2) { }
+ for (i = 0; i < 1600; i++) {
+ ret = journal_insert(jj, tm_chs(apex, i), NULL, NULL);
+ assert(ret == KNOT_EOK);
+ }
+
+ // finally: the test case. Reading the journal now must be no EMALF and
+ // the zone-in-journal must be little
+ ret = load_j_list(&jj, true, 0, &read, &l);
+ is_int(KNOT_EOK, ret, "journal: read chunks-shrinked zone-in-journal");
+ is_int(4, trie_weight(((changeset_t *)HEAD(l))->add->nodes->trie), "journal: small merged zone-in-journal");
+ changesets_free(&l);
+ journal_read_end(read);
+
+ ret = journal_scrape_with_md(jj, false);
+ assert(ret == KNOT_EOK);
+
+ // disallow merge
+ unset_conf();
+ set_conf(1000, 512 * 1024, apex);
+ ok(journal_allow_flush(jj), "journal: merge disallowed");
+
+ tm_rrs(NULL, 0);
+ tm_chs(NULL, 0);
+ tm_rrs_int(NULL, 0);
+ unset_conf();
+}
+
+static void test_stress_base(const knot_dname_t *apex,
+ size_t update_size, size_t file_size)
+{
+ uint32_t serial = 0;
+
+ int ret = knot_lmdb_reconfigure(&jdb, test_dir_name, file_size, journal_env_flags(JOURNAL_MODE_ASYNC, false));
+ is_int(KNOT_EOK, ret, "journal: reconfigure to mapsize %zu (%s)", file_size, knot_strerror(ret));
+
+ set_conf(1000, file_size / 2, apex);
+
+ changeset_t ch;
+ ret = changeset_init(&ch, apex);
+ ok(ret == KNOT_EOK, "journal: changeset init (%d)", ret);
+ init_random_changeset(&ch, serial, serial + 1, update_size, apex, false);
+
+ for (int i = 1; i <= 6; ++i) {
+ serial = 0;
+ while (true) {
+ changeset_set_soa_serials(&ch, serial, serial + 1, apex);
+ ret = journal_insert(jj, &ch, NULL, NULL);
+ if (ret == KNOT_EOK) {
+ serial++;
+ } else {
+ break;
+ }
+ }
+
+ ret = journal_set_flushed(jj);
+ if (ret == KNOT_EOK) {
+ ret = journal_sem_check(jj);
+ }
+ ok(serial > 0 && ret == KNOT_EOK, "journal: pass #%d fillup run (%d inserts) (%s)", i, serial, knot_strerror(ret));
+ }
+
+ changeset_clear(&ch);
+
+ unset_conf();
+}
+
+/*! \brief Test behavior when writing to the journal and flushing it. */
+static void test_stress(const knot_dname_t *apex)
+{
+ diag("stress test: small data");
+ test_stress_base(apex, 40, (1024 + 512) * 1024);
+
+ diag("stress test: medium data");
+ test_stress_base(apex, 400, 3 * 1024 * 1024);
+
+ diag("stress test: large data");
+ test_stress_base(apex, 4000, 10 * 1024 * 1024);
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ const knot_dname_t *apex = (const uint8_t *)"\4test";
+ const knot_dname_t *apex2 = (const uint8_t *)"\4ufoo";
+
+ test_dir_name = test_mkdtemp();
+
+ test_journal_db();
+
+ test_store_load(apex);
+
+ if (lmdb_page_size(&jdb) == 4096) {
+ test_size_control(apex, apex2);
+ } // else it is not manually optimized enough to test correctly
+
+ test_merge(apex);
+
+ test_stress(apex);
+
+ knot_lmdb_deinit(&jdb);
+
+ test_rm_rf(test_dir_name);
+ free(test_dir_name);
+
+ return 0;
+}
diff --git a/tests/knot/test_kasp_db.c b/tests/knot/test_kasp_db.c
new file mode 100644
index 0000000..e4f9766
--- /dev/null
+++ b/tests/knot/test_kasp_db.c
@@ -0,0 +1,233 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include <tap/basic.h>
+#include <tap/files.h>
+
+#include "libknot/libknot.h"
+#include "test_conf.h"
+#include "knot/dnssec/kasp/kasp_db.c"
+
+#define CHARS500_1 "kTZgFfrHPP2EOSK24zRjY9GlgCUEkZNBF5UwqsTWisCxGQT4ieinitjXWT1c" \
+ "pj+OR8UX/httSugee+MFsm5yOU/4/211BpLKwwOIAt4Yf8K7Bc+oXTdk15cH" \
+ "TRZtshM1AtfjRsX9rsLDsnaFCyMXzty9AQoRxSphjxnUUC6fszfrSsRx7htl" \
+ "/Xn1PAuwp9Bfn+FxAws98LYVuwiDqUgn4BR5lELdGd16zNOZnN7v023pmPDM" \
+ "nGyvIATuqTCPbFeXTfw7aIDyx2DF+y95/kSnPtY3c1b0Yf+oCv4t3Hx2jjWT" \
+ "9zuC6H+d+PL6HWqilJBs7ysn2FVpnE/Yo44VrQ8orw8QFZr1kR6z7AOVAcMk" \
+ "ac+44swsc8orGCyJx6OlUfN5oU3YahUfLqg9ewl13+P2chmeI6wUyttKsq/4" \
+ "Ud0YQAozBabiAKr1O/Eg7sZR6bV1YkCydQyYgmR/+VOu9D8Ld6uO4DcvhiE/" \
+ "2AmTkLsKLxtpMnQqsTnx"
+#define CHARS500_2 "pzqkMLvpxUYYg0KuMCcBsk9aMm4b5Ny+vJ5UnTq8DVC0jHJJyyGcljKqfpi3" \
+ "MkjfrWY0rbzXFZbZZ6i8bmhhRBcSxE+tK/3AU1LR7ZJsTuITuoJo5LKRH7Uu" \
+ "MU7RBAzFuk3o+Pcyk+9UdbiRn9p4QqPTvb+2xfYn1pJvGHofJcQsSsPEe9Hw" \
+ "ycVW+kdImvWiidn0/e1G6B2xibovnPKDUBFmTbdZIBKHb/eUUoUCNA9CWt5N" \
+ "g8MutK2ixlBJlOvA6CA1V/VW56EJpLqvMxLaoRks5VY5Ls7zWAy97GEFH0Pl" \
+ "uO/Rba1du5tsC0MAC08hljlmu9uoPhsvHdBYHUnQ7jDuYnu9GN3DN0Z6oVbV" \
+ "N01JQZYhKQK/Bl61oM5JubLydtAypryDoG3IH75LhoVC8iGxDoDkxt3zoi/Q" \
+ "PVfPZZsm5j5UOs3wrQL0KWylm2IDK42mrHK8F/XebnOYLNLQaan2a90C+fhH" \
+ "a6hvu0RorkZzGNAZkq/D"
+
+const knot_dname_t *zone1 = (const knot_dname_t *)"\x05""zonea";
+const knot_dname_t *zone2 = (const knot_dname_t *)"\x05""zoneb";
+
+knot_lmdb_db_t _db, *db = &_db;
+
+const key_params_t params1 = { .id = "key id 1", .keytag = 1, .timing = { 1, 11, 111, 1111, 11111 },
+ .public_key = { 520, (uint8_t *)"pk1 plus 500 chars: " CHARS500_1 } };
+const key_params_t params2 = { .id = "key id 2", .keytag = 2, .timing = { 2, 22, 222, 2222, 22222 },
+ .public_key = { 520, (uint8_t *)"pk2 plus 500 chars: " CHARS500_2 } };
+
+bool params_eq(const key_params_t *a, const key_params_t *b)
+{
+ return ((a->keytag == b->keytag) && (a->public_key.size == b->public_key.size) &&
+ (a->timing.retire == b->timing.retire) && (strcmp(a->id, b->id) == 0) &&
+ (memcmp(a->public_key.data, b->public_key.data, b->public_key.size) == 0));
+}
+
+static void init_key_records(key_records_t *r)
+{
+ knot_rrset_init(&r->dnskey, knot_dname_copy(zone1, NULL),
+ KNOT_RRTYPE_DNSKEY, KNOT_CLASS_IN, 3600);
+ knot_rrset_init(&r->cdnskey, knot_dname_copy(zone1, NULL),
+ KNOT_RRTYPE_CDNSKEY, KNOT_CLASS_IN, 0);
+ knot_rrset_init(&r->cds, knot_dname_copy(zone1, NULL),
+ KNOT_RRTYPE_CDS, KNOT_CLASS_IN, 0);
+ knot_rrset_init(&r->rrsig, knot_dname_copy(zone1, NULL),
+ KNOT_RRTYPE_RRSIG, KNOT_CLASS_IN, 3600);
+ knot_rrset_add_rdata(&r->rrsig, (uint8_t *)CHARS500_1, 500, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ char *test_dir_name = test_mkdtemp();
+ bool ignore = false;
+
+ list_t l;
+ key_params_t *params;
+#define free_params free(params->id); free(params->public_key.data); params->id = NULL; params->public_key.data = NULL;
+
+ knot_lmdb_init(db, test_dir_name, 500*1024*1024, 0, "keys_db");
+ int ret = knot_lmdb_open(db);
+ is_int(KNOT_EOK, ret, "kasp_db: open eok");
+ ok(db->env != NULL, "kasp_db: lmdb env notnull");
+
+ ret = kasp_db_add_key(db, zone1, &params1);
+ is_int(KNOT_EOK, ret, "kasp_db: add key 1 eok");
+
+ ret = kasp_db_list_keys(db, zone1, &l);
+ is_int(KNOT_EOK, ret, "kasp_db: list keys 1 eok");
+ is_int(1, list_size(&l), "kasp_db: list keys reports one key 1");
+ params = ((ptrnode_t *)HEAD(l))->d;
+ ok(params_eq(params, &params1), "kasp_db: key params equal 1");
+ free_params
+ ptrlist_deep_free(&l, NULL);
+
+ ret = kasp_db_list_keys(db, zone2, &l);
+ is_int(KNOT_ENOENT, ret, "kasp_db: list keys 1 enoent");
+ is_int(0, list_size(&l), "kasp_db: list keys reports no keys 1");
+ ptrlist_deep_free(&l, NULL);
+
+ ret = kasp_db_share_key(db, zone1, zone2, params1.id);
+ is_int(KNOT_EOK, ret, "kasp_db: share key eok");
+
+ ret = kasp_db_list_keys(db, zone2, &l);
+ is_int(KNOT_EOK, ret, "kasp_db: list keys 3 eok");
+ is_int(1, list_size(&l), "kasp_db: list keys reports one key 2");
+ params = ((ptrnode_t *)HEAD(l))->d;
+ free_params
+ ptrlist_deep_free(&l, NULL);
+
+ ret = kasp_db_add_key(db, zone2, &params2);
+ is_int(KNOT_EOK, ret, "kasp_db: add key 2 eok");
+
+ ret = kasp_db_list_keys(db, zone2, &l);
+ is_int(KNOT_EOK, ret, "kasp_db: list keys 4 eok");
+ is_int(2, list_size(&l), "kasp_db: list keys reports two keys 1");
+ params = ((ptrnode_t *)TAIL(l))->d;
+ ok(params_eq(params, &params2), "kasp_db: key params equal 2");
+ free_params
+ params = ((ptrnode_t *)HEAD(l))->d;
+ free_params
+ ptrlist_deep_free(&l, NULL);
+
+ ret = kasp_db_delete_key(db, zone1, params1.id, &ignore);
+ is_int(KNOT_EOK, ret, "kasp_db: delete key 1 eok");
+
+ ret = kasp_db_list_keys(db, zone1, &l);
+ is_int(KNOT_ENOENT, ret, "kasp_db: list keys 2 enoent");
+ is_int(list_size(&l), 0, "kasp_db: list keys reports no keys 2");
+ ptrlist_deep_free(&l, NULL);
+
+ dnssec_binary_t salt1 = { 500, (uint8_t *)CHARS500_1 }, salt2 = { 0 };
+ knot_time_t time = 0;
+ ret = kasp_db_store_nsec3salt(db, zone1, &salt1, 1234);
+ is_int(KNOT_EOK, ret, "kasp_db: store nsec3salt");
+ ret = kasp_db_load_nsec3salt(db, zone1, &salt2, &time);
+ is_int(KNOT_EOK, ret, "kasp_db: load nsec3salt");
+ is_int(1234, time, "kasp_db: salt_created preserved");
+ is_int(0, dnssec_binary_cmp(&salt1, &salt2), "kasp_db: salt preserved");
+ dnssec_binary_free(&salt2);
+ salt1.size = 0;
+ ret = kasp_db_store_nsec3salt(db, zone2, &salt1, 0);
+ is_int(KNOT_EOK, ret, "kasp_db: store empty nsec3salt");
+ ret = kasp_db_load_nsec3salt(db, zone2, &salt2, &time);
+ is_int(KNOT_EOK, ret, "kasp_db: load empty nsec3salt");
+ is_int(0, time, "kasp_db: empty salt_created preserved");
+ is_int(0, salt2.size, "kasp_db: empty salt preserved");
+ dnssec_binary_free(&salt2);
+
+ ret = kasp_db_delete_all(db, zone2);
+ is_int(KNOT_EOK, ret, "kasp_db: delete all");
+ ret = kasp_db_list_keys(db, zone2, &l);
+ is_int(KNOT_ENOENT, ret, "kasp_db: delete all deleted keys");
+ ret = kasp_db_load_nsec3salt(db, zone2, &salt2, &time);
+ is_int(KNOT_ENOENT, ret, "kasp_db: delete all removed nsec3salt");
+ dnssec_binary_free(&salt2);
+
+ ret = kasp_db_store_serial(db, zone2, KASPDB_SERIAL_MASTER, 1);
+ is_int(KNOT_EOK, ret, "kasp_db: store master_serial");
+ ret = kasp_db_store_serial(db, zone2, KASPDB_SERIAL_LASTSIGNED, 2);
+ is_int(KNOT_EOK, ret, "kasp_db: store lastsigned_serial");
+ uint32_t serial = 0;
+ ret = kasp_db_load_serial(db, zone2, KASPDB_SERIAL_MASTER, &serial);
+ is_int(KNOT_EOK, ret, "kasp_db: load master_serial");
+ is_int(1, serial, "kasp_db: master_serial preserved");
+ ret = kasp_db_load_serial(db, zone2, KASPDB_SERIAL_LASTSIGNED, &serial);
+ is_int(KNOT_EOK, ret, "kasp_db: load lastsigned_serial");
+ is_int(2, serial, "kasp_db: lastsigned_serial preserved");
+
+ ret = kasp_db_add_key(db, zone1, &params1);
+ ok(ret == KNOT_EOK, "kasp_db: add key1");
+ ret = kasp_db_add_key(db, zone2, &params2);
+ ok(ret == KNOT_EOK, "kasp_db: add key2");
+
+ ret = kasp_db_set_policy_last(db, "policy1", NULL, zone1, params1.id);
+ is_int(KNOT_EOK, ret, "kasp_db: set policylast");
+ knot_dname_t *zoneX;
+ char *keyidX;
+ ret = kasp_db_get_policy_last(db, "policy1", &zoneX, &keyidX);
+ is_int(KNOT_EOK, ret, "kasp_db: get policylast");
+ ok(knot_dname_cmp(zoneX, zone1) == 0 && keyidX != NULL &&
+ strcmp(keyidX, params1.id) == 0, "kasp_db: policy last preserved");
+ free(zoneX);
+ free(keyidX);
+ ret = kasp_db_set_policy_last(db, "policy1", params1.id, zone2, params2.id);
+ is_int(KNOT_EOK, ret, "kasp_db: reset policylast");
+ ret = kasp_db_get_policy_last(db, "policy1", &zoneX, &keyidX);
+ is_int(KNOT_EOK, ret, "kasp_db: reget policylast");
+ ok(knot_dname_cmp(zoneX, zone2) == 0 && keyidX != NULL &&
+ strcmp(keyidX, params2.id) == 0, "kasp_db: policy last represerved");
+ free(zoneX);
+ free(keyidX);
+ ret = kasp_db_set_policy_last(db, "policy1", params1.id, zone1, params1.id);
+ is_int(KNOT_ESEMCHECK, ret, "kasp_db: refused policylast with wrong keyid");
+ ret = kasp_db_get_policy_last(db, "policy1", &zoneX, &keyidX);
+ is_int(KNOT_EOK, ret, "kasp_db: reget policylast2");
+ ok(knot_dname_cmp(zoneX, zone2) == 0 && keyidX != NULL &&
+ strcmp(keyidX, params2.id) == 0, "kasp_db: policy last represerved2");
+ free(zoneX);
+ free(keyidX);
+
+ knot_time_t two = 2;
+ key_records_t kr;
+ init_key_records(&kr);
+ ret = kasp_db_store_offline_records(db, 1, &kr);
+ is_int(KNOT_EOK, ret, "kasp_db: store key records");
+ //key_records_clear_rdatasets(&kr);
+ ret = kasp_db_load_offline_records(db, zone1, &two, &time, &kr);
+ is_int(KNOT_EOK, ret, "kasp_db: load key records");
+ ok(kr.cds.type == KNOT_RRTYPE_CDS && kr.rrsig.rrs.count == 1, "kasp_db: key records ok");
+ is_int(0, time, "kasp_db: no next key records");
+ key_records_clear(&kr);
+ ret = kasp_db_delete_offline_records(db, zone1, 1, 3);
+ is_int(KNOT_EOK, ret, "kasp_db: delete key records");
+ ret = kasp_db_load_offline_records(db, zone1, &two, &time, &kr);
+ is_int(KNOT_ENOENT, ret, "kasp_db: no more key records");
+
+ knot_lmdb_deinit(db);
+
+ test_rm_rf(test_dir_name);
+ free(test_dir_name);
+
+ return 0;
+}
diff --git a/tests/knot/test_node.c b/tests/knot/test_node.c
new file mode 100644
index 0000000..e8c6cdb
--- /dev/null
+++ b/tests/knot/test_node.c
@@ -0,0 +1,128 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <tap/basic.h>
+
+#include "knot/zone/node.h"
+#include "libknot/libknot.h"
+
+static knot_rrset_t *create_dummy_rrset(const knot_dname_t *owner, uint16_t type)
+{
+ knot_rrset_t *r = knot_rrset_new(owner, type, KNOT_CLASS_IN, 3600, NULL);
+ assert(r);
+ uint8_t wire[16] = { 0 };
+ memcpy(wire, "testtest", strlen("testtest"));
+ int ret = knot_rrset_add_rdata(r, wire, strlen("testtest"), NULL);
+ assert(ret == KNOT_EOK);
+ (void)ret;
+ return r;
+}
+
+static knot_rrset_t *create_dummy_rrsig(const knot_dname_t *owner, uint16_t type)
+{
+ knot_rrset_t *r = knot_rrset_new(owner, KNOT_RRTYPE_RRSIG, KNOT_CLASS_IN,
+ 3600, NULL);
+ assert(r);
+ uint8_t wire[sizeof(uint16_t)];
+ knot_wire_write_u16(wire, type);
+ int ret = knot_rrset_add_rdata(r, wire, sizeof(uint16_t), NULL);
+ assert(ret == KNOT_EOK);
+ (void)ret;
+ return r;
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ knot_dname_t *dummy_owner = knot_dname_from_str_alloc("test.");
+ // Test new
+ zone_node_t *node = node_new(dummy_owner, false, false, NULL);
+ ok(node != NULL, "Node: new");
+ assert(node);
+ ok(knot_dname_is_equal(node->owner, dummy_owner), "Node: new - set fields");
+
+ // Test RRSet addition
+ knot_rrset_t *dummy_rrset = create_dummy_rrset(dummy_owner, KNOT_RRTYPE_TXT);
+ int ret = node_add_rrset(node, dummy_rrset, NULL);
+ ok(ret == KNOT_EOK && node->rrset_count == 1 &&
+ knot_rdataset_eq(&dummy_rrset->rrs, &node->rrs[0].rrs), "Node: add RRSet.");
+
+ // Test RRSet getters
+ knot_rrset_t *n_rrset = node_create_rrset(node, KNOT_RRTYPE_TXT);
+ ok(n_rrset && knot_rrset_equal(n_rrset, dummy_rrset, true),
+ "Node: create existing RRSet.");
+
+ knot_rrset_free(n_rrset, NULL);
+
+ n_rrset = node_create_rrset(node, KNOT_RRTYPE_SOA);
+ ok(n_rrset == NULL, "Node: create non-existing RRSet.");
+
+ knot_rrset_t stack_rrset = node_rrset(node, KNOT_RRTYPE_TXT);
+ ok(knot_rrset_equal(&stack_rrset, dummy_rrset, true), "Node: get existing RRSet.");
+ stack_rrset = node_rrset(node, KNOT_RRTYPE_SOA);
+ ok(knot_rrset_empty(&stack_rrset), "Node: get non-existent RRSet.");
+
+ knot_rdataset_t *n_rdataset = node_rdataset(node, KNOT_RRTYPE_TXT);
+ ok(n_rdataset && knot_rdataset_eq(n_rdataset, &dummy_rrset->rrs),
+ "Node: get existing rdataset.");
+ n_rdataset = node_rdataset(node, KNOT_RRTYPE_SOA);
+ ok(n_rdataset == NULL, "Node: get non-existing rdataset.");
+
+ stack_rrset = node_rrset_at(node, 0);
+ ok(knot_rrset_equal(&stack_rrset, dummy_rrset, true),
+ "Node: get existing position.");
+ stack_rrset = node_rrset_at(node, 1);
+ ok(knot_rrset_empty(&stack_rrset), "Node: get non-existent position.");
+
+ // Test TTL mismatch
+ dummy_rrset->ttl = 1800;
+ ret = node_add_rrset(node, dummy_rrset, NULL);
+ ok(ret == KNOT_ETTL && node->rrset_count == 1,
+ "Node: add RRSet, TTL mismatch.");
+
+ knot_rrset_free(dummy_rrset, NULL);
+
+ // Test bool functions
+ ok(node_rrtype_exists(node, KNOT_RRTYPE_TXT), "Node: type exists.");
+ ok(!node_rrtype_exists(node, KNOT_RRTYPE_AAAA), "Node: type does not exist.");
+ ok(!node_rrtype_is_signed(node, KNOT_RRTYPE_TXT), "Node: type is not signed.");
+
+ dummy_rrset = create_dummy_rrsig(dummy_owner, KNOT_RRTYPE_TXT);
+ ret = node_add_rrset(node, dummy_rrset, NULL);
+ assert(ret == KNOT_EOK);
+
+ ok(node_rrtype_is_signed(node, KNOT_RRTYPE_TXT), "Node: type is signed.");
+
+ knot_rrset_free(dummy_rrset, NULL);
+
+ // Test remove RRset
+ node_remove_rdataset(node, KNOT_RRTYPE_AAAA);
+ ok(node->rrset_count == 2, "Node: remove non-existent rdataset.");
+ node_remove_rdataset(node, KNOT_RRTYPE_TXT);
+ ok(node->rrset_count == 1, "Node: remove existing rdataset.");
+
+ // "Test" freeing
+ node_free_rrsets(node, NULL);
+ ok(node->rrset_count == 0, "Node: free RRSets.");
+
+ node_free(node, NULL);
+
+ knot_dname_free(dummy_owner, NULL);
+
+ return 0;
+}
diff --git a/tests/knot/test_process_query.c b/tests/knot/test_process_query.c
new file mode 100644
index 0000000..83f62d8
--- /dev/null
+++ b/tests/knot/test_process_query.c
@@ -0,0 +1,201 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <tap/basic.h>
+#include <tap/files.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libknot/descriptor.h"
+#include "libknot/packet/wire.h"
+#include "knot/nameserver/process_query.h"
+#include "test_server.h"
+#include "contrib/sockaddr.h"
+#include "contrib/ucw/mempool.h"
+
+/* Basic response check (4 TAP tests). */
+static void answer_sanity_check(const uint8_t *query,
+ const uint8_t *answer, uint16_t answer_len,
+ uint8_t expected_rcode, const char *name)
+{
+ ok(answer_len >= KNOT_WIRE_HEADER_SIZE, "ns: len(%s answer) >= DNS header", name);
+ if (answer_len >= KNOT_WIRE_HEADER_SIZE) {
+ ok(knot_wire_get_qr(answer), "ns: %s answer has QR=1", name);
+ is_int(expected_rcode, knot_wire_get_rcode(answer), "ns: %s answer RCODE=%d", name, expected_rcode);
+ is_int(knot_wire_get_id(query), knot_wire_get_id(answer), "ns: %s MSGID match", name);
+ } else {
+ skip_block(3, "ns: can't check DNS header");
+ }
+}
+
+/* Resolve query and check answer for sanity (2 TAP tests). */
+static void exec_query(knot_layer_t *layer, const char *name,
+ knot_pkt_t *query,
+ uint8_t expected_rcode)
+{
+ knot_pkt_t *answer = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
+ assert(answer);
+
+ /* Input packet. */
+ knot_pkt_parse(query, 0);
+ knot_layer_consume(layer, query);
+
+ ok(layer->state == KNOT_STATE_PRODUCE ||
+ layer->state == KNOT_STATE_FAIL, "ns: process %s query", name);
+
+ /* Create answer. */
+ knot_layer_produce(layer, answer);
+ if (layer->state == KNOT_STATE_FAIL) {
+ /* Allow 1 generic error response. */
+ knot_layer_produce(layer, answer);
+ }
+
+ ok(layer->state == KNOT_STATE_DONE, "ns: answer %s query", name);
+
+ /* Check answer. */
+ answer_sanity_check(query->wire, answer->wire, answer->size, expected_rcode, name);
+
+ knot_pkt_free(answer);
+}
+
+/* \internal Helpers */
+#define WIRE_COPY(dst, dst_len, src, src_len) \
+ memcpy(dst, src, src_len); \
+ dst_len = src_len;
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ knot_mm_t mm;
+ mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
+
+ /* Create processing context. */
+ knot_layer_t proc;
+ memset(&proc, 0, sizeof(knot_layer_t));
+ knot_layer_init(&proc, &mm, process_query_layer());
+
+ /* Create temporary storage directory. */
+ char *temp_dir = test_mkdtemp();
+ ok(temp_dir != NULL, "make temporary directory");
+
+ /* Create fake server environment. */
+ server_t server;
+ int ret = create_fake_server(&server, proc.mm, temp_dir);
+ is_int(KNOT_EOK, ret, "ns: fake server initialization");
+ if (ret != KNOT_EOK) {
+ goto fatal;
+ }
+
+ zone_t *zone = knot_zonedb_find(server.zone_db, ROOT_DNAME);
+
+ /* Prepare. */
+ knot_pkt_t *query = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, proc.mm);
+
+ /* Create query processing parameter. */
+ struct sockaddr_storage ss;
+ memset(&ss, 0, sizeof(struct sockaddr_storage));
+ sockaddr_set(&ss, AF_INET, "127.0.0.1", 53);
+ knotd_qdata_params_t params = {
+ .proto = KNOTD_QUERY_PROTO_TCP,
+ .remote = &ss,
+ .server = &server
+ };
+
+ /* Query processor (CH zone) */
+ knot_layer_begin(&proc, &params);
+ knot_pkt_clear(query);
+ knot_pkt_put_question(query, IDSERVER_DNAME, KNOT_CLASS_CH, KNOT_RRTYPE_TXT);
+ exec_query(&proc, "CH TXT", query, KNOT_RCODE_NOERROR);
+
+ /* Query processor (valid input). */
+ knot_layer_reset(&proc);
+ knot_pkt_clear(query);
+ knot_pkt_put_question(query, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
+ exec_query(&proc, "IN/root", query, KNOT_RCODE_NOERROR);
+
+ /* Query processor (-1 bytes, not enough data). */
+ knot_layer_reset(&proc);
+ query->size -= 1;
+ exec_query(&proc, "IN/few-data", query, KNOT_RCODE_FORMERR);
+ query->size += 1;
+
+ /* Query processor (+1 bytes trailing). */
+ knot_layer_reset(&proc);
+ query->wire[query->size] = '\1'; /* Initialize the "garbage" value. */
+ query->size += 1;
+ exec_query(&proc, "IN/trail-garbage", query, KNOT_RCODE_FORMERR);
+ query->size -= 1;
+
+ /* Forge NOTIFY query from SOA query. */
+ knot_layer_reset(&proc);
+ knot_wire_set_opcode(query->wire, KNOT_OPCODE_NOTIFY);
+ exec_query(&proc, "IN/notify", query, KNOT_RCODE_NOTAUTH);
+
+ /* Forge AXFR query. */
+ knot_layer_reset(&proc);
+ knot_pkt_clear(query);
+ knot_pkt_put_question(query, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_AXFR);
+ exec_query(&proc, "IN/axfr", query, KNOT_RCODE_NOTAUTH);
+
+ /* Forge IXFR query (well formed). */
+ knot_layer_reset(&proc);
+ knot_pkt_clear(query);
+ knot_pkt_put_question(query, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_IXFR);
+ /* Append SOA RR. */
+ knot_rrset_t soa_rr = node_rrset(zone->contents->apex, KNOT_RRTYPE_SOA);
+ knot_pkt_begin(query, KNOT_AUTHORITY);
+ knot_pkt_put(query, KNOT_COMPR_HINT_NONE, &soa_rr, 0);
+ exec_query(&proc, "IN/ixfr", query, KNOT_RCODE_NOTAUTH);
+
+ /* \note Tests below are not possible without proper zone and zone data. */
+ /* #189 Process UPDATE query. */
+ /* #189 Process AXFR client. */
+ /* #189 Process IXFR client. */
+
+ /* Query processor (smaller than DNS header, ignore). */
+ knot_layer_reset(&proc);
+ knot_pkt_clear(query);
+ knot_pkt_put_question(query, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
+ size_t orig_query_size = query->size;
+ query->size = KNOT_WIRE_HEADER_SIZE - 1;
+ knot_layer_consume(&proc, query);
+ ok(proc.state == KNOT_STATE_NOOP, "ns: IN/less-than-header query ignored");
+ query->size = orig_query_size;
+
+ /* Query processor (response, ignore). */
+ knot_layer_reset(&proc);
+ knot_wire_set_qr(query->wire);
+ knot_layer_consume(&proc, query);
+ ok(proc.state == KNOT_STATE_NOOP, "ns: IN/less-than-header query ignored");
+
+ /* Finish. */
+ knot_layer_finish(&proc);
+ ok(proc.state == KNOT_STATE_NOOP, "ns: processing end" );
+
+fatal:
+ /* Cleanup. */
+ mp_delete((struct mempool *)mm.ctx);
+ server_deinit(&server);
+ conf_free(conf());
+ test_rm_rf(temp_dir);
+ free(temp_dir);
+
+ return 0;
+}
+
+#undef WIRE_COPY
diff --git a/tests/knot/test_query_module.c b/tests/knot/test_query_module.c
new file mode 100644
index 0000000..4ab14d2
--- /dev/null
+++ b/tests/knot/test_query_module.c
@@ -0,0 +1,87 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libknot/libknot.h"
+#include "knot/nameserver/query_module.h"
+#include "libknot/packet/pkt.h"
+
+/* Universal processing stage. */
+unsigned state_visit(unsigned state, knot_pkt_t *pkt, knotd_qdata_t *qdata,
+ knotd_mod_t *mod)
+{
+ /* Visit current state */
+ bool *state_map = (bool *)mod;
+ state_map[state] = true;
+
+ return state + 1;
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ /* Create a map of expected steps. */
+ bool state_map[KNOTD_STAGES] = { false };
+
+ /* Prepare query plan. */
+ struct query_plan *plan = query_plan_create();
+ ok(plan != NULL, "query_plan: create");
+ if (plan == NULL) {
+ goto fatal;
+ }
+
+ /* Register all stage visits. */
+ int ret = KNOT_EOK;
+ for (unsigned stage = KNOTD_STAGE_BEGIN; stage < KNOTD_STAGES; ++stage) {
+ ret = query_plan_step(plan, stage, state_visit, state_map);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ }
+ is_int(KNOT_EOK, ret, "query_plan: planned all steps");
+
+ /* Execute the plan. */
+ int state = 0, next_state = 0;
+ for (unsigned stage = KNOTD_STAGE_BEGIN; stage < KNOTD_STAGES; ++stage) {
+ struct query_step *step = NULL;
+ WALK_LIST(step, plan->stage[stage]) {
+ next_state = step->process(state, NULL, NULL, step->ctx);
+ if (next_state != state + 1) {
+ break;
+ }
+ state = next_state;
+ }
+ }
+ ok(state == KNOTD_STAGES, "query_plan: executed all steps");
+
+ /* Verify if all steps executed their callback. */
+ for (state = 0; state < KNOTD_STAGES; ++state) {
+ if (state_map[state] == false) {
+ break;
+ }
+ }
+ ok(state == KNOTD_STAGES, "query_plan: executed all callbacks");
+
+fatal:
+ /* Free the query plan. */
+ query_plan_free(plan);
+
+ return 0;
+}
diff --git a/tests/knot/test_requestor.c b/tests/knot/test_requestor.c
new file mode 100644
index 0000000..e0bd360
--- /dev/null
+++ b/tests/knot/test_requestor.c
@@ -0,0 +1,188 @@
+/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <tap/basic.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "libknot/descriptor.h"
+#include "libknot/errcode.h"
+#include "knot/query/layer.h"
+#include "knot/query/requestor.h"
+#include "contrib/mempattern.h"
+#include "contrib/net.h"
+#include "contrib/sockaddr.h"
+#include "contrib/ucw/mempool.h"
+
+bool TFO = false;
+
+/* @note Purpose of this test is not to verify process_answer functionality,
+ * but simply if the requesting/receiving works, so mirror is okay. */
+static int reset(knot_layer_t *ctx) { return KNOT_STATE_PRODUCE; }
+static int begin(knot_layer_t *ctx, void *module_param) { return reset(ctx); }
+static int finish(knot_layer_t *ctx) { return reset(ctx); }
+static int in(knot_layer_t *ctx, knot_pkt_t *pkt) { return KNOT_STATE_DONE; }
+static int out(knot_layer_t *ctx, knot_pkt_t *pkt) { return KNOT_STATE_CONSUME; }
+
+static const int TIMEOUT = 2000;
+
+/*! \brief Dummy answer processing module. */
+const knot_layer_api_t dummy_module = {
+ &begin, &reset, &finish, &in, &out
+};
+
+static void set_blocking_mode(int sock)
+{
+ int flags = fcntl(sock, F_GETFL);
+ flags &= ~O_NONBLOCK;
+ fcntl(sock, F_SETFL, flags);
+}
+
+static void *responder_thread(void *arg)
+{
+ int fd = *(int *)arg;
+
+ set_blocking_mode(fd);
+ uint8_t buf[KNOT_WIRE_MAX_PKTSIZE] = { 0 };
+ while (true) {
+ int client = accept(fd, NULL, NULL);
+ if (client < 0) {
+ break;
+ }
+ int len = net_dns_tcp_recv(client, buf, sizeof(buf), -1);
+ if (len < KNOT_WIRE_HEADER_SIZE) {
+ close(client);
+ break;
+ }
+ knot_wire_set_qr(buf);
+ net_dns_tcp_send(client, buf, len, -1, NULL);
+ close(client);
+ }
+
+ return NULL;
+}
+
+/* Test implementations. */
+
+static knot_request_t *make_query(knot_requestor_t *requestor,
+ const struct sockaddr_storage *dst,
+ const struct sockaddr_storage *src)
+{
+ knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, requestor->mm);
+ assert(pkt);
+ static const knot_dname_t *root = (uint8_t *)"";
+ knot_pkt_put_question(pkt, root, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
+
+ knot_request_flag_t flags = TFO ? KNOT_REQUEST_TFO: KNOT_REQUEST_NONE;
+
+ return knot_request_make(requestor->mm, dst, src, pkt, NULL, flags);
+}
+
+static void test_disconnected(knot_requestor_t *requestor,
+ const struct sockaddr_storage *dst,
+ const struct sockaddr_storage *src)
+{
+ knot_request_t *req = make_query(requestor, dst, src);
+ int ret = knot_requestor_exec(requestor, req, TIMEOUT);
+ /* ECONNREFUSED on FreeBSD, ETIMEOUT on NetBSD/OpenBSD/macOS. */
+ ret = (ret == KNOT_ECONNREFUSED || ret == KNOT_ETIMEOUT) ? KNOT_ECONN : ret;
+ is_int(KNOT_ECONN, ret, "requestor: disconnected/exec");
+ knot_request_free(req, requestor->mm);
+
+}
+
+static void test_connected(knot_requestor_t *requestor,
+ const struct sockaddr_storage *dst,
+ const struct sockaddr_storage *src)
+{
+ /* Enqueue packet. */
+ knot_request_t *req = make_query(requestor, dst, src);
+ int ret = knot_requestor_exec(requestor, req, TIMEOUT);
+ is_int(KNOT_EOK, ret, "requestor: connected/exec");
+ knot_request_free(req, requestor->mm);
+}
+
+int main(int argc, char *argv[])
+{
+#if defined(__linux__)
+ FILE *fd = fopen("/proc/sys/net/ipv4/tcp_fastopen", "r");
+ if (fd != NULL) {
+ int val = fgetc(fd);
+ fclose(fd);
+ // 0 - disabled, 1 - server TFO (client fallbacks),
+ // 2 - client TFO, 3 - both
+ if (val == '1' || val == '3') {
+ TFO = true;
+ }
+ }
+#endif
+ plan_lazy();
+
+ knot_mm_t mm;
+ mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
+
+ /* Initialize requestor. */
+ knot_requestor_t requestor;
+ knot_requestor_init(&requestor, &dummy_module, NULL, &mm);
+
+ /* Define endpoints. */
+ struct sockaddr_storage client = { 0 };
+ sockaddr_set(&client, AF_INET, "127.0.0.1", 0);
+ struct sockaddr_storage server = { 0 };
+ sockaddr_set(&server, AF_INET, "127.0.0.1", 0);
+
+ /* Bind to random port. */
+ int responder_fd = net_bound_socket(SOCK_STREAM, &server, 0, 0);
+ assert(responder_fd >= 0);
+ socklen_t addr_len = sockaddr_len(&server);
+ int ret = getsockname(responder_fd, (struct sockaddr *)&server, &addr_len);
+ ok(ret == 0, "check getsockname return");
+
+ /* Test requestor in disconnected environment. */
+ test_disconnected(&requestor, &server, &client);
+
+ /* Start responder. */
+ ret = listen(responder_fd, 10);
+ ok(ret == 0, "check listen return");
+
+ if (TFO) {
+ ret = net_bound_tfo(responder_fd, 10);
+ ok(ret == KNOT_EOK, "check bound TFO return");
+ }
+
+ pthread_t thread;
+ pthread_create(&thread, 0, responder_thread, &responder_fd);
+
+ /* Test requestor in connected environment. */
+ test_connected(&requestor, &server, &client);
+
+ /* Terminate responder. */
+ int conn = net_connected_socket(SOCK_STREAM, &server, NULL, false);
+ assert(conn > 0);
+ conn = net_dns_tcp_send(conn, (uint8_t *)"", 1, TIMEOUT, NULL);
+ assert(conn > 0);
+ pthread_join(thread, NULL);
+ close(responder_fd);
+
+ /* Cleanup. */
+ mp_delete((struct mempool *)mm.ctx);
+
+ return 0;
+}
diff --git a/tests/knot/test_semantic_check.in b/tests/knot/test_semantic_check.in
new file mode 100644
index 0000000..dc29f0a
--- /dev/null
+++ b/tests/knot/test_semantic_check.in
@@ -0,0 +1,169 @@
+#!/bin/sh
+
+KZONECHECK="@top_builddir@/src/kzonecheck"
+DATA="@top_srcdir@/tests/knot/semantic_check_data"
+
+. "@top_srcdir@/tests/tap/libtap.sh"
+
+TMPDIR=$(test_tmpdir)
+LOG="$TMPDIR/log"
+
+# Params: zonefile fatal_error expected_erros_count semcheck_err_msg
+expect_error()
+{
+ if [ ! -r "$DATA/$1" ]; then
+ skip_block 4 "missing zone file for test"
+ return
+ fi
+
+ "$KZONECHECK" -o example.com "$DATA/$1" > "$LOG"
+ ok "$1 - check program return" test $? -eq 1
+
+ fatal=$(grep -E "^Serious semantic error detected" $LOG | wc -l)
+ ok "$1 - check fatal" test $fatal -eq $2
+
+ errors=$(grep -E "^\[.+\] $4" $LOG | wc -l)
+ ok "$1 - check errors" test $errors -eq $3
+ if [ $errors != $3 ]; then
+ diag "expected errors $3 but found $errors"
+ fi
+}
+
+#param zonefile
+test_correct()
+{
+ $KZONECHECK -o example.com "$DATA/$1" > /dev/null
+ ok "$1 - correct zone, without error" test $? -eq 0
+}
+
+#param zonefile
+test_correct_no_dnssec()
+{
+ $KZONECHECK -o example.com -d off "$DATA/$1" > /dev/null
+ ok "$1 - correct zone, without error" test $? -eq 0
+}
+
+if [ ! -x $KZONECHECK ]; then
+ skip_all "kzonecheck is missing or is not executable"
+fi
+
+# error messages exported from knot/src/zone/semantic-check.c
+CDNSKEY_NONE="missing CDNSKEY"
+CDNSKEY_NO_CDS="CDNSKEY without corresponding CDS"
+CDNSKEY_DELETE="invalid CDNSKEY/CDS for DNSSEC delete algorithm"
+CDS_NONE="missing CDS"
+CDS_NOT_MATCH="CDS not match CDNSKEY"
+CNAME_EXTRA_RECORDS="another record exists beside CNAME"
+CNAME_MULTIPLE="multiple CNAME records"
+DNAME_CHILDREN="child record exists under DNAME"
+DNAME_MULTIPLE="multiple DNAME records"
+DNAME_EXTRA_NS="NS record exists beside DNAME"
+DNSKEY_INVALID="invalid DNSKEY"
+DS_ALG="invalid algorithm in DS"
+NSEC3PARAM_FLAGS="invalid flags in NSEC3PARAM"
+NSEC_NONE="missing NSEC\(3\) record"
+NSEC_RDATA_BITMAP="wrong NSEC\(3\) bitmap"
+NSEC_RDATA_CHAIN="inconsistent NSEC\(3\) chain"
+NSEC3_INSECURE_DELEGATION_OPT="wrong NSEC3 opt-out"
+NS_APEX="missing NS at the zone apex"
+NS_GLUE="missing glue record"
+RRSIG_UNVERIFIABLE="no valid signature for a record"
+
+plan_lazy
+
+expect_error "cname_extra_01.zone" 1 1 "$CNAME_EXTRA_RECORDS"
+expect_error "cname_extra_02.signed" 1 1 "$CNAME_EXTRA_RECORDS"
+expect_error "cname_multiple.zone" 1 1 "$CNAME_MULTIPLE"
+expect_error "dname_children.zone" 1 1 "$DNAME_CHILDREN"
+expect_error "dname_multiple.zone" 1 1 "$DNAME_MULTIPLE"
+expect_error "dname_extra_ns.zone" 1 1 "$DNAME_EXTRA_NS"
+
+expect_error "ns_apex.missing" 0 1 "$NS_APEX"
+expect_error "glue_apex_both.missing" 0 2 "$NS_GLUE"
+expect_error "glue_apex_one.missing" 0 1 "$NS_GLUE"
+expect_error "glue_besides.missing" 0 1 "$NS_GLUE"
+expect_error "glue_deleg.missing" 0 1 "$NS_GLUE"
+expect_error "glue_in_apex.missing" 0 1 "$NS_GLUE"
+expect_error "different_signer_name.signed" 0 1 "$RRSIG_UNVERIFIABLE"
+expect_error "no_rrsig.signed" 0 1 "$RRSIG_UNVERIFIABLE"
+expect_error "no_rrsig_with_delegation.signed" 0 1 "$RRSIG_UNVERIFIABLE"
+expect_error "nsec_broken_chain_01.signed" 0 1 "$NSEC_RDATA_CHAIN"
+expect_error "nsec_broken_chain_02.signed" 0 1 "$NSEC_RDATA_CHAIN"
+expect_error "nsec_missing.signed" 0 1 "$NSEC_NONE"
+expect_error "nsec_multiple.signed" 0 1 "$NSEC_NONE"
+expect_error "nsec_wrong_bitmap_01.signed" 0 1 "$NSEC_RDATA_BITMAP"
+expect_error "nsec_wrong_bitmap_02.signed" 0 1 "$NSEC_RDATA_BITMAP"
+expect_error "nsec3_missing.signed" 0 1 "$NSEC_NONE"
+expect_error "nsec3_optout_ent.invalid" 0 1 "$NSEC_NONE"
+expect_error "nsec3_wrong_bitmap_01.signed" 0 1 "$NSEC_RDATA_BITMAP"
+expect_error "nsec3_wrong_bitmap_02.signed" 0 1 "$NSEC_RDATA_BITMAP"
+expect_error "nsec3_ds.signed" 0 1 "$NSEC_NONE"
+expect_error "nsec3_optout.signed" 0 1 "$NSEC3_INSECURE_DELEGATION_OPT"
+expect_error "nsec3_chain_01.signed" 0 1 "$NSEC_RDATA_CHAIN"
+expect_error "nsec3_chain_02.signed" 0 1 "$NSEC_RDATA_CHAIN"
+expect_error "nsec3_chain_03.signed" 0 1 "$NSEC_RDATA_CHAIN"
+expect_error "nsec3_param_invalid.signed" 0 1 "$NSEC_NONE"
+expect_error "nsec3_param_invalid.signed" 0 1 "$NSEC3PARAM_FLAGS"
+expect_error "rrsig_signed.signed" 0 1 "$RRSIG_UNVERIFIABLE"
+expect_error "rrsig_rdata_ttl.signed" 0 1 "$RRSIG_UNVERIFIABLE"
+expect_error "duplicate.signature" 0 1 "$RRSIG_UNVERIFIABLE"
+expect_error "missing.signed" 0 1 "$NSEC_NONE"
+expect_error "dnskey_param_error.signed" 0 1 "$DNSKEY_INVALID"
+expect_error "invalid_ds.signed" 0 2 "$DS_ALG \(keytag 60485\)"
+expect_error "cdnskey.invalid" 0 1 "$CDS_NOT_MATCH"
+expect_error "cdnskey.invalid.param" 0 1 "$CDS_NOT_MATCH"
+expect_error "cdnskey.nocds" 0 1 "$CDS_NONE"
+expect_error "cdnskey.nocdnskey" 0 1 "$CDNSKEY_NONE"
+expect_error "cdnskey.nodnskey" 0 1 "$CDNSKEY_NOT_MATCH"
+expect_error "cdnskey.orphan.cds" 0 1 "$CDS_NOT_MATCH"
+expect_error "cdnskey.orphan.cdnskey" 0 1 "$CDNSKEY_NO_CDS"
+expect_error "cdnskey.delete.invalid.cds" 0 1 "$CDNSKEY_DELETE"
+expect_error "cdnskey.delete.invalid.cdnskey" 0 1 "$CDNSKEY_DELETE"
+expect_error "delegation.signed" 0 1 "$NSEC_RDATA_BITMAP"
+
+test_correct "rrsig_ttl.signed"
+test_correct "no_error_delegation_bitmap.signed"
+test_correct "no_error_nsec3_optout.signed"
+test_correct "glue_wildcard.valid"
+test_correct "glue_no_foreign.valid"
+test_correct "glue_in_deleg.valid"
+test_correct "cdnskey.cds"
+test_correct "cdnskey.delete.both"
+test_correct "dname_apex_nsec3.signed"
+test_correct "nsec3_optout_ent.valid"
+test_correct "nsec3_optout_ent.all"
+
+test_correct_no_dnssec "no_rrsig.signed"
+test_correct_no_dnssec "no_rrsig_with_delegation.signed"
+test_correct_no_dnssec "nsec_broken_chain_01.signed"
+test_correct_no_dnssec "nsec_broken_chain_02.signed"
+test_correct_no_dnssec "nsec_missing.signed"
+test_correct_no_dnssec "nsec_multiple.signed"
+test_correct_no_dnssec "nsec_wrong_bitmap_01.signed"
+test_correct_no_dnssec "nsec_wrong_bitmap_02.signed"
+test_correct_no_dnssec "nsec3_missing.signed"
+test_correct_no_dnssec "nsec3_wrong_bitmap_01.signed"
+test_correct_no_dnssec "nsec3_wrong_bitmap_02.signed"
+test_correct_no_dnssec "nsec3_ds.signed"
+test_correct_no_dnssec "nsec3_optout.signed"
+test_correct_no_dnssec "nsec3_chain_01.signed"
+test_correct_no_dnssec "nsec3_chain_02.signed"
+test_correct_no_dnssec "nsec3_chain_03.signed"
+test_correct_no_dnssec "nsec3_param_invalid.signed"
+test_correct_no_dnssec "rrsig_signed.signed"
+test_correct_no_dnssec "rrsig_rdata_ttl.signed"
+test_correct_no_dnssec "duplicate.signature"
+test_correct_no_dnssec "missing.signed"
+test_correct_no_dnssec "dnskey_param_error.signed"
+test_correct_no_dnssec "cdnskey.invalid"
+test_correct_no_dnssec "cdnskey.invalid.param"
+test_correct_no_dnssec "cdnskey.nocds"
+test_correct_no_dnssec "cdnskey.nocdnskey"
+test_correct_no_dnssec "cdnskey.nodnskey"
+test_correct_no_dnssec "cdnskey.orphan.cds"
+test_correct_no_dnssec "cdnskey.orphan.cdnskey"
+test_correct_no_dnssec "cdnskey.delete.invalid.cds"
+test_correct_no_dnssec "cdnskey.delete.invalid.cdnskey"
+test_correct_no_dnssec "delegation.signed"
+
+rm $LOG
diff --git a/tests/knot/test_server.c b/tests/knot/test_server.c
new file mode 100644
index 0000000..bde3d10
--- /dev/null
+++ b/tests/knot/test_server.c
@@ -0,0 +1,72 @@
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <signal.h>
+#include <tap/basic.h>
+#include "knot/server/server.h"
+#include "test_conf.h"
+
+// Signal handler
+static void interrupt_handle(int s)
+{
+}
+
+/*! API: run tests. */
+int main(int argc, char *argv[])
+{
+ plan(2);
+
+ server_t server;
+ int ret = 0;
+
+ /* Some random configuration just to apply the default conf schema */
+ ret = test_conf("", NULL);
+ assert(ret == KNOT_EOK);
+
+ /* Register service and signal handler */
+ struct sigaction sa;
+ sa.sa_handler = interrupt_handle;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, NULL); // Interrupt
+
+ /* Test server for correct initialization */
+ ret = server_init(&server, 1);
+ is_int(KNOT_EOK, ret, "server: initialized");
+ if (ret != KNOT_EOK) {
+ return 1;
+ }
+
+ /* Test server startup */
+ ret = server_start(&server, false);
+ is_int(KNOT_EOK, ret, "server: started ok");
+ if (ret != KNOT_EOK) {
+ return 1;
+ }
+
+ server_stop(&server);
+
+ /* Wait for server to finish. */
+ server_wait(&server);
+
+ /* Destroy the server structure. */
+ server_deinit(&server);
+
+ /* Remove the configuration. */
+ conf_free(conf());
+
+ return 0;
+}
diff --git a/tests/knot/test_server.h b/tests/knot/test_server.h
new file mode 100644
index 0000000..d68561d
--- /dev/null
+++ b/tests/knot/test_server.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "test_conf.h"
+#include "knot/server/server.h"
+#include "knot/zone/adjust.h"
+#include "contrib/mempattern.h"
+
+/* Some domain names. */
+#define ROOT_DNAME ((const uint8_t *)"")
+#define EXAMPLE_DNAME ((const uint8_t *)"\x7""example")
+#define IDSERVER_DNAME ((const uint8_t *)"\2""id""\6""server")
+
+/* Create fake root zone. */
+static inline void create_root_zone(server_t *server, knot_mm_t *mm)
+{
+ /* SOA RDATA. */
+ #define SOA_RDLEN 30
+ static const uint8_t SOA_RDATA[SOA_RDLEN] = {
+ 0x02, 'n', 's', 0x00, /* ns. */
+ 0x04, 'm', 'a', 'i', 'l', 0x00,/* mail. */
+ 0x77, 0xdf, 0x1e, 0x63, /* serial */
+ 0x00, 0x01, 0x51, 0x80, /* refresh */
+ 0x00, 0x00, 0x1c, 0x20, /* retry */
+ 0x00, 0x0a, 0x8c, 0x00, /* expire */
+ 0x00, 0x00, 0x0e, 0x10 /* min ttl */
+ };
+
+ /* Insert root zone. */
+ zone_t *root = zone_new(ROOT_DNAME);
+ root->server = server;
+ root->contents = zone_contents_new(root->name, true);
+
+ knot_rrset_t *soa = knot_rrset_new(root->name, KNOT_RRTYPE_SOA, KNOT_CLASS_IN,
+ 7200, mm);
+ knot_rrset_add_rdata(soa, SOA_RDATA, SOA_RDLEN, mm);
+ node_add_rrset(root->contents->apex, soa, NULL);
+ knot_rrset_free(soa, mm);
+
+ /* Bake the zone. */
+ (void)zone_adjust_full(root->contents, 1);
+
+ /* Switch zone db. */
+ knot_zonedb_free(&server->zone_db);
+ server->zone_db = knot_zonedb_new();
+ knot_zonedb_insert(server->zone_db, root);
+}
+
+/* Create fake server. */
+static inline int create_fake_server(server_t *server, knot_mm_t *mm, const char *db_storage)
+{
+ int ret;
+
+ /* Create test configuration. */
+ /* String `db_storage' obtained from test_mkdtemp() may be up to 4096 bytes. */
+ char conf_str[4096 + 512];
+ (void)snprintf(conf_str, sizeof(conf_str),
+ "server:\n"
+ " identity: bogus.ns\n"
+ " version: 0.11\n"
+ " nsid: \n"
+ "database:\n"
+ " storage: %s\n"
+ "zone:\n"
+ " - domain: .\n"
+ " zonefile-sync: -1\n",
+ db_storage);
+
+ /* Load test configuration. */
+ ret = test_conf(conf_str, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Create name server. */
+ ret = server_init(server, 1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Insert root zone. */
+ create_root_zone(server, mm);
+
+ return KNOT_EOK;
+}
diff --git a/tests/knot/test_unreachable.c b/tests/knot/test_unreachable.c
new file mode 100644
index 0000000..826544d
--- /dev/null
+++ b/tests/knot/test_unreachable.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+
+#include "knot/common/unreachable.h"
+
+#include "contrib/sockaddr.h"
+
+#define UR_TEST_ADDRS 32
+struct sockaddr_storage ur_test_addrs[UR_TEST_ADDRS] = { { 0 } };
+struct sockaddr_storage ur_test_via[2] = { { 0 } };
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ global_unreachables = knot_unreachables_init(10);
+ ok(global_unreachables != NULL, "unreachables: init");
+
+ // ur_test_via[0] left empty - AF_UNSPEC
+ sockaddr_set(&ur_test_via[1], AF_INET6, "::1", 0);
+
+ for (int i = 0; i < UR_TEST_ADDRS; i++) {
+ struct sockaddr_storage *s = &ur_test_addrs[i];
+ sockaddr_set(s, AF_INET6, "::2", i + 1);
+ struct sockaddr_storage *via = &ur_test_via[i % 2];
+ struct sockaddr_storage *not_via = &ur_test_via[1 - i % 2];
+
+ ok(!knot_unreachable_is(global_unreachables, s, via), "unreachables: pre[%d]", i);
+ knot_unreachable_add(global_unreachables, s, via);
+ ok(knot_unreachable_is(global_unreachables, s, via), "unreachables: post[%d]", i);
+ ok(!knot_unreachable_is(global_unreachables, s, not_via), "unreachables: via[%d]", i);
+
+ usleep(1000);
+ if (i >= 10) {
+ ok(!knot_unreachable_is(global_unreachables, &ur_test_addrs[i - 10], via),
+ "unreachables: expired[%d]", i - 10);
+ }
+ }
+
+ knot_unreachables_deinit(&global_unreachables);
+ ok(global_unreachables == NULL, "unreachables: deinit");
+
+ return 0;
+}
diff --git a/tests/knot/test_worker_pool.c b/tests/knot/test_worker_pool.c
new file mode 100644
index 0000000..59dee36
--- /dev/null
+++ b/tests/knot/test_worker_pool.c
@@ -0,0 +1,152 @@
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <time.h>
+
+#include "knot/worker/pool.h"
+#include "knot/worker/queue.h"
+
+#define THREADS 4
+#define TASKS_BATCH 40
+
+/*!
+ * Task execution log.
+ */
+typedef struct task_log {
+ pthread_mutex_t mx;
+ unsigned executed;
+} task_log_t;
+
+/*!
+ * Get number of executed tasks and clear.
+ */
+static unsigned executed_reset(task_log_t *log)
+{
+ pthread_mutex_lock(&log->mx);
+ unsigned result = log->executed;
+ log->executed = 0;
+ pthread_mutex_unlock(&log->mx);
+
+ return result;
+}
+
+/*!
+ * Simple task, just increases the counter in the log.
+ */
+static void task_counting(worker_task_t *task)
+{
+ task_log_t *log = task->ctx;
+
+ pthread_mutex_lock(&log->mx);
+ log->executed += 1;
+ pthread_mutex_unlock(&log->mx);
+}
+
+static void interrupt_handle(int s)
+{
+}
+
+int main(void)
+{
+ plan_lazy();
+
+ struct sigaction sa;
+ sa.sa_handler = interrupt_handle;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, NULL); // Interrupt
+
+ // create pool
+
+ worker_pool_t *pool = worker_pool_create(THREADS);
+ ok(pool != NULL, "create worker pool");
+ if (!pool) {
+ return 1;
+ }
+
+ task_log_t log = {
+ .mx = PTHREAD_MUTEX_INITIALIZER,
+ };
+
+ // schedule jobs while pool is stopped
+
+ worker_task_t task = { .run = task_counting, .ctx = &log };
+ for (int i = 0; i < TASKS_BATCH; i++) {
+ worker_pool_assign(pool, &task);
+ }
+
+ sched_yield();
+ ok(executed_reset(&log) == 0, "executed count before start");
+
+ // start and wait for finish
+
+ worker_pool_start(pool);
+ worker_pool_wait(pool);
+ ok(executed_reset(&log) == TASKS_BATCH, "executed count after start");
+
+ // add additional jobs while pool is running
+
+ for (int i = 0; i < TASKS_BATCH; i++) {
+ worker_pool_assign(pool, &task);
+ }
+
+ worker_pool_wait(pool);
+ ok(executed_reset(&log) == TASKS_BATCH, "executed count after add");
+
+ // temporary suspension
+
+ worker_pool_suspend(pool);
+
+ for (int i = 0; i < TASKS_BATCH; i++) {
+ worker_pool_assign(pool, &task);
+ }
+
+ sched_yield();
+ ok(executed_reset(&log) == 0, "executed count after suspend");
+
+ worker_pool_resume(pool);
+ worker_pool_wait(pool);
+ ok(executed_reset(&log) == TASKS_BATCH, "executed count after resume");
+
+ // try clean
+
+ pthread_mutex_lock(&log.mx);
+ for (int i = 0; i < THREADS + TASKS_BATCH; i++) {
+ worker_pool_assign(pool, &task);
+ }
+ sched_yield();
+ worker_pool_clear(pool);
+ pthread_mutex_unlock(&log.mx);
+
+ worker_pool_wait(pool);
+ ok(executed_reset(&log) <= THREADS, "executed count after clear");
+
+ // cleanup
+
+ worker_pool_stop(pool);
+ worker_pool_join(pool);
+ worker_pool_destroy(pool);
+
+ pthread_mutex_destroy(&log.mx);
+
+ return 0;
+}
diff --git a/tests/knot/test_worker_queue.c b/tests/knot/test_worker_queue.c
new file mode 100644
index 0000000..2d20afd
--- /dev/null
+++ b/tests/knot/test_worker_queue.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+
+#include "knot/worker/queue.h"
+
+int main(void)
+{
+ plan_lazy();
+
+ worker_task_t task_one = { 0 };
+ worker_task_t task_two = { 0 };
+ worker_task_t task_three = { 0 };
+
+ // init
+
+ worker_queue_t queue;
+ worker_queue_init(&queue);
+ ok(1, "queue init");
+
+ // enqueue
+
+ worker_queue_enqueue(&queue, &task_one);
+ ok(1, "enqueue first");
+ worker_queue_enqueue(&queue, &task_two);
+ ok(1, "enqueue second");
+
+ // dequeue
+
+ ok(worker_queue_dequeue(&queue) == &task_one, "dequeue first");
+ ok(worker_queue_dequeue(&queue) == &task_two, "dequeue second");
+ ok(worker_queue_dequeue(&queue) == NULL, "dequeue from empty");
+
+ // deinit
+
+ worker_queue_enqueue(&queue, &task_three);
+ ok(1, "enqueue third");
+
+ worker_queue_deinit(&queue);
+ ok(1, "queue deinit");
+
+ return 0;
+}
diff --git a/tests/knot/test_zone-tree.c b/tests/knot/test_zone-tree.c
new file mode 100644
index 0000000..59207ae
--- /dev/null
+++ b/tests/knot/test_zone-tree.c
@@ -0,0 +1,135 @@
+/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <tap/basic.h>
+
+#include "libknot/errcode.h"
+#include "knot/zone/zone-tree.h"
+
+#define NCOUNT 4
+static knot_dname_t* NAME[NCOUNT];
+static zone_node_t NODEE[NCOUNT];
+static knot_dname_t* ORDER[NCOUNT];
+static void ztree_init_data(void)
+{
+ NAME[0] = knot_dname_from_str_alloc(".");
+ NAME[1] = knot_dname_from_str_alloc("master.ac.");
+ NAME[2] = knot_dname_from_str_alloc("ac.");
+ NAME[3] = knot_dname_from_str_alloc("ns.");
+
+ knot_dname_t *order[NCOUNT] = {
+ NAME[0], NAME[2], NAME[1], NAME[3]
+ };
+ memcpy(ORDER, order, NCOUNT * sizeof(knot_dname_t*));
+
+ for (unsigned i = 0; i < NCOUNT; ++i) {
+ memset(NODEE + i, 0, sizeof(zone_node_t));
+ NODEE[i].owner = NAME[i];
+ NODEE[i].prev = NODEE + ((NCOUNT + i - 1) % NCOUNT);
+ NODEE[i].rrset_count = 1; /* required for ordered search */
+ }
+}
+
+static void ztree_free_data(void)
+{
+ for (unsigned i = 0; i < NCOUNT; ++i) {
+ knot_dname_free(NAME[i], NULL);
+ }
+}
+
+static int ztree_iter_data(zone_node_t *node, void *data)
+{
+ unsigned *i = (unsigned *)data;
+ knot_dname_t *owner = node->owner;
+ int result = KNOT_EOK;
+ if (owner != ORDER[*i]) {
+ result = KNOT_ERROR;
+ char *exp_s = knot_dname_to_str_alloc(ORDER[*i]);
+ char *owner_s = knot_dname_to_str_alloc(owner);
+ diag("ztree: at index: %u expected '%s' got '%s'\n", *i, exp_s, owner_s);
+ free(exp_s);
+ free(owner_s);
+ }
+ ++(*i);
+ return result;
+}
+
+static int ztree_node_counter(zone_node_t *node, void *data)
+{
+ (void)node;
+ int *counter = data;
+ (*counter)++;
+ return KNOT_EOK;
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ ztree_init_data();
+
+ /* 1. create test */
+ zone_tree_t* t = zone_tree_create(false);
+ ok(t != NULL, "ztree: created");
+
+ /* 2. insert test */
+ unsigned passed = 1;
+ for (unsigned i = 0; i < NCOUNT; ++i) {
+ zone_node_t *node = NODEE + i;
+ if (zone_tree_insert(t, &node) != KNOT_EOK) {
+ passed = 0;
+ break;
+ }
+ }
+ ok(passed, "ztree: insertion");
+
+ /* 3. check data test */
+ passed = 1;
+ for (unsigned i = 0; i < NCOUNT; ++i) {
+ zone_node_t *node = zone_tree_get(t, NAME[i]);
+ if (node == NULL || node != NODEE + i) {
+ passed = 0;
+ break;
+ }
+ }
+ ok(passed, "ztree: lookup");
+
+ /* 4. ordered lookup */
+ zone_node_t *node = NULL;
+ zone_node_t *prev = NULL;
+ knot_dname_t *tmp_dn = knot_dname_from_str_alloc("z.ac.");
+ zone_tree_get_less_or_equal(t, tmp_dn, &node, &prev);
+ knot_dname_free(tmp_dn, NULL);
+ ok(prev == NODEE + 1, "ztree: ordered lookup");
+
+ /* 5. ordered traversal */
+ unsigned i = 0;
+ int ret = zone_tree_apply(t, ztree_iter_data, &i);
+ ok (ret == KNOT_EOK, "ztree: ordered traversal");
+
+ /* 6. subtree apply */
+ int counter = 0;
+ ret = zone_tree_sub_apply(t, (const knot_dname_t *)"\x02""ac", false, ztree_node_counter, &counter);
+ ok(ret == KNOT_EOK && counter == 2, "ztree: subtree iteration");
+ counter = 0;
+ ret = zone_tree_sub_apply(t, (const knot_dname_t *)"\x02""ac", true, ztree_node_counter, &counter);
+ ok(ret == KNOT_EOK && counter == 1, "ztree: subtree iteration excluding root");
+
+ zone_tree_free(&t);
+ ztree_free_data();
+ return 0;
+}
diff --git a/tests/knot/test_zone-update.c b/tests/knot/test_zone-update.c
new file mode 100644
index 0000000..1346aaf
--- /dev/null
+++ b/tests/knot/test_zone-update.c
@@ -0,0 +1,337 @@
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <pthread.h>
+#include <tap/basic.h>
+#include <tap/files.h>
+#include <unistd.h>
+
+#include "test_conf.h"
+#include "contrib/getline.h"
+#include "knot/server/server.h"
+#include "knot/updates/zone-update.h"
+#include "knot/zone/adjust.h"
+#include "knot/zone/node.h"
+#include "libzscanner/scanner.h"
+
+static const char *zone_str1 = "test. 600 IN SOA ns.test. m.test. 1 900 300 4800 900 \n";
+static const char *zone_str2 = "test. 600 IN TXT \"test\"\n";
+static const char *add_str = "test. 600 IN TXT \"test2\"\n";
+static const char *del_str = "test. 600 IN TXT \"test\"\n";
+static const char *node_str1 = "node.test. 601 IN TXT \"abc\"\n";
+static const char *node_str2 = "node.test. 601 IN TXT \"def\"\n";
+
+knot_rrset_t rrset;
+
+/*!< \brief Returns true if node contains given RR in its RRSets. */
+static bool node_contains_rr(const zone_node_t *node, const knot_rrset_t *data)
+{
+ const knot_rdataset_t *zone_rrs = node_rdataset(node, data->type);
+ if (zone_rrs != NULL) {
+ knot_rdata_t *rr = data->rrs.rdata;
+ for (size_t i = 0; i < data->rrs.count; ++i) {
+ if (!knot_rdataset_member(zone_rrs, rr)) {
+ return false;
+ }
+ rr = knot_rdataset_next(rr);
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static void process_rr(zs_scanner_t *scanner)
+{
+ knot_rrset_init(&rrset, scanner->r_owner, scanner->r_type, scanner->r_class,
+ scanner->r_ttl);
+
+ int ret = knot_rrset_add_rdata(&rrset, scanner->r_data,
+ scanner->r_data_length, NULL);
+ (void)ret;
+ assert(ret == KNOT_EOK);
+}
+
+static int rr_data_cmp(struct rr_data *a, struct rr_data *b)
+{
+ if (a->type != b->type) {
+ return 1;
+ }
+ if (a->ttl != b->ttl) {
+ return 1;
+ }
+ if (a->rrs.count != b->rrs.count) {
+ return 1;
+ }
+ if (a->rrs.rdata != b->rrs.rdata) {
+ return 1;
+ }
+ if (a->additional != b->additional) {
+ return 1;
+ }
+ return 0;
+}
+
+static int test_node_unified(zone_node_t *n1, _unused_ void *v)
+{
+ zone_node_t *n2 = binode_node(n1, false);
+ if (n2 == n1) {
+ n2 = binode_node(n1, true);
+ }
+ ok(n1->owner == n2->owner, "binode %s has equal %s owner", n1->owner, n2->owner);
+ ok(n1->rrset_count == n2->rrset_count, "binode %s has equal rrset_count", n1->owner);
+ for (uint16_t i = 0; i < n1->rrset_count; i++) {
+ ok(rr_data_cmp(&n1->rrs[i], &n2->rrs[i]) == 0, "binode %s has equal rrs", n1->owner);
+ }
+ if (n1->flags & NODE_FLAGS_BINODE) {
+ ok((n1->flags ^ n2->flags) == NODE_FLAGS_SECOND, "binode %s has correct flags", n1->owner);
+ }
+ ok(n1->children == n2->children, "binode %s has equal children count", n1->owner);
+ return KNOT_EOK;
+}
+
+static void test_zone_unified(zone_t *z)
+{
+ knot_sem_wait(&z->cow_lock);
+ zone_tree_apply(z->contents->nodes, test_node_unified, NULL);
+ knot_sem_post(&z->cow_lock);
+}
+
+void test_full(zone_t *zone, zs_scanner_t *sc)
+{
+ zone_update_t update;
+ /* Init update */
+ int ret = zone_update_init(&update, zone, UPDATE_FULL);
+ is_int(KNOT_EOK, ret, "zone update: init full");
+
+ if (zs_set_input_string(sc, zone_str1, strlen(zone_str1)) != 0 ||
+ zs_parse_all(sc) != 0) {
+ assert(0);
+ }
+
+ /* First addition */
+ ret = zone_update_add(&update, &rrset);
+ knot_rdataset_clear(&rrset.rrs, NULL);
+ is_int(KNOT_EOK, ret, "full zone update: first addition");
+
+ if (zs_set_input_string(sc, zone_str2, strlen(zone_str2)) != 0 ||
+ zs_parse_all(sc) != 0) {
+ assert(0);
+ }
+
+ /* Second addition */
+ ret = zone_update_add(&update, &rrset);
+ zone_node_t *node = (zone_node_t *) zone_update_get_node(&update, rrset.owner);
+ bool rrset_present = node_contains_rr(node, &rrset);
+ ok(ret == KNOT_EOK && rrset_present, "full zone update: second addition");
+
+ /* Removal */
+ ret = zone_update_remove(&update, &rrset);
+ node = (zone_node_t *) zone_update_get_node(&update, rrset.owner);
+ rrset_present = node_contains_rr(node, &rrset);
+ ok(ret == KNOT_EOK && !rrset_present, "full zone update: removal");
+
+ /* Last addition */
+ ret = zone_update_add(&update, &rrset);
+ node = (zone_node_t *) zone_update_get_node(&update, rrset.owner);
+ rrset_present = node_contains_rr(node, &rrset);
+ ok(ret == KNOT_EOK && rrset_present, "full zone update: last addition");
+
+ knot_rdataset_clear(&rrset.rrs, NULL);
+
+ /* Prepare node removal */
+ if (zs_set_input_string(sc, node_str1, strlen(node_str1)) != 0 ||
+ zs_parse_all(sc) != 0) {
+ assert(0);
+ }
+ ret = zone_update_add(&update, &rrset);
+ assert(ret == KNOT_EOK);
+ knot_rdataset_clear(&rrset.rrs, NULL);
+
+ if (zs_set_input_string(sc, node_str2, strlen(node_str2)) != 0 ||
+ zs_parse_all(sc) != 0) {
+ assert(0);
+ }
+ ret = zone_update_add(&update, &rrset);
+ assert(ret == KNOT_EOK);
+ knot_rdataset_clear(&rrset.rrs, NULL);
+ knot_dname_t *rem_node_name = knot_dname_from_str_alloc("node.test");
+ node = (zone_node_t *) zone_update_get_node(&update, rem_node_name);
+ assert(node && node_rdataset(node, KNOT_RRTYPE_TXT)->count == 2);
+ /* Node removal */
+ ret = zone_update_remove_node(&update, rem_node_name);
+ node = (zone_node_t *) zone_update_get_node(&update, rem_node_name);
+ ok(ret == KNOT_EOK && !node, "full zone update: node removal");
+ knot_dname_free(rem_node_name, NULL);
+
+ /* Re-add a node for later incremental functionality test */
+ if (zs_set_input_string(sc, node_str1, strlen(node_str1)) != 0 ||
+ zs_parse_all(sc) != 0) {
+ assert(0);
+ }
+ ret = zone_update_add(&update, &rrset);
+ assert(ret == KNOT_EOK);
+ knot_rdataset_clear(&rrset.rrs, NULL);
+
+ /* Commit */
+ ret = zone_update_commit(conf(), &update);
+ node = zone_contents_find_node_for_rr(zone->contents, &rrset);
+ rrset_present = node_contains_rr(node, &rrset);
+ ok(ret == KNOT_EOK && rrset_present, "full zone update: commit (max TTL: %u)", zone->contents->max_ttl);
+
+ test_zone_unified(zone);
+
+ knot_rdataset_clear(&rrset.rrs, NULL);
+}
+
+void test_incremental(zone_t *zone, zs_scanner_t *sc)
+{
+ int ret = KNOT_EOK;
+
+ /* Init update */
+ zone_update_t update;
+ zone_update_init(&update, zone, UPDATE_INCREMENTAL);
+ ok(update.zone == zone && changeset_empty(&update.change),
+ "incremental zone update: init");
+
+ if (zs_set_input_string(sc, add_str, strlen(add_str)) != 0 ||
+ zs_parse_all(sc) != 0) {
+ assert(0);
+ }
+
+ /* Addition */
+ ret = zone_update_add(&update, &rrset);
+ knot_rdataset_clear(&rrset.rrs, NULL);
+ is_int(KNOT_EOK, ret, "incremental zone update: addition");
+
+ const zone_node_t *synth_node = update.new_cont->apex;
+ ok(synth_node && node_rdataset(synth_node, KNOT_RRTYPE_TXT)->count == 2,
+ "incremental zone update: add change");
+
+ if (zs_set_input_string(sc, del_str, strlen(del_str)) != 0 ||
+ zs_parse_all(sc) != 0) {
+ assert(0);
+ }
+ /* Removal */
+ ret = zone_update_remove(&update, &rrset);
+ is_int(KNOT_EOK, ret, "incremental zone update: removal");
+ knot_rdataset_clear(&rrset.rrs, NULL);
+
+ ok(node_rdataset(synth_node, KNOT_RRTYPE_TXT)->count == 1,
+ "incremental zone update: del change");
+
+ /* Prepare node removal */
+ if (zs_set_input_string(sc, node_str2, strlen(node_str2)) != 0 ||
+ zs_parse_all(sc) != 0) {
+ assert(0);
+ }
+ ret = zone_update_add(&update, &rrset);
+ assert(ret == KNOT_EOK);
+ knot_rdataset_clear(&rrset.rrs, NULL);
+
+ knot_dname_t *rem_node_name = knot_dname_from_str_alloc("node.test");
+ synth_node = zone_update_get_node(&update, rem_node_name);
+ assert(synth_node && node_rdataset(synth_node, KNOT_RRTYPE_TXT)->count == 2);
+ /* Node Removal */
+ ret = zone_update_remove_node(&update, rem_node_name);
+ synth_node = zone_update_get_node(&update, rem_node_name);
+ ok(ret == KNOT_EOK && !synth_node,
+ "incremental zone update: node removal");
+ knot_dname_free(rem_node_name, NULL);
+
+ /* Re-add a node for later incremental functionality test */
+ if (zs_set_input_string(sc, node_str1, strlen(node_str1)) != 0 ||
+ zs_parse_all(sc) != 0) {
+ assert(0);
+ }
+ ret = zone_update_add(&update, &rrset);
+ assert(ret == KNOT_EOK);
+ knot_rdataset_clear(&rrset.rrs, NULL);
+
+ /* Commit */
+ ret = zone_update_commit(conf(), &update);
+ const zone_node_t *iter_node = zone_contents_find_node_for_rr(zone->contents, &rrset);
+ bool rrset_present = node_contains_rr(iter_node, &rrset);
+ ok(ret == KNOT_EOK && rrset_present, "incremental zone update: commit");
+
+ test_zone_unified(zone);
+
+ knot_rdataset_clear(&rrset.rrs, NULL);
+
+ size_t zone_size1 = zone->contents->size;
+ uint32_t zone_max_ttl1 = zone->contents->max_ttl;
+ ret = zone_adjust_full(zone->contents, 2);
+ ok(ret == KNOT_EOK, "zone adjust full shall work");
+ size_t zone_size2 = zone->contents->size;
+ uint32_t zone_max_ttl2 = zone->contents->max_ttl;
+ ok(zone_size1 == zone_size2, "zone size measured the same incremental vs full (%zu, %zu)", zone_size1, zone_size2);
+ ok(zone_max_ttl1 == zone_max_ttl2, "zone max TTL measured the same incremental vs full (%u, %u)", zone_max_ttl1, zone_max_ttl2);
+ // TODO test more things after re-adjust, search for non-unified bi-nodes
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ char *temp_dir = test_mkdtemp();
+ ok(temp_dir != NULL, "make temporary directory");
+
+ char conf_str[512];
+ snprintf(conf_str, sizeof(conf_str),
+ "zone:\n"
+ " - domain: test.\n"
+ "database:\n"
+ " journal-db-max-size: 100M\n"
+ " storage: %s\n",
+ temp_dir);
+
+ /* Load test configuration. */
+ int ret = test_conf(conf_str, NULL);
+ is_int(KNOT_EOK, ret, "load configuration");
+
+ server_t server;
+ ret = server_init(&server, 1);
+ is_int(KNOT_EOK, ret, "server init");
+
+ /* Set up empty zone */
+ knot_dname_t *apex = knot_dname_from_str_alloc("test");
+ assert(apex);
+ zone_t *zone = zone_new(apex);
+ zone->server = &server;
+
+ /* Setup zscanner */
+ zs_scanner_t sc;
+ if (zs_init(&sc, "test.", KNOT_CLASS_IN, 3600) != 0 ||
+ zs_set_processing(&sc, process_rr, NULL, NULL) != 0) {
+ assert(0);
+ }
+
+ /* Test FULL update, commit it and use the result to test the INCREMENTAL update */
+ test_full(zone, &sc);
+ test_incremental(zone, &sc);
+
+ zs_deinit(&sc);
+ zone_free(&zone);
+ server_deinit(&server);
+ knot_dname_free(apex, NULL);
+ conf_free(conf());
+ test_rm_rf(temp_dir);
+ free(temp_dir);
+
+ return 0;
+}
diff --git a/tests/knot/test_zone_events.c b/tests/knot/test_zone_events.c
new file mode 100644
index 0000000..18df288
--- /dev/null
+++ b/tests/knot/test_zone_events.c
@@ -0,0 +1,99 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+
+#include "knot/common/evsched.h"
+#include "knot/worker/pool.h"
+#include "knot/events/events.h"
+#include "knot/zone/zone.h"
+
+static void test_scheduling(zone_t *zone)
+{
+ const time_t now = time(NULL);
+ const unsigned offset = 1000;
+
+ time_t timestamp = 0;
+ zone_event_type_t event = 0;
+
+ timestamp = zone_events_get_next(zone, &event);
+ ok(timestamp < 0 && event == ZONE_EVENT_INVALID, "nothing planned");
+
+ // scheduling
+
+ zone_events_schedule_at(zone, ZONE_EVENT_EXPIRE, now + offset);
+ zone_events_schedule_at(zone, ZONE_EVENT_FLUSH, now + (offset / 2));
+
+ for (int i = 0; i < ZONE_EVENT_COUNT; i++) {
+ time_t t = zone_events_get_time(zone, i);
+ bool scheduled = i == ZONE_EVENT_EXPIRE || i == ZONE_EVENT_FLUSH;
+ const char *name = zone_events_get_name(i);
+
+ ok((t > 0) == scheduled && name, "event %s (%s)", name,
+ scheduled ? "scheduled" : "not scheduled");
+ }
+
+ // queuing
+
+ timestamp = zone_events_get_next(zone, &event);
+ ok(timestamp >= now + (offset / 2) && event == ZONE_EVENT_FLUSH, "flush is next");
+
+ zone_events_schedule_at(zone, ZONE_EVENT_FLUSH, 0);
+
+ timestamp = zone_events_get_next(zone, &event);
+ ok(timestamp >= now + offset && event == ZONE_EVENT_EXPIRE, "expire is next");
+
+ zone_events_schedule_at(zone, ZONE_EVENT_EXPIRE, 0);
+
+ timestamp = zone_events_get_next(zone, &event);
+ ok(timestamp < 0 && event == ZONE_EVENT_INVALID, "nothing planned");
+
+ // zone_events_enqueue
+
+ // zone_events_freeze
+ // zone_events_start
+}
+
+int main(void)
+{
+ plan_lazy();
+
+ int r;
+
+ evsched_t sched = { 0 };
+ worker_pool_t *pool = NULL;
+ zone_t zone = { 0 };
+
+ r = evsched_init(&sched, NULL);
+ ok(r == KNOT_EOK, "create scheduler");
+
+ pool = worker_pool_create(1);
+ ok(pool != NULL, "create worker pool");
+
+ r = zone_events_init(&zone);
+ ok(r == KNOT_EOK, "zone events init");
+
+ r = zone_events_setup(&zone, pool, &sched);
+ ok(r == KNOT_EOK, "zone events setup");
+
+ test_scheduling(&zone);
+
+ zone_events_deinit(&zone);
+ worker_pool_destroy(pool);
+ evsched_deinit(&sched);
+
+ return 0;
+}
diff --git a/tests/knot/test_zone_serial.c b/tests/knot/test_zone_serial.c
new file mode 100644
index 0000000..2d50720
--- /dev/null
+++ b/tests/knot/test_zone_serial.c
@@ -0,0 +1,159 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "knot/zone/serial.h"
+#include "knot/conf/schema.h"
+#include "contrib/strtonum.h"
+
+enum serials {
+ S_LOWEST = 0, // lowest value
+ S_2LOWEST = 1, // second lowest value
+ S_BELOW_MIDDLE = 0x7fffffff, // one below middle
+ S_ABOVE_MIDDLE = 0x80000000, // one above middle
+ S_2HIGHEST = 0xffffffff - 1, // second highest value
+ S_HIGHEST = 0xffffffff // highest value
+};
+
+static uint32_t random_serial(void)
+{
+ uint32_t s = rand() & 0xff;
+ s |= (rand() & 0xff) << 8;
+ s |= (rand() & 0xff) << 16;
+ s |= (rand() & 0xff) << 24;
+
+ return s;
+}
+
+static void check_unixtime(uint32_t current, uint32_t increment, uint32_t expected, const char *msg)
+{
+ uint32_t next = serial_next(current, SERIAL_POLICY_UNIXTIME, increment);
+ ok(next == expected, "unixtime: %s", msg);
+}
+
+/* Test will wrongly fail if the next second starts while running;
+ * this is unlikely, so not taking any action */
+static void test_unixtime(void)
+{
+ time_t serial0 = time(NULL);
+
+ check_unixtime(1000000000, 1, serial0, "from old second or policy");
+ check_unixtime(serial0, 0, serial0, "reuse current second");
+ check_unixtime(serial0, 1, serial0 + 1, "this second's first increment");
+ check_unixtime(serial0 + 1, 1, serial0 + 2, "this second's second increment");
+ check_unixtime(3000000000, 1, 3000000001, "from future second");
+ check_unixtime(3000000000, 0, 3000000000, "at future second");
+}
+
+static void check_dateserial(uint32_t current, uint32_t increment, uint32_t expected, const char *msg)
+{
+ uint32_t next = serial_next(current, SERIAL_POLICY_DATESERIAL, increment);
+ ok(next == expected, "dateserial: %s", msg);
+}
+
+/* Test will wrongly fail if the next day starts while running;
+ * this is EXTREMELY unlikely, so definitely not taking any action */
+static void test_dateserial(void)
+{
+ time_t now = time(NULL);
+
+ struct tm *gm_ret = gmtime(&now);
+
+ char str[32];
+ int ret1 = strftime(str, sizeof(str), "%Y%m%d00", gm_ret);
+
+ uint32_t serial0 = 0;
+ int ret2 = str_to_u32(str, &serial0);
+
+ ok(gm_ret != NULL && ret1 > 0 && ret2 == KNOT_EOK,
+ "dateserial: prepare current value");
+
+ check_dateserial(2000010100, 1, serial0, "from old date or policy");
+ check_dateserial(serial0, 1, serial0 + 1, "today's first increment");
+ check_dateserial(serial0 + 98, 1, serial0 + 99, "today's last increment");
+ check_dateserial(serial0 + 99, 1, serial0 + 100, "wrap from today");
+ check_dateserial(2100010100, 1, 2100010101, "from future date");
+ check_dateserial(2100010100, 0, 2100010100, "at future date");
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ /* Serial compare test. */
+ ok(serial_compare(S_LOWEST, S_BELOW_MIDDLE) == SERIAL_LOWER,
+ "serial compare: lowest < below middle");
+ ok(serial_compare(S_BELOW_MIDDLE, S_LOWEST) == SERIAL_GREATER,
+ "serial compare: below middle > lowest");
+
+ /* Corner-case: these serials' distance is exactly 2^31. */
+ ok(serial_compare(S_LOWEST, S_ABOVE_MIDDLE) == SERIAL_INCOMPARABLE,
+ "serial compare: lowest < above_middle");
+ ok(serial_compare(S_ABOVE_MIDDLE, S_LOWEST) == SERIAL_INCOMPARABLE,
+ "serial compare: above_middle < lowest");
+
+ ok(serial_compare(S_LOWEST, S_HIGHEST) == SERIAL_GREATER,
+ "serial compare: lowest > highest");
+ ok(serial_compare(S_HIGHEST, S_LOWEST) == SERIAL_LOWER,
+ "serial compare: highest < lowest");
+
+ ok(serial_compare(S_2LOWEST, S_ABOVE_MIDDLE) == SERIAL_LOWER,
+ "serial compare: 2nd lowest < above middle");
+ ok(serial_compare(S_ABOVE_MIDDLE, S_2LOWEST) == SERIAL_GREATER,
+ "serial compare: above middle > 2nd lowest");
+
+ /* Corner-case: these serials' distance is exactly 2^31. */
+ ok(serial_compare(S_BELOW_MIDDLE, S_HIGHEST) == SERIAL_INCOMPARABLE,
+ "serial compare: below middle < highest");
+ ok(serial_compare(S_HIGHEST, S_BELOW_MIDDLE) == SERIAL_INCOMPARABLE,
+ "serial compare: highest < below middle");
+
+ ok(serial_compare(S_BELOW_MIDDLE, S_2HIGHEST) == SERIAL_LOWER,
+ "serial compare: below middle < 2nd highest");
+ ok(serial_compare(S_2HIGHEST, S_BELOW_MIDDLE) == SERIAL_GREATER,
+ "serial compare: 2nd highest > below middle");
+
+ ok(serial_compare(S_ABOVE_MIDDLE, S_HIGHEST) == SERIAL_LOWER,
+ "serial compare: above middle < highest");
+ ok(serial_compare(S_HIGHEST, S_ABOVE_MIDDLE) == SERIAL_GREATER,
+ "serial compare: highest > above middle");
+
+ ok(serial_compare(S_LOWEST, S_LOWEST) == SERIAL_EQUAL,
+ "serial compare: lowest == lowest");
+ ok(serial_compare(S_HIGHEST, S_HIGHEST) == SERIAL_EQUAL,
+ "serial compare: highest == highest");
+
+ ok(serial_compare(S_LOWEST - 1, S_HIGHEST) == SERIAL_EQUAL,
+ "serial compare: lowest - 1 == highest");
+ ok(serial_compare(S_LOWEST, S_HIGHEST + 1) == SERIAL_EQUAL,
+ "serial compare: lowest== highest + 1");
+
+ /* Corner-case: these serials' distance is exactly 2^31. */
+ uint32_t s1 = random_serial();
+ uint32_t s2 = s1 + S_ABOVE_MIDDLE; // exactly the 'opposite' number
+ ok(serial_compare(s1, s2) == SERIAL_INCOMPARABLE,
+ "serial compare: random opposites (s1 < s2)");
+ ok(serial_compare(s2, s1) == SERIAL_INCOMPARABLE,
+ "serial compare: random opposites (s2 < s1)");
+
+ test_dateserial();
+ test_unixtime();
+
+ return 0;
+}
diff --git a/tests/knot/test_zone_timers.c b/tests/knot/test_zone_timers.c
new file mode 100644
index 0000000..272733c
--- /dev/null
+++ b/tests/knot/test_zone_timers.c
@@ -0,0 +1,110 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tap/basic.h>
+#include <tap/files.h>
+
+#include "knot/zone/timers.h"
+#include "libknot/db/db_lmdb.h"
+#include "libknot/dname.h"
+#include "libknot/error.h"
+
+static const zone_timers_t MOCK_TIMERS = {
+ .next_refresh = 1474559960,
+ .last_notified_serial = 0,
+ .last_flush = 1,
+ .next_ds_check = 1474559961,
+ .next_ds_push = 1474559962,
+ .catalog_member = 1474559963,
+ .next_expire = 1639727731,
+};
+
+static bool timers_eq(const zone_timers_t *a, const zone_timers_t *b)
+{
+ return a->next_refresh == b->next_refresh &&
+ a->last_notified_serial == b->last_notified_serial &&
+ a->last_flush == b->last_flush &&
+ a->next_ds_check == b->next_ds_check &&
+ a->next_ds_push == b->next_ds_push &&
+ a->catalog_member == b->catalog_member &&
+ a->next_expire == b->next_expire;
+}
+
+static bool keep_all(const knot_dname_t *zone, void *data)
+{
+ return true;
+}
+
+static bool remove_all(const knot_dname_t *zone, void *data)
+{
+ return false;
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+ assert(knot_db_lmdb_api());
+
+ char *dbid = test_mkdtemp();
+ if (!dbid) {
+ return EXIT_FAILURE;
+ }
+
+ const knot_dname_t *zone = (uint8_t *)"\x7""example""\x3""com";
+ struct zone_timers timers = MOCK_TIMERS;
+
+ // Create database
+ knot_lmdb_db_t _db = { 0 }, *db = &_db;
+ knot_lmdb_init(db, dbid, 1024 * 1024, 0, NULL);
+ int ret = knot_lmdb_open(db);
+ ok(ret == KNOT_EOK && db != NULL, "open timers");
+
+ // Lookup nonexistent
+ ret = zone_timers_read(db, zone, &timers);
+ is_int(KNOT_ENOENT, ret, "zone_timer_read() nonexistent");
+
+ // Write timers
+ ret = zone_timers_write(db, zone, &timers);
+ is_int(KNOT_EOK, ret, "zone_timers_write()");
+
+ // Read timers
+ memset(&timers, 0, sizeof(timers));
+ ret = zone_timers_read(db, zone, &timers);
+ ok(ret == KNOT_EOK, "zone_timers_read()");
+ ok(timers_eq(&timers, &MOCK_TIMERS), "inconsistent timers");
+
+ // Sweep none
+ ret = zone_timers_sweep(db, keep_all, NULL);
+ is_int(KNOT_EOK, ret, "zone_timers_sweep() none");
+ ret = zone_timers_read(db, zone, &timers);
+ is_int(KNOT_EOK, ret, "zone_timers_read()");
+
+ // Sweep all
+ ret = zone_timers_sweep(db, remove_all, NULL);
+ is_int(KNOT_EOK, ret, "zone_timers_sweep() all");
+ ret = zone_timers_read(db, zone, &timers);
+ is_int(KNOT_ENOENT, ret, "zone_timers_read() nonexistent");
+
+ // Clean up.
+ knot_lmdb_deinit(db);
+ test_rm_rf(dbid);
+ free(dbid);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/knot/test_zonedb.c b/tests/knot/test_zonedb.c
new file mode 100644
index 0000000..3ef7632
--- /dev/null
+++ b/tests/knot/test_zonedb.c
@@ -0,0 +1,115 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+
+#include "knot/zone/zone.h"
+#include "knot/zone/zonedb.h"
+#include "contrib/openbsd/strlcat.h"
+#include "contrib/openbsd/strlcpy.h"
+
+#define ZONE_COUNT 10
+static const char *zone_list[ZONE_COUNT] = {
+ ".",
+ "com",
+ "net",
+ "c.com",
+ "a.com",
+ "a.net",
+ "b.net",
+ "c.a.com",
+ "b.b.b.com",
+ "b.b.b.b.net",
+};
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ /* Create database. */
+ knot_dname_txt_storage_t buf;
+ const char *prefix = "zzz.";
+ size_t nr_passed = 0;
+ knot_dname_t *dname = NULL;
+ zone_t *zones[ZONE_COUNT] = {0};
+ knot_zonedb_t *db = knot_zonedb_new();
+ ok(db != NULL, "zonedb: new");
+
+ /* Populate. */
+ for (unsigned i = 0; i < ZONE_COUNT; ++i) {
+ knot_dname_t *zone_name = knot_dname_from_str_alloc(zone_list[i]);
+ zones[i] = zone_new(zone_name);
+ knot_dname_free(zone_name, NULL);
+
+ if (zones[i] == NULL) {
+ goto cleanup;
+ }
+ if (knot_zonedb_insert(db, zones[i]) == KNOT_EOK) {
+ ++nr_passed;
+ } else {
+ diag("knot_zonedb_add_zone(%s) failed", zone_list[i]);
+ }
+ }
+ ok(nr_passed == ZONE_COUNT, "zonedb: add zones");
+
+ /* Lookup of exact names. */
+ nr_passed = 0;
+ for (unsigned i = 0; i < ZONE_COUNT; ++i) {
+ dname = knot_dname_from_str_alloc(zone_list[i]);
+ if (knot_zonedb_find(db, dname) == zones[i]) {
+ ++nr_passed;
+ } else {
+ diag("knot_zonedb_find(%s) failed", zone_list[i]);
+ }
+ knot_dname_free(dname, NULL);
+ }
+ ok(nr_passed == ZONE_COUNT, "zonedb: find exact zones");
+
+ /* Lookup of sub-names. */
+ nr_passed = 0;
+ for (unsigned i = 0; i < ZONE_COUNT; ++i) {
+ strlcpy(buf, prefix, sizeof(buf));
+ if (strcmp(zone_list[i], ".") != 0) {
+ strlcat(buf, zone_list[i], sizeof(buf));
+ }
+ dname = knot_dname_from_str_alloc(buf);
+ if (knot_zonedb_find_suffix(db, dname) == zones[i]) {
+ ++nr_passed;
+ } else {
+ diag("knot_zonedb_find_suffix(%s) failed", buf);
+ }
+ knot_dname_free(dname, NULL);
+ }
+ ok(nr_passed == ZONE_COUNT, "zonedb: find zones for subnames");
+
+ /* Remove all zones. */
+ nr_passed = 0;
+ for (unsigned i = 0; i < ZONE_COUNT; ++i) {
+ dname = knot_dname_from_str_alloc(zone_list[i]);
+ if (knot_zonedb_del(db, dname) == KNOT_EOK) {
+ zone_free(&zones[i]);
+ ++nr_passed;
+ } else {
+ diag("knot_zonedb_remove_zone(%s) failed", zone_list[i]);
+ }
+ knot_dname_free(dname, NULL);
+ }
+ ok(nr_passed == ZONE_COUNT, "zonedb: removed all zones");
+
+cleanup:
+ knot_zonedb_deep_free(&db, false);
+ return 0;
+}