From 45d6379135504814ab723b57f0eb8be23393a51d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 09:24:22 +0200 Subject: Adding upstream version 1:9.16.44. Signed-off-by: Daniel Baumann --- .clang-format | 76 + .clang-format.headers | 64 + .dir-locals.el | 120 + .gitattributes | 13 + .github/workflows/codeql.yml | 55 + .github/workflows/sonarcloud.yml | 50 + .gitlab-ci.yml | 1800 ++ .gitlab/issue_templates/Bug.md | 46 + .gitlab/issue_templates/Feature_Request.md | 11 + .gitlab/issue_templates/Release.md | 65 + .pylintrc | 9 + .readthedocs.yaml | 20 + .reuse/dep5 | 233 + .reuse/templates/isc.jinja2 | 16 + .tsan-suppress | 2 + .uncrustify.cfg | 1434 + CHANGES | 19658 ++++++++++++++ CODE_OF_CONDUCT | 79 + CODE_OF_CONDUCT.md | 84 + CONTRIBUTING | 189 + CONTRIBUTING.md | 208 + COPYRIGHT | 369 + HISTORY | 600 + HISTORY.md | 617 + Kyuafile | 15 + LICENSE | 362 + LICENSES/Apache-2.0.txt | 73 + LICENSES/Autoconf-exception-3.0.txt | 26 + LICENSES/BSD-2-Clause.txt | 9 + LICENSES/BSD-3-Clause.txt | 11 + LICENSES/CC0-1.0.txt | 121 + LICENSES/FSFAP.txt | 1 + LICENSES/GPL-3.0-or-later.txt | 232 + LICENSES/ISC.txt | 8 + LICENSES/LLVM-exception.txt | 15 + LICENSES/MIT.txt | 9 + LICENSES/MPL-2.0.txt | 144 + Makefile.in | 111 + OPTIONS | 28 + OPTIONS.md | 29 + README | 244 + README.md | 259 + aclocal.m4 | 388 + autogen.sh | 15 + bin/Makefile.in | 20 + bin/check/Makefile.in | 88 + bin/check/check-tool.c | 812 + bin/check/check-tool.h | 62 + bin/check/named-checkconf.c | 771 + bin/check/named-checkconf.rst | 95 + bin/check/named-checkzone.c | 569 + bin/check/named-checkzone.rst | 193 + bin/check/named-compilezone.rst | 195 + bin/check/win32/checkconf.vcxproj.filters.in | 27 + bin/check/win32/checkconf.vcxproj.in | 124 + bin/check/win32/checkconf.vcxproj.user | 3 + bin/check/win32/checktool.vcxproj.filters.in | 18 + bin/check/win32/checktool.vcxproj.in | 110 + bin/check/win32/checktool.vcxproj.user | 3 + bin/check/win32/checkzone.vcxproj.filters.in | 27 + bin/check/win32/checkzone.vcxproj.in | 135 + bin/check/win32/checkzone.vcxproj.user | 3 + bin/confgen/Makefile.in | 97 + bin/confgen/ddns-confgen.c | 311 + bin/confgen/ddns-confgen.rst | 88 + bin/confgen/include/.clang-format | 1 + bin/confgen/include/confgen/os.h | 36 + bin/confgen/keygen.c | 204 + bin/confgen/keygen.h | 44 + bin/confgen/rndc-confgen.c | 284 + bin/confgen/rndc-confgen.rst | 106 + bin/confgen/tsig-keygen.rst | 50 + bin/confgen/unix/Makefile.in | 30 + bin/confgen/unix/os.c | 36 + bin/confgen/util.c | 49 + bin/confgen/util.h | 46 + bin/confgen/win32/confgentool.vcxproj.filters.in | 39 + bin/confgen/win32/confgentool.vcxproj.in | 120 + bin/confgen/win32/confgentool.vcxproj.user | 3 + bin/confgen/win32/ddnsconfgen.vcxproj.filters.in | 18 + bin/confgen/win32/ddnsconfgen.vcxproj.in | 132 + bin/confgen/win32/ddnsconfgen.vcxproj.user | 3 + bin/confgen/win32/os.c | 27 + bin/confgen/win32/rndcconfgen.vcxproj.filters.in | 18 + bin/confgen/win32/rndcconfgen.vcxproj.in | 121 + bin/confgen/win32/rndcconfgen.vcxproj.user | 3 + bin/delv/Makefile.in | 70 + bin/delv/delv.c | 1889 ++ bin/delv/delv.rst | 326 + bin/delv/win32/delv.vcxproj.filters.in | 22 + bin/delv/win32/delv.vcxproj.in | 119 + bin/delv/win32/delv.vcxproj.user | 3 + bin/dig/Makefile.in | 98 + bin/dig/dig.c | 2728 ++ bin/dig/dig.rst | 645 + bin/dig/dighost.c | 4604 ++++ bin/dig/host.c | 927 + bin/dig/host.rst | 171 + bin/dig/include/.clang-format | 1 + bin/dig/include/dig/dig.h | 425 + bin/dig/nslookup.c | 1047 + bin/dig/nslookup.rst | 206 + bin/dig/win32/dig.vcxproj.filters.in | 27 + bin/dig/win32/dig.vcxproj.in | 122 + bin/dig/win32/dig.vcxproj.user | 3 + bin/dig/win32/dighost.vcxproj.filters.in | 18 + bin/dig/win32/dighost.vcxproj.in | 115 + bin/dig/win32/dighost.vcxproj.user | 3 + bin/dig/win32/host.vcxproj.filters.in | 18 + bin/dig/win32/host.vcxproj.in | 119 + bin/dig/win32/host.vcxproj.user | 3 + bin/dig/win32/nslookup.vcxproj.filters.in | 21 + bin/dig/win32/nslookup.vcxproj.in | 120 + bin/dig/win32/nslookup.vcxproj.user | 3 + bin/dnssec/Makefile.in | 112 + bin/dnssec/dnssec-cds.c | 1314 + bin/dnssec/dnssec-cds.rst | 203 + bin/dnssec/dnssec-dsfromkey.c | 568 + bin/dnssec/dnssec-dsfromkey.rst | 144 + bin/dnssec/dnssec-importkey.c | 485 + bin/dnssec/dnssec-importkey.rst | 113 + bin/dnssec/dnssec-keyfromlabel.c | 782 + bin/dnssec/dnssec-keyfromlabel.rst | 262 + bin/dnssec/dnssec-keygen.c | 1315 + bin/dnssec/dnssec-keygen.rst | 318 + bin/dnssec/dnssec-revoke.c | 278 + bin/dnssec/dnssec-revoke.rst | 71 + bin/dnssec/dnssec-settime.c | 985 + bin/dnssec/dnssec-settime.rst | 231 + bin/dnssec/dnssec-signzone.c | 4197 +++ bin/dnssec/dnssec-signzone.rst | 396 + bin/dnssec/dnssec-verify.c | 366 + bin/dnssec/dnssec-verify.rst | 98 + bin/dnssec/dnssectool.c | 594 + bin/dnssec/dnssectool.h | 119 + bin/dnssec/win32/cds.vcxproj.filters.in | 18 + bin/dnssec/win32/cds.vcxproj.in | 121 + bin/dnssec/win32/cds.vcxproj.user | 3 + bin/dnssec/win32/dnssectool.vcxproj.filters.in | 27 + bin/dnssec/win32/dnssectool.vcxproj.in | 118 + bin/dnssec/win32/dnssectool.vcxproj.user | 3 + bin/dnssec/win32/dsfromkey.vcxproj.filters.in | 18 + bin/dnssec/win32/dsfromkey.vcxproj.in | 147 + bin/dnssec/win32/dsfromkey.vcxproj.user | 3 + bin/dnssec/win32/importkey.vcxproj.filters.in | 18 + bin/dnssec/win32/importkey.vcxproj.in | 121 + bin/dnssec/win32/importkey.vcxproj.user | 3 + bin/dnssec/win32/keyfromlabel.vcxproj.filters.in | 18 + bin/dnssec/win32/keyfromlabel.vcxproj.in | 121 + bin/dnssec/win32/keyfromlabel.vcxproj.user | 3 + bin/dnssec/win32/keygen.vcxproj.filters.in | 18 + bin/dnssec/win32/keygen.vcxproj.in | 121 + bin/dnssec/win32/keygen.vcxproj.user | 3 + bin/dnssec/win32/revoke.vcxproj.filters.in | 18 + bin/dnssec/win32/revoke.vcxproj.in | 121 + bin/dnssec/win32/revoke.vcxproj.user | 3 + bin/dnssec/win32/settime.vcxproj.filters.in | 18 + bin/dnssec/win32/settime.vcxproj.in | 121 + bin/dnssec/win32/settime.vcxproj.user | 3 + bin/dnssec/win32/signzone.vcxproj.filters.in | 18 + bin/dnssec/win32/signzone.vcxproj.in | 121 + bin/dnssec/win32/signzone.vcxproj.user | 3 + bin/dnssec/win32/verify.vcxproj.filters.in | 18 + bin/dnssec/win32/verify.vcxproj.in | 121 + bin/dnssec/win32/verify.vcxproj.user | 3 + bin/named/Makefile.in | 180 + bin/named/bind9.xsl | 1144 + bin/named/bind9.xsl.h | 1267 + bin/named/builtin.c | 592 + bin/named/config.c | 1090 + bin/named/control.c | 311 + bin/named/controlconf.c | 1563 ++ bin/named/convertxsl.pl | 53 + bin/named/fuzz.c | 782 + bin/named/geoip.c | 146 + bin/named/include/.clang-format | 1 + bin/named/include/dlz/dlz_dlopen_driver.h | 22 + bin/named/include/named/builtin.h | 27 + bin/named/include/named/config.h | 88 + bin/named/include/named/control.h | 111 + bin/named/include/named/fuzz.h | 25 + bin/named/include/named/geoip.h | 28 + bin/named/include/named/globals.h | 162 + bin/named/include/named/log.h | 79 + bin/named/include/named/logconf.h | 28 + bin/named/include/named/main.h | 38 + bin/named/include/named/server.h | 397 + bin/named/include/named/smf_globals.h | 41 + bin/named/include/named/statschannel.h | 54 + bin/named/include/named/tkeyconf.h | 46 + bin/named/include/named/tsigconf.h | 44 + bin/named/include/named/types.h | 41 + bin/named/include/named/zoneconf.h | 79 + bin/named/log.c | 212 + bin/named/logconf.c | 373 + bin/named/main.c | 1788 ++ bin/named/named.conf.rst | 1082 + bin/named/named.rst | 248 + bin/named/server.c | 16272 +++++++++++ bin/named/statschannel.c | 4224 +++ bin/named/tkeyconf.c | 115 + bin/named/tsigconf.c | 181 + bin/named/unix/Makefile.in | 32 + bin/named/unix/dlz_dlopen_driver.c | 596 + bin/named/unix/include/.clang-format | 1 + bin/named/unix/include/named/os.h | 81 + bin/named/unix/os.c | 940 + bin/named/win32/dlz_dlopen_driver.c | 578 + bin/named/win32/include/.clang-format | 1 + bin/named/win32/include/named/ntservice.h | 31 + bin/named/win32/include/named/os.h | 78 + bin/named/win32/named.vcxproj.filters.in | 121 + bin/named/win32/named.vcxproj.in | 156 + bin/named/win32/named.vcxproj.user | 3 + bin/named/win32/ntservice.c | 190 + bin/named/win32/os.c | 473 + bin/named/zoneconf.c | 2173 ++ bin/nsupdate/Makefile.in | 86 + bin/nsupdate/nsupdate.c | 3491 +++ bin/nsupdate/nsupdate.rst | 357 + bin/nsupdate/win32/nsupdate.vcxproj.filters.in | 18 + bin/nsupdate/win32/nsupdate.vcxproj.in | 119 + bin/nsupdate/win32/nsupdate.vcxproj.user | 3 + bin/pkcs11/Makefile.in | 82 + bin/pkcs11/pkcs11-destroy.c | 268 + bin/pkcs11/pkcs11-destroy.rst | 61 + bin/pkcs11/pkcs11-keygen.c | 476 + bin/pkcs11/pkcs11-keygen.rst | 80 + bin/pkcs11/pkcs11-list.c | 277 + bin/pkcs11/pkcs11-list.rst | 56 + bin/pkcs11/pkcs11-tokens.c | 103 + bin/pkcs11/pkcs11-tokens.rst | 43 + bin/pkcs11/win32/pk11destroy.vcxproj.filters.in | 22 + bin/pkcs11/win32/pk11destroy.vcxproj.in | 121 + bin/pkcs11/win32/pk11destroy.vcxproj.user | 3 + bin/pkcs11/win32/pk11keygen.vcxproj.filters.in | 22 + bin/pkcs11/win32/pk11keygen.vcxproj.in | 121 + bin/pkcs11/win32/pk11keygen.vcxproj.user | 3 + bin/pkcs11/win32/pk11list.vcxproj.filters.in | 22 + bin/pkcs11/win32/pk11list.vcxproj.in | 121 + bin/pkcs11/win32/pk11list.vcxproj.user | 3 + bin/pkcs11/win32/pk11tokens.vcxproj.filters.in | 22 + bin/pkcs11/win32/pk11tokens.vcxproj.in | 121 + bin/pkcs11/win32/pk11tokens.vcxproj.user | 3 + bin/plugins/Makefile.in | 67 + bin/plugins/filter-aaaa.c | 881 + bin/plugins/filter-aaaa.rst | 89 + bin/python/Makefile.in | 66 + bin/python/dnssec-checkds.py.in | 32 + bin/python/dnssec-checkds.rst | 68 + bin/python/dnssec-coverage.py.in | 32 + bin/python/dnssec-coverage.rst | 152 + bin/python/dnssec-keymgr.py.in | 32 + bin/python/dnssec-keymgr.rst | 223 + bin/python/isc/Makefile.in | 45 + bin/python/isc/__init__.py.in | 38 + bin/python/isc/checkds.py.in | 226 + bin/python/isc/coverage.py.in | 333 + bin/python/isc/dnskey.py.in | 570 + bin/python/isc/eventlist.py.in | 178 + bin/python/isc/keydict.py.in | 87 + bin/python/isc/keyevent.py.in | 80 + bin/python/isc/keymgr.py.in | 207 + bin/python/isc/keyseries.py.in | 232 + bin/python/isc/keyzone.py.in | 59 + bin/python/isc/policy.py.in | 761 + bin/python/isc/rndc.py.in | 193 + bin/python/isc/tests/Makefile.in | 33 + bin/python/isc/tests/dnskey_test.py.in | 54 + bin/python/isc/tests/policy_test.py.in | 104 + bin/python/isc/tests/test-policies/01-keysize.pol | 54 + .../isc/tests/test-policies/02-prepublish.pol | 44 + .../isc/tests/test-policies/03-postpublish.pol | 44 + .../tests/test-policies/04-combined-pre-post.pol | 68 + .../isc/tests/test-policies/05-numeric-zone.pol | 17 + .../isc/tests/testdata/Kexample.com.+007+35529.key | 8 + .../tests/testdata/Kexample.com.+007+35529.private | 18 + bin/python/isc/utils.py.in | 71 + bin/python/setup.py | 28 + bin/rndc/Makefile.in | 74 + bin/rndc/include/.clang-format | 1 + bin/rndc/include/rndc/os.h | 36 + bin/rndc/rndc.c | 1105 + bin/rndc/rndc.conf | 41 + bin/rndc/rndc.conf.rst | 156 + bin/rndc/rndc.rst | 608 + bin/rndc/util.c | 49 + bin/rndc/util.h | 46 + bin/rndc/win32/rndc.vcxproj.filters.in | 27 + bin/rndc/win32/rndc.vcxproj.in | 122 + bin/rndc/win32/rndc.vcxproj.user | 3 + bin/rndc/win32/rndcutil.vcxproj.filters.in | 27 + bin/rndc/win32/rndcutil.vcxproj.in | 113 + bin/rndc/win32/rndcutil.vcxproj.user | 3 + bin/tests/Makefile.in | 87 + bin/tests/bigtest/README | 18 + bin/tests/bigtest/buildzones.sh | 269 + bin/tests/bigtest/rndc.key | 5 + bin/tests/bigtest/tests.sh | 78 + bin/tests/bigtest/zones | 18 + bin/tests/cfg_test.c | 195 + bin/tests/headerdep_test.sh.in | 51 + bin/tests/makejournal.c | 160 + bin/tests/named.conf | 619 + bin/tests/optional/Kchild.example.+005+33180.key | 5 + .../optional/Kchild.example.+005+33180.private | 13 + bin/tests/optional/Makefile.in | 254 + bin/tests/optional/adb_test.c | 410 + bin/tests/optional/backtrace_test.c | 88 + bin/tests/optional/byaddr_test.c | 250 + bin/tests/optional/byname_test.c | 350 + bin/tests/optional/db_test.c | 983 + bin/tests/optional/fsaccess_test.c | 69 + bin/tests/optional/gsstest.c | 550 + bin/tests/optional/inter_test.c | 133 + bin/tests/optional/lex_test.c | 159 + bin/tests/optional/lfsr_test.c | 93 + bin/tests/optional/log_test.c | 344 + bin/tests/optional/master_test.c | 88 + bin/tests/optional/mempool_test.c | 112 + bin/tests/optional/name_test.c | 365 + bin/tests/optional/nsecify.c | 217 + bin/tests/optional/ratelimiter_test.c | 142 + bin/tests/optional/rbt_test.c | 432 + bin/tests/optional/rbt_test.out | 395 + bin/tests/optional/rbt_test.txt | 87 + bin/tests/optional/rwlock_test.c | 130 + bin/tests/optional/serial_test.c | 45 + bin/tests/optional/shutdown_test.c | 226 + bin/tests/optional/sig0_test.c | 282 + bin/tests/optional/sock_test.c | 394 + bin/tests/optional/sym_test.c | 122 + bin/tests/optional/task_test.c | 207 + bin/tests/optional/timer_test.c | 184 + bin/tests/optional/zone_test.c | 318 + bin/tests/pkcs11/Makefile.in | 32 + bin/tests/pkcs11/README | 15 + bin/tests/pkcs11/benchmarks/Makefile.in | 74 + bin/tests/pkcs11/benchmarks/create.c | 264 + bin/tests/pkcs11/benchmarks/find.c | 230 + bin/tests/pkcs11/benchmarks/genrsa.c | 296 + bin/tests/pkcs11/benchmarks/login.c | 251 + bin/tests/pkcs11/benchmarks/privrsa.c | 332 + bin/tests/pkcs11/benchmarks/pubrsa.c | 278 + bin/tests/pkcs11/benchmarks/session.c | 218 + bin/tests/pkcs11/benchmarks/sha1.c | 217 + bin/tests/pkcs11/benchmarks/sign.c | 336 + bin/tests/pkcs11/benchmarks/verify.c | 285 + bin/tests/prepare-softhsm2.sh | 22 + bin/tests/startperf/README | 30 + bin/tests/startperf/clean.sh | 15 + bin/tests/startperf/makenames.pl | 30 + bin/tests/startperf/mkzonefile.pl | 47 + bin/tests/startperf/setup.sh | 82 + bin/tests/startperf/smallzone.db | 28 + bin/tests/system/Makefile.in | 108 + bin/tests/system/README | 724 + bin/tests/system/acl/clean.sh | 26 + bin/tests/system/acl/ns2/named1.conf.in | 61 + bin/tests/system/acl/ns2/named2.conf.in | 65 + bin/tests/system/acl/ns2/named3.conf.in | 74 + bin/tests/system/acl/ns2/named4.conf.in | 73 + bin/tests/system/acl/ns2/named5.conf.in | 63 + bin/tests/system/acl/ns3/example.db | 21 + bin/tests/system/acl/ns3/named.conf.in | 35 + bin/tests/system/acl/ns4/example.db | 21 + bin/tests/system/acl/ns4/existing.db | 21 + bin/tests/system/acl/ns4/named.conf.in | 40 + bin/tests/system/acl/setup.sh | 22 + bin/tests/system/acl/tests.sh | 228 + bin/tests/system/additional/clean.sh | 23 + bin/tests/system/additional/ns1/mx.db | 18 + bin/tests/system/additional/ns1/named.args | 2 + bin/tests/system/additional/ns1/named1.conf.in | 62 + bin/tests/system/additional/ns1/named2.conf.in | 62 + bin/tests/system/additional/ns1/named3.conf.in | 63 + bin/tests/system/additional/ns1/named4.conf.in | 72 + bin/tests/system/additional/ns1/naptr.db | 20 + bin/tests/system/additional/ns1/naptr2.db | 20 + bin/tests/system/additional/ns1/nid.db | 21 + bin/tests/system/additional/ns1/root.db | 21 + bin/tests/system/additional/ns1/rt.db | 21 + bin/tests/system/additional/ns1/rt2.db | 20 + bin/tests/system/additional/ns1/srv.db | 18 + bin/tests/system/additional/ns2/named.conf.in | 30 + bin/tests/system/additional/ns2/root.db | 21 + bin/tests/system/additional/ns3/ex.db | 16 + bin/tests/system/additional/ns3/ex2.db | 15 + bin/tests/system/additional/ns3/named.conf.in | 42 + bin/tests/system/additional/ns3/root.hint | 13 + bin/tests/system/additional/setup.sh | 20 + bin/tests/system/additional/tests.sh | 378 + bin/tests/system/addzone/clean.sh | 44 + bin/tests/system/addzone/ns1/inlinesec.db | 26 + bin/tests/system/addzone/ns1/named.conf.in | 46 + bin/tests/system/addzone/ns1/redirect.db.1 | 13 + bin/tests/system/addzone/ns1/redirect.db.2 | 13 + bin/tests/system/addzone/ns2/added.db | 26 + bin/tests/system/addzone/ns2/default.nzf.in | 14 + bin/tests/system/addzone/ns2/hints.db | 14 + bin/tests/system/addzone/ns2/inline.db | 26 + bin/tests/system/addzone/ns2/named1.conf.in | 43 + bin/tests/system/addzone/ns2/named2.conf.in | 67 + bin/tests/system/addzone/ns2/named3.conf.in | 77 + bin/tests/system/addzone/ns2/normal.db | 26 + bin/tests/system/addzone/ns2/previous.db | 26 + bin/tests/system/addzone/ns2/redirect.db.1 | 13 + bin/tests/system/addzone/ns2/redirect.db.2 | 13 + bin/tests/system/addzone/ns3/e.db | 14 + bin/tests/system/addzone/ns3/example.db | 13 + bin/tests/system/addzone/ns3/named1.conf.in | 37 + bin/tests/system/addzone/ns3/named2.conf.in | 28 + bin/tests/system/addzone/ns3/redirect.db.1 | 14 + bin/tests/system/addzone/ns3/redirect.db.2 | 14 + bin/tests/system/addzone/setup.sh | 26 + bin/tests/system/addzone/tests.sh | 755 + bin/tests/system/addzone/tests_rndc_deadlock.py | 92 + bin/tests/system/allow-query/clean.sh | 24 + bin/tests/system/allow-query/ns1/named.conf.in | 25 + bin/tests/system/allow-query/ns1/root.db | 18 + bin/tests/system/allow-query/ns2/generic.db | 33 + bin/tests/system/allow-query/ns2/named01.conf.in | 32 + bin/tests/system/allow-query/ns2/named02.conf.in | 33 + bin/tests/system/allow-query/ns2/named03.conf.in | 33 + bin/tests/system/allow-query/ns2/named04.conf.in | 33 + bin/tests/system/allow-query/ns2/named05.conf.in | 33 + bin/tests/system/allow-query/ns2/named06.conf.in | 33 + bin/tests/system/allow-query/ns2/named07.conf.in | 35 + bin/tests/system/allow-query/ns2/named08.conf.in | 35 + bin/tests/system/allow-query/ns2/named09.conf.in | 35 + bin/tests/system/allow-query/ns2/named10.conf.in | 38 + bin/tests/system/allow-query/ns2/named11.conf.in | 44 + bin/tests/system/allow-query/ns2/named12.conf.in | 38 + bin/tests/system/allow-query/ns2/named21.conf.in | 35 + bin/tests/system/allow-query/ns2/named22.conf.in | 38 + bin/tests/system/allow-query/ns2/named23.conf.in | 37 + bin/tests/system/allow-query/ns2/named24.conf.in | 37 + bin/tests/system/allow-query/ns2/named25.conf.in | 37 + bin/tests/system/allow-query/ns2/named26.conf.in | 37 + bin/tests/system/allow-query/ns2/named27.conf.in | 40 + bin/tests/system/allow-query/ns2/named28.conf.in | 39 + bin/tests/system/allow-query/ns2/named29.conf.in | 39 + bin/tests/system/allow-query/ns2/named30.conf.in | 42 + bin/tests/system/allow-query/ns2/named31.conf.in | 49 + bin/tests/system/allow-query/ns2/named32.conf.in | 42 + bin/tests/system/allow-query/ns2/named33.conf.in | 39 + bin/tests/system/allow-query/ns2/named34.conf.in | 38 + bin/tests/system/allow-query/ns2/named40.conf.in | 107 + bin/tests/system/allow-query/ns2/named53.conf.in | 34 + bin/tests/system/allow-query/ns2/named54.conf.in | 34 + bin/tests/system/allow-query/ns2/named55.conf.in | 39 + bin/tests/system/allow-query/ns2/named56.conf.in | 38 + bin/tests/system/allow-query/ns2/named57.conf.in | 42 + bin/tests/system/allow-query/ns3/named.args | 2 + bin/tests/system/allow-query/ns3/named1.conf.in | 35 + bin/tests/system/allow-query/ns3/named2.conf.in | 38 + bin/tests/system/allow-query/ns3/named3.conf.in | 38 + bin/tests/system/allow-query/ns3/named4.conf.in | 38 + bin/tests/system/allow-query/setup.sh | 20 + bin/tests/system/allow-query/tests.sh | 688 + bin/tests/system/ans.pl | 531 + bin/tests/system/auth/clean.sh | 20 + bin/tests/system/auth/ns1/chaos.db | 23 + bin/tests/system/auth/ns1/example.com.db | 25 + bin/tests/system/auth/ns1/example.net.db | 22 + bin/tests/system/auth/ns1/named.conf.in | 43 + bin/tests/system/auth/ns2/named.conf.in | 36 + bin/tests/system/auth/setup.sh | 18 + bin/tests/system/auth/tests.sh | 191 + bin/tests/system/autosign/clean.sh | 75 + bin/tests/system/autosign/ns1/keygen.sh | 54 + bin/tests/system/autosign/ns1/named.conf.in | 47 + bin/tests/system/autosign/ns1/root.db.in | 26 + bin/tests/system/autosign/ns2/Xbar.+013+59973.key | 5 + .../system/autosign/ns2/Xbar.+013+59973.private | 6 + bin/tests/system/autosign/ns2/Xbar.+013+60101.key | 5 + .../system/autosign/ns2/Xbar.+013+60101.private | 6 + bin/tests/system/autosign/ns2/bar.db.in | 80 + .../system/autosign/ns2/child.nsec3.example.db | 20 + .../system/autosign/ns2/child.optout.example.db | 20 + bin/tests/system/autosign/ns2/dst.example.db.in | 21 + bin/tests/system/autosign/ns2/example.db.in | 88 + .../system/autosign/ns2/insecure.secure.example.db | 26 + bin/tests/system/autosign/ns2/keygen.sh | 66 + bin/tests/system/autosign/ns2/named.conf.in | 108 + .../system/autosign/ns2/optout-with-ent.db.in | 22 + .../autosign/ns2/private.secure.example.db.in | 27 + .../system/autosign/ns3/autonsec3.example.db.in | 37 + .../autosign/ns3/cdnskey-delete.example.db.in | 28 + .../system/autosign/ns3/cds-delete.example.db.in | 28 + bin/tests/system/autosign/ns3/delay.example.db | 26 + bin/tests/system/autosign/ns3/delzsk.example.db.in | 25 + .../autosign/ns3/dname-at-apex-nsec3.example.db.in | 16 + .../system/autosign/ns3/inacksk2.example.db.in | 26 + .../system/autosign/ns3/inacksk3.example.db.in | 26 + .../system/autosign/ns3/inaczsk.example.db.in | 26 + .../system/autosign/ns3/inaczsk2.example.db.in | 26 + .../system/autosign/ns3/inaczsk3.example.db.in | 26 + bin/tests/system/autosign/ns3/insecure.example.db | 26 + .../system/autosign/ns3/jitter.nsec3.example.db.in | 22 + bin/tests/system/autosign/ns3/keygen.sh | 399 + .../system/autosign/ns3/kskonly.example.db.in | 34 + bin/tests/system/autosign/ns3/named.conf.in | 334 + bin/tests/system/autosign/ns3/noksk.example.db.in | 26 + bin/tests/system/autosign/ns3/nozsk.example.db.in | 26 + .../system/autosign/ns3/nsec-only.example.db.in | 26 + .../autosign/ns3/nsec3-to-nsec.example.db.in | 26 + bin/tests/system/autosign/ns3/nsec3.example.db.in | 37 + .../system/autosign/ns3/nsec3.nsec3.example.db.in | 35 + .../system/autosign/ns3/nsec3.optout.example.db.in | 35 + .../system/autosign/ns3/oldsigs.example.db.in | 26 + bin/tests/system/autosign/ns3/optout.example.db.in | 38 + .../system/autosign/ns3/optout.nsec3.example.db.in | 35 + .../autosign/ns3/optout.optout.example.db.in | 35 + .../system/autosign/ns3/rsasha256.example.db.in | 28 + .../system/autosign/ns3/rsasha512.example.db.in | 28 + .../autosign/ns3/secure-to-insecure.example.db.in | 26 + .../autosign/ns3/secure-to-insecure2.example.db.in | 26 + bin/tests/system/autosign/ns3/secure.example.db.in | 37 + .../system/autosign/ns3/secure.nsec3.example.db.in | 35 + .../autosign/ns3/secure.optout.example.db.in | 35 + bin/tests/system/autosign/ns3/sync.example.db.in | 34 + bin/tests/system/autosign/ns3/ttl1.example.db.in | 26 + bin/tests/system/autosign/ns3/ttl2.example.db.in | 26 + bin/tests/system/autosign/ns3/ttl3.example.db.in | 26 + bin/tests/system/autosign/ns3/ttl4.example.db.in | 26 + bin/tests/system/autosign/ns4/named.conf.in | 35 + bin/tests/system/autosign/ns5/named.conf.in | 33 + bin/tests/system/autosign/setup.sh | 24 + bin/tests/system/autosign/tests.sh | 1788 ++ bin/tests/system/builtin/clean.sh | 20 + bin/tests/system/builtin/ns1/named.conf.in | 30 + bin/tests/system/builtin/ns2/named.conf.in | 31 + bin/tests/system/builtin/ns3/named.conf.in | 33 + bin/tests/system/builtin/setup.sh | 19 + bin/tests/system/builtin/tests.sh | 247 + bin/tests/system/cacheclean/clean.sh | 27 + bin/tests/system/cacheclean/dig.batch | 924 + bin/tests/system/cacheclean/knowngood.dig.out | 953 + bin/tests/system/cacheclean/ns1/example.db | 2942 ++ bin/tests/system/cacheclean/ns1/expire-test.db | 21 + bin/tests/system/cacheclean/ns1/flushtest.db | 44 + bin/tests/system/cacheclean/ns1/named.args | 1 + bin/tests/system/cacheclean/ns1/named.conf.in | 42 + bin/tests/system/cacheclean/ns2/named.args | 1 + bin/tests/system/cacheclean/ns2/named.conf.in | 50 + bin/tests/system/cacheclean/setup.sh | 18 + bin/tests/system/cacheclean/tests.sh | 268 + bin/tests/system/case/clean.sh | 24 + bin/tests/system/case/dynamic.good | 6 + bin/tests/system/case/ns1/dynamic.db.in | 26 + bin/tests/system/case/ns1/example.db | 23 + bin/tests/system/case/ns1/named.conf.in | 40 + bin/tests/system/case/ns2/named.conf.in | 40 + bin/tests/system/case/postns1.good | 6 + bin/tests/system/case/postupdate.good | 6 + bin/tests/system/case/setup.sh | 19 + bin/tests/system/case/tests.sh | 150 + bin/tests/system/catz/clean.sh | 32 + bin/tests/system/catz/ns1/catalog.example.db.in | 14 + bin/tests/system/catz/ns1/named.conf.in | 72 + bin/tests/system/catz/ns2/named1.conf.in | 98 + bin/tests/system/catz/ns2/named2.conf.in | 62 + bin/tests/system/catz/ns3/catalog.example.db.in | 14 + bin/tests/system/catz/ns3/dom5.example.db | 13 + bin/tests/system/catz/ns3/dom6.example.db | 13 + bin/tests/system/catz/ns3/named.conf.in | 57 + bin/tests/system/catz/ns4/catalog.example.db.in | 14 + bin/tests/system/catz/ns4/named.conf.in | 55 + bin/tests/system/catz/setup.sh | 30 + bin/tests/system/catz/tests.sh | 1915 ++ bin/tests/system/cds/checkmtime.pl | 18 + bin/tests/system/cds/checktime.pl | 27 + bin/tests/system/cds/clean.sh | 23 + bin/tests/system/cds/mangle.pl | 19 + bin/tests/system/cds/setup.sh | 133 + bin/tests/system/cds/tests.sh | 243 + bin/tests/system/chain/README | 22 + bin/tests/system/chain/ans3/ans.pl | 131 + bin/tests/system/chain/ans4/README.anspy | 24 + bin/tests/system/chain/ans4/ans.py | 386 + bin/tests/system/chain/clean.sh | 18 + bin/tests/system/chain/ns1/named.conf.in | 27 + bin/tests/system/chain/ns1/root.db | 51 + bin/tests/system/chain/ns2/example.db | 69 + bin/tests/system/chain/ns2/generic.db | 22 + bin/tests/system/chain/ns2/named.conf.in | 74 + bin/tests/system/chain/ns2/sign.sh | 55 + bin/tests/system/chain/ns2/sub.db | 26 + bin/tests/system/chain/ns2/wildcard-secure.db | 29 + bin/tests/system/chain/ns2/wildcard.db | 28 + bin/tests/system/chain/ns5/named.conf.in | 42 + bin/tests/system/chain/ns5/sub.db | 26 + bin/tests/system/chain/ns7/named.conf.in | 45 + bin/tests/system/chain/ns7/root.hint | 14 + bin/tests/system/chain/prereq.sh | 50 + bin/tests/system/chain/setup.sh | 23 + bin/tests/system/chain/tests.sh | 625 + bin/tests/system/checkconf/altdb.conf | 19 + bin/tests/system/checkconf/altdlz.conf | 27 + bin/tests/system/checkconf/ancient.conf | 19 + bin/tests/system/checkconf/bad-acl.conf | 21 + bin/tests/system/checkconf/bad-also-notify.conf | 22 + bin/tests/system/checkconf/bad-catz-zone.conf | 18 + .../checkconf/bad-checknames-primary-dup-2.conf | 17 + .../checkconf/bad-checknames-primary-dup.conf | 17 + .../checkconf/bad-checknames-secondary-dup.conf | 17 + .../system/checkconf/bad-dnskey-validity.conf | 16 + bin/tests/system/checkconf/bad-dnssec.conf | 31 + bin/tests/system/checkconf/bad-duplicate-key.conf | 36 + .../checkconf/bad-duplicate-primaries-1.conf | 15 + .../checkconf/bad-duplicate-primaries-2.conf | 15 + .../system/checkconf/bad-duplicate-root-key.conf | 36 + bin/tests/system/checkconf/bad-geoip-use-ecs.conf | 16 + .../system/checkconf/bad-glue-cache-bogus.conf | 16 + bin/tests/system/checkconf/bad-hint.conf | 18 + bin/tests/system/checkconf/bad-in-view-dup.conf | 21 + bin/tests/system/checkconf/bad-inline-options.conf | 24 + bin/tests/system/checkconf/bad-inline-slave.conf | 22 + bin/tests/system/checkconf/bad-inline-view.conf | 31 + .../system/checkconf/bad-interface-interval.conf | 16 + .../system/checkconf/bad-ipv4-prefix-dotted1.conf | 16 + .../system/checkconf/bad-ipv4-prefix-dotted2.conf | 16 + bin/tests/system/checkconf/bad-ipv4-prefix2.conf | 16 + .../system/checkconf/bad-kasp-define-default.conf | 23 + .../system/checkconf/bad-kasp-define-insecure.conf | 23 + .../system/checkconf/bad-kasp-define-none.conf | 23 + bin/tests/system/checkconf/bad-kasp-duplicate.conf | 15 + bin/tests/system/checkconf/bad-kasp-key1.conf | 24 + bin/tests/system/checkconf/bad-kasp-key2.conf | 24 + bin/tests/system/checkconf/bad-kasp-key3.conf | 24 + bin/tests/system/checkconf/bad-kasp-key4.conf | 24 + .../system/checkconf/bad-kasp-keydir1.conf.in | 50 + .../system/checkconf/bad-kasp-keydir2.conf.in | 48 + .../system/checkconf/bad-kasp-keydir3.conf.in | 55 + .../system/checkconf/bad-kasp-keydir4.conf.in | 52 + .../system/checkconf/bad-kasp-keydir5.conf.in | 52 + .../bad-kasp-policy-undefined-inherited-view.conf | 25 + .../bad-kasp-policy-undefined-inherited.conf | 25 + bin/tests/system/checkconf/bad-kasp10.conf | 28 + bin/tests/system/checkconf/bad-kasp11.conf | 28 + bin/tests/system/checkconf/bad-kasp12.conf | 30 + bin/tests/system/checkconf/bad-kasp13.conf | 28 + bin/tests/system/checkconf/bad-kasp2.conf | 24 + bin/tests/system/checkconf/bad-kasp3.conf | 24 + bin/tests/system/checkconf/bad-kasp4.conf | 25 + bin/tests/system/checkconf/bad-kasp6.conf | 27 + bin/tests/system/checkconf/bad-kasp7.conf | 28 + bin/tests/system/checkconf/bad-kasp8.conf | 28 + bin/tests/system/checkconf/bad-kasp9.conf | 28 + .../system/checkconf/bad-keep-response-order.conf | 18 + .../system/checkconf/bad-ksk-without-zsk.conf | 24 + bin/tests/system/checkconf/bad-lifetime.conf | 16 + .../system/checkconf/bad-lmdb-mapsize-bogus.conf | 16 + .../checkconf/bad-lmdb-mapsize-toolarge.conf | 16 + .../checkconf/bad-lmdb-mapsize-toosmall.conf | 16 + .../checkconf/bad-lmdb-mapsize-unlimited.conf | 16 + .../system/checkconf/bad-master-request-ixfr.conf | 22 + bin/tests/system/checkconf/bad-masters-dup.conf | 18 + bin/tests/system/checkconf/bad-maxcachettl.conf | 16 + bin/tests/system/checkconf/bad-maxncachettl-1.conf | 16 + bin/tests/system/checkconf/bad-maxncachettl-2.conf | 16 + bin/tests/system/checkconf/bad-maxncachettl-3.conf | 19 + bin/tests/system/checkconf/bad-maxncachettl-4.conf | 16 + bin/tests/system/checkconf/bad-maxratio1.conf | 19 + bin/tests/system/checkconf/bad-maxratio2.conf | 19 + bin/tests/system/checkconf/bad-maxttlmap.conf | 19 + bin/tests/system/checkconf/bad-mincachettl.conf | 16 + bin/tests/system/checkconf/bad-minncachettl.conf | 16 + .../checkconf/bad-mirror-allow-recursion-none.conf | 22 + .../checkconf/bad-mirror-explicit-notify-yes.conf | 17 + .../bad-mirror-non-root-zone-without-masters.conf | 16 + .../system/checkconf/bad-mirror-recursion-no.conf | 20 + .../system/checkconf/bad-mirror-zonename.conf | 17 + bin/tests/system/checkconf/bad-noddns.conf | 19 + .../system/checkconf/bad-notify-source-v6.conf | 22 + bin/tests/system/checkconf/bad-notify-source.conf | 22 + .../system/checkconf/bad-options-also-notify.conf | 21 + .../checkconf/bad-parental-agents-def-options.conf | 21 + .../checkconf/bad-parental-agents-def-view.conf | 20 + .../checkconf/bad-parental-agents-def-view2.conf | 22 + .../checkconf/bad-parental-agents-def-zone.conf | 18 + .../system/checkconf/bad-parental-agents-dup.conf | 19 + .../checkconf/bad-parental-agents-dupdef.conf | 26 + .../checkconf/bad-parental-agents-empty.conf | 20 + .../checkconf/bad-parental-agents-empty2.conf | 18 + .../checkconf/bad-parental-agents-mirror.conf | 18 + .../checkconf/bad-parental-agents-notfound.conf | 22 + .../system/checkconf/bad-parental-source-v6.conf | 22 + .../system/checkconf/bad-parental-source.conf | 22 + bin/tests/system/checkconf/bad-port.conf | 16 + bin/tests/system/checkconf/bad-primaries-key.conf | 17 + .../system/checkconf/bad-primaries-notfound.conf | 21 + bin/tests/system/checkconf/bad-printtime.conf | 19 + bin/tests/system/checkconf/bad-rate-limit-acl.conf | 20 + .../checkconf/bad-rate-limit-all-per-second.conf | 18 + .../bad-rate-limit-errors-per-second.conf | 18 + .../bad-rate-limit-ipv4-prefix-length.conf | 18 + .../bad-rate-limit-ipv6-prefix-length.conf | 18 + .../checkconf/bad-rate-limit-max-table-size.conf | 18 + .../bad-rate-limit-nodata-per-second.conf | 18 + .../bad-rate-limit-nxdomains-per-second.conf | 18 + .../system/checkconf/bad-rate-limit-qps-scale.conf | 18 + .../bad-rate-limit-referrals-per-second.conf | 18 + .../bad-rate-limit-responses-per-second.conf | 18 + .../system/checkconf/bad-rate-limit-slip.conf | 18 + .../system/checkconf/bad-rate-limit-window.conf | 18 + bin/tests/system/checkconf/bad-root-mixed-key.conf | 41 + .../system/checkconf/bad-rpz-too-many-zones.conf | 148 + bin/tests/system/checkconf/bad-rpz-ttl.conf | 24 + bin/tests/system/checkconf/bad-rpz-update.conf | 25 + bin/tests/system/checkconf/bad-rpz-zone.conf | 18 + .../system/checkconf/bad-sharedwritable1.conf | 22 + .../system/checkconf/bad-sharedwritable2.conf | 23 + bin/tests/system/checkconf/bad-sharedzone1.conf | 31 + bin/tests/system/checkconf/bad-sharedzone2.conf | 33 + bin/tests/system/checkconf/bad-sharedzone3.conf | 25 + bin/tests/system/checkconf/bad-sig-validity.conf | 16 + .../system/checkconf/bad-static-initial-1.conf | 17 + .../system/checkconf/bad-static-initial-2.conf | 17 + .../system/checkconf/bad-static-initial-3.conf | 17 + .../system/checkconf/bad-static-initial-4.conf | 17 + .../system/checkconf/bad-stub-masters-dialup.conf | 36 + .../system/checkconf/bad-transfer-source-v6.conf | 22 + .../system/checkconf/bad-transfer-source.conf | 22 + bin/tests/system/checkconf/bad-tsig.conf | 19 + bin/tests/system/checkconf/bad-unpaired-keys.conf | 27 + bin/tests/system/checkconf/bad-update-policy1.conf | 20 + .../system/checkconf/bad-update-policy10.conf | 20 + .../system/checkconf/bad-update-policy11.conf | 20 + .../system/checkconf/bad-update-policy12.conf | 20 + .../system/checkconf/bad-update-policy13.conf | 20 + .../system/checkconf/bad-update-policy14.conf | 20 + .../system/checkconf/bad-update-policy15.conf | 20 + bin/tests/system/checkconf/bad-update-policy2.conf | 20 + bin/tests/system/checkconf/bad-update-policy3.conf | 20 + bin/tests/system/checkconf/bad-update-policy4.conf | 20 + bin/tests/system/checkconf/bad-update-policy5.conf | 20 + bin/tests/system/checkconf/bad-update-policy6.conf | 20 + bin/tests/system/checkconf/bad-update-policy7.conf | 20 + bin/tests/system/checkconf/bad-update-policy8.conf | 20 + bin/tests/system/checkconf/bad-update-policy9.conf | 20 + .../system/checkconf/bad-validation-auto-key.conf | 26 + .../system/checkconf/bad-view-also-notify.conf | 20 + .../system/checkconf/bad-zsk-without-ksk.conf | 24 + .../system/checkconf/check-dup-records-fail.conf | 23 + bin/tests/system/checkconf/check-dup-records.db | 33 + bin/tests/system/checkconf/check-missing-zone.conf | 26 + bin/tests/system/checkconf/check-mixed-keys.conf | 43 + .../system/checkconf/check-mx-cname-fail.conf | 22 + bin/tests/system/checkconf/check-mx-cname.db | 26 + bin/tests/system/checkconf/check-mx-fail.conf | 22 + bin/tests/system/checkconf/check-mx.db | 24 + bin/tests/system/checkconf/check-names-fail.conf | 22 + bin/tests/system/checkconf/check-names.db | 28 + .../system/checkconf/check-root-ksk-2010.conf | 26 + .../system/checkconf/check-root-ksk-2017.conf | 29 + .../system/checkconf/check-root-ksk-both.conf | 41 + .../system/checkconf/check-root-static-ds.conf | 16 + .../system/checkconf/check-root-static-key.conf | 29 + .../system/checkconf/check-root-trusted-key.conf | 29 + .../system/checkconf/check-srv-cname-fail.conf | 22 + bin/tests/system/checkconf/check-srv-cname.db | 28 + bin/tests/system/checkconf/check-wildcard-no.conf | 18 + bin/tests/system/checkconf/check-wildcard.conf | 18 + bin/tests/system/checkconf/check-wildcard.db | 23 + bin/tests/system/checkconf/clean.sh | 25 + .../deprecated-masterfile-format-map.conf | 22 + bin/tests/system/checkconf/deprecated.conf | 43 + bin/tests/system/checkconf/dlz-bad.conf | 27 + bin/tests/system/checkconf/dnssec.1 | 16 + bin/tests/system/checkconf/dnssec.2 | 27 + bin/tests/system/checkconf/dnssec.3 | 34 + bin/tests/system/checkconf/dnssec.4 | 18 + bin/tests/system/checkconf/good-acl.conf | 21 + .../good-allow-update-forwarding-view.conf | 16 + .../checkconf/good-allow-update-forwarding.conf | 16 + .../system/checkconf/good-allow-update-view.conf | 16 + bin/tests/system/checkconf/good-allow-update.conf | 16 + bin/tests/system/checkconf/good-class.conf | 14 + .../checkconf/good-dnskey-validity-3660.conf | 16 + .../checkconf/good-dnskey-validity-zero.conf | 16 + bin/tests/system/checkconf/good-ds-key-1.conf | 17 + bin/tests/system/checkconf/good-ds-key-2.conf | 17 + .../system/checkconf/good-dup-managed-key.conf | 33 + .../system/checkconf/good-dup-trusted-key.conf | 33 + bin/tests/system/checkconf/good-glue-cache.conf | 16 + bin/tests/system/checkconf/good-initial-ds.conf | 16 + .../system/checkconf/good-interface-interval.conf | 16 + bin/tests/system/checkconf/good-kasp.conf | 68 + bin/tests/system/checkconf/good-key-directory.conf | 73 + .../checkconf/good-lmdb-mapsize-largest.conf | 16 + .../checkconf/good-lmdb-mapsize-smallest.conf | 16 + .../checkconf/good-masterfile-format-raw.conf | 22 + .../checkconf/good-masterfile-format-text.conf | 22 + .../checkconf/good-masters-and-primaries.conf | 15 + bin/tests/system/checkconf/good-maxcachettl.conf | 34 + bin/tests/system/checkconf/good-maxncachettl.conf | 34 + bin/tests/system/checkconf/good-maxratio1.conf | 19 + bin/tests/system/checkconf/good-maxratio2.conf | 19 + bin/tests/system/checkconf/good-mincachettl.conf | 28 + bin/tests/system/checkconf/good-minncachettl.conf | 28 + .../good-mirror-inherited-notify-yes.conf | 20 + .../good-mirror-root-zone-without-masters.conf | 16 + bin/tests/system/checkconf/good-nested.conf | 20 + .../system/checkconf/good-notify-source-v6.conf | 22 + bin/tests/system/checkconf/good-notify-source.conf | 22 + .../system/checkconf/good-options-also-notify.conf | 22 + .../system/checkconf/good-parental-source-v6.conf | 22 + .../system/checkconf/good-parental-source.conf | 22 + bin/tests/system/checkconf/good-printtime.conf | 35 + bin/tests/system/checkconf/good-response-dot.conf | 23 + bin/tests/system/checkconf/good-rpz-ttl.conf | 24 + bin/tests/system/checkconf/good-rpz-update.conf | 25 + .../system/checkconf/good-rrset-order-none.conf | 18 + bin/tests/system/checkconf/good-static-ds.conf | 16 + .../system/checkconf/good-transfer-source-v6.conf | 22 + .../system/checkconf/good-transfer-source.conf | 22 + .../system/checkconf/good-update-policy1.conf | 20 + .../system/checkconf/good-update-policy10.conf | 20 + .../system/checkconf/good-update-policy11.conf | 20 + .../system/checkconf/good-update-policy12.conf | 20 + .../system/checkconf/good-update-policy2.conf | 20 + .../system/checkconf/good-update-policy3.conf | 20 + .../system/checkconf/good-update-policy4.conf | 20 + .../system/checkconf/good-update-policy5.conf | 20 + .../system/checkconf/good-update-policy6.conf | 20 + .../system/checkconf/good-update-policy7.conf | 20 + .../system/checkconf/good-update-policy8.conf | 20 + .../system/checkconf/good-update-policy9.conf | 20 + .../system/checkconf/good-view-also-notify.conf | 21 + bin/tests/system/checkconf/good.conf | 289 + bin/tests/system/checkconf/good.zonelist | 24 + bin/tests/system/checkconf/hint-nofile.conf | 17 + bin/tests/system/checkconf/in-view-good.conf | 25 + bin/tests/system/checkconf/inline-bad.conf | 27 + bin/tests/system/checkconf/inline-good.conf | 28 + bin/tests/system/checkconf/inline-no.conf | 27 + .../checkconf/kasp-and-other-dnssec-options.conf | 28 + bin/tests/system/checkconf/kasp-bad-keylen.conf | 24 + bin/tests/system/checkconf/kasp-bad-nsec3-alg.conf | 26 + .../system/checkconf/kasp-bad-nsec3-iter.conf | 61 + .../system/checkconf/kasp-bad-nsec3-salt.conf | 23 + bin/tests/system/checkconf/kasp-ignore-keylen.conf | 27 + .../system/checkconf/max-cache-size-good.conf | 16 + bin/tests/system/checkconf/max-ttl.conf | 34 + bin/tests/system/checkconf/maxttl-bad.conf | 24 + bin/tests/system/checkconf/maxttl-bad.db | 25 + bin/tests/system/checkconf/maxttl.db | 25 + bin/tests/system/checkconf/notify.conf | 84 + bin/tests/system/checkconf/portrange-good.conf | 22 + bin/tests/system/checkconf/range.conf | 25 + .../checkconf/servestale.stale-refresh-time.0.conf | 16 + .../servestale.stale-refresh-time.29.conf | 16 + bin/tests/system/checkconf/shared.example.db | 13 + bin/tests/system/checkconf/tests.sh | 643 + bin/tests/system/checkconf/view-class-any1.conf | 14 + bin/tests/system/checkconf/view-class-any2.conf | 14 + bin/tests/system/checkconf/view-class-in1.conf | 14 + bin/tests/system/checkconf/view-class-in2.conf | 14 + bin/tests/system/checkconf/warn-dlv-auto.conf | 16 + .../system/checkconf/warn-dlv-dlv.example.com.conf | 16 + .../system/checkconf/warn-dlv-dlv.isc.org.conf | 16 + bin/tests/system/checkconf/warn-geoip-use-ecs.conf | 16 + .../system/checkconf/warn-kasp-max-zone-ttl.conf | 27 + bin/tests/system/checkconf/warn-keydir.conf | 25 + bin/tests/system/checkconf/warn-maxratio1.conf | 19 + bin/tests/system/checkconf/warn-notify-source.conf | 22 + .../system/checkconf/warn-parental-source.conf | 22 + .../system/checkconf/warn-transfer-source.conf | 22 + bin/tests/system/checkds/README | 26 + bin/tests/system/checkds/clean.sh | 26 + bin/tests/system/checkds/ns2/named.conf.in | 45 + bin/tests/system/checkds/ns2/setup.sh | 34 + bin/tests/system/checkds/ns2/template.db.in | 38 + bin/tests/system/checkds/ns4/named.conf.in | 41 + bin/tests/system/checkds/ns5/named.conf.in | 45 + bin/tests/system/checkds/ns5/setup.sh | 26 + bin/tests/system/checkds/ns5/template.db.in | 38 + bin/tests/system/checkds/ns6/named.conf.in | 45 + bin/tests/system/checkds/ns7/named.conf.in | 46 + bin/tests/system/checkds/ns9/named.conf.in | 218 + bin/tests/system/checkds/ns9/setup.sh | 63 + bin/tests/system/checkds/ns9/template.db.in | 27 + bin/tests/system/checkds/prereq.sh | 31 + bin/tests/system/checkds/setup.sh | 40 + bin/tests/system/checkds/tests_checkds.py | 450 + bin/tests/system/checkdstool/clean.sh | 15 + bin/tests/system/checkdstool/dig.bat | 32 + bin/tests/system/checkdstool/dig.pl | 41 + bin/tests/system/checkdstool/dig.sh | 24 + .../system/checkdstool/missing.example.dnskey.db | 3 + bin/tests/system/checkdstool/missing.example.ds.db | 2 + .../system/checkdstool/none.example.dnskey.db | 3 + bin/tests/system/checkdstool/none.example.ds.db | 0 bin/tests/system/checkdstool/ok.example.dnskey.db | 2 + bin/tests/system/checkdstool/ok.example.ds.db | 2 + bin/tests/system/checkdstool/prep.example.db | 121 + bin/tests/system/checkdstool/prep.example.ds.db | 2 + bin/tests/system/checkdstool/tests.sh | 117 + .../system/checkdstool/wrong.example.dnskey.db | 2 + bin/tests/system/checkdstool/wrong.example.ds.db | 2 + bin/tests/system/checknames/clean.sh | 27 + bin/tests/system/checknames/ns1/fail.example.db.in | 17 + bin/tests/system/checknames/ns1/fail.update.db.in | 16 + .../system/checknames/ns1/ignore.example.db.in | 18 + .../system/checknames/ns1/ignore.update.db.in | 16 + bin/tests/system/checknames/ns1/named.conf.in | 70 + bin/tests/system/checknames/ns1/root.db | 30 + bin/tests/system/checknames/ns1/warn.example.db.in | 17 + bin/tests/system/checknames/ns1/warn.update.db.in | 16 + bin/tests/system/checknames/ns2/named.conf.in | 31 + bin/tests/system/checknames/ns2/root.hints | 14 + bin/tests/system/checknames/ns3/named.conf.in | 31 + bin/tests/system/checknames/ns3/root.hints | 14 + bin/tests/system/checknames/ns4/named.conf.in | 44 + .../checknames/ns4/primary-ignore.update.db.in | 18 + bin/tests/system/checknames/ns4/root.hints | 14 + .../checknames/ns5/master-ignore.update.db.in | 18 + bin/tests/system/checknames/ns5/named.conf.in | 44 + bin/tests/system/checknames/ns5/root.hints | 14 + bin/tests/system/checknames/setup.sh | 35 + bin/tests/system/checknames/tests.sh | 191 + bin/tests/system/checkzone/clean.sh | 16 + bin/tests/system/checkzone/setup.sh | 24 + bin/tests/system/checkzone/tests.sh | 200 + bin/tests/system/checkzone/zones/.gitattributes | 1 + bin/tests/system/checkzone/zones/bad-badclass.raw | Bin 0 -> 104 bytes bin/tests/system/checkzone/zones/bad-caa-rr.db | Bin 0 -> 601 bytes bin/tests/system/checkzone/zones/bad-cdnskey.db | 15 + bin/tests/system/checkzone/zones/bad-cds.db | 15 + bin/tests/system/checkzone/zones/bad-dhcid.db | 13 + .../system/checkzone/zones/bad-dns-sd-reverse.db | 21 + bin/tests/system/checkzone/zones/bad-ds.db | 15 + bin/tests/system/checkzone/zones/bad-eid.db | 13 + .../system/checkzone/zones/bad-generate-garbage.db | 17 + .../checkzone/zones/bad-generate-missing-brace.db | 17 + .../system/checkzone/zones/bad-generate-range.db | 18 + .../system/checkzone/zones/bad-generate-tkey.db | 17 + bin/tests/system/checkzone/zones/bad-nimloc.db | 10 + bin/tests/system/checkzone/zones/bad-nsap-empty.db | 18 + .../system/checkzone/zones/bad-nsap-odd-nibble.db | 18 + .../system/checkzone/zones/bad-nsec3-padded.db | 21 + .../checkzone/zones/bad-nsec3owner-padded.db | 19 + .../system/checkzone/zones/bad-svcb-mandatory.db | 17 + .../system/checkzone/zones/bad-svcb-servername.db | 17 + bin/tests/system/checkzone/zones/bad-svcb.db | 17 + bin/tests/system/checkzone/zones/bad-tkey.db | 17 + bin/tests/system/checkzone/zones/bad-tsig.db.in | 17 + bin/tests/system/checkzone/zones/bad-unspec.db | 16 + bin/tests/system/checkzone/zones/bad1.db | Bin 0 -> 508 bytes bin/tests/system/checkzone/zones/bad2.db | 19 + bin/tests/system/checkzone/zones/bad3.db | 19 + bin/tests/system/checkzone/zones/bad4.db | 19 + bin/tests/system/checkzone/zones/badttl.db | 19 + bin/tests/system/checkzone/zones/crashzone.db | 62 + .../zones/delegating-ns-address-below-dname.db | 24 + .../system/checkzone/zones/generate-overflow.db | 17 + bin/tests/system/checkzone/zones/good-cdnskey.db | 15 + .../system/checkzone/zones/good-cds-unsigned.db | 16 + bin/tests/system/checkzone/zones/good-cds.db | 15 + .../system/checkzone/zones/good-dns-sd-reverse.db | 23 + bin/tests/system/checkzone/zones/good-gc-msdcs.db | 16 + .../checkzone/zones/good-generate-modifier.db | 20 + bin/tests/system/checkzone/zones/good-nsap.db | 18 + .../system/checkzone/zones/good-nsec3-nopadhash.db | 19 + .../checkzone/zones/good-occulted-ns-by-dname.db | 22 + .../checkzone/zones/good-occulted-ns-by-ns.db | 22 + .../system/checkzone/zones/good-spf-exception.db | 18 + bin/tests/system/checkzone/zones/good-svcb.db | 27 + bin/tests/system/checkzone/zones/good1.db | 19 + bin/tests/system/checkzone/zones/inherit.db | 12 + .../checkzone/zones/nowarn.inherited.owner.db | 13 + .../checkzone/zones/ns-address-below-dname.db | 22 + bin/tests/system/checkzone/zones/spf.db | 18 + bin/tests/system/checkzone/zones/test1.db | 17 + bin/tests/system/checkzone/zones/test2.db | 18 + .../system/checkzone/zones/warn.inherit.origin.db | 14 + .../system/checkzone/zones/warn.inherited.owner.db | 13 + bin/tests/system/ckdnsrps.sh | 168 + bin/tests/system/cleanall.sh | 37 + bin/tests/system/cleanpkcs11.sh | 18 + bin/tests/system/common/controls.conf.in | 22 + bin/tests/system/common/rndc.conf | 21 + bin/tests/system/common/rndc.key | 15 + bin/tests/system/common/root.hint | 14 + bin/tests/system/conf.sh.common | 744 + bin/tests/system/conf.sh.in | 131 + bin/tests/system/conf.sh.win32 | 129 + bin/tests/system/conftest.py | 31 + bin/tests/system/cookie/ans9/ans.py | 300 + bin/tests/system/cookie/bad-cookie-badaes.conf | 17 + bin/tests/system/cookie/bad-cookie-badhex.conf | 16 + .../system/cookie/bad-cookie-badsiphash24.conf | 17 + bin/tests/system/cookie/bad-cookie-toolong.conf | 16 + bin/tests/system/cookie/clean.sh | 24 + bin/tests/system/cookie/good-cookie-aes.conf | 17 + bin/tests/system/cookie/good-cookie-siphash24.conf | 17 + bin/tests/system/cookie/ns1/example.db | 24 + bin/tests/system/cookie/ns1/named.conf.in | 60 + bin/tests/system/cookie/ns1/root.hint | 14 + bin/tests/system/cookie/ns2/named.conf.in | 31 + bin/tests/system/cookie/ns2/root.db | 28 + bin/tests/system/cookie/ns3/named.conf.in | 52 + bin/tests/system/cookie/ns3/root.hint | 14 + bin/tests/system/cookie/ns4/named.conf.in | 41 + bin/tests/system/cookie/ns4/root.hint | 14 + bin/tests/system/cookie/ns5/named.conf.in | 42 + bin/tests/system/cookie/ns5/root.hint | 14 + bin/tests/system/cookie/ns6/named.conf.in | 41 + bin/tests/system/cookie/ns6/root.hint | 14 + bin/tests/system/cookie/ns7/named.conf.in | 31 + bin/tests/system/cookie/ns7/root.db | 24 + bin/tests/system/cookie/ns8/example.db | 13 + bin/tests/system/cookie/ns8/named.conf.in | 39 + bin/tests/system/cookie/prereq.sh | 33 + bin/tests/system/cookie/setup.sh | 24 + bin/tests/system/cookie/tests.sh | 515 + bin/tests/system/coverage/01-ksk-inactive/README | 10 + bin/tests/system/coverage/01-ksk-inactive/expect | 6 + bin/tests/system/coverage/02-zsk-inactive/README | 10 + bin/tests/system/coverage/02-zsk-inactive/expect | 6 + .../system/coverage/03-ksk-unpublished/README | 10 + .../system/coverage/03-ksk-unpublished/expect | 8 + .../system/coverage/04-zsk-unpublished/README | 10 + .../system/coverage/04-zsk-unpublished/expect | 8 + .../system/coverage/05-ksk-unpub-active/README | 12 + .../system/coverage/05-ksk-unpub-active/expect | 8 + .../system/coverage/06-zsk-unpub-active/README | 12 + .../system/coverage/06-zsk-unpub-active/expect | 8 + bin/tests/system/coverage/07-ksk-ttl/README | 4 + bin/tests/system/coverage/07-ksk-ttl/expect | 9 + bin/tests/system/coverage/08-zsk-ttl/README | 4 + bin/tests/system/coverage/08-zsk-ttl/expect | 9 + bin/tests/system/coverage/09-check-zsk/README | 6 + bin/tests/system/coverage/09-check-zsk/expect | 6 + bin/tests/system/coverage/10-check-ksk/README | 7 + bin/tests/system/coverage/10-check-ksk/expect | 6 + bin/tests/system/coverage/11-cutoff/README | 10 + bin/tests/system/coverage/11-cutoff/expect | 6 + bin/tests/system/coverage/12-ksk-deletion/expect | 6 + bin/tests/system/coverage/13-dotted-dotless/expect | 7 + bin/tests/system/coverage/clean.sh | 19 + bin/tests/system/coverage/setup.sh | 119 + bin/tests/system/coverage/tests.sh | 87 + bin/tests/system/database/clean.sh | 17 + bin/tests/system/database/ns1/named1.conf.in | 41 + bin/tests/system/database/ns1/named2.conf.in | 41 + bin/tests/system/database/setup.sh | 17 + bin/tests/system/database/tests.sh | 55 + bin/tests/system/dialup/clean.sh | 18 + bin/tests/system/dialup/ns1/example.db | 19 + bin/tests/system/dialup/ns1/named.conf.in | 40 + bin/tests/system/dialup/ns1/root.db | 20 + bin/tests/system/dialup/ns2/hint.db | 13 + bin/tests/system/dialup/ns2/named.conf.in | 40 + bin/tests/system/dialup/ns3/hint.db | 13 + bin/tests/system/dialup/ns3/named.conf.in | 40 + bin/tests/system/dialup/setup.sh | 19 + bin/tests/system/dialup/tests.sh | 65 + bin/tests/system/digcomp.pl | 164 + bin/tests/system/digdelv/ans4/startme | 1 + bin/tests/system/digdelv/ans5/ans.pl | 176 + bin/tests/system/digdelv/ans6/ans.pl | 84 + bin/tests/system/digdelv/ans7/ans.pl | 68 + bin/tests/system/digdelv/clean.sh | 33 + bin/tests/system/digdelv/ns1/named.conf.in | 30 + bin/tests/system/digdelv/ns1/root.db | 26 + bin/tests/system/digdelv/ns2/example.db.in | 51 + bin/tests/system/digdelv/ns2/named.conf.in | 34 + bin/tests/system/digdelv/ns2/sign.sh | 29 + bin/tests/system/digdelv/ns3/named.conf.in | 28 + bin/tests/system/digdelv/prereq.sh | 25 + bin/tests/system/digdelv/setup.sh | 23 + bin/tests/system/digdelv/tests.sh | 1347 + bin/tests/system/digdelv/yamlget.py | 35 + bin/tests/system/ditch.pl | 87 + bin/tests/system/dlz/clean.sh | 19 + .../com/broken/dns.d/@/DNAME=10=example.net.= | 6 + .../com/broken/dns.d/@/NS=10=example.com.= | 6 + ...om.=root.example.com.=None=None=None=None=None= | 6 + .../com/example/dns.d/@/DNAME=10=example.net.= | 6 + .../com/example/dns.d/@/NS=10=example.com.= | 6 + ...ple.com.=root.example.com.=2010062900=0=0=0=10= | 6 + .../dlz/ns1/dns-root/com/example/xfr.d/10.53.0.1 | 6 + bin/tests/system/dlz/ns1/named.conf.in | 27 + bin/tests/system/dlz/prereq.sh | 21 + bin/tests/system/dlz/setup.sh | 18 + bin/tests/system/dlz/tests.sh | 77 + bin/tests/system/dlzexternal/Makefile.in | 49 + bin/tests/system/dlzexternal/clean.sh | 26 + bin/tests/system/dlzexternal/driver.c | 845 + bin/tests/system/dlzexternal/driver.h | 35 + bin/tests/system/dlzexternal/ns1/dlzs.conf.in | 44 + bin/tests/system/dlzexternal/ns1/named.conf.in | 54 + bin/tests/system/dlzexternal/ns1/root.db | 26 + bin/tests/system/dlzexternal/prereq.sh | 27 + bin/tests/system/dlzexternal/setup.sh | 19 + bin/tests/system/dlzexternal/tests.sh | 230 + bin/tests/system/dns64/clean.sh | 22 + bin/tests/system/dns64/conf/bad1.conf | 16 + bin/tests/system/dns64/conf/bad10.conf | 16 + bin/tests/system/dns64/conf/bad11.conf | 16 + bin/tests/system/dns64/conf/bad12.conf | 16 + bin/tests/system/dns64/conf/bad13.conf | 16 + bin/tests/system/dns64/conf/bad14.conf | 16 + bin/tests/system/dns64/conf/bad15.conf | 16 + bin/tests/system/dns64/conf/bad16.conf | 16 + bin/tests/system/dns64/conf/bad17.conf | 16 + bin/tests/system/dns64/conf/bad18.conf | 16 + bin/tests/system/dns64/conf/bad19.conf | 16 + bin/tests/system/dns64/conf/bad2.conf | 16 + bin/tests/system/dns64/conf/bad3.conf | 16 + bin/tests/system/dns64/conf/bad4.conf | 16 + bin/tests/system/dns64/conf/bad5.conf | 16 + bin/tests/system/dns64/conf/bad6.conf | 16 + bin/tests/system/dns64/conf/bad7.conf | 18 + bin/tests/system/dns64/conf/bad8.conf | 18 + bin/tests/system/dns64/conf/bad9.conf | 18 + bin/tests/system/dns64/conf/good1.conf | 22 + bin/tests/system/dns64/conf/good2.conf | 21 + bin/tests/system/dns64/conf/good3.conf | 21 + bin/tests/system/dns64/conf/good4.conf | 21 + bin/tests/system/dns64/conf/good5.conf | 18 + bin/tests/system/dns64/ns1/example.db | 56 + bin/tests/system/dns64/ns1/named.conf.in | 54 + bin/tests/system/dns64/ns1/root.db | 19 + bin/tests/system/dns64/ns1/sign.sh | 26 + bin/tests/system/dns64/ns2/named.conf.in | 71 + bin/tests/system/dns64/ns2/rpz.db | 23 + bin/tests/system/dns64/setup.sh | 20 + bin/tests/system/dns64/tests.sh | 1406 + bin/tests/system/dnssec/README | 32 + bin/tests/system/dnssec/ans10/ans.py | 158 + bin/tests/system/dnssec/clean.sh | 116 + bin/tests/system/dnssec/dnssec_update_test.pl | 99 + bin/tests/system/dnssec/ns1/named.conf.in | 36 + bin/tests/system/dnssec/ns1/root.db.in | 37 + bin/tests/system/dnssec/ns1/sign.sh | 62 + bin/tests/system/dnssec/ns2/algroll.db.in | 26 + bin/tests/system/dnssec/ns2/badparam.db.in | 21 + .../system/dnssec/ns2/cdnskey-auto.secure.db.in | 14 + .../system/dnssec/ns2/cdnskey-kskonly.secure.db.in | 14 + .../system/dnssec/ns2/cdnskey-update.secure.db.in | 14 + bin/tests/system/dnssec/ns2/cdnskey.secure.db.in | 14 + bin/tests/system/dnssec/ns2/cds-auto.secure.db.in | 14 + .../system/dnssec/ns2/cds-kskonly.secure.db.in | 14 + .../system/dnssec/ns2/cds-update.secure.db.in | 14 + bin/tests/system/dnssec/ns2/cds.secure.db.in | 14 + bin/tests/system/dnssec/ns2/child.nsec3.example.db | 20 + .../system/dnssec/ns2/child.optout.example.db | 20 + bin/tests/system/dnssec/ns2/corp.db | 23 + bin/tests/system/dnssec/ns2/dst.example.db.in | 21 + bin/tests/system/dnssec/ns2/example.db.in | 171 + bin/tests/system/dnssec/ns2/hours-vs-days.db.in | 167 + bin/tests/system/dnssec/ns2/in-addr.arpa.db.in | 19 + .../system/dnssec/ns2/insecure.secure.example.db | 26 + bin/tests/system/dnssec/ns2/key.db.in | 45 + bin/tests/system/dnssec/ns2/named.conf.in | 201 + .../system/dnssec/ns2/private.secure.example.db.in | 28 + bin/tests/system/dnssec/ns2/rfc2335.example.db | 114 + bin/tests/system/dnssec/ns2/sign.sh | 333 + bin/tests/system/dnssec/ns2/single-nsec3.db.in | 21 + bin/tests/system/dnssec/ns2/template.secure.db.in | 14 + .../system/dnssec/ns2/too-many-iterations.db.in | 27 + .../system/dnssec/ns3/auto-nsec.example.db.in | 40 + .../system/dnssec/ns3/auto-nsec3.example.db.in | 40 + bin/tests/system/dnssec/ns3/bogus.example.db.in | 27 + .../dnssec/ns3/dname-at-apex-nsec3.example.db.in | 15 + .../dnssec/ns3/dnskey-nsec3-unknown.example.db.in | 29 + .../system/dnssec/ns3/dnskey-unknown.example.db.in | 29 + .../dnssec/ns3/dnskey-unsupported-2.example.db.in | 29 + .../dnssec/ns3/dnskey-unsupported.example.db.in | 29 + bin/tests/system/dnssec/ns3/dynamic.example.db.in | 25 + bin/tests/system/dnssec/ns3/expired.example.db.in | 44 + bin/tests/system/dnssec/ns3/expiring.example.db.in | 40 + bin/tests/system/dnssec/ns3/future.example.db.in | 40 + bin/tests/system/dnssec/ns3/generic.example.db.in | 23 + bin/tests/system/dnssec/ns3/inline.example.db | 26 + .../dnssec/ns3/insecure.below-cname.example.db | 26 + bin/tests/system/dnssec/ns3/insecure.example.db | 27 + .../system/dnssec/ns3/insecure.nsec3.example.db | 26 + .../system/dnssec/ns3/insecure.optout.example.db | 26 + bin/tests/system/dnssec/ns3/insecure2.example.db | 27 + bin/tests/system/dnssec/ns3/key.db.in | 26 + bin/tests/system/dnssec/ns3/kskonly.example.db.in | 26 + bin/tests/system/dnssec/ns3/lower.example.db.in | 21 + .../system/dnssec/ns3/managed-future.example.db.in | 40 + bin/tests/system/dnssec/ns3/multiple.example.db.in | 29 + bin/tests/system/dnssec/ns3/named.conf.in | 382 + bin/tests/system/dnssec/ns3/nosign.example.db.in | 23 + .../system/dnssec/ns3/nsec3-unknown.example.db.in | 29 + bin/tests/system/dnssec/ns3/nsec3.example.db.in | 38 + .../system/dnssec/ns3/nsec3.nsec3.example.db.in | 35 + .../system/dnssec/ns3/nsec3.optout.example.db.in | 35 + bin/tests/system/dnssec/ns3/occluded.example.db.in | 26 + .../system/dnssec/ns3/optout-unknown.example.db.in | 29 + bin/tests/system/dnssec/ns3/optout.example.db.in | 40 + .../system/dnssec/ns3/optout.nsec3.example.db.in | 35 + .../system/dnssec/ns3/optout.optout.example.db.in | 35 + .../dnssec/ns3/publish-inactive.example.db.in | 26 + .../system/dnssec/ns3/rsasha256.example.db.in | 28 + .../system/dnssec/ns3/rsasha512.example.db.in | 28 + .../dnssec/ns3/secure.below-cname.example.db.in | 26 + bin/tests/system/dnssec/ns3/secure.example.db.in | 49 + .../system/dnssec/ns3/secure.nsec3.example.db.in | 35 + .../system/dnssec/ns3/secure.optout.example.db.in | 35 + .../system/dnssec/ns3/siginterval.example.db.in | 21 + bin/tests/system/dnssec/ns3/siginterval1.conf | 21 + bin/tests/system/dnssec/ns3/siginterval2.conf | 21 + bin/tests/system/dnssec/ns3/sign.sh | 673 + .../system/dnssec/ns3/split-dnssec.example.db.in | 38 + .../system/dnssec/ns3/split-smart.example.db.in | 38 + bin/tests/system/dnssec/ns3/ttlpatch.example.db.in | 26 + .../system/dnssec/ns3/unsupported-algorithm.key | 1 + .../system/dnssec/ns3/update-nsec3.example.db.in | 40 + bin/tests/system/dnssec/ns3/upper.example.db.in | 21 + bin/tests/system/dnssec/ns4/managed-keys.bind.in | 21 + bin/tests/system/dnssec/ns4/named1.conf.in | 61 + bin/tests/system/dnssec/ns4/named2.conf.in | 43 + bin/tests/system/dnssec/ns4/named3.conf.in | 43 + bin/tests/system/dnssec/ns4/named4.conf.in | 78 + bin/tests/system/dnssec/ns4/named5.conf.in | 39 + bin/tests/system/dnssec/ns5/named1.conf.in | 43 + bin/tests/system/dnssec/ns5/named2.conf.in | 52 + bin/tests/system/dnssec/ns5/sign.sh | 39 + bin/tests/system/dnssec/ns6/named.args | 1 + bin/tests/system/dnssec/ns6/named.conf.in | 40 + bin/tests/system/dnssec/ns6/optout-tld.db.in | 22 + bin/tests/system/dnssec/ns6/sign.sh | 29 + bin/tests/system/dnssec/ns7/named.conf.in | 76 + bin/tests/system/dnssec/ns7/named.nosoa | 12 + .../system/dnssec/ns7/nosoa.secure.example.db | 22 + bin/tests/system/dnssec/ns7/sign.sh | 44 + bin/tests/system/dnssec/ns7/split-rrsig.db.in | 21 + bin/tests/system/dnssec/ns8/named.conf.in | 47 + bin/tests/system/dnssec/ns9/named.conf.in | 39 + bin/tests/system/dnssec/ntadiff.pl | 24 + bin/tests/system/dnssec/prereq.sh | 45 + bin/tests/system/dnssec/setup.sh | 52 + bin/tests/system/dnssec/signer/example.db.in | 17 + .../signer/general/Kexample.com.+008+15002.key | 5 + .../signer/general/Kexample.com.+008+15002.private | 13 + .../signer/general/Kexample.com.+008+63613.key | 5 + .../signer/general/Kexample.com.+008+63613.private | 13 + .../signer/general/Kexample.com.+010+18240.key | 5 + .../signer/general/Kexample.com.+010+18240.private | 13 + .../signer/general/Kexample.com.+010+28633.key | 5 + .../signer/general/Kexample.com.+010+28633.private | 13 + .../system/dnssec/signer/general/bogus-ksk.key | 6 + .../system/dnssec/signer/general/bogus-zsk.key | 6 + bin/tests/system/dnssec/signer/general/test1.zone | 19 + bin/tests/system/dnssec/signer/general/test2.zone | 18 + bin/tests/system/dnssec/signer/general/test3.zone | 18 + bin/tests/system/dnssec/signer/general/test4.zone | 20 + bin/tests/system/dnssec/signer/general/test5.zone | 19 + bin/tests/system/dnssec/signer/general/test6.zone | 21 + bin/tests/system/dnssec/signer/general/test7.zone | 19 + bin/tests/system/dnssec/signer/general/test8.zone | 19 + bin/tests/system/dnssec/signer/general/test9.zone | 19 + bin/tests/system/dnssec/signer/prepub.db.in | 17 + bin/tests/system/dnssec/signer/remove.db.in | 18 + bin/tests/system/dnssec/signer/remove2.db.in | 16 + bin/tests/system/dnssec/tests.sh | 4441 +++ bin/tests/system/dnstap/README | 27 + .../system/dnstap/bad-fstrm-reopen-interval.conf | 16 + .../dnstap/bad-fstrm-set-buffer-hint-max.conf | 16 + .../dnstap/bad-fstrm-set-buffer-hint-min.conf | 16 + .../dnstap/bad-fstrm-set-flush-timeout-max.conf | 16 + .../dnstap/bad-fstrm-set-flush-timeout-min.conf | 16 + .../dnstap/bad-fstrm-set-input-queue-size-max.conf | 16 + .../dnstap/bad-fstrm-set-input-queue-size-min.conf | 16 + .../dnstap/bad-fstrm-set-input-queue-size-po2.conf | 16 + .../bad-fstrm-set-output-notify-threshold.conf | 16 + .../bad-fstrm-set-output-queue-size-max.conf | 19 + .../bad-fstrm-set-output-queue-size-min.conf | 16 + .../dnstap/bad-fstrm-set-reopen-interval-max.conf | 16 + .../dnstap/bad-fstrm-set-reopen-interval-min.conf | 16 + .../dnstap/bad-missing-dnstap-output-view.conf | 16 + .../system/dnstap/bad-missing-dnstap-output.conf | 17 + bin/tests/system/dnstap/bad-size-version.conf | 16 + bin/tests/system/dnstap/clean.sh | 31 + .../system/dnstap/good-dnstap-in-options.conf | 18 + bin/tests/system/dnstap/good-dnstap-in-view.conf | 21 + .../system/dnstap/good-fstrm-reopen-interval.conf | 16 + .../system/dnstap/good-fstrm-set-buffer-hint.conf | 16 + .../dnstap/good-fstrm-set-flush-timeout.conf | 16 + .../dnstap/good-fstrm-set-input-queue-size.conf | 16 + .../good-fstrm-set-output-notify-threshold.conf | 16 + .../good-fstrm-set-output-queue-model-mpsc.conf | 16 + .../good-fstrm-set-output-queue-model-spsc.conf | 16 + .../dnstap/good-fstrm-set-output-queue-size.conf | 16 + .../dnstap/good-fstrm-set-reopen-interval.conf | 16 + bin/tests/system/dnstap/good-size-unlimited.conf | 17 + bin/tests/system/dnstap/good-size-version.conf | 17 + bin/tests/system/dnstap/large-answer.fstrm | Bin 0 -> 981 bytes bin/tests/system/dnstap/ns1/named.conf.in | 47 + bin/tests/system/dnstap/ns1/root.db | 24 + bin/tests/system/dnstap/ns2/example.db.in | 30 + bin/tests/system/dnstap/ns2/named.conf.in | 53 + bin/tests/system/dnstap/ns3/named.args | 2 + bin/tests/system/dnstap/ns3/named.conf.in | 50 + bin/tests/system/dnstap/ns4/named.conf.in | 49 + bin/tests/system/dnstap/prereq.sh | 20 + bin/tests/system/dnstap/setup.sh | 22 + bin/tests/system/dnstap/tests.sh | 834 + bin/tests/system/dnstap/ydump.py | 29 + bin/tests/system/dscp/clean.sh | 20 + bin/tests/system/dscp/ns1/named.args | 1 + bin/tests/system/dscp/ns1/named.conf.in | 31 + bin/tests/system/dscp/ns1/root.db | 19 + bin/tests/system/dscp/ns2/named.args | 1 + bin/tests/system/dscp/ns2/named.conf.in | 32 + bin/tests/system/dscp/ns3/hint.db | 16 + bin/tests/system/dscp/ns3/named.args | 1 + bin/tests/system/dscp/ns3/named.conf.in | 31 + bin/tests/system/dscp/ns4/named.args | 1 + bin/tests/system/dscp/ns4/named.conf.in | 31 + bin/tests/system/dscp/ns4/root.db | 19 + bin/tests/system/dscp/ns5/named.args | 1 + bin/tests/system/dscp/ns5/named.conf.in | 33 + bin/tests/system/dscp/ns6/hint.db | 16 + bin/tests/system/dscp/ns6/named.args | 1 + bin/tests/system/dscp/ns6/named.conf.in | 31 + bin/tests/system/dscp/ns7/named.args | 1 + bin/tests/system/dscp/ns7/named.conf.in | 36 + bin/tests/system/dscp/setup.sh | 23 + bin/tests/system/dscp/tests.sh | 42 + bin/tests/system/dsdigest/clean.sh | 24 + bin/tests/system/dsdigest/ns1/named.conf.in | 36 + bin/tests/system/dsdigest/ns1/root.db.in | 26 + bin/tests/system/dsdigest/ns1/sign.sh | 37 + bin/tests/system/dsdigest/ns2/bad.db.in | 23 + bin/tests/system/dsdigest/ns2/good.db.in | 23 + bin/tests/system/dsdigest/ns2/named.conf.in | 46 + bin/tests/system/dsdigest/ns2/sign.sh | 44 + bin/tests/system/dsdigest/ns3/named.conf.in | 39 + bin/tests/system/dsdigest/ns4/named.conf.in | 37 + bin/tests/system/dsdigest/setup.sh | 22 + bin/tests/system/dsdigest/tests.sh | 54 + bin/tests/system/dupsigs/check_journal.pl | 211 + bin/tests/system/dupsigs/clean.sh | 24 + bin/tests/system/dupsigs/ns1/named.args | 1 + bin/tests/system/dupsigs/ns1/named.conf.in | 33 + bin/tests/system/dupsigs/ns1/reset_keys.sh | 100 + bin/tests/system/dupsigs/ns1/signing.test.db.in | 18 + bin/tests/system/dupsigs/setup.sh | 24 + bin/tests/system/dupsigs/tests.sh | 70 + bin/tests/system/dyndb/Makefile.in | 23 + bin/tests/system/dyndb/clean.sh | 25 + bin/tests/system/dyndb/driver/AUTHORS | 33 + bin/tests/system/dyndb/driver/Makefile.in | 60 + bin/tests/system/dyndb/driver/README | 92 + bin/tests/system/dyndb/driver/db.c | 814 + bin/tests/system/dyndb/driver/db.h | 47 + bin/tests/system/dyndb/driver/driver.c | 179 + bin/tests/system/dyndb/driver/instance.c | 231 + bin/tests/system/dyndb/driver/instance.h | 76 + bin/tests/system/dyndb/driver/lock.c | 81 + bin/tests/system/dyndb/driver/lock.h | 42 + bin/tests/system/dyndb/driver/log.c | 44 + bin/tests/system/dyndb/driver/log.h | 50 + bin/tests/system/dyndb/driver/syncptr.c | 337 + bin/tests/system/dyndb/driver/syncptr.h | 46 + bin/tests/system/dyndb/driver/util.h | 85 + bin/tests/system/dyndb/driver/zone.c | 265 + bin/tests/system/dyndb/driver/zone.h | 45 + bin/tests/system/dyndb/ns1/named.conf.in | 39 + bin/tests/system/dyndb/prereq.sh | 27 + bin/tests/system/dyndb/setup.sh | 17 + bin/tests/system/dyndb/tests.sh | 165 + bin/tests/system/ecdsa/clean.sh | 24 + bin/tests/system/ecdsa/ns1/named.conf.in | 36 + bin/tests/system/ecdsa/ns1/root.db.in | 21 + bin/tests/system/ecdsa/ns1/sign.sh | 56 + bin/tests/system/ecdsa/ns2/named.conf.in | 36 + bin/tests/system/ecdsa/ns3/named.conf.in | 36 + bin/tests/system/ecdsa/setup.sh | 33 + bin/tests/system/ecdsa/tests.sh | 53 + bin/tests/system/eddsa/clean.sh | 25 + bin/tests/system/eddsa/ns1/named.conf.in | 36 + bin/tests/system/eddsa/ns1/root.db.in | 21 + bin/tests/system/eddsa/ns1/sign.sh | 56 + .../system/eddsa/ns2/Xexample.com.+015+03613.key | 1 + .../eddsa/ns2/Xexample.com.+015+03613.private | 4 + .../system/eddsa/ns2/Xexample.com.+015+35217.key | 1 + .../eddsa/ns2/Xexample.com.+015+35217.private | 3 + bin/tests/system/eddsa/ns2/example.com.db.in | 22 + bin/tests/system/eddsa/ns2/named.conf.in | 36 + bin/tests/system/eddsa/ns2/sign.sh | 37 + .../system/eddsa/ns3/Xexample.com.+016+09713.key | 1 + .../eddsa/ns3/Xexample.com.+016+09713.private | 3 + .../system/eddsa/ns3/Xexample.com.+016+38353.key | 1 + .../eddsa/ns3/Xexample.com.+016+38353.private | 3 + bin/tests/system/eddsa/ns3/example.com.db.in | 22 + bin/tests/system/eddsa/ns3/named.conf.in | 36 + bin/tests/system/eddsa/ns3/sign.sh | 36 + bin/tests/system/eddsa/prereq.sh | 25 + bin/tests/system/eddsa/setup.sh | 40 + bin/tests/system/eddsa/tests.sh | 84 + bin/tests/system/ednscompliance/clean.sh | 19 + bin/tests/system/ednscompliance/ns1/named.conf.in | 28 + bin/tests/system/ednscompliance/ns1/root.db | 21 + bin/tests/system/ednscompliance/setup.sh | 17 + bin/tests/system/ednscompliance/tests.sh | 113 + bin/tests/system/emptyzones/clean.sh | 19 + bin/tests/system/emptyzones/ns1/empty.db | 13 + bin/tests/system/emptyzones/ns1/named1.conf.in | 45 + bin/tests/system/emptyzones/ns1/named2.conf.in | 48 + bin/tests/system/emptyzones/ns1/rfc1918.zones | 32 + bin/tests/system/emptyzones/ns1/root.hint | 14 + bin/tests/system/emptyzones/setup.sh | 18 + bin/tests/system/emptyzones/tests.sh | 45 + bin/tests/system/feature-test.c | 241 + bin/tests/system/fetchlimit/ans4/ans.pl | 86 + bin/tests/system/fetchlimit/clean.sh | 19 + bin/tests/system/fetchlimit/ns1/named.conf.in | 35 + bin/tests/system/fetchlimit/ns1/root.db | 24 + bin/tests/system/fetchlimit/ns2/example.db | 37 + bin/tests/system/fetchlimit/ns2/named.conf.in | 41 + bin/tests/system/fetchlimit/ns3/named.args | 1 + bin/tests/system/fetchlimit/ns3/named1.conf.in | 47 + bin/tests/system/fetchlimit/ns3/named2.conf.in | 45 + bin/tests/system/fetchlimit/ns3/named3.conf.in | 45 + bin/tests/system/fetchlimit/ns3/root.hint | 14 + bin/tests/system/fetchlimit/prereq.sh | 23 + bin/tests/system/fetchlimit/setup.sh | 19 + bin/tests/system/fetchlimit/tests.sh | 200 + bin/tests/system/filter-aaaa/clean.sh | 33 + bin/tests/system/filter-aaaa/conf/bad1.conf | 17 + bin/tests/system/filter-aaaa/conf/bad2.conf | 26 + bin/tests/system/filter-aaaa/conf/bad3.conf | 19 + bin/tests/system/filter-aaaa/conf/bad4.conf | 19 + bin/tests/system/filter-aaaa/conf/bad5.conf | 21 + bin/tests/system/filter-aaaa/conf/good1.conf | 16 + bin/tests/system/filter-aaaa/conf/good2.conf | 16 + bin/tests/system/filter-aaaa/conf/good3.conf | 17 + bin/tests/system/filter-aaaa/conf/good4.conf | 17 + bin/tests/system/filter-aaaa/conf/good5.conf | 19 + bin/tests/system/filter-aaaa/ns1/named1.conf.in | 47 + bin/tests/system/filter-aaaa/ns1/named2.conf.in | 44 + bin/tests/system/filter-aaaa/ns1/root.db | 25 + bin/tests/system/filter-aaaa/ns1/sign.sh | 35 + bin/tests/system/filter-aaaa/ns1/signed.db.in | 25 + bin/tests/system/filter-aaaa/ns1/unsigned.db | 25 + bin/tests/system/filter-aaaa/ns2/hints | 16 + bin/tests/system/filter-aaaa/ns2/named1.conf.in | 44 + bin/tests/system/filter-aaaa/ns2/named2.conf.in | 44 + bin/tests/system/filter-aaaa/ns3/hints | 16 + bin/tests/system/filter-aaaa/ns3/named1.conf.in | 44 + bin/tests/system/filter-aaaa/ns3/named2.conf.in | 44 + bin/tests/system/filter-aaaa/ns4/named1.conf.in | 44 + bin/tests/system/filter-aaaa/ns4/named2.conf.in | 44 + bin/tests/system/filter-aaaa/ns4/root.db | 24 + bin/tests/system/filter-aaaa/ns4/sign.sh | 28 + bin/tests/system/filter-aaaa/ns4/signed.db.in | 25 + bin/tests/system/filter-aaaa/ns4/unsigned.db | 25 + bin/tests/system/filter-aaaa/ns5/hints | 16 + bin/tests/system/filter-aaaa/ns5/named.conf.in | 49 + bin/tests/system/filter-aaaa/prereq.sh | 27 + bin/tests/system/filter-aaaa/setup.sh | 24 + bin/tests/system/filter-aaaa/tests.sh | 1419 + bin/tests/system/formerr/clean.sh | 21 + bin/tests/system/formerr/formerr.pl | 97 + bin/tests/system/formerr/nametoolong | 19 + bin/tests/system/formerr/noquestions | 1 + bin/tests/system/formerr/ns1/named.conf.in | 28 + bin/tests/system/formerr/ns1/root.db | 21 + bin/tests/system/formerr/setup.sh | 17 + bin/tests/system/formerr/tests.sh | 47 + bin/tests/system/formerr/twoquestions | 7 + bin/tests/system/forward/ans11/ans.py | 143 + bin/tests/system/forward/ans6/ans.pl | 562 + bin/tests/system/forward/clean.sh | 27 + bin/tests/system/forward/ns1/diditwork.net.db | 22 + bin/tests/system/forward/ns1/example.db | 23 + bin/tests/system/forward/ns1/named.conf.in | 87 + bin/tests/system/forward/ns1/net.example.lll | 15 + bin/tests/system/forward/ns1/root.db.in | 36 + bin/tests/system/forward/ns1/sign.sh | 34 + bin/tests/system/forward/ns1/sld.tld.db | 22 + bin/tests/system/forward/ns1/spoofed.net.db | 22 + bin/tests/system/forward/ns1/sub.local.net.db | 22 + bin/tests/system/forward/ns10/fakenet.zone | 17 + bin/tests/system/forward/ns10/fakenet2.zone | 15 + bin/tests/system/forward/ns10/fakesublocalnet.zone | 15 + bin/tests/system/forward/ns10/fakesublocaltld.zone | 15 + bin/tests/system/forward/ns10/named.conf.in | 53 + bin/tests/system/forward/ns10/net.example.lll | 15 + bin/tests/system/forward/ns10/spoofednet.zone | 16 + bin/tests/system/forward/ns2/example.db | 23 + bin/tests/system/forward/ns2/named.conf.in | 72 + bin/tests/system/forward/ns2/root.db | 30 + bin/tests/system/forward/ns2/tld.db | 29 + bin/tests/system/forward/ns3/named1.conf.in | 66 + bin/tests/system/forward/ns3/named2.conf.in | 43 + bin/tests/system/forward/ns3/root.db | 30 + bin/tests/system/forward/ns4/malicious.db | 24 + bin/tests/system/forward/ns4/named.conf.in | 69 + bin/tests/system/forward/ns4/root.db | 30 + bin/tests/system/forward/ns4/sibling.tld.db | 22 + bin/tests/system/forward/ns5/named.conf.in | 36 + bin/tests/system/forward/ns5/rebind.db | 24 + bin/tests/system/forward/ns5/root.db | 30 + bin/tests/system/forward/ns7/named.conf.in | 30 + bin/tests/system/forward/ns7/root.db | 30 + bin/tests/system/forward/ns8/named.conf.in | 35 + bin/tests/system/forward/ns8/root.db | 13 + bin/tests/system/forward/ns8/sub.local.tld.db | 15 + bin/tests/system/forward/ns9/local.net.db | 16 + bin/tests/system/forward/ns9/local.tld.db | 15 + bin/tests/system/forward/ns9/named1.conf.in | 67 + bin/tests/system/forward/ns9/named2.conf.in | 70 + bin/tests/system/forward/ns9/named3.conf.in | 50 + bin/tests/system/forward/ns9/named4.conf.in | 47 + bin/tests/system/forward/ns9/root.db | 13 + bin/tests/system/forward/prereq.sh | 37 + bin/tests/system/forward/rfc1918-inherited.conf | 17 + bin/tests/system/forward/rfc1918-notinherited.conf | 18 + bin/tests/system/forward/setup.sh | 30 + bin/tests/system/forward/tests.sh | 383 + bin/tests/system/forward/ula-inherited.conf | 17 + bin/tests/system/forward/ula-notinherited.conf | 18 + bin/tests/system/fromhex.pl | 47 + bin/tests/system/genzone.sh | 511 + bin/tests/system/geoip2/clean.sh | 20 + bin/tests/system/geoip2/conf/bad-areacode.conf | 38 + bin/tests/system/geoip2/conf/bad-dbname.conf | 30 + bin/tests/system/geoip2/conf/bad-netspeed.conf | 37 + bin/tests/system/geoip2/conf/bad-regiondb.conf | 44 + bin/tests/system/geoip2/conf/bad-threeletter.conf | 35 + bin/tests/system/geoip2/conf/good-options.conf | 36 + bin/tests/system/geoip2/data/GeoIP2-City.json | 506 + bin/tests/system/geoip2/data/GeoIP2-City.mmdb | Bin 0 -> 3165 bytes bin/tests/system/geoip2/data/GeoIP2-Country.json | 242 + bin/tests/system/geoip2/data/GeoIP2-Country.mmdb | Bin 0 -> 2971 bytes bin/tests/system/geoip2/data/GeoIP2-Domain.json | 72 + bin/tests/system/geoip2/data/GeoIP2-Domain.mmdb | Bin 0 -> 2524 bytes bin/tests/system/geoip2/data/GeoIP2-ISP.json | 86 + bin/tests/system/geoip2/data/GeoIP2-ISP.mmdb | Bin 0 -> 2626 bytes bin/tests/system/geoip2/data/GeoLite2-ASN.json | 86 + bin/tests/system/geoip2/data/GeoLite2-ASN.mmdb | Bin 0 -> 2672 bytes bin/tests/system/geoip2/data/README.md | 23 + bin/tests/system/geoip2/data/write-test-data.pl | 194 + bin/tests/system/geoip2/ns2/example.db.in | 21 + bin/tests/system/geoip2/ns2/named1.conf.in | 108 + bin/tests/system/geoip2/ns2/named10.conf.in | 100 + bin/tests/system/geoip2/ns2/named11.conf.in | 100 + bin/tests/system/geoip2/ns2/named12.conf.in | 41 + bin/tests/system/geoip2/ns2/named2.conf.in | 108 + bin/tests/system/geoip2/ns2/named3.conf.in | 100 + bin/tests/system/geoip2/ns2/named4.conf.in | 84 + bin/tests/system/geoip2/ns2/named5.conf.in | 92 + bin/tests/system/geoip2/ns2/named6.conf.in | 100 + bin/tests/system/geoip2/ns2/named7.conf.in | 100 + bin/tests/system/geoip2/ns2/named8.conf.in | 100 + bin/tests/system/geoip2/ns2/named9.conf.in | 100 + bin/tests/system/geoip2/prereq.sh | 21 + bin/tests/system/geoip2/setup.sh | 24 + bin/tests/system/geoip2/tests.sh | 489 + bin/tests/system/get_algorithms.py | 243 + bin/tests/system/glue/clean.sh | 23 + bin/tests/system/glue/fi.good | 27 + bin/tests/system/glue/noglue.good | 14 + bin/tests/system/glue/ns1/named.conf.in | 38 + bin/tests/system/glue/ns1/net.db | 34 + bin/tests/system/glue/ns1/root-servers.nil.db | 25 + bin/tests/system/glue/ns1/root.db | 44 + bin/tests/system/glue/setup.sh | 17 + bin/tests/system/glue/tests.sh | 34 + bin/tests/system/idna/clean.sh | 19 + bin/tests/system/idna/ns1/named.conf.in | 30 + bin/tests/system/idna/ns1/root.db | 26 + bin/tests/system/idna/setup.sh | 18 + bin/tests/system/idna/tests.sh | 378 + bin/tests/system/ifconfig.bat | 49 + bin/tests/system/ifconfig.sh | 271 + bin/tests/system/inline/clean.sh | 27 + bin/tests/system/inline/ns1/named.conf.in | 36 + bin/tests/system/inline/ns1/root.db.in | 59 + bin/tests/system/inline/ns1/sign.sh | 26 + bin/tests/system/inline/ns2/bits.db.in | 22 + bin/tests/system/inline/ns2/named.conf.in | 85 + bin/tests/system/inline/ns2/nsec3-loop.db.in | 25 + bin/tests/system/inline/ns3/include.db.in | 12 + bin/tests/system/inline/ns3/master.db.in | 21 + bin/tests/system/inline/ns3/master2.db.in | 23 + bin/tests/system/inline/ns3/master3.db.in | 24 + bin/tests/system/inline/ns3/master4.db.in | 24 + bin/tests/system/inline/ns3/master5.db.in | 24 + bin/tests/system/inline/ns3/master6.db.in | 26 + bin/tests/system/inline/ns3/master7.db.in | 26 + bin/tests/system/inline/ns3/named.conf.in | 179 + bin/tests/system/inline/ns3/sign.sh | 160 + bin/tests/system/inline/ns4/named.conf.in | 33 + bin/tests/system/inline/ns4/noixfr.db.in | 22 + bin/tests/system/inline/ns5/named.conf.post | 42 + bin/tests/system/inline/ns5/named.conf.pre | 39 + bin/tests/system/inline/ns6/named.conf.in | 40 + bin/tests/system/inline/ns7/named.conf.in | 50 + bin/tests/system/inline/ns7/sign.sh | 25 + bin/tests/system/inline/ns8/example.com.db.in | 21 + bin/tests/system/inline/ns8/example.db.in | 26 + bin/tests/system/inline/ns8/example2.db.in | 26 + bin/tests/system/inline/ns8/example3.db.in | 26 + bin/tests/system/inline/ns8/named.conf.in | 162 + bin/tests/system/inline/ns8/sign.sh | 36 + bin/tests/system/inline/setup.sh | 57 + bin/tests/system/inline/tests.sh | 1488 + bin/tests/system/inline/tests_signed_zone_files.py | 67 + bin/tests/system/integrity/clean.sh | 18 + bin/tests/system/integrity/ns1/mx-cname.db | 17 + bin/tests/system/integrity/ns1/named.conf.in | 114 + bin/tests/system/integrity/ns1/srv-cname.db | 17 + bin/tests/system/integrity/setup.sh | 17 + bin/tests/system/integrity/tests.sh | 131 + bin/tests/system/ixfr/ans2/startme | 0 bin/tests/system/ixfr/clean.sh | 26 + bin/tests/system/ixfr/ixfr-stats.good | 3 + bin/tests/system/ixfr/ns1/named.conf.in | 33 + bin/tests/system/ixfr/ns1/startme | 0 bin/tests/system/ixfr/ns3/named.conf.in | 52 + bin/tests/system/ixfr/ns4/named.conf.in | 50 + bin/tests/system/ixfr/ns5/named.conf.in | 50 + bin/tests/system/ixfr/prereq.sh | 23 + bin/tests/system/ixfr/setup.sh | 69 + bin/tests/system/ixfr/tests.sh | 412 + bin/tests/system/journal/clean.sh | 22 + .../system/journal/ns1/changed.ver1.jnl.saved | Bin 0 -> 707 bytes .../system/journal/ns1/changed.ver2.jnl.saved | Bin 0 -> 718 bytes bin/tests/system/journal/ns1/d1212.jnl.saved | Bin 0 -> 1478 bytes bin/tests/system/journal/ns1/d2121.jnl.saved | Bin 0 -> 1478 bytes bin/tests/system/journal/ns1/generic.db.in | 17 + bin/tests/system/journal/ns1/ixfr.db.in | 18 + bin/tests/system/journal/ns1/ixfr.ver1.jnl.saved | Bin 0 -> 686 bytes bin/tests/system/journal/ns1/managed-keys.bind.in | 2 + .../system/journal/ns1/managed-keys.bind.jnl.in | 704 + bin/tests/system/journal/ns1/maxjournal.jnl.saved | Bin 0 -> 13660 bytes bin/tests/system/journal/ns1/maxjournal2.jnl.saved | Bin 0 -> 14259 bytes bin/tests/system/journal/ns1/named.conf.in | 92 + .../system/journal/ns1/unchanged.ver1.jnl.saved | Bin 0 -> 512 bytes .../system/journal/ns1/unchanged.ver2.jnl.saved | Bin 0 -> 512 bytes bin/tests/system/journal/ns2/managed-keys.bind.in | 14 + .../system/journal/ns2/managed-keys.bind.jnl.in | Bin 0 -> 2944 bytes bin/tests/system/journal/ns2/named.conf.in | 36 + bin/tests/system/journal/setup.sh | 51 + bin/tests/system/journal/tests.sh | 255 + bin/tests/system/kasp.sh | 1238 + bin/tests/system/kasp/README | 23 + bin/tests/system/kasp/clean.sh | 36 + bin/tests/system/kasp/kasp.conf | 27 + bin/tests/system/kasp/ns2/named.conf.in | 61 + bin/tests/system/kasp/ns2/secondary.kasp.db.in | 29 + bin/tests/system/kasp/ns2/secondary.kasp.db.in2 | 30 + bin/tests/system/kasp/ns2/setup.sh | 35 + bin/tests/system/kasp/ns2/template.tld.db.in | 27 + bin/tests/system/kasp/ns3/ed25519.conf | 29 + bin/tests/system/kasp/ns3/ed448.conf | 29 + bin/tests/system/kasp/ns3/named-fips.conf.in | 519 + bin/tests/system/kasp/ns3/named.conf.in | 30 + .../system/kasp/ns3/policies/autosign.conf.in | 133 + .../system/kasp/ns3/policies/kasp-fips.conf.in | 118 + bin/tests/system/kasp/ns3/policies/kasp.conf.in | 34 + bin/tests/system/kasp/ns3/setup.sh | 1470 + bin/tests/system/kasp/ns3/template.db.in | 27 + bin/tests/system/kasp/ns3/template2.db.in | 27 + bin/tests/system/kasp/ns4/example1.db.in | 24 + bin/tests/system/kasp/ns4/example2.db.in | 24 + bin/tests/system/kasp/ns4/named.conf.in | 176 + bin/tests/system/kasp/ns4/setup.sh | 33 + bin/tests/system/kasp/ns4/template.db.in | 27 + bin/tests/system/kasp/ns5/named.conf.in | 132 + bin/tests/system/kasp/ns5/setup.sh | 30 + bin/tests/system/kasp/ns5/template.db.in | 27 + bin/tests/system/kasp/ns6/example.db.in | 26 + bin/tests/system/kasp/ns6/example2.db.in | 26 + bin/tests/system/kasp/ns6/example3.db.in | 26 + bin/tests/system/kasp/ns6/named.conf.in | 97 + bin/tests/system/kasp/ns6/named2.conf.in | 185 + bin/tests/system/kasp/ns6/policies/csk1.conf.in | 30 + bin/tests/system/kasp/ns6/policies/csk2.conf.in | 30 + .../system/kasp/ns6/policies/kasp-fips.conf.in | 63 + bin/tests/system/kasp/ns6/policies/kasp.conf.in | 33 + bin/tests/system/kasp/ns6/setup.sh | 409 + bin/tests/system/kasp/ns6/template.db.in | 27 + bin/tests/system/kasp/prereq.sh | 21 + bin/tests/system/kasp/setup.sh | 80 + bin/tests/system/kasp/tests.sh | 4882 ++++ bin/tests/system/keepalive/clean.sh | 21 + bin/tests/system/keepalive/expected | 4 + bin/tests/system/keepalive/ns1/named.conf.in | 38 + bin/tests/system/keepalive/ns1/root.db | 24 + bin/tests/system/keepalive/ns2/example.db | 16 + bin/tests/system/keepalive/ns2/named.conf.in | 45 + bin/tests/system/keepalive/ns3/named.conf.in | 44 + bin/tests/system/keepalive/setup.sh | 19 + bin/tests/system/keepalive/tests.sh | 98 + bin/tests/system/keymgr/01-ksk-inactive/README | 6 + bin/tests/system/keymgr/01-ksk-inactive/expect | 9 + bin/tests/system/keymgr/02-zsk-inactive/README | 6 + bin/tests/system/keymgr/02-zsk-inactive/expect | 9 + bin/tests/system/keymgr/03-ksk-unpublished/README | 6 + bin/tests/system/keymgr/03-ksk-unpublished/expect | 9 + bin/tests/system/keymgr/04-zsk-unpublished/README | 6 + bin/tests/system/keymgr/04-zsk-unpublished/expect | 9 + bin/tests/system/keymgr/05-ksk-unpub-active/README | 7 + bin/tests/system/keymgr/05-ksk-unpub-active/expect | 9 + bin/tests/system/keymgr/06-zsk-unpub-active/README | 7 + bin/tests/system/keymgr/06-zsk-unpub-active/expect | 9 + bin/tests/system/keymgr/07-ksk-ttl/README | 6 + bin/tests/system/keymgr/07-ksk-ttl/expect | 9 + bin/tests/system/keymgr/08-zsk-ttl/README | 6 + bin/tests/system/keymgr/08-zsk-ttl/expect | 9 + bin/tests/system/keymgr/09-no-keys/README | 5 + bin/tests/system/keymgr/09-no-keys/expect | 9 + bin/tests/system/keymgr/10-change-roll/README | 7 + bin/tests/system/keymgr/10-change-roll/expect | 9 + bin/tests/system/keymgr/11-many-simul/README | 6 + bin/tests/system/keymgr/11-many-simul/expect | 9 + bin/tests/system/keymgr/12-many-active/README | 6 + bin/tests/system/keymgr/12-many-active/expect | 9 + bin/tests/system/keymgr/13-noroll/README | 6 + bin/tests/system/keymgr/13-noroll/expect | 9 + bin/tests/system/keymgr/14-wrongalg/README | 6 + bin/tests/system/keymgr/14-wrongalg/expect | 9 + bin/tests/system/keymgr/15-unspec/README | 6 + bin/tests/system/keymgr/15-unspec/expect | 9 + bin/tests/system/keymgr/16-wrongalg-unspec/README | 6 + bin/tests/system/keymgr/16-wrongalg-unspec/expect | 9 + bin/tests/system/keymgr/17-noforce/README | 6 + bin/tests/system/keymgr/17-noforce/expect | 9 + bin/tests/system/keymgr/18-nonstd-prepub/README | 7 + bin/tests/system/keymgr/18-nonstd-prepub/expect | 9 + .../system/keymgr/18-nonstd-prepub/policy.conf.in | 20 + bin/tests/system/keymgr/19-old-keys/README | 7 + bin/tests/system/keymgr/19-old-keys/expect | 12 + bin/tests/system/keymgr/19-old-keys/extra.sh | 23 + bin/tests/system/keymgr/19-old-keys/policy.conf.in | 20 + bin/tests/system/keymgr/clean.sh | 21 + bin/tests/system/keymgr/policy.conf.in | 23 + bin/tests/system/keymgr/policy.good | 187 + bin/tests/system/keymgr/policy.sample | 60 + bin/tests/system/keymgr/setup.sh | 192 + bin/tests/system/keymgr/testpolicy.py | 39 + bin/tests/system/keymgr/tests.sh | 146 + bin/tests/system/keymgr2kasp/README | 17 + bin/tests/system/keymgr2kasp/clean.sh | 34 + bin/tests/system/keymgr2kasp/ns3/kasp.conf.in | 84 + bin/tests/system/keymgr2kasp/ns3/named.conf.in | 98 + bin/tests/system/keymgr2kasp/ns3/named2.conf.in | 87 + bin/tests/system/keymgr2kasp/ns3/setup.sh | 131 + bin/tests/system/keymgr2kasp/ns3/template.db.in | 27 + bin/tests/system/keymgr2kasp/ns4/named.conf.in | 72 + bin/tests/system/keymgr2kasp/ns4/named2.conf.in | 89 + bin/tests/system/keymgr2kasp/ns4/setup.sh | 46 + .../system/keymgr2kasp/ns4/template.ext.db.in | 24 + .../system/keymgr2kasp/ns4/template.int.db.in | 24 + bin/tests/system/keymgr2kasp/setup.sh | 34 + bin/tests/system/keymgr2kasp/tests.sh | 1137 + bin/tests/system/legacy/build.sh | 22 + bin/tests/system/legacy/clean.sh | 31 + bin/tests/system/legacy/ns1/named1.conf.in | 41 + bin/tests/system/legacy/ns1/named2.conf.in | 34 + bin/tests/system/legacy/ns1/root.db | 33 + bin/tests/system/legacy/ns1/trusted.conf | 16 + bin/tests/system/legacy/ns10/ednsrefused.db | 14 + bin/tests/system/legacy/ns10/named.conf.in | 29 + bin/tests/system/legacy/ns10/named.ednsrefused | 1 + bin/tests/system/legacy/ns2/dropedns.db | 14 + bin/tests/system/legacy/ns2/named.conf.in | 29 + bin/tests/system/legacy/ns2/named.dropedns | 1 + bin/tests/system/legacy/ns3/dropedns-notcp.db | 14 + bin/tests/system/legacy/ns3/named.conf.in | 29 + bin/tests/system/legacy/ns3/named.dropedns | 1 + bin/tests/system/legacy/ns3/named.notcp | 1 + bin/tests/system/legacy/ns4/named.args | 1 + bin/tests/system/legacy/ns4/named.conf.in | 29 + bin/tests/system/legacy/ns4/plain.db | 14 + bin/tests/system/legacy/ns5/named.args | 1 + bin/tests/system/legacy/ns5/named.conf.in | 29 + bin/tests/system/legacy/ns5/named.notcp | 1 + bin/tests/system/legacy/ns5/plain-notcp.db | 14 + bin/tests/system/legacy/ns6/edns512.db.in | 14 + bin/tests/system/legacy/ns6/edns512.db.signed | 248 + bin/tests/system/legacy/ns6/named.args | 1 + bin/tests/system/legacy/ns6/named.conf.in | 29 + bin/tests/system/legacy/ns6/sign.sh | 31 + bin/tests/system/legacy/ns7/edns512-notcp.db.in | 14 + .../system/legacy/ns7/edns512-notcp.db.signed | 248 + bin/tests/system/legacy/ns7/named.args | 1 + bin/tests/system/legacy/ns7/named.conf.in | 32 + bin/tests/system/legacy/ns7/named.notcp | 1 + bin/tests/system/legacy/ns7/sign.sh | 34 + bin/tests/system/legacy/ns8/ednsformerr.db | 14 + bin/tests/system/legacy/ns8/named.conf.in | 29 + bin/tests/system/legacy/ns8/named.ednsformerr | 1 + bin/tests/system/legacy/ns9/ednsnotimp.db | 14 + bin/tests/system/legacy/ns9/named.conf.in | 29 + bin/tests/system/legacy/ns9/named.ednsnotimp | 1 + bin/tests/system/legacy/setup.sh | 26 + bin/tests/system/legacy/tests.sh | 275 + bin/tests/system/limits/clean.sh | 22 + bin/tests/system/limits/knowngood.dig.out.1000 | 1023 + bin/tests/system/limits/knowngood.dig.out.2000 | 2023 ++ bin/tests/system/limits/knowngood.dig.out.3000 | 3023 +++ bin/tests/system/limits/knowngood.dig.out.4000 | 4023 +++ .../limits/knowngood.dig.out.a-maximum-rrset | 4114 +++ bin/tests/system/limits/ns1/example.db | 19112 +++++++++++++ bin/tests/system/limits/ns1/named.conf.in | 35 + bin/tests/system/limits/ns1/root.db | 24 + bin/tests/system/limits/setup.sh | 17 + bin/tests/system/limits/tests.sh | 56 + bin/tests/system/logfileconfig/clean.sh | 36 + bin/tests/system/logfileconfig/named1.args | 1 + bin/tests/system/logfileconfig/named2.args | 1 + .../system/logfileconfig/ns1/named.dirconf.in | 43 + .../system/logfileconfig/ns1/named.iso8601-utc.in | 43 + .../system/logfileconfig/ns1/named.iso8601.in | 43 + .../system/logfileconfig/ns1/named.pipeconf.in | 43 + bin/tests/system/logfileconfig/ns1/named.plain.in | 50 + .../system/logfileconfig/ns1/named.plainconf.in | 34 + .../system/logfileconfig/ns1/named.symconf.in | 43 + bin/tests/system/logfileconfig/ns1/named.tsconf.in | 52 + .../system/logfileconfig/ns1/named.unlimited.in | 52 + .../system/logfileconfig/ns1/named.versconf.in | 52 + bin/tests/system/logfileconfig/setup.sh | 19 + bin/tests/system/logfileconfig/tests.sh | 244 + bin/tests/system/masterfile/clean.sh | 20 + bin/tests/system/masterfile/knowngood.dig.out | 32 + bin/tests/system/masterfile/ns1/include.db | 35 + bin/tests/system/masterfile/ns1/named.conf.in | 39 + bin/tests/system/masterfile/ns1/sub.db | 15 + bin/tests/system/masterfile/ns1/ttl1.db | 27 + bin/tests/system/masterfile/ns1/ttl2.db | 30 + bin/tests/system/masterfile/ns2/example.db | 21 + bin/tests/system/masterfile/ns2/named.conf.in | 42 + bin/tests/system/masterfile/setup.sh | 19 + bin/tests/system/masterfile/tests.sh | 62 + .../masterfile/zone/inheritownerafterinclude.db | 14 + .../masterfile/zone/inheritownerafterinclude.good | 3 + bin/tests/system/masterfile/zone/nameservers.db | 12 + bin/tests/system/masterformat/clean.sh | 35 + bin/tests/system/masterformat/ns1/compile.sh | 36 + bin/tests/system/masterformat/ns1/example.db | 58 + bin/tests/system/masterformat/ns1/large.db.in | 22 + bin/tests/system/masterformat/ns1/named.conf.in | 87 + bin/tests/system/masterformat/ns1/signed.db | 29 + .../system/masterformat/ns2/formerly-text.db.in | 48 + bin/tests/system/masterformat/ns2/named.conf.in | 63 + bin/tests/system/masterformat/ns3/named.conf.in | 45 + bin/tests/system/masterformat/setup.sh | 31 + bin/tests/system/masterformat/tests.sh | 357 + bin/tests/system/metadata/child.db | 24 + bin/tests/system/metadata/clean.sh | 21 + bin/tests/system/metadata/parent.db | 31 + bin/tests/system/metadata/setup.sh | 61 + bin/tests/system/metadata/tests.sh | 213 + bin/tests/system/mirror/README | 26 + bin/tests/system/mirror/clean.sh | 30 + bin/tests/system/mirror/ns1/named.conf.in | 28 + bin/tests/system/mirror/ns1/root.db.in | 19 + bin/tests/system/mirror/ns1/sign.sh | 38 + bin/tests/system/mirror/ns2/example.db.in | 17 + .../system/mirror/ns2/initially-unavailable.db.in | 16 + bin/tests/system/mirror/ns2/named.conf.in | 85 + bin/tests/system/mirror/ns2/sign.sh | 80 + bin/tests/system/mirror/ns2/sub.example.db.in | 15 + bin/tests/system/mirror/ns2/verify.db.in | 15 + bin/tests/system/mirror/ns3/named.args | 1 + bin/tests/system/mirror/ns3/named.conf.in | 101 + bin/tests/system/mirror/setup.sh | 26 + bin/tests/system/mirror/tests.sh | 557 + bin/tests/system/mkeys/README | 34 + bin/tests/system/mkeys/clean.sh | 33 + bin/tests/system/mkeys/ns1/named1.conf.in | 59 + bin/tests/system/mkeys/ns1/named2.conf.in | 57 + bin/tests/system/mkeys/ns1/named3.conf.in | 51 + bin/tests/system/mkeys/ns1/root.db | 28 + bin/tests/system/mkeys/ns1/sign.sh | 94 + bin/tests/system/mkeys/ns1/sub.tld.db | 21 + bin/tests/system/mkeys/ns1/tld.db | 23 + bin/tests/system/mkeys/ns1/unsupported.key | 1 + bin/tests/system/mkeys/ns2/named.args | 1 + bin/tests/system/mkeys/ns2/named.conf.in | 43 + bin/tests/system/mkeys/ns3/named.args | 1 + bin/tests/system/mkeys/ns3/named.conf.in | 45 + bin/tests/system/mkeys/ns4/named.conf.in | 48 + bin/tests/system/mkeys/ns4/sign.sh | 25 + bin/tests/system/mkeys/ns4/sub.foo.db | 21 + bin/tests/system/mkeys/ns5/foo.db | 23 + bin/tests/system/mkeys/ns5/named.conf.in | 51 + bin/tests/system/mkeys/ns5/named1.args | 1 + bin/tests/system/mkeys/ns5/named2.args | 1 + bin/tests/system/mkeys/ns6/named.args | 1 + bin/tests/system/mkeys/ns6/named.conf.in | 44 + bin/tests/system/mkeys/ns6/setup.sh | 34 + bin/tests/system/mkeys/ns6/unsupported-managed.key | 1 + bin/tests/system/mkeys/ns7/named.conf.in | 51 + bin/tests/system/mkeys/setup.sh | 45 + bin/tests/system/mkeys/tests.sh | 885 + bin/tests/system/names/clean.sh | 20 + bin/tests/system/names/ns1/example.db | 50 + bin/tests/system/names/ns1/named.conf.in | 44 + bin/tests/system/names/setup.sh | 17 + bin/tests/system/names/tests.sh | 48 + bin/tests/system/notify/clean.sh | 39 + bin/tests/system/notify/ns1/named.conf.in | 29 + bin/tests/system/notify/ns1/root.db | 24 + bin/tests/system/notify/ns2/example1.db | 144 + bin/tests/system/notify/ns2/example2.db | 144 + bin/tests/system/notify/ns2/example3.db | 144 + bin/tests/system/notify/ns2/example4.db | 144 + bin/tests/system/notify/ns2/generic.db | 25 + bin/tests/system/notify/ns2/named.conf.in | 84 + bin/tests/system/notify/ns3/named.conf.in | 35 + bin/tests/system/notify/ns4/named.conf.in | 35 + bin/tests/system/notify/ns4/named.port.in | 1 + bin/tests/system/notify/ns5/named.conf.in | 69 + bin/tests/system/notify/ns5/x21.db | 22 + bin/tests/system/notify/setup.sh | 26 + bin/tests/system/notify/tests.sh | 242 + bin/tests/system/nsec3/clean.sh | 21 + bin/tests/system/nsec3/ns2/named.conf.in | 46 + bin/tests/system/nsec3/ns2/setup.sh | 22 + bin/tests/system/nsec3/ns2/template.db.in | 28 + bin/tests/system/nsec3/ns3/named.conf.in | 162 + bin/tests/system/nsec3/ns3/named2.conf.in | 153 + .../nsec3/ns3/nsec3-fails-to-load.kasp.db.in | 19 + bin/tests/system/nsec3/ns3/setup.sh | 35 + bin/tests/system/nsec3/ns3/template.db.in | 27 + bin/tests/system/nsec3/setup.sh | 30 + bin/tests/system/nsec3/tests.sh | 388 + bin/tests/system/nslookup/clean.sh | 20 + bin/tests/system/nslookup/ns1/example.net.db | 31 + bin/tests/system/nslookup/ns1/named.conf.in | 33 + bin/tests/system/nslookup/setup.sh | 21 + bin/tests/system/nslookup/tests.sh | 112 + bin/tests/system/nsupdate/ans4/ans.pl | 60 + bin/tests/system/nsupdate/clean.sh | 69 + bin/tests/system/nsupdate/commandlist | 15 + bin/tests/system/nsupdate/knowngood.ns1.after | 99 + bin/tests/system/nsupdate/knowngood.ns1.afterstop | 3 + bin/tests/system/nsupdate/knowngood.ns1.before | 98 + bin/tests/system/nsupdate/krb/setup.sh | 117 + bin/tests/system/nsupdate/ns1/example1.db | 146 + bin/tests/system/nsupdate/ns1/many.test.db.in | 21 + bin/tests/system/nsupdate/ns1/max-ttl.db | 29 + bin/tests/system/nsupdate/ns1/maxjournal.db.in | 20 + bin/tests/system/nsupdate/ns1/named.conf.in | 162 + bin/tests/system/nsupdate/ns1/sample.db.in | 19 + bin/tests/system/nsupdate/ns10/dns.keytab | Bin 0 -> 168 bytes bin/tests/system/nsupdate/ns10/example.com.db.in | 21 + bin/tests/system/nsupdate/ns10/in-addr.db.in | 21 + bin/tests/system/nsupdate/ns10/machine.ccache | Bin 0 -> 1217 bytes bin/tests/system/nsupdate/ns10/named.conf.in | 50 + bin/tests/system/nsupdate/ns2/named.conf.in | 74 + bin/tests/system/nsupdate/ns2/sample.db.in | 21 + .../system/nsupdate/ns3/delegation.test.db.in | 15 + bin/tests/system/nsupdate/ns3/dnskey.test.db.in | 15 + bin/tests/system/nsupdate/ns3/example.db.in | 15 + .../system/nsupdate/ns3/multisigner.test.db.in | 14 + bin/tests/system/nsupdate/ns3/named.conf.in | 73 + .../system/nsupdate/ns3/nsec3param.test.db.in | 15 + bin/tests/system/nsupdate/ns3/sign.sh | 51 + bin/tests/system/nsupdate/ns3/too-big.test.db.in | 15 + bin/tests/system/nsupdate/ns5/local.db.in | 25 + bin/tests/system/nsupdate/ns5/named.args | 1 + bin/tests/system/nsupdate/ns5/named.conf.in | 40 + bin/tests/system/nsupdate/ns6/in-addr.db.in | 21 + bin/tests/system/nsupdate/ns6/named.args | 1 + bin/tests/system/nsupdate/ns6/named.conf.in | 40 + bin/tests/system/nsupdate/ns7/dns.keytab | Bin 0 -> 166 bytes bin/tests/system/nsupdate/ns7/example.com.db.in | 21 + bin/tests/system/nsupdate/ns7/in-addr.db.in | 21 + bin/tests/system/nsupdate/ns7/machine.ccache | Bin 0 -> 1327 bytes bin/tests/system/nsupdate/ns7/named.conf.in | 50 + .../nsupdate/ns8/dns-other-than-KRB5_KTNAME.keytab | Bin 0 -> 166 bytes bin/tests/system/nsupdate/ns8/example.com.db.in | 21 + bin/tests/system/nsupdate/ns8/in-addr.db.in | 21 + bin/tests/system/nsupdate/ns8/machine.ccache | Bin 0 -> 1327 bytes bin/tests/system/nsupdate/ns8/named.conf.in | 50 + bin/tests/system/nsupdate/ns9/dns.keytab | Bin 0 -> 166 bytes bin/tests/system/nsupdate/ns9/example.com.db.in | 21 + bin/tests/system/nsupdate/ns9/in-addr.db.in | 21 + bin/tests/system/nsupdate/ns9/machine.ccache | Bin 0 -> 1215 bytes bin/tests/system/nsupdate/ns9/named.conf.in | 64 + bin/tests/system/nsupdate/prereq.sh | 28 + bin/tests/system/nsupdate/setup.sh | 106 + bin/tests/system/nsupdate/tests.sh | 1552 ++ bin/tests/system/nsupdate/update_test.pl | 429 + bin/tests/system/nsupdate/verylarge.in | 3 + bin/tests/system/nzd2nzf/clean.sh | 21 + bin/tests/system/nzd2nzf/ns1/added.db | 26 + bin/tests/system/nzd2nzf/ns1/named.conf.in | 31 + bin/tests/system/nzd2nzf/prereq.sh | 20 + bin/tests/system/nzd2nzf/setup.sh | 17 + bin/tests/system/nzd2nzf/tests.sh | 80 + bin/tests/system/org.isc.bind.system | 27 + bin/tests/system/org.isc.bind.system.plist | 17 + bin/tests/system/packet.pl | 164 + bin/tests/system/padding/clean.sh | 21 + bin/tests/system/padding/ns1/named.conf.in | 38 + bin/tests/system/padding/ns1/root.db | 24 + bin/tests/system/padding/ns2/example.db | 15 + bin/tests/system/padding/ns2/named.conf.in | 45 + bin/tests/system/padding/ns3/named.conf.in | 44 + bin/tests/system/padding/ns4/named.conf.in | 44 + bin/tests/system/padding/setup.sh | 24 + bin/tests/system/padding/tests.sh | 134 + bin/tests/system/parallel.sh | 36 + bin/tests/system/pending/clean.sh | 27 + bin/tests/system/pending/ns1/named.conf.in | 30 + bin/tests/system/pending/ns1/root.db.in | 29 + bin/tests/system/pending/ns1/sign.sh | 36 + bin/tests/system/pending/ns2/example.com.db.in | 27 + bin/tests/system/pending/ns2/example.db.in | 26 + bin/tests/system/pending/ns2/forgery.db | 24 + bin/tests/system/pending/ns2/named.conf.in | 51 + bin/tests/system/pending/ns2/sign.sh | 34 + bin/tests/system/pending/ns3/hostile.db | 22 + bin/tests/system/pending/ns3/mail.example.db | 23 + bin/tests/system/pending/ns3/named.conf.in | 44 + bin/tests/system/pending/ns4/named.conf.in | 30 + bin/tests/system/pending/setup.sh | 24 + bin/tests/system/pending/tests.sh | 199 + bin/tests/system/pipelined/Makefile.in | 49 + bin/tests/system/pipelined/ans5/ans.py | 212 + bin/tests/system/pipelined/clean.sh | 19 + bin/tests/system/pipelined/input | 8 + bin/tests/system/pipelined/inputb | 8 + bin/tests/system/pipelined/ns1/named.conf.in | 39 + bin/tests/system/pipelined/ns1/root.db | 27 + bin/tests/system/pipelined/ns2/examplea.db | 32 + bin/tests/system/pipelined/ns2/named.conf.in | 45 + bin/tests/system/pipelined/ns3/exampleb.db | 32 + bin/tests/system/pipelined/ns3/named.conf.in | 45 + bin/tests/system/pipelined/ns4/named.conf.in | 41 + bin/tests/system/pipelined/pipequeries.c | 322 + bin/tests/system/pipelined/prereq.sh | 31 + bin/tests/system/pipelined/ref | 8 + bin/tests/system/pipelined/refb | 8 + bin/tests/system/pipelined/setup.sh | 22 + bin/tests/system/pipelined/tests.sh | 81 + .../system/pkcs11/2037-pk11_numbits-crash-test.pkt | 20 + bin/tests/system/pkcs11/clean.sh | 21 + bin/tests/system/pkcs11/ns1/example.db.in | 24 + bin/tests/system/pkcs11/ns1/named.conf.in | 36 + bin/tests/system/pkcs11/setup.sh | 96 + bin/tests/system/pkcs11/tests.sh | 149 + bin/tests/system/pkcs11/usepkcs11 | 1 + bin/tests/system/pytest_custom_markers.py | 60 + bin/tests/system/qmin/ans2/ans.py | 401 + bin/tests/system/qmin/ans3/ans.py | 274 + bin/tests/system/qmin/ans4/ans.py | 320 + bin/tests/system/qmin/clean.sh | 20 + bin/tests/system/qmin/ns1/named.conf.in | 32 + bin/tests/system/qmin/ns1/root.db | 41 + bin/tests/system/qmin/ns5/named.conf.in | 43 + bin/tests/system/qmin/ns6/named.conf.in | 43 + bin/tests/system/qmin/ns7/named.conf.in | 51 + bin/tests/system/qmin/prereq.sh | 31 + bin/tests/system/qmin/setup.sh | 20 + bin/tests/system/qmin/tests.sh | 541 + bin/tests/system/reclimit/README | 19 + bin/tests/system/reclimit/ans2/ans.pl | 235 + bin/tests/system/reclimit/ans4/ans.pl | 240 + bin/tests/system/reclimit/ans7/ans.pl | 76 + bin/tests/system/reclimit/clean.sh | 22 + bin/tests/system/reclimit/ns1/named.conf.in | 27 + bin/tests/system/reclimit/ns1/root.db | 21 + bin/tests/system/reclimit/ns3/hints.db | 13 + bin/tests/system/reclimit/ns3/named1.conf.in | 39 + bin/tests/system/reclimit/ns3/named2.conf.in | 39 + bin/tests/system/reclimit/ns3/named3.conf.in | 40 + bin/tests/system/reclimit/ns3/named4.conf.in | 40 + bin/tests/system/reclimit/prereq.sh | 37 + bin/tests/system/reclimit/setup.sh | 18 + bin/tests/system/reclimit/tests.sh | 211 + bin/tests/system/redirect/clean.sh | 38 + bin/tests/system/redirect/conf/bad1.conf | 25 + bin/tests/system/redirect/conf/bad2.conf | 25 + bin/tests/system/redirect/conf/bad3.conf | 24 + bin/tests/system/redirect/conf/good1.conf | 22 + bin/tests/system/redirect/conf/good2.conf | 22 + bin/tests/system/redirect/conf/good3.conf | 23 + bin/tests/system/redirect/conf/good4.conf | 23 + bin/tests/system/redirect/ns1/example.db | 50 + bin/tests/system/redirect/ns1/named.conf.in | 57 + bin/tests/system/redirect/ns1/redirect.db | 20 + bin/tests/system/redirect/ns1/root.db | 19 + bin/tests/system/redirect/ns1/sign.sh | 37 + bin/tests/system/redirect/ns2/example.db.in | 16 + bin/tests/system/redirect/ns2/named.conf.in | 57 + bin/tests/system/redirect/ns2/redirect.db.in | 20 + bin/tests/system/redirect/ns3/example.db | 50 + bin/tests/system/redirect/ns3/named.conf.in | 54 + bin/tests/system/redirect/ns3/redirect.db | 16 + bin/tests/system/redirect/ns3/root.db | 20 + bin/tests/system/redirect/ns3/sign.sh | 37 + bin/tests/system/redirect/ns4/example.db.in | 16 + bin/tests/system/redirect/ns4/named.conf.in | 51 + bin/tests/system/redirect/ns4/root.hint | 14 + bin/tests/system/redirect/ns5/named.conf.in | 32 + bin/tests/system/redirect/ns5/root.db.in | 18 + bin/tests/system/redirect/ns5/sign.sh | 45 + bin/tests/system/redirect/ns5/signed.db.in | 20 + bin/tests/system/redirect/ns5/unsigned.db | 20 + bin/tests/system/redirect/ns6/named.conf.in | 32 + bin/tests/system/redirect/ns6/root.db | 18 + bin/tests/system/redirect/setup.sh | 30 + bin/tests/system/redirect/tests.sh | 539 + bin/tests/system/resolve.c | 501 + bin/tests/system/resolver/ans2/ans.pl | 140 + bin/tests/system/resolver/ans3/ans.pl | 183 + bin/tests/system/resolver/ans8/ans.pl | 168 + bin/tests/system/resolver/clean.sh | 39 + bin/tests/system/resolver/ns1/chaostest.db | 16 + bin/tests/system/resolver/ns1/named.conf.in | 79 + bin/tests/system/resolver/ns1/root.hint | 14 + bin/tests/system/resolver/ns4/broken.db | 24 + bin/tests/system/resolver/ns4/child.server.db | 23 + bin/tests/system/resolver/ns4/moves.db | 22 + bin/tests/system/resolver/ns4/named.conf.in | 72 + bin/tests/system/resolver/ns4/named.noaa | 12 + bin/tests/system/resolver/ns4/root.db | 34 + bin/tests/system/resolver/ns4/sourcens.db | 91 + bin/tests/system/resolver/ns4/tld1.db | 35 + bin/tests/system/resolver/ns4/tld2.db | 35 + bin/tests/system/resolver/ns4/v4only.net.db | 22 + bin/tests/system/resolver/ns5/child.server.db | 23 + bin/tests/system/resolver/ns5/moves.db | 22 + bin/tests/system/resolver/ns5/named.conf.in | 60 + bin/tests/system/resolver/ns5/root.hint | 14 + bin/tests/system/resolver/ns6/broken.db | 28 + bin/tests/system/resolver/ns6/delegation-only.db | 33 + bin/tests/system/resolver/ns6/ds.example.net.db.in | 15 + bin/tests/system/resolver/ns6/example.net.db.in | 23 + bin/tests/system/resolver/ns6/fetch.tld.db | 23 + bin/tests/system/resolver/ns6/keygen.sh | 39 + bin/tests/system/resolver/ns6/moves.db | 22 + bin/tests/system/resolver/ns6/named.conf.in | 101 + .../system/resolver/ns6/no-edns-version.tld.db | 14 + bin/tests/system/resolver/ns6/redirect.com.db | 27 + bin/tests/system/resolver/ns6/root.db | 36 + bin/tests/system/resolver/ns6/targetns.db | 25 + bin/tests/system/resolver/ns6/tld1.db | 17 + .../system/resolver/ns6/to-be-removed.tld.db.in | 28 + bin/tests/system/resolver/ns7/all-cnames.db | 20 + bin/tests/system/resolver/ns7/edns-version.tld.db | 14 + bin/tests/system/resolver/ns7/named1.conf.in | 74 + bin/tests/system/resolver/ns7/named2.conf.in | 74 + bin/tests/system/resolver/ns7/root.hint | 14 + bin/tests/system/resolver/ns7/server.db.in | 24 + bin/tests/system/resolver/ns7/sub.tld1.db | 17 + bin/tests/system/resolver/ns7/tld2.db | 18 + bin/tests/system/resolver/ns9/named.args | 2 + bin/tests/system/resolver/ns9/named.conf.in | 39 + bin/tests/system/resolver/ns9/named.ipv6-only | 0 bin/tests/system/resolver/ns9/root.hint | 15 + bin/tests/system/resolver/prereq.sh | 31 + bin/tests/system/resolver/setup.sh | 28 + bin/tests/system/resolver/tests.sh | 927 + bin/tests/system/rndc/Makefile.in | 48 + bin/tests/system/rndc/clean.sh | 33 + bin/tests/system/rndc/gencheck.c | 90 + bin/tests/system/rndc/ns2/incl.db | 13 + bin/tests/system/rndc/ns2/named.conf.in | 64 + bin/tests/system/rndc/ns2/secondkey.conf | 21 + bin/tests/system/rndc/ns3/named.conf.in | 48 + bin/tests/system/rndc/ns4/named.conf.in | 38 + bin/tests/system/rndc/ns5/named.conf.in | 34 + bin/tests/system/rndc/ns6/named.args | 3 + bin/tests/system/rndc/ns6/named.conf.in | 29 + bin/tests/system/rndc/ns7/include.db.in | 16 + bin/tests/system/rndc/ns7/include2.db.in | 16 + bin/tests/system/rndc/ns7/named.conf.in | 57 + bin/tests/system/rndc/ns7/test.db.in | 13 + bin/tests/system/rndc/setup.sh | 57 + bin/tests/system/rndc/tests.sh | 839 + bin/tests/system/rootkeysentinel/clean.sh | 26 + bin/tests/system/rootkeysentinel/ns1/named.conf.in | 32 + bin/tests/system/rootkeysentinel/ns1/root.db.in | 24 + bin/tests/system/rootkeysentinel/ns1/sign.sh | 36 + bin/tests/system/rootkeysentinel/ns2/example.db.in | 21 + bin/tests/system/rootkeysentinel/ns2/named.conf.in | 32 + bin/tests/system/rootkeysentinel/ns2/sign.sh | 44 + bin/tests/system/rootkeysentinel/ns3/hint.db | 13 + bin/tests/system/rootkeysentinel/ns3/named.conf.in | 33 + bin/tests/system/rootkeysentinel/ns4/hint.db | 13 + bin/tests/system/rootkeysentinel/ns4/named.conf.in | 33 + bin/tests/system/rootkeysentinel/setup.sh | 23 + bin/tests/system/rootkeysentinel/tests.sh | 296 + bin/tests/system/rpz/Makefile.in | 48 + bin/tests/system/rpz/README | 36 + bin/tests/system/rpz/clean.sh | 57 + bin/tests/system/rpz/dnsrps.c | 172 + bin/tests/system/rpz/dnsrpzd-license.conf | 23 + bin/tests/system/rpz/dnsrpzd.conf.in | 62 + bin/tests/system/rpz/ns1/named.conf.in | 36 + bin/tests/system/rpz/ns1/root.db | 42 + bin/tests/system/rpz/ns10/hints | 13 + bin/tests/system/rpz/ns10/named.conf.in | 42 + bin/tests/system/rpz/ns10/stub.db | 21 + bin/tests/system/rpz/ns2/base-tld2s.db | 26 + bin/tests/system/rpz/ns2/bl.tld2.db.in | 21 + bin/tests/system/rpz/ns2/blv2.tld2.db.in | 19 + bin/tests/system/rpz/ns2/blv3.tld2.db.in | 21 + bin/tests/system/rpz/ns2/hints | 13 + bin/tests/system/rpz/ns2/named.conf.in | 55 + bin/tests/system/rpz/ns2/stub.db | 20 + bin/tests/system/rpz/ns2/tld2.db | 125 + bin/tests/system/rpz/ns3/base.db | 24 + bin/tests/system/rpz/ns3/broken.db.in | 18 + bin/tests/system/rpz/ns3/crash1 | 18 + bin/tests/system/rpz/ns3/crash2 | 24 + bin/tests/system/rpz/ns3/hints | 13 + bin/tests/system/rpz/ns3/manual-update-rpz-2.db.in | 22 + bin/tests/system/rpz/ns3/manual-update-rpz.db.in | 21 + bin/tests/system/rpz/ns3/mixed-case-rpz-1.db.in | 16 + bin/tests/system/rpz/ns3/mixed-case-rpz-2.db.in | 17 + bin/tests/system/rpz/ns3/named.conf.in | 160 + bin/tests/system/rpz/ns4/hints | 13 + bin/tests/system/rpz/ns4/named.conf.in | 45 + bin/tests/system/rpz/ns4/tld4.db | 66 + bin/tests/system/rpz/ns5/empty.db.in | 14 + bin/tests/system/rpz/ns5/expire.conf.in | 19 + bin/tests/system/rpz/ns5/fast-expire.db.in | 18 + bin/tests/system/rpz/ns5/hints | 13 + bin/tests/system/rpz/ns5/named.args | 2 + bin/tests/system/rpz/ns5/named.conf.in | 91 + bin/tests/system/rpz/ns5/tld5.db | 32 + bin/tests/system/rpz/ns6/bl.tld2s.db.in | 20 + bin/tests/system/rpz/ns6/hints | 13 + bin/tests/system/rpz/ns6/named.conf.in | 67 + bin/tests/system/rpz/ns7/hints | 13 + bin/tests/system/rpz/ns7/named.conf.in | 59 + bin/tests/system/rpz/ns8/hints | 13 + bin/tests/system/rpz/ns8/manual-update-rpz.db.in | 21 + bin/tests/system/rpz/ns8/named.conf.in | 66 + bin/tests/system/rpz/ns9/hints | 13 + bin/tests/system/rpz/ns9/named.conf.in | 60 + bin/tests/system/rpz/ns9/rpz.db | 16 + bin/tests/system/rpz/qperf.sh | 22 + bin/tests/system/rpz/setup.sh | 180 + bin/tests/system/rpz/test1 | 99 + bin/tests/system/rpz/test2 | 77 + bin/tests/system/rpz/test3 | 47 + bin/tests/system/rpz/test4 | 36 + bin/tests/system/rpz/test4a | 27 + bin/tests/system/rpz/test5 | 60 + bin/tests/system/rpz/test6 | 37 + bin/tests/system/rpz/tests.sh | 1012 + bin/tests/system/rpzrecurse/README | 124 + bin/tests/system/rpzrecurse/ans5/ans.pl | 81 + bin/tests/system/rpzrecurse/clean.sh | 34 + bin/tests/system/rpzrecurse/ns1/db.l0 | 17 + bin/tests/system/rpzrecurse/ns1/db.l1.l0 | 17 + bin/tests/system/rpzrecurse/ns1/example.com.db | 18 + bin/tests/system/rpzrecurse/ns1/example.db | 16 + bin/tests/system/rpzrecurse/ns1/named.conf.in | 75 + bin/tests/system/rpzrecurse/ns1/root.db | 24 + .../system/rpzrecurse/ns1/test1.example.net.db | 17 + .../system/rpzrecurse/ns1/test2.example.net.db | 17 + bin/tests/system/rpzrecurse/ns2/db.clientip1 | 17 + bin/tests/system/rpzrecurse/ns2/db.clientip2 | 16 + bin/tests/system/rpzrecurse/ns2/db.clientip21 | 17 + bin/tests/system/rpzrecurse/ns2/db.given | 21 + .../system/rpzrecurse/ns2/db.invalidprefixlength | 16 + bin/tests/system/rpzrecurse/ns2/db.log1 | 16 + bin/tests/system/rpzrecurse/ns2/db.log2 | 17 + bin/tests/system/rpzrecurse/ns2/db.log3 | 18 + bin/tests/system/rpzrecurse/ns2/db.passthru | 20 + bin/tests/system/rpzrecurse/ns2/db.wildcard1 | 17 + bin/tests/system/rpzrecurse/ns2/db.wildcard2a | 17 + bin/tests/system/rpzrecurse/ns2/db.wildcard2b | 17 + bin/tests/system/rpzrecurse/ns2/db.wildcard3 | 16 + .../system/rpzrecurse/ns2/named.clientip.conf | 37 + .../system/rpzrecurse/ns2/named.clientip2.conf | 37 + .../system/rpzrecurse/ns2/named.conf.header.in | 41 + bin/tests/system/rpzrecurse/ns2/named.default.conf | 25 + .../rpzrecurse/ns2/named.invalidprefixlength.conf | 30 + bin/tests/system/rpzrecurse/ns2/named.log.conf | 39 + bin/tests/system/rpzrecurse/ns2/named.max.conf | 161 + .../system/rpzrecurse/ns2/named.wildcard1.conf | 35 + .../system/rpzrecurse/ns2/named.wildcard2.conf | 37 + .../system/rpzrecurse/ns2/named.wildcard3.conf | 35 + .../system/rpzrecurse/ns2/named.wildcard4.conf | 37 + bin/tests/system/rpzrecurse/ns2/root.hint | 14 + bin/tests/system/rpzrecurse/ns3/example.db | 17 + bin/tests/system/rpzrecurse/ns3/named1.conf.in | 43 + bin/tests/system/rpzrecurse/ns3/named2.conf.in | 42 + bin/tests/system/rpzrecurse/ns3/policy.db | 15 + bin/tests/system/rpzrecurse/ns3/root.db | 17 + bin/tests/system/rpzrecurse/ns4/child.example.db | 18 + bin/tests/system/rpzrecurse/ns4/named.conf.in | 38 + bin/tests/system/rpzrecurse/prereq.sh | 25 + bin/tests/system/rpzrecurse/setup.sh | 89 + bin/tests/system/rpzrecurse/testgen.pl | 343 + bin/tests/system/rpzrecurse/tests.sh | 545 + bin/tests/system/rrchecker/classlist.good | 3 + bin/tests/system/rrchecker/clean.sh | 15 + bin/tests/system/rrchecker/privatelist.good | 0 bin/tests/system/rrchecker/tests.sh | 84 + bin/tests/system/rrchecker/typelist.good | 81 + bin/tests/system/rrl/broken.conf.in | 46 + bin/tests/system/rrl/clean.sh | 23 + bin/tests/system/rrl/ns1/named.conf.in | 28 + bin/tests/system/rrl/ns1/root.db | 27 + bin/tests/system/rrl/ns2/hints | 13 + bin/tests/system/rrl/ns2/named.conf.in | 65 + bin/tests/system/rrl/ns2/tld2.db | 42 + bin/tests/system/rrl/ns3/hints | 13 + bin/tests/system/rrl/ns3/named.conf.in | 48 + bin/tests/system/rrl/ns3/tld3.db | 20 + bin/tests/system/rrl/ns4/hints | 13 + bin/tests/system/rrl/ns4/named.conf.in | 67 + bin/tests/system/rrl/ns4/tld4.db | 45 + bin/tests/system/rrl/setup.sh | 23 + bin/tests/system/rrl/tests.sh | 291 + bin/tests/system/rrsetorder/clean.sh | 23 + bin/tests/system/rrsetorder/dig.out.fixed.good | 4 + bin/tests/system/rrsetorder/dig.out.random.good1 | 4 + bin/tests/system/rrsetorder/dig.out.random.good10 | 4 + bin/tests/system/rrsetorder/dig.out.random.good11 | 4 + bin/tests/system/rrsetorder/dig.out.random.good12 | 4 + bin/tests/system/rrsetorder/dig.out.random.good13 | 4 + bin/tests/system/rrsetorder/dig.out.random.good14 | 4 + bin/tests/system/rrsetorder/dig.out.random.good15 | 4 + bin/tests/system/rrsetorder/dig.out.random.good16 | 4 + bin/tests/system/rrsetorder/dig.out.random.good17 | 4 + bin/tests/system/rrsetorder/dig.out.random.good18 | 4 + bin/tests/system/rrsetorder/dig.out.random.good19 | 4 + bin/tests/system/rrsetorder/dig.out.random.good2 | 4 + bin/tests/system/rrsetorder/dig.out.random.good20 | 4 + bin/tests/system/rrsetorder/dig.out.random.good21 | 4 + bin/tests/system/rrsetorder/dig.out.random.good22 | 4 + bin/tests/system/rrsetorder/dig.out.random.good23 | 4 + bin/tests/system/rrsetorder/dig.out.random.good24 | 4 + bin/tests/system/rrsetorder/dig.out.random.good3 | 4 + bin/tests/system/rrsetorder/dig.out.random.good4 | 4 + bin/tests/system/rrsetorder/dig.out.random.good5 | 4 + bin/tests/system/rrsetorder/dig.out.random.good6 | 4 + bin/tests/system/rrsetorder/dig.out.random.good7 | 4 + bin/tests/system/rrsetorder/dig.out.random.good8 | 4 + bin/tests/system/rrsetorder/dig.out.random.good9 | 4 + bin/tests/system/rrsetorder/ns1/named.conf.in | 40 + bin/tests/system/rrsetorder/ns1/root.db | 51 + bin/tests/system/rrsetorder/ns2/named.conf.in | 39 + bin/tests/system/rrsetorder/ns3/named.conf.in | 38 + bin/tests/system/rrsetorder/ns4/named.conf.in | 34 + bin/tests/system/rrsetorder/ns5/named.conf.in | 30 + bin/tests/system/rrsetorder/setup.sh | 22 + bin/tests/system/rrsetorder/tests.sh | 553 + bin/tests/system/rsabigexponent/Makefile.in | 51 + bin/tests/system/rsabigexponent/README.md | 39 + bin/tests/system/rsabigexponent/bigkey.c | 162 + bin/tests/system/rsabigexponent/clean.sh | 23 + bin/tests/system/rsabigexponent/conf/bad01.conf | 16 + bin/tests/system/rsabigexponent/conf/bad02.conf | 16 + bin/tests/system/rsabigexponent/conf/bad03.conf | 16 + bin/tests/system/rsabigexponent/conf/good01.conf | 16 + bin/tests/system/rsabigexponent/conf/good02.conf | 16 + bin/tests/system/rsabigexponent/conf/good03.conf | 16 + bin/tests/system/rsabigexponent/ns1/named.conf.in | 34 + bin/tests/system/rsabigexponent/ns1/root.db.in | 24 + bin/tests/system/rsabigexponent/ns1/sign.sh | 34 + .../rsabigexponent/ns2/Xexample.+008+51650.key | 5 + .../rsabigexponent/ns2/Xexample.+008+51650.private | 13 + .../rsabigexponent/ns2/Xexample.+008+52810.key | 2 + .../rsabigexponent/ns2/Xexample.+008+52810.private | 10 + .../system/rsabigexponent/ns2/dsset-example.in | 1 + bin/tests/system/rsabigexponent/ns2/example.db.bad | 156 + bin/tests/system/rsabigexponent/ns2/example.db.in | 23 + bin/tests/system/rsabigexponent/ns2/named.conf.in | 38 + bin/tests/system/rsabigexponent/ns2/sign.sh | 29 + bin/tests/system/rsabigexponent/ns3/named.conf.in | 35 + bin/tests/system/rsabigexponent/prereq.sh | 24 + bin/tests/system/rsabigexponent/setup.sh | 21 + bin/tests/system/rsabigexponent/tests.sh | 57 + bin/tests/system/run.gdb | 1 + bin/tests/system/run.sh | 346 + bin/tests/system/runall.sh | 107 + bin/tests/system/runsequential.sh | 27 + bin/tests/system/runtime/README | 13 + bin/tests/system/runtime/clean.sh | 25 + bin/tests/system/runtime/ctrl-chars | 1 + bin/tests/system/runtime/long-cmd-line | 1 + bin/tests/system/runtime/ns2/named-alt1.conf.in | 25 + bin/tests/system/runtime/ns2/named-alt2.conf.in | 25 + bin/tests/system/runtime/ns2/named-alt3.conf.in | 26 + bin/tests/system/runtime/ns2/named-alt4.conf.in | 21 + bin/tests/system/runtime/ns2/named-alt5.conf.in | 21 + bin/tests/system/runtime/ns2/named-alt6.conf.in | 21 + bin/tests/system/runtime/ns2/named-alt7.conf.in | 19 + bin/tests/system/runtime/ns2/named-alt9.conf.in | 20 + bin/tests/system/runtime/ns2/named1.conf.in | 34 + bin/tests/system/runtime/setup.sh | 36 + bin/tests/system/runtime/tests.sh | 254 + bin/tests/system/send.pl | 33 + bin/tests/system/serve-stale/ans2/ans.pl | 331 + bin/tests/system/serve-stale/clean.sh | 22 + bin/tests/system/serve-stale/ns1/named1.conf.in | 43 + bin/tests/system/serve-stale/ns1/named2.conf.in | 42 + bin/tests/system/serve-stale/ns1/named3.conf.in | 48 + bin/tests/system/serve-stale/ns1/root.db | 18 + bin/tests/system/serve-stale/ns1/stale.test.db | 19 + bin/tests/system/serve-stale/ns3/named1.conf.in | 39 + bin/tests/system/serve-stale/ns3/named2.conf.in | 51 + bin/tests/system/serve-stale/ns3/named3.conf.in | 48 + bin/tests/system/serve-stale/ns3/named4.conf.in | 50 + bin/tests/system/serve-stale/ns3/named5.conf.in | 49 + bin/tests/system/serve-stale/ns3/named6.conf.in | 46 + bin/tests/system/serve-stale/ns3/named7.conf.in | 55 + bin/tests/system/serve-stale/ns3/named8.conf.in | 46 + bin/tests/system/serve-stale/ns3/root.db | 13 + bin/tests/system/serve-stale/ns4/named.conf.in | 40 + bin/tests/system/serve-stale/ns5/named.conf.in | 42 + bin/tests/system/serve-stale/prereq.sh | 43 + bin/tests/system/serve-stale/setup.sh | 22 + bin/tests/system/serve-stale/tests.sh | 2621 ++ bin/tests/system/setup.sh | 34 + bin/tests/system/sfcache/README | 19 + bin/tests/system/sfcache/clean.sh | 27 + bin/tests/system/sfcache/ns1/named.conf.in | 34 + bin/tests/system/sfcache/ns1/root.db.in | 26 + bin/tests/system/sfcache/ns1/sign.sh | 38 + bin/tests/system/sfcache/ns2/example.db.in | 103 + bin/tests/system/sfcache/ns2/named.conf.in | 49 + bin/tests/system/sfcache/ns2/sign.sh | 28 + bin/tests/system/sfcache/ns5/named.conf.in | 43 + bin/tests/system/sfcache/ns5/sign.sh | 21 + bin/tests/system/sfcache/setup.sh | 24 + bin/tests/system/sfcache/tests.sh | 108 + bin/tests/system/shutdown/clean.sh | 20 + bin/tests/system/shutdown/ns1/named.conf.in | 42 + bin/tests/system/shutdown/ns1/root.db | 25 + bin/tests/system/shutdown/ns2/named.conf.in | 40 + bin/tests/system/shutdown/ns2/test.db | 18 + bin/tests/system/shutdown/prereq.sh | 38 + bin/tests/system/shutdown/resolver/named.conf.in | 47 + bin/tests/system/shutdown/resolver/root.db | 21 + bin/tests/system/shutdown/setup.sh | 23 + bin/tests/system/shutdown/tests_shutdown.py | 209 + bin/tests/system/smartsign/child.db | 24 + bin/tests/system/smartsign/clean.sh | 15 + bin/tests/system/smartsign/parent.db | 31 + bin/tests/system/smartsign/tests.sh | 368 + bin/tests/system/sortlist/clean.sh | 19 + bin/tests/system/sortlist/ns1/example.db | 37 + bin/tests/system/sortlist/ns1/named.conf.in | 45 + bin/tests/system/sortlist/ns1/root.db | 24 + bin/tests/system/sortlist/setup.sh | 17 + bin/tests/system/sortlist/tests.sh | 51 + bin/tests/system/spf/clean.sh | 18 + bin/tests/system/spf/ns1/named.conf.in | 42 + bin/tests/system/spf/ns1/spf.db | 18 + bin/tests/system/spf/setup.sh | 17 + bin/tests/system/spf/tests.sh | 46 + bin/tests/system/start.pl | 451 + bin/tests/system/start.sh | 19 + bin/tests/system/staticstub/clean.sh | 28 + bin/tests/system/staticstub/conf/bad01.conf | 32 + bin/tests/system/staticstub/conf/bad02.conf | 32 + bin/tests/system/staticstub/conf/bad03.conf | 32 + bin/tests/system/staticstub/conf/bad04.conf | 32 + bin/tests/system/staticstub/conf/bad05.conf | 33 + bin/tests/system/staticstub/conf/bad06.conf | 33 + bin/tests/system/staticstub/conf/bad07.conf | 33 + bin/tests/system/staticstub/conf/bad08.conf | 33 + bin/tests/system/staticstub/conf/bad09.conf | 32 + bin/tests/system/staticstub/conf/bad10.conf | 34 + bin/tests/system/staticstub/conf/bad11.conf | 34 + bin/tests/system/staticstub/conf/good01.conf | 33 + bin/tests/system/staticstub/conf/good02.conf | 32 + bin/tests/system/staticstub/conf/good03.conf | 32 + bin/tests/system/staticstub/conf/good04.conf | 32 + bin/tests/system/staticstub/conf/good05.conf | 33 + bin/tests/system/staticstub/knowngood.dig.out.rec | 18 + bin/tests/system/staticstub/ns1/named.conf.in | 25 + bin/tests/system/staticstub/ns1/root.db | 19 + bin/tests/system/staticstub/ns2/named.conf.in | 62 + bin/tests/system/staticstub/ns3/example.db.in | 32 + bin/tests/system/staticstub/ns3/example.org.db | 24 + bin/tests/system/staticstub/ns3/named.conf.in | 46 + bin/tests/system/staticstub/ns3/sign.sh | 44 + bin/tests/system/staticstub/ns3/undelegated.db.in | 23 + bin/tests/system/staticstub/ns4/example.com.db | 23 + bin/tests/system/staticstub/ns4/example.info.db | 24 + bin/tests/system/staticstub/ns4/example.org.db | 25 + bin/tests/system/staticstub/ns4/named.conf.in | 45 + bin/tests/system/staticstub/ns4/sign.sh | 26 + bin/tests/system/staticstub/ns4/sub.example.db.in | 26 + bin/tests/system/staticstub/setup.sh | 26 + bin/tests/system/staticstub/tests.sh | 218 + bin/tests/system/statistics/ans4/ans.pl | 118 + bin/tests/system/statistics/clean.sh | 32 + bin/tests/system/statistics/ns1/named.conf.in | 44 + bin/tests/system/statistics/ns1/root.db | 24 + bin/tests/system/statistics/ns1/zone.db | 14 + bin/tests/system/statistics/ns2/example.db | 28 + bin/tests/system/statistics/ns2/internal.db | 30 + bin/tests/system/statistics/ns2/named.conf.in | 50 + bin/tests/system/statistics/ns2/named2.conf.in | 50 + bin/tests/system/statistics/ns3/internal.db | 28 + bin/tests/system/statistics/ns3/named.conf.in | 59 + bin/tests/system/statistics/ns3/root.hint | 14 + bin/tests/system/statistics/prereq.sh | 29 + bin/tests/system/statistics/setup.sh | 19 + bin/tests/system/statistics/tests.sh | 280 + bin/tests/system/statschannel/clean.sh | 32 + bin/tests/system/statschannel/conftest.py | 25 + bin/tests/system/statschannel/fetch.pl | 43 + bin/tests/system/statschannel/generic.py | 106 + bin/tests/system/statschannel/generic_dnspython.py | 128 + bin/tests/system/statschannel/mem-xml.pl | 21 + bin/tests/system/statschannel/ns1/example.db | 49 + bin/tests/system/statschannel/ns1/named.conf.in | 43 + bin/tests/system/statschannel/ns2/dnssec.db.in | 28 + bin/tests/system/statschannel/ns2/example.db | 49 + bin/tests/system/statschannel/ns2/manykeys.db.in | 28 + bin/tests/system/statschannel/ns2/named.conf.in | 72 + bin/tests/system/statschannel/ns2/named2.conf.in | 68 + bin/tests/system/statschannel/ns2/sign.sh | 45 + bin/tests/system/statschannel/ns3/named.conf.in | 43 + bin/tests/system/statschannel/prereq.sh | 27 + bin/tests/system/statschannel/server-json.pl | 35 + bin/tests/system/statschannel/server-xml.pl | 25 + bin/tests/system/statschannel/setup.sh | 21 + bin/tests/system/statschannel/tests.sh | 392 + bin/tests/system/statschannel/tests_json.py | 105 + bin/tests/system/statschannel/tests_xml.py | 135 + bin/tests/system/statschannel/traffic-json.pl | 49 + bin/tests/system/statschannel/traffic-xml.pl | 46 + bin/tests/system/statschannel/traffic.expect.1 | 2 + bin/tests/system/statschannel/traffic.expect.2 | 4 + bin/tests/system/statschannel/traffic.expect.4 | 5 + bin/tests/system/statschannel/traffic.expect.5 | 7 + bin/tests/system/statschannel/traffic.expect.6 | 8 + bin/tests/system/statschannel/zones-json.pl | 37 + bin/tests/system/statschannel/zones-xml.pl | 40 + bin/tests/system/stop.pl | 292 + bin/tests/system/stop.sh | 19 + bin/tests/system/stopall.sh | 24 + bin/tests/system/stress/clean.sh | 22 + bin/tests/system/stress/ns2/named.conf.in | 57 + bin/tests/system/stress/ns2/zone.template.db | 21 + bin/tests/system/stress/ns3/named.conf.in | 74 + bin/tests/system/stress/ns4/named.conf.in | 57 + bin/tests/system/stress/prereq.sh | 31 + bin/tests/system/stress/setup.sh | 25 + bin/tests/system/stress/tests_stress_update.py | 77 + bin/tests/system/stub/clean.sh | 23 + bin/tests/system/stub/knowngood.dig.out.norec | 21 + bin/tests/system/stub/knowngood.dig.out.rec | 18 + bin/tests/system/stub/ns1/named.conf.in | 30 + bin/tests/system/stub/ns1/root.db | 24 + bin/tests/system/stub/ns2/child.example.db | 22 + bin/tests/system/stub/ns2/named.conf.in | 35 + bin/tests/system/stub/ns3/example.db | 22 + bin/tests/system/stub/ns3/named.conf.in | 41 + bin/tests/system/stub/ns4/example.db | 23 + bin/tests/system/stub/ns4/named.conf.in | 31 + bin/tests/system/stub/ns5/named.conf.in | 34 + bin/tests/system/stub/setup.sh | 21 + bin/tests/system/stub/tests.sh | 87 + bin/tests/system/synthfromdnssec/clean.sh | 31 + bin/tests/system/synthfromdnssec/ns1/dnamed.db.in | 16 + bin/tests/system/synthfromdnssec/ns1/example.db.in | 19 + bin/tests/system/synthfromdnssec/ns1/named.conf.in | 44 + bin/tests/system/synthfromdnssec/ns1/root.db.in | 19 + bin/tests/system/synthfromdnssec/ns1/sign.sh | 45 + bin/tests/system/synthfromdnssec/ns2/named.conf.in | 34 + bin/tests/system/synthfromdnssec/ns2/root.hints | 13 + bin/tests/system/synthfromdnssec/ns3/named.conf.in | 39 + bin/tests/system/synthfromdnssec/ns3/redirect.db | 20 + bin/tests/system/synthfromdnssec/ns3/root.hints | 13 + bin/tests/system/synthfromdnssec/ns4/named.conf.in | 35 + bin/tests/system/synthfromdnssec/ns4/root.hints | 13 + bin/tests/system/synthfromdnssec/ns5/named.conf.in | 35 + bin/tests/system/synthfromdnssec/ns5/root.hints | 13 + bin/tests/system/synthfromdnssec/setup.sh | 28 + bin/tests/system/synthfromdnssec/tests.sh | 202 + bin/tests/system/system-test-driver.sh | 80 + .../system/tcp/1996-alloc_dnsbuf-crash-test.pkt | 12 + bin/tests/system/tcp/ans6/ans.py | 157 + bin/tests/system/tcp/clean.sh | 22 + bin/tests/system/tcp/ns1/named.conf.in | 39 + bin/tests/system/tcp/ns1/root.db | 24 + bin/tests/system/tcp/ns2/example.db | 28 + bin/tests/system/tcp/ns2/named.conf.in | 46 + bin/tests/system/tcp/ns3/named.conf.in | 41 + bin/tests/system/tcp/ns4/named.conf.in | 43 + bin/tests/system/tcp/ns5/named.conf.in | 45 + bin/tests/system/tcp/ns7/named.conf.in | 41 + bin/tests/system/tcp/ns7/named.dropedns | 1 + bin/tests/system/tcp/ns7/root.db | 24 + bin/tests/system/tcp/prereq.sh | 21 + bin/tests/system/tcp/setup.sh | 24 + bin/tests/system/tcp/tests.sh | 204 + bin/tests/system/tcp/tests_tcp.py | 70 + bin/tests/system/testcrypto.sh | 98 + bin/tests/system/testsock.pl | 44 + bin/tests/system/testsock6.pl | 25 + bin/tests/system/testsummary.sh | 86 + bin/tests/system/timeouts/clean.sh | 21 + bin/tests/system/timeouts/ns1/example.db | 25 + bin/tests/system/timeouts/ns1/named.args | 1 + bin/tests/system/timeouts/ns1/named.conf.in | 46 + bin/tests/system/timeouts/ns1/root.db | 24 + bin/tests/system/timeouts/prereq.sh | 31 + bin/tests/system/timeouts/setup.sh | 31 + bin/tests/system/timeouts/tests_tcp_timeouts.py | 284 + bin/tests/system/tkey/Makefile.in | 55 + bin/tests/system/tkey/clean.sh | 20 + bin/tests/system/tkey/keycreate.c | 301 + bin/tests/system/tkey/keydelete.c | 242 + bin/tests/system/tkey/ns1/example.db | 27 + bin/tests/system/tkey/ns1/named.conf.in | 49 + bin/tests/system/tkey/ns1/setup.sh | 20 + bin/tests/system/tkey/setup.sh | 17 + bin/tests/system/tkey/tests.sh | 160 + bin/tests/system/tools/clean.sh | 17 + bin/tests/system/tools/setup.sh | 17 + bin/tests/system/tools/tests.sh | 105 + bin/tests/system/tsig/ans2/ans.pl | 52 + bin/tests/system/tsig/badlocation | 37 + bin/tests/system/tsig/badtime | 37 + bin/tests/system/tsig/clean.sh | 26 + bin/tests/system/tsig/ns1/example.db | 163 + bin/tests/system/tsig/ns1/named.conf.in | 93 + bin/tests/system/tsig/prereq.sh | 24 + bin/tests/system/tsig/setup.sh | 35 + bin/tests/system/tsig/tests.sh | 262 + bin/tests/system/tsiggss/authsock.pl | 96 + bin/tests/system/tsiggss/clean.sh | 28 + bin/tests/system/tsiggss/ns1/administrator.ccache | Bin 0 -> 2315 bytes bin/tests/system/tsiggss/ns1/dns.keytab | Bin 0 -> 1087 bytes bin/tests/system/tsiggss/ns1/example.nil.db.in | 62 + bin/tests/system/tsiggss/ns1/named.conf.in | 49 + bin/tests/system/tsiggss/ns1/testdenied.ccache | Bin 0 -> 2188 bytes bin/tests/system/tsiggss/prereq.sh | 23 + bin/tests/system/tsiggss/setup.sh | 22 + bin/tests/system/tsiggss/tests.sh | 177 + bin/tests/system/tsiggss/tests_isc_spnego_flaws.py | 219 + bin/tests/system/ttl/clean.sh | 17 + bin/tests/system/ttl/ns1/max-example.db | 20 + bin/tests/system/ttl/ns1/min-example.db | 20 + bin/tests/system/ttl/ns1/named.conf.in | 48 + bin/tests/system/ttl/ns2/hints.db | 13 + bin/tests/system/ttl/ns2/named.conf.in | 42 + bin/tests/system/ttl/prereq.sh | 31 + bin/tests/system/ttl/setup.sh | 17 + bin/tests/system/ttl/tests_cache_ttl.py | 32 + bin/tests/system/unknown/clean.sh | 22 + bin/tests/system/unknown/large.out | 1 + bin/tests/system/unknown/ns1/broken1.db | 23 + bin/tests/system/unknown/ns1/broken2.db | 23 + bin/tests/system/unknown/ns1/broken3.db | 23 + bin/tests/system/unknown/ns1/broken4.db | 23 + bin/tests/system/unknown/ns1/broken5.db | 23 + bin/tests/system/unknown/ns1/class10.hints | 13 + bin/tests/system/unknown/ns1/example-class10.db | 31 + bin/tests/system/unknown/ns1/example-in.db | 56 + bin/tests/system/unknown/ns1/large.db | 3011 +++ bin/tests/system/unknown/ns1/named.conf.in | 68 + bin/tests/system/unknown/ns2/named.conf.in | 32 + bin/tests/system/unknown/ns3/named.conf.in | 34 + bin/tests/system/unknown/ns3/sign.sh | 21 + bin/tests/system/unknown/setup.sh | 21 + bin/tests/system/unknown/tests.sh | 229 + bin/tests/system/unknown/zones/nan.bad | 12 + bin/tests/system/upforwd/ans4/ans.pl | 363 + bin/tests/system/upforwd/clean.sh | 35 + bin/tests/system/upforwd/knowngood.after1 | 10 + bin/tests/system/upforwd/knowngood.after2 | 11 + bin/tests/system/upforwd/knowngood.before | 8 + bin/tests/system/upforwd/knowngood.ns2.before | 6 + bin/tests/system/upforwd/ns1/example1.db | 18 + bin/tests/system/upforwd/ns1/named.conf.in | 41 + bin/tests/system/upforwd/ns2/named.conf.in | 36 + bin/tests/system/upforwd/ns3/named1.conf.in | 63 + bin/tests/system/upforwd/ns3/named2.conf.in | 41 + bin/tests/system/upforwd/ns3/nomaster.db | 14 + bin/tests/system/upforwd/prereq.sh | 23 + bin/tests/system/upforwd/setup.sh | 48 + bin/tests/system/upforwd/tests.sh | 294 + bin/tests/system/verify/clean.sh | 21 + bin/tests/system/verify/setup.sh | 17 + bin/tests/system/verify/tests.sh | 112 + bin/tests/system/verify/zones/genzones.sh | 248 + bin/tests/system/verify/zones/unsigned.db | 29 + bin/tests/system/views/clean.sh | 38 + bin/tests/system/views/ns1/named.conf.in | 29 + bin/tests/system/views/ns1/root.db | 24 + bin/tests/system/views/ns2/1.10.in-addr.arpa.db | 13 + bin/tests/system/views/ns2/clone.db | 25 + bin/tests/system/views/ns2/example1.db | 28 + bin/tests/system/views/ns2/example2.db | 28 + bin/tests/system/views/ns2/external/inline.db | 29 + bin/tests/system/views/ns2/internal.db | 30 + bin/tests/system/views/ns2/internal/inline.db | 29 + bin/tests/system/views/ns2/named1.conf.in | 53 + bin/tests/system/views/ns2/named2.conf.in | 100 + bin/tests/system/views/ns2/named3.conf.in | 35 + bin/tests/system/views/ns3/child.clone.db | 22 + bin/tests/system/views/ns3/internal.db | 28 + bin/tests/system/views/ns3/named1.conf.in | 50 + bin/tests/system/views/ns3/named2.conf.in | 50 + bin/tests/system/views/ns5/child.clone.db | 22 + bin/tests/system/views/ns5/named.conf.in | 44 + bin/tests/system/views/setup.sh | 39 + bin/tests/system/views/tests.sh | 190 + bin/tests/system/wildcard/clean.sh | 28 + bin/tests/system/wildcard/ns1/allwild.db.in | 15 + bin/tests/system/wildcard/ns1/dlv.db.in | 14 + bin/tests/system/wildcard/ns1/example.db.in | 23 + bin/tests/system/wildcard/ns1/named.conf.in | 43 + bin/tests/system/wildcard/ns1/nsec.db.in | 17 + bin/tests/system/wildcard/ns1/nsec3.db.in | 17 + bin/tests/system/wildcard/ns1/private.nsec.db.in | 16 + bin/tests/system/wildcard/ns1/private.nsec3.db.in | 17 + bin/tests/system/wildcard/ns1/root.db.in | 17 + bin/tests/system/wildcard/ns1/sign.sh | 96 + bin/tests/system/wildcard/ns2/named.conf.in | 30 + bin/tests/system/wildcard/ns3/named.conf.in | 32 + bin/tests/system/wildcard/ns4/named.conf.in | 31 + bin/tests/system/wildcard/ns5/named.conf.in | 32 + bin/tests/system/wildcard/setup.sh | 23 + bin/tests/system/wildcard/tests.sh | 272 + bin/tests/system/wildcard/tests_wildcard.py | 112 + bin/tests/system/win32/bigkey.vcxproj.filters.in | 22 + bin/tests/system/win32/bigkey.vcxproj.in | 119 + bin/tests/system/win32/bigkey.vcxproj.user | 3 + .../system/win32/feature-test.vcxproj.filters.in | 22 + bin/tests/system/win32/feature-test.vcxproj.in | 119 + bin/tests/system/win32/feature-test.vcxproj.user | 3 + bin/tests/system/win32/gencheck.vcxproj.filters.in | 22 + bin/tests/system/win32/gencheck.vcxproj.in | 119 + bin/tests/system/win32/gencheck.vcxproj.user | 3 + .../system/win32/keycreate.vcxproj.filters.in | 22 + bin/tests/system/win32/keycreate.vcxproj.in | 119 + bin/tests/system/win32/keycreate.vcxproj.user | 3 + .../system/win32/keydelete.vcxproj.filters.in | 22 + bin/tests/system/win32/keydelete.vcxproj.in | 119 + bin/tests/system/win32/keydelete.vcxproj.user | 3 + .../system/win32/pipequeries.vcxproj.filters.in | 22 + bin/tests/system/win32/pipequeries.vcxproj.in | 119 + bin/tests/system/win32/pipequeries.vcxproj.user | 3 + bin/tests/system/win32/resolve.vcxproj.filters.in | 22 + bin/tests/system/win32/resolve.vcxproj.in | 119 + bin/tests/system/win32/resolve.vcxproj.user | 3 + bin/tests/system/xfer/ans5/badkeydata | 10 + bin/tests/system/xfer/ans5/badmessageid | 10 + bin/tests/system/xfer/ans5/goodaxfr | 10 + bin/tests/system/xfer/ans5/partial | 11 + bin/tests/system/xfer/ans5/soamismatch | 10 + bin/tests/system/xfer/ans5/unknownkey | 11 + bin/tests/system/xfer/ans5/unsigned | 11 + bin/tests/system/xfer/ans5/wrongkey | 11 + bin/tests/system/xfer/axfr-stats.good | 3 + bin/tests/system/xfer/clean.sh | 39 + bin/tests/system/xfer/dig1.good | 178 + bin/tests/system/xfer/dig2.good | 178 + bin/tests/system/xfer/knowngood.mapped | 26 + bin/tests/system/xfer/ns1/axfr-too-big.db | 15 + bin/tests/system/xfer/ns1/ixfr-too-big.db.in | 18 + bin/tests/system/xfer/ns1/named.conf.in | 61 + bin/tests/system/xfer/ns1/root.db | 27 + bin/tests/system/xfer/ns1/xfer-stats.db | 15 + bin/tests/system/xfer/ns2/mapped.db.in | 28 + bin/tests/system/xfer/ns2/named.conf.in | 74 + bin/tests/system/xfer/ns2/sec.db.in | 19 + bin/tests/system/xfer/ns3/named.conf.in | 79 + bin/tests/system/xfer/ns4/named.conf.base | 49 + bin/tests/system/xfer/ns4/root.db.in | 14 + bin/tests/system/xfer/ns6/named.conf.in | 69 + bin/tests/system/xfer/ns7/named.conf.in | 54 + bin/tests/system/xfer/ns8/example.db | 24 + bin/tests/system/xfer/ns8/named.conf.in | 46 + bin/tests/system/xfer/prereq.sh | 35 + bin/tests/system/xfer/setup.sh | 44 + bin/tests/system/xfer/tests.sh | 547 + bin/tests/system/xferquota/clean.sh | 26 + bin/tests/system/xferquota/ns1/changing1.db | 27 + bin/tests/system/xferquota/ns1/changing2.db | 27 + bin/tests/system/xferquota/ns1/named.conf.in | 45 + bin/tests/system/xferquota/ns1/root.db | 29 + bin/tests/system/xferquota/ns2/example.db | 146 + bin/tests/system/xferquota/ns2/named.conf.in | 40 + bin/tests/system/xferquota/setup.pl | 40 + bin/tests/system/xferquota/setup.sh | 26 + bin/tests/system/xferquota/tests.sh | 64 + bin/tests/system/zero/ans5/ans.pl | 81 + bin/tests/system/zero/clean.sh | 22 + bin/tests/system/zero/ns1/named.conf.in | 29 + bin/tests/system/zero/ns1/root.db | 26 + bin/tests/system/zero/ns2/named.args | 1 + bin/tests/system/zero/ns2/named.conf.in | 34 + bin/tests/system/zero/ns2/tld.db | 20 + bin/tests/system/zero/ns3/named.args | 1 + bin/tests/system/zero/ns3/named.conf.in | 29 + bin/tests/system/zero/ns3/root.hint | 13 + bin/tests/system/zero/ns4/named.args | 1 + bin/tests/system/zero/ns4/named.conf.in | 35 + bin/tests/system/zero/ns4/one.tld.db | 17 + bin/tests/system/zero/prereq.sh | 23 + bin/tests/system/zero/setup.sh | 22 + bin/tests/system/zero/tests.sh | 122 + bin/tests/system/zonechecks/a.db | 14 + bin/tests/system/zonechecks/aaaa.db | 14 + bin/tests/system/zonechecks/bigserial.db | 14 + bin/tests/system/zonechecks/clean.sh | 22 + bin/tests/system/zonechecks/cname.db | 14 + bin/tests/system/zonechecks/dname.db | 14 + bin/tests/system/zonechecks/noaddress.db | 14 + bin/tests/system/zonechecks/ns1/named.conf.in | 72 + bin/tests/system/zonechecks/ns2/named.conf.in | 42 + bin/tests/system/zonechecks/nxdomain.db | 14 + bin/tests/system/zonechecks/setup.sh | 34 + bin/tests/system/zonechecks/tests.sh | 257 + bin/tests/testdata/wire/wire_test.data | 9 + bin/tests/testdata/wire/wire_test.data2 | 14 + bin/tests/testdata/wire/wire_test.data3 | 14 + bin/tests/testdata/wire/wire_test.data4 | 31 + bin/tests/win32/backtrace_test.vcxproj.filters.in | 22 + bin/tests/win32/backtrace_test.vcxproj.in | 119 + bin/tests/win32/backtrace_test.vcxproj.user | 3 + bin/tests/win32/inter_test.vcxproj.filters.in | 22 + bin/tests/win32/inter_test.vcxproj.in | 119 + bin/tests/win32/inter_test.vcxproj.user | 3 + bin/tests/win32/makejournal.vcxproj.filters.in | 18 + bin/tests/win32/makejournal.vcxproj.in | 119 + bin/tests/win32/makejournal.vcxproj.user | 3 + bin/tests/win32/rwlock_test.vcxproj.filters.in | 22 + bin/tests/win32/rwlock_test.vcxproj.in | 119 + bin/tests/win32/rwlock_test.vcxproj.user | 3 + bin/tests/win32/shutdown_test.vcxproj.filters.in | 22 + bin/tests/win32/shutdown_test.vcxproj.in | 119 + bin/tests/win32/shutdown_test.vcxproj.user | 3 + bin/tests/win32/sock_test.vcxproj.filters.in | 22 + bin/tests/win32/sock_test.vcxproj.in | 119 + bin/tests/win32/sock_test.vcxproj.user | 3 + bin/tests/win32/task_test.vcxproj.filters.in | 22 + bin/tests/win32/task_test.vcxproj.in | 119 + bin/tests/win32/task_test.vcxproj.user | 3 + bin/tests/win32/timer_test.vcxproj.filters.in | 22 + bin/tests/win32/timer_test.vcxproj.in | 119 + bin/tests/win32/timer_test.vcxproj.user | 3 + bin/tests/wire_test.c | 359 + bin/tools/Makefile.in | 136 + bin/tools/arpaname.c | 48 + bin/tools/arpaname.rst | 33 + bin/tools/dnstap-read.c | 429 + bin/tools/dnstap-read.rst | 52 + bin/tools/mdig.c | 2285 ++ bin/tools/mdig.rst | 322 + bin/tools/named-journalprint.c | 134 + bin/tools/named-journalprint.rst | 64 + bin/tools/named-nzd2nzf.c | 103 + bin/tools/named-nzd2nzf.rst | 42 + bin/tools/named-rrchecker.c | 335 + bin/tools/named-rrchecker.rst | 55 + bin/tools/nsec3hash.c | 193 + bin/tools/nsec3hash.rst | 63 + bin/tools/win32/arpaname.vcxproj.filters.in | 22 + bin/tools/win32/arpaname.vcxproj.in | 119 + bin/tools/win32/arpaname.vcxproj.user | 3 + bin/tools/win32/journalprint.vcxproj.filters.in | 18 + bin/tools/win32/journalprint.vcxproj.in | 121 + bin/tools/win32/journalprint.vcxproj.user | 3 + bin/tools/win32/mdig.vcxproj.filters.in | 18 + bin/tools/win32/mdig.vcxproj.in | 119 + bin/tools/win32/mdig.vcxproj.user | 3 + bin/tools/win32/nsec3hash.vcxproj.filters.in | 18 + bin/tools/win32/nsec3hash.vcxproj.in | 119 + bin/tools/win32/nsec3hash.vcxproj.user | 3 + bin/tools/win32/rrchecker.vcxproj.filters.in | 18 + bin/tools/win32/rrchecker.vcxproj.in | 121 + bin/tools/win32/rrchecker.vcxproj.user | 3 + bin/win32/BINDInstall/AccountInfo.cpp | 465 + bin/win32/BINDInstall/AccountInfo.h | 44 + bin/win32/BINDInstall/BINDInstall.cpp | 100 + bin/win32/BINDInstall/BINDInstall.h | 58 + bin/win32/BINDInstall/BINDInstall.rc | 325 + .../BINDInstall/BINDInstall.vcxproj.filters.in | 79 + bin/win32/BINDInstall/BINDInstall.vcxproj.in | 155 + bin/win32/BINDInstall/BINDInstall.vcxproj.user | 3 + bin/win32/BINDInstall/BINDInstallDlg.cpp | 1601 ++ bin/win32/BINDInstall/BINDInstallDlg.h | 167 + bin/win32/BINDInstall/DirBrowse.cpp | 98 + bin/win32/BINDInstall/DirBrowse.h | 74 + bin/win32/BINDInstall/StdAfx.cpp | 21 + bin/win32/BINDInstall/StdAfx.h | 51 + bin/win32/BINDInstall/VersionInfo.cpp | 304 + bin/win32/BINDInstall/VersionInfo.h | 104 + bin/win32/BINDInstall/res/BINDInstall.ico | Bin 0 -> 1078 bytes bin/win32/BINDInstall/res/BINDInstall.rc2 | 13 + bin/win32/BINDInstall/resource.h | 118 + bind.keys | 38 + bind.keys.h | 57 + cocci/UV_RUNTIME_CHECK.spatch | 8 + cocci/config-h.spatch | 4 + cocci/dns_message_create.spatch | 84 + cocci/dns_message_destroy.spatch | 6 + cocci/dns_name_copy-with-result.spatch | 30 + cocci/dns_name_copy.spatch | 30 + cocci/dns_name_copynf.spatch | 6 + cocci/dns_name_dup.disabled | 40 + cocci/dns_rbtnodechain_init.disabled | 7 + cocci/isc_buffer_allocate_never_fail.spatch | 84 + cocci/isc_event_allocat_never_fail.spatch | 33 + cocci/isc_mem_allocate_never_fail.spatch | 41 + cocci/isc_mem_create_never_fail.disabled | 95 + cocci/isc_mem_get_never_fail.spatch | 41 + cocci/isc_mem_putanddetach.spatch | 8 + cocci/isc_mem_strdup_never_fail.spatch | 33 + cocci/isc_mempool_create_cannot_fail.cocci | 49 + cocci/memcpy.spatch | 14 + cocci/null-the-pointer-early.disabled | 21 + cocci/return-void-from-void.spatch | 19 + cocci/unreachable.spatch | 19 + config.guess | 1421 + config.h.in | 692 + config.h.win32 | 417 + config.sub | 1807 ++ config.threads.in | 125 + configure | 26911 +++++++++++++++++++ configure.ac | 3150 +++ contrib/README | 52 + contrib/dane/mkdane.sh | 130 + contrib/dane/tlsa6698.pem | 26 + contrib/dlz/bin/dlzbdb/Makefile.in | 56 + contrib/dlz/bin/dlzbdb/dlzbdb.c | 1277 + contrib/dlz/config.dlz.in | 510 + contrib/dlz/drivers/dlz_bdb_driver.c | 780 + contrib/dlz/drivers/dlz_bdbhpt_driver.c | 849 + contrib/dlz/drivers/dlz_dlopen_driver.c | 0 contrib/dlz/drivers/dlz_drivers.c | 156 + contrib/dlz/drivers/dlz_filesystem_driver.c | 1000 + contrib/dlz/drivers/dlz_ldap_driver.c | 1216 + contrib/dlz/drivers/dlz_mysql_driver.c | 1037 + contrib/dlz/drivers/dlz_odbc_driver.c | 1406 + contrib/dlz/drivers/dlz_postgres_driver.c | 1240 + contrib/dlz/drivers/dlz_stub_driver.c | 295 + contrib/dlz/drivers/include/.clang-format | 1 + contrib/dlz/drivers/include/dlz/dlz_bdb_driver.h | 24 + .../dlz/drivers/include/dlz/dlz_bdbhpt_driver.h | 24 + .../dlz/drivers/include/dlz/dlz_dlopen_driver.h | 0 contrib/dlz/drivers/include/dlz/dlz_drivers.h | 26 + .../drivers/include/dlz/dlz_filesystem_driver.h | 24 + contrib/dlz/drivers/include/dlz/dlz_ldap_driver.h | 24 + contrib/dlz/drivers/include/dlz/dlz_mysql_driver.h | 24 + contrib/dlz/drivers/include/dlz/dlz_odbc_driver.h | 24 + .../dlz/drivers/include/dlz/dlz_postgres_driver.h | 24 + contrib/dlz/drivers/include/dlz/dlz_stub_driver.h | 24 + contrib/dlz/drivers/include/dlz/sdlz_helper.h | 99 + contrib/dlz/drivers/rules.in | 50 + contrib/dlz/drivers/sdlz_helper.c | 468 + contrib/dlz/example/Makefile | 27 + contrib/dlz/example/README | 256 + contrib/dlz/example/dlz_example.c | 822 + contrib/dlz/example/named.conf | 60 + contrib/dlz/example/win32/DLLMain.c | 50 + contrib/dlz/example/win32/dxdriver.def | 20 + contrib/dlz/example/win32/dxdriver.dsp | 121 + contrib/dlz/example/win32/dxdriver.dsw | 29 + contrib/dlz/example/win32/dxdriver.mak | 298 + contrib/dlz/modules/bdbhpt/Makefile | 43 + contrib/dlz/modules/bdbhpt/README.md | 113 + contrib/dlz/modules/bdbhpt/dlz_bdbhpt_dynamic.c | 837 + contrib/dlz/modules/bdbhpt/testing/README | 11 + .../dlz/modules/bdbhpt/testing/bdbhpt-populate.pl | 244 + contrib/dlz/modules/bdbhpt/testing/dns-data.txt | 19 + contrib/dlz/modules/bdbhpt/testing/named.conf | 37 + contrib/dlz/modules/common/dlz_dbi.c | 484 + contrib/dlz/modules/filesystem/Makefile | 45 + contrib/dlz/modules/filesystem/dir.c | 118 + contrib/dlz/modules/filesystem/dir.h | 43 + .../modules/filesystem/dlz_filesystem_dynamic.c | 1008 + contrib/dlz/modules/include/.clang-format | 1 + contrib/dlz/modules/include/dlz_dbi.h | 107 + contrib/dlz/modules/include/dlz_list.h | 73 + contrib/dlz/modules/include/dlz_minimal.h | 336 + contrib/dlz/modules/include/dlz_pthread.h | 43 + contrib/dlz/modules/ldap/Makefile | 46 + contrib/dlz/modules/ldap/dlz_ldap_dynamic.c | 1254 + contrib/dlz/modules/ldap/testing/README | 10 + contrib/dlz/modules/ldap/testing/dlz.schema | 192 + contrib/dlz/modules/ldap/testing/example.ldif | 192 + contrib/dlz/modules/ldap/testing/named.conf | 43 + contrib/dlz/modules/ldap/testing/slapd.conf | 44 + contrib/dlz/modules/mysql/Makefile.in | 52 + contrib/dlz/modules/mysql/dlz_mysql_dynamic.c | 1109 + contrib/dlz/modules/mysql/testing/README | 7 + contrib/dlz/modules/mysql/testing/dlz.data | 12 + contrib/dlz/modules/mysql/testing/dlz.schema | 30 + contrib/dlz/modules/mysql/testing/named.conf | 46 + contrib/dlz/modules/mysqldyn/Makefile.in | 52 + contrib/dlz/modules/mysqldyn/README | 87 + contrib/dlz/modules/mysqldyn/dlz_mysqldyn_mod.c | 1800 ++ contrib/dlz/modules/mysqldyn/testing/README | 11 + contrib/dlz/modules/mysqldyn/testing/dlz.data | 18 + contrib/dlz/modules/mysqldyn/testing/dlz.schema | 31 + contrib/dlz/modules/mysqldyn/testing/named.conf | 39 + contrib/dlz/modules/perl/Makefile | 63 + contrib/dlz/modules/perl/README | 38 + contrib/dlz/modules/perl/dlz_perl_callback.xs | 88 + .../modules/perl/dlz_perl_callback_clientinfo.xs | 94 + contrib/dlz/modules/perl/dlz_perl_driver.c | 715 + contrib/dlz/modules/perl/dlz_perl_driver.h | 37 + .../dlz/modules/perl/testing/dlz_perl_example.pm | 185 + contrib/dlz/modules/perl/testing/named.conf | 26 + contrib/dlz/modules/sqlite3/Makefile | 46 + contrib/dlz/modules/sqlite3/dlz_sqlite3_dynamic.c | 1093 + contrib/dlz/modules/sqlite3/testing/README | 10 + contrib/dlz/modules/sqlite3/testing/dlz.data | 18 + contrib/dlz/modules/sqlite3/testing/dlz.schema | 28 + contrib/dlz/modules/sqlite3/testing/named.conf | 45 + contrib/dlz/modules/wildcard/Makefile | 46 + contrib/dlz/modules/wildcard/README | 59 + .../dlz/modules/wildcard/dlz_wildcard_dynamic.c | 773 + contrib/dlz/modules/wildcard/testing/named.conf | 55 + contrib/dnspriv/README.md | 23 + contrib/dnspriv/named.conf | 20 + contrib/dnspriv/nginx.conf | 43 + contrib/kasp/README | 11 + contrib/kasp/kasp.xml | 146 + contrib/kasp/kasp2policy.py | 223 + contrib/kasp/policy.good | 24 + contrib/scripts/catzhash.py | 35 + contrib/scripts/check-secure-delegation.pl.in | 116 + contrib/scripts/check5011.pl | 210 + contrib/scripts/dnssec-keyset.sh | 207 + contrib/scripts/named-bootconf.sh | 301 + contrib/scripts/nanny.pl | 49 + contrib/scripts/zone-edit.sh.in | 153 + dangerfile.py | 434 + doc/Makefile.in | 23 + doc/arm/.gitattributes | 7 + doc/arm/Makefile.in | 82 + doc/arm/_static/custom.css | 25 + doc/arm/advanced.rst | 632 + doc/arm/build.rst | 199 + doc/arm/catz.rst | 241 + doc/arm/conf.py | 188 + doc/arm/configuration.rst | 320 + doc/arm/dlz.rst | 134 + doc/arm/dnssec-guide.rst | 23 + doc/arm/dnssec.inc.rst | 521 + doc/arm/dyndb.rst | 89 + doc/arm/general.rst | 432 + doc/arm/history.rst | 77 + doc/arm/index.rst | 41 + doc/arm/introduction.rst | 311 + doc/arm/isc-logo.pdf | Bin 0 -> 17189 bytes doc/arm/logging-categories.rst | 117 + doc/arm/managed-keys.rst | 92 + doc/arm/manpages.rst | 55 + doc/arm/notes.rst | 116 + doc/arm/pkcs11.rst | 287 + doc/arm/platforms.rst | 113 + doc/arm/plugins.rst | 82 + doc/arm/reference.rst | 7057 +++++ doc/arm/requirements.rst | 74 + doc/arm/requirements.txt | 5 + doc/arm/security.rst | 228 + doc/arm/troubleshooting.rst | 107 + doc/dnssec-guide/advanced-discussions.rst | 1089 + doc/dnssec-guide/commonly-asked-questions.rst | 172 + doc/dnssec-guide/getting-started.rst | 147 + doc/dnssec-guide/img/add-ds-1.png | Bin 0 -> 290596 bytes doc/dnssec-guide/img/add-ds-2.png | Bin 0 -> 93324 bytes doc/dnssec-guide/img/add-ds-3.png | Bin 0 -> 49418 bytes doc/dnssec-guide/img/add-ds-4.png | Bin 0 -> 87273 bytes doc/dnssec-guide/img/add-ds-5.png | Bin 0 -> 48202 bytes doc/dnssec-guide/img/add-ds-6.png | Bin 0 -> 70617 bytes doc/dnssec-guide/img/dnssec-12-steps.png | Bin 0 -> 91732 bytes doc/dnssec-guide/img/dnssec-8-steps.png | Bin 0 -> 82495 bytes doc/dnssec-guide/img/dnssec-inline-signing-1.png | Bin 0 -> 118780 bytes doc/dnssec-guide/img/dnssec-inline-signing-2.png | Bin 0 -> 138019 bytes doc/dnssec-guide/img/dnsviz-example-small.png | Bin 0 -> 116889 bytes doc/dnssec-guide/img/remove-ds-1.png | Bin 0 -> 86552 bytes doc/dnssec-guide/img/remove-ds-2.png | Bin 0 -> 58176 bytes doc/dnssec-guide/img/remove-ds-3.png | Bin 0 -> 62774 bytes doc/dnssec-guide/img/signature-generation.png | Bin 0 -> 19920 bytes doc/dnssec-guide/img/signature-verification.png | Bin 0 -> 32267 bytes doc/dnssec-guide/img/unsign-1.png | Bin 0 -> 216627 bytes doc/dnssec-guide/img/unsign-2.png | Bin 0 -> 86552 bytes doc/dnssec-guide/img/unsign-3.png | Bin 0 -> 70314 bytes doc/dnssec-guide/img/unsign-4.png | Bin 0 -> 63392 bytes .../img/verisign-dnssec-debugger-example.png | Bin 0 -> 70292 bytes doc/dnssec-guide/introduction.rst | 394 + doc/dnssec-guide/preface.rst | 83 + doc/dnssec-guide/recipes.rst | 1084 + doc/dnssec-guide/signing.rst | 1647 ++ doc/dnssec-guide/troubleshooting.rst | 589 + doc/dnssec-guide/validation.rst | 864 + doc/doxygen/Doxyfile.in | 1280 + doc/doxygen/Makefile.in | 33 + doc/doxygen/doxygen-input-filter.in | 55 + doc/doxygen/isc-footer.html | 21 + doc/doxygen/isc-header.html | 21 + doc/doxygen/mainpage | 96 + doc/man/Makefile.in | 275 + doc/man/arpaname.1in | 48 + doc/man/arpaname.rst | 14 + doc/man/conf.py | 216 + doc/man/ddns-confgen.8in | 102 + doc/man/ddns-confgen.rst | 14 + doc/man/delv.1in | 345 + doc/man/delv.rst | 14 + doc/man/dig.1in | 670 + doc/man/dig.rst | 14 + doc/man/dnssec-cds.8in | 229 + doc/man/dnssec-cds.rst | 14 + doc/man/dnssec-checkds.8in | 96 + doc/man/dnssec-checkds.rst | 14 + doc/man/dnssec-coverage.8in | 192 + doc/man/dnssec-coverage.rst | 14 + doc/man/dnssec-dsfromkey.8in | 153 + doc/man/dnssec-dsfromkey.rst | 14 + doc/man/dnssec-importkey.8in | 126 + doc/man/dnssec-importkey.rst | 14 + doc/man/dnssec-keyfromlabel.8in | 277 + doc/man/dnssec-keyfromlabel.rst | 14 + doc/man/dnssec-keygen.8in | 331 + doc/man/dnssec-keygen.rst | 14 + doc/man/dnssec-keymgr.8in | 297 + doc/man/dnssec-keymgr.rst | 14 + doc/man/dnssec-revoke.8in | 86 + doc/man/dnssec-revoke.rst | 14 + doc/man/dnssec-settime.8in | 246 + doc/man/dnssec-settime.rst | 14 + doc/man/dnssec-signzone.8in | 438 + doc/man/dnssec-signzone.rst | 14 + doc/man/dnssec-verify.8in | 113 + doc/man/dnssec-verify.rst | 14 + doc/man/dnstap-read.1in | 67 + doc/man/dnstap-read.rst | 14 + doc/man/filter-aaaa.8in | 110 + doc/man/filter-aaaa.rst | 14 + doc/man/host.1in | 182 + doc/man/host.rst | 14 + doc/man/index.rst | 10 + doc/man/mdig.1in | 341 + doc/man/mdig.rst | 14 + doc/man/named-checkconf.8in | 108 + doc/man/named-checkconf.rst | 14 + doc/man/named-checkzone.8in | 204 + doc/man/named-checkzone.rst | 14 + doc/man/named-compilezone.8in | 206 + doc/man/named-compilezone.rst | 14 + doc/man/named-journalprint.8in | 79 + doc/man/named-journalprint.rst | 14 + doc/man/named-nzd2nzf.8in | 57 + doc/man/named-nzd2nzf.rst | 14 + doc/man/named-rrchecker.1in | 70 + doc/man/named-rrchecker.rst | 14 + doc/man/named.8in | 296 + doc/man/named.conf.5in | 1175 + doc/man/named.conf.rst | 14 + doc/man/named.rst | 14 + doc/man/nsec3hash.8in | 78 + doc/man/nsec3hash.rst | 14 + doc/man/nslookup.1in | 225 + doc/man/nslookup.rst | 14 + doc/man/nsupdate.1in | 385 + doc/man/nsupdate.rst | 14 + doc/man/pkcs11-destroy.8in | 74 + doc/man/pkcs11-destroy.rst | 14 + doc/man/pkcs11-keygen.8in | 95 + doc/man/pkcs11-keygen.rst | 14 + doc/man/pkcs11-list.8in | 73 + doc/man/pkcs11-list.rst | 14 + doc/man/pkcs11-tokens.8in | 58 + doc/man/pkcs11-tokens.rst | 14 + doc/man/rndc-confgen.8in | 119 + doc/man/rndc-confgen.rst | 14 + doc/man/rndc.8in | 627 + doc/man/rndc.conf.5in | 196 + doc/man/rndc.conf.rst | 14 + doc/man/rndc.rst | 14 + doc/man/tsig-keygen.8in | 64 + doc/man/tsig-keygen.rst | 14 + doc/misc/Makefile.in | 83 + doc/misc/acl.grammar.rst | 14 + doc/misc/controls.grammar.rst | 24 + doc/misc/delegation-only.zoneopt | 3 + doc/misc/delegation-only.zoneopt.rst | 16 + doc/misc/dnssec-policy.default.conf | 38 + doc/misc/dnssec-policy.grammar.rst | 28 + doc/misc/format-options.pl | 43 + doc/misc/forward.zoneopt | 6 + doc/misc/forward.zoneopt.rst | 19 + doc/misc/hint.zoneopt | 6 + doc/misc/hint.zoneopt.rst | 19 + doc/misc/in-view.zoneopt | 3 + doc/misc/in-view.zoneopt.rst | 16 + doc/misc/key.grammar.rst | 17 + doc/misc/logging.grammar.rst | 28 + doc/misc/managed-keys.grammar.rst | 17 + doc/misc/master.zoneopt | 61 + doc/misc/master.zoneopt.rst | 74 + doc/misc/mirror.zoneopt | 44 + doc/misc/mirror.zoneopt.rst | 57 + doc/misc/options | 1031 + doc/misc/options.active | 942 + doc/misc/options.grammar.rst | 313 + doc/misc/parental-agents.grammar.rst | 18 + doc/misc/primaries.grammar.rst | 18 + doc/misc/redirect.zoneopt | 14 + doc/misc/redirect.zoneopt.rst | 27 + doc/misc/rst-grammars.pl | 81 + doc/misc/rst-options.pl | 135 + doc/misc/rst-zoneopt.pl | 59 + doc/misc/server.grammar.rst | 45 + doc/misc/slave.zoneopt | 65 + doc/misc/slave.zoneopt.rst | 78 + doc/misc/sort-options.pl | 45 + doc/misc/static-stub.zoneopt | 11 + doc/misc/static-stub.zoneopt.rst | 24 + doc/misc/statistics-channels.grammar.rst | 19 + doc/misc/stub.zoneopt | 28 + doc/misc/stub.zoneopt.rst | 41 + doc/misc/trust-anchors.grammar.rst | 17 + doc/misc/trusted-keys.grammar.rst | 16 + doc/notes/notes-9.16.0.rst | 152 + doc/notes/notes-9.16.1.rst | 48 + doc/notes/notes-9.16.10.rst | 58 + doc/notes/notes-9.16.11.rst | 74 + doc/notes/notes-9.16.12.rst | 123 + doc/notes/notes-9.16.13.rst | 79 + doc/notes/notes-9.16.14.rst | 19 + doc/notes/notes-9.16.15.rst | 112 + doc/notes/notes-9.16.16.rst | 76 + doc/notes/notes-9.16.17.rst | 67 + doc/notes/notes-9.16.18.rst | 33 + doc/notes/notes-9.16.19.rst | 68 + doc/notes/notes-9.16.2.rst | 59 + doc/notes/notes-9.16.20.rst | 57 + doc/notes/notes-9.16.21.rst | 68 + doc/notes/notes-9.16.22.rst | 86 + doc/notes/notes-9.16.23.rst | 27 + doc/notes/notes-9.16.24.rst | 43 + doc/notes/notes-9.16.25.rst | 48 + doc/notes/notes-9.16.26.rst | 46 + doc/notes/notes-9.16.27.rst | 65 + doc/notes/notes-9.16.28.rst | 40 + doc/notes/notes-9.16.29.rst | 27 + doc/notes/notes-9.16.3.rst | 95 + doc/notes/notes-9.16.30.rst | 37 + doc/notes/notes-9.16.31.rst | 31 + doc/notes/notes-9.16.32.rst | 56 + doc/notes/notes-9.16.33.rst | 68 + doc/notes/notes-9.16.34.rst | 46 + doc/notes/notes-9.16.35.rst | 56 + doc/notes/notes-9.16.36.rst | 49 + doc/notes/notes-9.16.37.rst | 80 + doc/notes/notes-9.16.38.rst | 33 + doc/notes/notes-9.16.39.rst | 60 + doc/notes/notes-9.16.4.rst | 120 + doc/notes/notes-9.16.40.rst | 32 + doc/notes/notes-9.16.41.rst | 27 + doc/notes/notes-9.16.42.rst | 45 + doc/notes/notes-9.16.43.rst | 27 + doc/notes/notes-9.16.44.rst | 31 + doc/notes/notes-9.16.5.rst | 72 + doc/notes/notes-9.16.6.rst | 121 + doc/notes/notes-9.16.7.rst | 63 + doc/notes/notes-9.16.8.rst | 63 + doc/notes/notes-9.16.9.rst | 50 + doc/notes/notes-known-issues.rst | 46 + fuzz/FUZZING.md | 37 + fuzz/Makefile.in | 55 + .../generate-counter-overflow.db | Bin 0 -> 47 bytes fuzz/dns_name_fromtext_target.c | 45 + fuzz/dns_name_fromtext_target.in/example.com | 1 + fuzz/dns_rdata_fromtext.in/svbc-max-token | 1 + fuzz/dns_rdata_fromwire_text.c | 225 + fuzz/dns_rdata_fromwire_text.in/cdnskey | Bin 0 -> 20 bytes fuzz/dns_rdata_fromwire_text.in/input-0 | Bin 0 -> 15 bytes fuzz/dns_rdata_fromwire_text.in/input-1 | Bin 0 -> 7 bytes fuzz/dns_rdata_fromwire_text.in/input-10 | Bin 0 -> 77 bytes fuzz/dns_rdata_fromwire_text.in/input-100 | Bin 0 -> 12 bytes fuzz/dns_rdata_fromwire_text.in/input-101 | Bin 0 -> 25 bytes fuzz/dns_rdata_fromwire_text.in/input-102 | Bin 0 -> 26 bytes fuzz/dns_rdata_fromwire_text.in/input-103 | Bin 0 -> 44 bytes fuzz/dns_rdata_fromwire_text.in/input-104 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-105 | Bin 0 -> 22 bytes fuzz/dns_rdata_fromwire_text.in/input-106 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-107 | Bin 0 -> 31 bytes fuzz/dns_rdata_fromwire_text.in/input-108 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-109 | Bin 0 -> 68 bytes fuzz/dns_rdata_fromwire_text.in/input-11 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-110 | Bin 0 -> 71 bytes fuzz/dns_rdata_fromwire_text.in/input-111 | Bin 0 -> 84 bytes fuzz/dns_rdata_fromwire_text.in/input-112 | Bin 0 -> 69 bytes fuzz/dns_rdata_fromwire_text.in/input-113 | Bin 0 -> 93 bytes fuzz/dns_rdata_fromwire_text.in/input-114 | Bin 0 -> 57 bytes fuzz/dns_rdata_fromwire_text.in/input-115 | Bin 0 -> 57 bytes fuzz/dns_rdata_fromwire_text.in/input-116 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-117 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-118 | Bin 0 -> 115 bytes fuzz/dns_rdata_fromwire_text.in/input-119 | Bin 0 -> 57 bytes fuzz/dns_rdata_fromwire_text.in/input-12 | Bin 0 -> 8 bytes fuzz/dns_rdata_fromwire_text.in/input-120 | Bin 0 -> 126 bytes fuzz/dns_rdata_fromwire_text.in/input-121 | Bin 0 -> 110 bytes fuzz/dns_rdata_fromwire_text.in/input-122 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-123 | Bin 0 -> 25 bytes fuzz/dns_rdata_fromwire_text.in/input-124 | Bin 0 -> 65 bytes fuzz/dns_rdata_fromwire_text.in/input-125 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-126 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-127 | Bin 0 -> 48 bytes fuzz/dns_rdata_fromwire_text.in/input-128 | Bin 0 -> 56 bytes fuzz/dns_rdata_fromwire_text.in/input-129 | Bin 0 -> 26 bytes fuzz/dns_rdata_fromwire_text.in/input-13 | Bin 0 -> 30 bytes fuzz/dns_rdata_fromwire_text.in/input-130 | Bin 0 -> 60 bytes fuzz/dns_rdata_fromwire_text.in/input-131 | Bin 0 -> 51 bytes fuzz/dns_rdata_fromwire_text.in/input-132 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-133 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-134 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-135 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-136 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-137 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-138 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-139 | Bin 0 -> 51 bytes fuzz/dns_rdata_fromwire_text.in/input-14 | Bin 0 -> 38 bytes fuzz/dns_rdata_fromwire_text.in/input-140 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-141 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-142 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-143 | 1 + fuzz/dns_rdata_fromwire_text.in/input-15 | Bin 0 -> 7 bytes fuzz/dns_rdata_fromwire_text.in/input-16 | Bin 0 -> 5 bytes fuzz/dns_rdata_fromwire_text.in/input-17 | 1 + fuzz/dns_rdata_fromwire_text.in/input-18 | Bin 0 -> 23 bytes fuzz/dns_rdata_fromwire_text.in/input-19 | Bin 0 -> 22 bytes fuzz/dns_rdata_fromwire_text.in/input-2 | 1 + fuzz/dns_rdata_fromwire_text.in/input-20 | Bin 0 -> 151 bytes fuzz/dns_rdata_fromwire_text.in/input-21 | Bin 0 -> 75 bytes fuzz/dns_rdata_fromwire_text.in/input-22 | Bin 0 -> 19 bytes fuzz/dns_rdata_fromwire_text.in/input-23 | Bin 0 -> 12 bytes fuzz/dns_rdata_fromwire_text.in/input-24 | Bin 0 -> 8 bytes fuzz/dns_rdata_fromwire_text.in/input-25 | Bin 0 -> 15 bytes fuzz/dns_rdata_fromwire_text.in/input-26 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-27 | Bin 0 -> 7 bytes fuzz/dns_rdata_fromwire_text.in/input-28 | Bin 0 -> 8 bytes fuzz/dns_rdata_fromwire_text.in/input-29 | Bin 0 -> 8 bytes fuzz/dns_rdata_fromwire_text.in/input-3 | Bin 0 -> 72 bytes fuzz/dns_rdata_fromwire_text.in/input-30 | Bin 0 -> 33 bytes fuzz/dns_rdata_fromwire_text.in/input-31 | Bin 0 -> 37 bytes fuzz/dns_rdata_fromwire_text.in/input-32 | 1 + fuzz/dns_rdata_fromwire_text.in/input-33 | Bin 0 -> 11 bytes fuzz/dns_rdata_fromwire_text.in/input-34 | Bin 0 -> 7 bytes fuzz/dns_rdata_fromwire_text.in/input-35 | Bin 0 -> 12 bytes fuzz/dns_rdata_fromwire_text.in/input-36 | Bin 0 -> 10 bytes fuzz/dns_rdata_fromwire_text.in/input-37 | Bin 0 -> 66 bytes fuzz/dns_rdata_fromwire_text.in/input-38 | Bin 0 -> 66 bytes fuzz/dns_rdata_fromwire_text.in/input-39 | 1 + fuzz/dns_rdata_fromwire_text.in/input-4 | Bin 0 -> 5 bytes fuzz/dns_rdata_fromwire_text.in/input-40 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-41 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-42 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-43 | Bin 0 -> 30 bytes fuzz/dns_rdata_fromwire_text.in/input-44 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-45 | Bin 0 -> 38 bytes fuzz/dns_rdata_fromwire_text.in/input-46 | Bin 0 -> 23 bytes fuzz/dns_rdata_fromwire_text.in/input-47 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-48 | Bin 0 -> 54 bytes fuzz/dns_rdata_fromwire_text.in/input-49 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-5 | 1 + fuzz/dns_rdata_fromwire_text.in/input-50 | 1 + fuzz/dns_rdata_fromwire_text.in/input-51 | Bin 0 -> 12 bytes fuzz/dns_rdata_fromwire_text.in/input-52 | Bin 0 -> 6 bytes fuzz/dns_rdata_fromwire_text.in/input-53 | 1 + fuzz/dns_rdata_fromwire_text.in/input-54 | Bin 0 -> 83 bytes fuzz/dns_rdata_fromwire_text.in/input-55 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-56 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-57 | Bin 0 -> 49 bytes fuzz/dns_rdata_fromwire_text.in/input-58 | Bin 0 -> 38 bytes fuzz/dns_rdata_fromwire_text.in/input-59 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-6 | Bin 0 -> 5 bytes fuzz/dns_rdata_fromwire_text.in/input-60 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-61 | Bin 0 -> 29 bytes fuzz/dns_rdata_fromwire_text.in/input-62 | Bin 0 -> 28 bytes fuzz/dns_rdata_fromwire_text.in/input-63 | Bin 0 -> 23 bytes fuzz/dns_rdata_fromwire_text.in/input-64 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-65 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-66 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-67 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-68 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-69 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-7 | Bin 0 -> 9 bytes fuzz/dns_rdata_fromwire_text.in/input-70 | Bin 0 -> 27 bytes fuzz/dns_rdata_fromwire_text.in/input-71 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-72 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-73 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-74 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-75 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-76 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-77 | Bin 0 -> 8 bytes fuzz/dns_rdata_fromwire_text.in/input-78 | Bin 0 -> 12 bytes fuzz/dns_rdata_fromwire_text.in/input-79 | Bin 0 -> 9 bytes fuzz/dns_rdata_fromwire_text.in/input-8 | Bin 0 -> 67 bytes fuzz/dns_rdata_fromwire_text.in/input-80 | Bin 0 -> 11 bytes fuzz/dns_rdata_fromwire_text.in/input-81 | Bin 0 -> 11 bytes fuzz/dns_rdata_fromwire_text.in/input-82 | Bin 0 -> 12 bytes fuzz/dns_rdata_fromwire_text.in/input-83 | Bin 0 -> 15 bytes fuzz/dns_rdata_fromwire_text.in/input-84 | Bin 0 -> 9 bytes fuzz/dns_rdata_fromwire_text.in/input-85 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-86 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-87 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-88 | Bin 0 -> 36 bytes fuzz/dns_rdata_fromwire_text.in/input-89 | Bin 0 -> 63 bytes fuzz/dns_rdata_fromwire_text.in/input-9 | 1 + fuzz/dns_rdata_fromwire_text.in/input-90 | Bin 0 -> 74 bytes fuzz/dns_rdata_fromwire_text.in/input-91 | Bin 0 -> 42 bytes fuzz/dns_rdata_fromwire_text.in/input-92 | Bin 0 -> 74 bytes fuzz/dns_rdata_fromwire_text.in/input-93 | Bin 0 -> 48 bytes fuzz/dns_rdata_fromwire_text.in/input-94 | Bin 0 -> 23 bytes fuzz/dns_rdata_fromwire_text.in/input-95 | Bin 0 -> 21 bytes fuzz/dns_rdata_fromwire_text.in/input-96 | Bin 0 -> 11 bytes fuzz/dns_rdata_fromwire_text.in/input-97 | Bin 0 -> 17 bytes fuzz/dns_rdata_fromwire_text.in/input-98 | Bin 0 -> 50 bytes fuzz/dns_rdata_fromwire_text.in/input-99 | 1 + fuzz/dns_rdata_fromwire_text.in/smimea | 1 + fuzz/dns_rdata_fromwire_text.in/sshfp | 1 + fuzz/dns_rdata_fromwire_text.in/svcb | Bin 0 -> 39 bytes fuzz/fuzz.h | 33 + fuzz/main.c | 145 + install-sh | 501 + lib/Kyuafile | 20 + lib/Makefile.in | 23 + lib/bind9/Makefile.in | 79 + lib/bind9/check.c | 5512 ++++ lib/bind9/getaddresses.c | 164 + lib/bind9/include/.clang-format | 1 + lib/bind9/include/Makefile.in | 19 + lib/bind9/include/bind9/Makefile.in | 41 + lib/bind9/include/bind9/check.h | 66 + lib/bind9/include/bind9/getaddresses.h | 54 + lib/bind9/include/bind9/version.h | 18 + lib/bind9/version.c | 18 + lib/bind9/win32/DLLMain.c | 49 + lib/bind9/win32/libbind9.def | 8 + lib/bind9/win32/libbind9.vcxproj.filters.in | 45 + lib/bind9/win32/libbind9.vcxproj.in | 134 + lib/bind9/win32/libbind9.vcxproj.user | 3 + lib/bind9/win32/version.c | 18 + lib/dns/Kyuafile | 15 + lib/dns/Makefile.in | 215 + lib/dns/acl.c | 665 + lib/dns/adb.c | 4885 ++++ lib/dns/badcache.c | 525 + lib/dns/byaddr.c | 282 + lib/dns/cache.c | 1510 ++ lib/dns/callbacks.c | 107 + lib/dns/catz.c | 2105 ++ lib/dns/client.c | 1353 + lib/dns/clientinfo.c | 38 + lib/dns/compress.c | 584 + lib/dns/db.c | 1139 + lib/dns/dbiterator.c | 135 + lib/dns/dbtable.c | 249 + lib/dns/diff.c | 688 + lib/dns/dispatch.c | 3591 +++ lib/dns/dlz.c | 541 + lib/dns/dns64.c | 325 + lib/dns/dnsrps.c | 1005 + lib/dns/dnssec.c | 2522 ++ lib/dns/dnstap.c | 1386 + lib/dns/dnstap.proto | 289 + lib/dns/ds.c | 135 + lib/dns/dst_api.c | 2797 ++ lib/dns/dst_internal.h | 286 + lib/dns/dst_openssl.h | 73 + lib/dns/dst_parse.c | 804 + lib/dns/dst_parse.h | 134 + lib/dns/dst_pkcs11.h | 43 + lib/dns/dst_result.c | 110 + lib/dns/dyndb.c | 465 + lib/dns/ecdb.c | 797 + lib/dns/ecs.c | 113 + lib/dns/fixedname.c | 39 + lib/dns/forward.c | 227 + lib/dns/gen-unix.h | 100 + lib/dns/gen-win32.h | 295 + lib/dns/gen.c | 1028 + lib/dns/geoip2.c | 389 + lib/dns/gssapi_link.c | 358 + lib/dns/gssapictx.c | 957 + lib/dns/hmac_link.c | 521 + lib/dns/include/.clang-format | 1 + lib/dns/include/Makefile.in | 19 + lib/dns/include/dns/Makefile.in | 63 + lib/dns/include/dns/acl.h | 253 + lib/dns/include/dns/adb.h | 835 + lib/dns/include/dns/badcache.h | 152 + lib/dns/include/dns/bit.h | 28 + lib/dns/include/dns/byaddr.h | 152 + lib/dns/include/dns/cache.h | 360 + lib/dns/include/dns/callbacks.h | 103 + lib/dns/include/dns/catz.h | 473 + lib/dns/include/dns/cert.h | 63 + lib/dns/include/dns/client.h | 476 + lib/dns/include/dns/clientinfo.h | 95 + lib/dns/include/dns/compress.h | 302 + lib/dns/include/dns/db.h | 1800 ++ lib/dns/include/dns/dbiterator.h | 293 + lib/dns/include/dns/dbtable.h | 159 + lib/dns/include/dns/diff.h | 282 + lib/dns/include/dns/dispatch.h | 586 + lib/dns/include/dns/dlz.h | 336 + lib/dns/include/dns/dlz_dlopen.h | 159 + lib/dns/include/dns/dns64.h | 174 + lib/dns/include/dns/dnsrps.h | 115 + lib/dns/include/dns/dnssec.h | 401 + lib/dns/include/dns/dnstap.h | 396 + lib/dns/include/dns/ds.h | 68 + lib/dns/include/dns/dsdigest.h | 72 + lib/dns/include/dns/dyndb.h | 162 + lib/dns/include/dns/ecdb.h | 49 + lib/dns/include/dns/ecs.h | 84 + lib/dns/include/dns/edns.h | 29 + lib/dns/include/dns/events.h | 90 + lib/dns/include/dns/fixedname.h | 85 + lib/dns/include/dns/forward.h | 124 + lib/dns/include/dns/geoip.h | 114 + lib/dns/include/dns/ipkeylist.h | 90 + lib/dns/include/dns/iptable.h | 70 + lib/dns/include/dns/journal.h | 341 + lib/dns/include/dns/kasp.h | 717 + lib/dns/include/dns/keydata.h | 51 + lib/dns/include/dns/keyflags.h | 48 + lib/dns/include/dns/keymgr.h | 134 + lib/dns/include/dns/keytable.h | 350 + lib/dns/include/dns/keyvalues.h | 107 + lib/dns/include/dns/lib.h | 45 + lib/dns/include/dns/librpz.h | 956 + lib/dns/include/dns/lmdb.h | 25 + lib/dns/include/dns/log.h | 114 + lib/dns/include/dns/lookup.h | 131 + lib/dns/include/dns/master.h | 264 + lib/dns/include/dns/masterdump.h | 364 + lib/dns/include/dns/message.h | 1492 + lib/dns/include/dns/name.h | 1410 + lib/dns/include/dns/ncache.h | 187 + lib/dns/include/dns/nsec.h | 114 + lib/dns/include/dns/nsec3.h | 272 + lib/dns/include/dns/nta.h | 218 + lib/dns/include/dns/opcode.h | 46 + lib/dns/include/dns/order.h | 93 + lib/dns/include/dns/peer.h | 279 + lib/dns/include/dns/portlist.h | 102 + lib/dns/include/dns/private.h | 69 + lib/dns/include/dns/rbt.h | 1060 + lib/dns/include/dns/rcode.h | 110 + lib/dns/include/dns/rdata.h | 812 + lib/dns/include/dns/rdataclass.h | 94 + lib/dns/include/dns/rdatalist.h | 123 + lib/dns/include/dns/rdataset.h | 615 + lib/dns/include/dns/rdatasetiter.h | 164 + lib/dns/include/dns/rdataslab.h | 173 + lib/dns/include/dns/rdatatype.h | 97 + lib/dns/include/dns/request.h | 365 + lib/dns/include/dns/resolver.h | 747 + lib/dns/include/dns/result.h | 212 + lib/dns/include/dns/rootns.h | 39 + lib/dns/include/dns/rpz.h | 435 + lib/dns/include/dns/rriterator.h | 182 + lib/dns/include/dns/rrl.h | 272 + lib/dns/include/dns/sdb.h | 214 + lib/dns/include/dns/sdlz.h | 359 + lib/dns/include/dns/secalg.h | 72 + lib/dns/include/dns/secproto.h | 65 + lib/dns/include/dns/soa.h | 96 + lib/dns/include/dns/ssu.h | 243 + lib/dns/include/dns/stats.h | 826 + lib/dns/include/dns/tcpmsg.h | 143 + lib/dns/include/dns/time.h | 73 + lib/dns/include/dns/timer.h | 48 + lib/dns/include/dns/tkey.h | 246 + lib/dns/include/dns/tsec.h | 132 + lib/dns/include/dns/tsig.h | 297 + lib/dns/include/dns/ttl.h | 80 + lib/dns/include/dns/types.h | 438 + lib/dns/include/dns/update.h | 75 + lib/dns/include/dns/validator.h | 243 + lib/dns/include/dns/version.h | 25 + lib/dns/include/dns/view.h | 1359 + lib/dns/include/dns/xfrin.h | 98 + lib/dns/include/dns/zone.h | 2726 ++ lib/dns/include/dns/zonekey.h | 38 + lib/dns/include/dns/zoneverify.h | 50 + lib/dns/include/dns/zt.h | 224 + lib/dns/include/dst/Makefile.in | 36 + lib/dns/include/dst/dst.h | 1227 + lib/dns/include/dst/gssapi.h | 196 + lib/dns/include/dst/result.h | 67 + lib/dns/ipkeylist.c | 209 + lib/dns/iptable.c | 174 + lib/dns/journal.c | 2856 ++ lib/dns/kasp.c | 527 + lib/dns/key.c | 192 + lib/dns/keydata.c | 76 + lib/dns/keymgr.c | 2628 ++ lib/dns/keytable.c | 943 + lib/dns/lib.c | 119 + lib/dns/log.c | 84 + lib/dns/lookup.c | 450 + lib/dns/mapapi | 16 + lib/dns/master.c | 3264 +++ lib/dns/masterdump.c | 2133 ++ lib/dns/message.c | 4748 ++++ lib/dns/name.c | 2692 ++ lib/dns/ncache.c | 777 + lib/dns/nsec.c | 466 + lib/dns/nsec3.c | 2195 ++ lib/dns/nta.c | 722 + lib/dns/openssl_link.c | 214 + lib/dns/openssldh_link.c | 815 + lib/dns/opensslecdsa_link.c | 905 + lib/dns/openssleddsa_link.c | 708 + lib/dns/opensslrsa_link.c | 1405 + lib/dns/order.c | 150 + lib/dns/peer.c | 919 + lib/dns/pkcs11.c | 40 + lib/dns/pkcs11ecdsa_link.c | 1153 + lib/dns/pkcs11eddsa_link.c | 1124 + lib/dns/pkcs11rsa_link.c | 2115 ++ lib/dns/portlist.c | 252 + lib/dns/private.c | 417 + lib/dns/rbt.c | 3808 +++ lib/dns/rbtdb.c | 10667 ++++++++ lib/dns/rbtdb.h | 52 + lib/dns/rcode.c | 588 + lib/dns/rdata.c | 2365 ++ lib/dns/rdata/any_255/tsig_250.c | 621 + lib/dns/rdata/any_255/tsig_250.h | 32 + lib/dns/rdata/ch_3/a_1.c | 325 + lib/dns/rdata/ch_3/a_1.h | 31 + lib/dns/rdata/generic/afsdb_18.c | 316 + lib/dns/rdata/generic/afsdb_18.h | 27 + lib/dns/rdata/generic/amtrelay_260.c | 471 + lib/dns/rdata/generic/amtrelay_260.h | 30 + lib/dns/rdata/generic/avc_258.c | 144 + lib/dns/rdata/generic/avc_258.h | 32 + lib/dns/rdata/generic/caa_257.c | 627 + lib/dns/rdata/generic/caa_257.h | 27 + lib/dns/rdata/generic/cdnskey_60.c | 163 + lib/dns/rdata/generic/cdnskey_60.h | 20 + lib/dns/rdata/generic/cds_59.c | 166 + lib/dns/rdata/generic/cds_59.h | 20 + lib/dns/rdata/generic/cert_37.c | 284 + lib/dns/rdata/generic/cert_37.h | 28 + lib/dns/rdata/generic/cname_5.c | 230 + lib/dns/rdata/generic/cname_5.h | 23 + lib/dns/rdata/generic/csync_62.c | 273 + lib/dns/rdata/generic/csync_62.h | 30 + lib/dns/rdata/generic/dlv_32769.c | 162 + lib/dns/rdata/generic/dlv_32769.h | 20 + lib/dns/rdata/generic/dname_39.c | 230 + lib/dns/rdata/generic/dname_39.h | 26 + lib/dns/rdata/generic/dnskey_48.c | 164 + lib/dns/rdata/generic/dnskey_48.h | 23 + lib/dns/rdata/generic/doa_259.c | 361 + lib/dns/rdata/generic/doa_259.h | 29 + lib/dns/rdata/generic/ds_43.c | 385 + lib/dns/rdata/generic/ds_43.h | 29 + lib/dns/rdata/generic/eui48_108.c | 211 + lib/dns/rdata/generic/eui48_108.h | 23 + lib/dns/rdata/generic/eui64_109.c | 214 + lib/dns/rdata/generic/eui64_109.h | 23 + lib/dns/rdata/generic/gpos_27.c | 256 + lib/dns/rdata/generic/gpos_27.h | 31 + lib/dns/rdata/generic/hinfo_13.c | 219 + lib/dns/rdata/generic/hinfo_13.h | 26 + lib/dns/rdata/generic/hip_55.c | 525 + lib/dns/rdata/generic/hip_55.h | 42 + lib/dns/rdata/generic/ipseckey_45.c | 526 + lib/dns/rdata/generic/ipseckey_45.h | 30 + lib/dns/rdata/generic/isdn_20.c | 247 + lib/dns/rdata/generic/isdn_20.h | 29 + lib/dns/rdata/generic/key_25.c | 468 + lib/dns/rdata/generic/key_25.h | 30 + lib/dns/rdata/generic/keydata_65533.c | 462 + lib/dns/rdata/generic/keydata_65533.h | 30 + lib/dns/rdata/generic/l32_105.c | 230 + lib/dns/rdata/generic/l32_105.h | 24 + lib/dns/rdata/generic/l64_106.c | 224 + lib/dns/rdata/generic/l64_106.h | 24 + lib/dns/rdata/generic/loc_29.c | 838 + lib/dns/rdata/generic/loc_29.h | 37 + lib/dns/rdata/generic/lp_107.c | 276 + lib/dns/rdata/generic/lp_107.h | 25 + lib/dns/rdata/generic/mb_7.c | 232 + lib/dns/rdata/generic/mb_7.h | 24 + lib/dns/rdata/generic/md_3.c | 234 + lib/dns/rdata/generic/md_3.h | 24 + lib/dns/rdata/generic/mf_4.c | 233 + lib/dns/rdata/generic/mf_4.h | 24 + lib/dns/rdata/generic/mg_8.c | 228 + lib/dns/rdata/generic/mg_8.h | 24 + lib/dns/rdata/generic/minfo_14.c | 332 + lib/dns/rdata/generic/minfo_14.h | 25 + lib/dns/rdata/generic/mr_9.c | 229 + lib/dns/rdata/generic/mr_9.h | 24 + lib/dns/rdata/generic/mx_15.c | 356 + lib/dns/rdata/generic/mx_15.h | 25 + lib/dns/rdata/generic/naptr_35.c | 740 + lib/dns/rdata/generic/naptr_35.h | 34 + lib/dns/rdata/generic/nid_104.c | 224 + lib/dns/rdata/generic/nid_104.h | 24 + lib/dns/rdata/generic/ninfo_56.c | 169 + lib/dns/rdata/generic/ninfo_56.h | 36 + lib/dns/rdata/generic/ns_2.c | 254 + lib/dns/rdata/generic/ns_2.h | 24 + lib/dns/rdata/generic/nsec3_50.c | 424 + lib/dns/rdata/generic/nsec3_50.h | 112 + lib/dns/rdata/generic/nsec3param_51.c | 321 + lib/dns/rdata/generic/nsec3param_51.h | 32 + lib/dns/rdata/generic/nsec_47.c | 290 + lib/dns/rdata/generic/nsec_47.h | 28 + lib/dns/rdata/generic/null_10.c | 186 + lib/dns/rdata/generic/null_10.h | 25 + lib/dns/rdata/generic/nxt_30.c | 350 + lib/dns/rdata/generic/nxt_30.h | 28 + lib/dns/rdata/generic/openpgpkey_61.c | 249 + lib/dns/rdata/generic/openpgpkey_61.h | 24 + lib/dns/rdata/generic/opt_41.c | 472 + lib/dns/rdata/generic/opt_41.h | 49 + lib/dns/rdata/generic/proforma.c | 164 + lib/dns/rdata/generic/proforma.h | 25 + lib/dns/rdata/generic/ptr_12.c | 278 + lib/dns/rdata/generic/ptr_12.h | 24 + lib/dns/rdata/generic/rkey_57.c | 160 + lib/dns/rdata/generic/rkey_57.h | 19 + lib/dns/rdata/generic/rp_17.c | 320 + lib/dns/rdata/generic/rp_17.h | 27 + lib/dns/rdata/generic/rrsig_46.c | 639 + lib/dns/rdata/generic/rrsig_46.h | 34 + lib/dns/rdata/generic/rt_21.c | 322 + lib/dns/rdata/generic/rt_21.h | 27 + lib/dns/rdata/generic/sig_24.c | 590 + lib/dns/rdata/generic/sig_24.h | 35 + lib/dns/rdata/generic/sink_40.c | 291 + lib/dns/rdata/generic/sink_40.h | 27 + lib/dns/rdata/generic/smimea_53.c | 152 + lib/dns/rdata/generic/smimea_53.h | 19 + lib/dns/rdata/generic/soa_6.c | 452 + lib/dns/rdata/generic/soa_6.h | 30 + lib/dns/rdata/generic/spf_99.c | 145 + lib/dns/rdata/generic/spf_99.h | 35 + lib/dns/rdata/generic/sshfp_44.c | 296 + lib/dns/rdata/generic/sshfp_44.h | 29 + lib/dns/rdata/generic/ta_32768.c | 162 + lib/dns/rdata/generic/ta_32768.h | 22 + lib/dns/rdata/generic/talink_58.c | 267 + lib/dns/rdata/generic/talink_58.h | 28 + lib/dns/rdata/generic/tkey_249.c | 580 + lib/dns/rdata/generic/tkey_249.h | 34 + lib/dns/rdata/generic/tlsa_52.c | 339 + lib/dns/rdata/generic/tlsa_52.h | 30 + lib/dns/rdata/generic/txt_16.c | 359 + lib/dns/rdata/generic/txt_16.h | 46 + lib/dns/rdata/generic/uri_256.c | 318 + lib/dns/rdata/generic/uri_256.h | 26 + lib/dns/rdata/generic/x25_19.c | 232 + lib/dns/rdata/generic/x25_19.h | 27 + lib/dns/rdata/generic/zonemd_63.c | 350 + lib/dns/rdata/generic/zonemd_63.h | 34 + lib/dns/rdata/hs_4/a_1.c | 235 + lib/dns/rdata/hs_4/a_1.h | 23 + lib/dns/rdata/in_1/a6_38.c | 486 + lib/dns/rdata/in_1/a6_38.h | 28 + lib/dns/rdata/in_1/a_1.c | 278 + lib/dns/rdata/in_1/a_1.h | 23 + lib/dns/rdata/in_1/aaaa_28.c | 265 + lib/dns/rdata/in_1/aaaa_28.h | 25 + lib/dns/rdata/in_1/apl_42.c | 481 + lib/dns/rdata/in_1/apl_42.h | 53 + lib/dns/rdata/in_1/atma_34.c | 317 + lib/dns/rdata/in_1/atma_34.h | 28 + lib/dns/rdata/in_1/dhcid_49.c | 235 + lib/dns/rdata/in_1/dhcid_49.h | 25 + lib/dns/rdata/in_1/eid_31.c | 224 + lib/dns/rdata/in_1/eid_31.h | 28 + lib/dns/rdata/in_1/https_65.c | 186 + lib/dns/rdata/in_1/https_65.h | 35 + lib/dns/rdata/in_1/kx_36.c | 289 + lib/dns/rdata/in_1/kx_36.h | 27 + lib/dns/rdata/in_1/nimloc_32.c | 224 + lib/dns/rdata/in_1/nimloc_32.h | 28 + lib/dns/rdata/in_1/nsap-ptr_23.c | 243 + lib/dns/rdata/in_1/nsap-ptr_23.h | 26 + lib/dns/rdata/in_1/nsap_22.c | 259 + lib/dns/rdata/in_1/nsap_22.h | 27 + lib/dns/rdata/in_1/px_26.c | 379 + lib/dns/rdata/in_1/px_26.h | 28 + lib/dns/rdata/in_1/srv_33.c | 410 + lib/dns/rdata/in_1/srv_33.h | 29 + lib/dns/rdata/in_1/svcb_64.c | 1268 + lib/dns/rdata/in_1/svcb_64.h | 40 + lib/dns/rdata/in_1/wks_11.c | 440 + lib/dns/rdata/in_1/wks_11.h | 26 + lib/dns/rdata/rdatastructpre.h | 36 + lib/dns/rdata/rdatastructsuf.h | 16 + lib/dns/rdatalist.c | 448 + lib/dns/rdatalist_p.h | 65 + lib/dns/rdataset.c | 750 + lib/dns/rdatasetiter.c | 71 + lib/dns/rdataslab.c | 1005 + lib/dns/request.c | 1545 ++ lib/dns/resolver.c | 12095 +++++++++ lib/dns/result.c | 454 + lib/dns/rootns.c | 566 + lib/dns/rpz.c | 2891 ++ lib/dns/rriterator.c | 220 + lib/dns/rrl.c | 1367 + lib/dns/sdb.c | 1613 ++ lib/dns/sdlz.c | 2108 ++ lib/dns/soa.c | 137 + lib/dns/ssu.c | 667 + lib/dns/ssu_external.c | 260 + lib/dns/stats.c | 653 + lib/dns/tcpmsg.c | 236 + lib/dns/tests/Kdh.+002+18602.key | 1 + lib/dns/tests/Krsa.+008+29238.key | 5 + lib/dns/tests/Kyuafile | 45 + lib/dns/tests/Makefile.in | 287 + lib/dns/tests/acl_test.c | 158 + .../tests/comparekeys/Kexample-d.+008+53461.key | 5 + .../comparekeys/Kexample-d.+008+53461.private | 13 + .../tests/comparekeys/Kexample-e.+008+53973.key | 5 + .../comparekeys/Kexample-e.+008+53973.private | 13 + .../tests/comparekeys/Kexample-n.+008+37464.key | 5 + .../comparekeys/Kexample-n.+008+37464.private | 13 + .../tests/comparekeys/Kexample-p.+008+53461.key | 5 + .../comparekeys/Kexample-p.+008+53461.private | 13 + .../comparekeys/Kexample-private.+002+65316.key | 1 + .../Kexample-private.+002+65316.private | 9 + .../tests/comparekeys/Kexample-q.+008+53461.key | 5 + .../comparekeys/Kexample-q.+008+53461.private | 13 + lib/dns/tests/comparekeys/Kexample.+002+65316.key | 1 + .../tests/comparekeys/Kexample.+002+65316.private | 9 + lib/dns/tests/comparekeys/Kexample.+008+53461.key | 5 + .../tests/comparekeys/Kexample.+008+53461.private | 13 + lib/dns/tests/comparekeys/Kexample.+013+19786.key | 5 + .../tests/comparekeys/Kexample.+013+19786.private | 6 + lib/dns/tests/comparekeys/Kexample.+015+63663.key | 5 + .../tests/comparekeys/Kexample.+015+63663.private | 6 + lib/dns/tests/comparekeys/Kexample2.+002+19823.key | 1 + .../tests/comparekeys/Kexample2.+002+19823.private | 9 + lib/dns/tests/comparekeys/Kexample2.+008+37993.key | 5 + .../tests/comparekeys/Kexample2.+008+37993.private | 13 + lib/dns/tests/comparekeys/Kexample2.+013+16384.key | 5 + .../tests/comparekeys/Kexample2.+013+16384.private | 6 + lib/dns/tests/comparekeys/Kexample2.+015+37529.key | 5 + .../tests/comparekeys/Kexample2.+015+37529.private | 6 + lib/dns/tests/comparekeys/Kexample3.+002+17187.key | 1 + .../tests/comparekeys/Kexample3.+002+17187.private | 9 + lib/dns/tests/db_test.c | 428 + lib/dns/tests/dbdiff_test.c | 185 + lib/dns/tests/dbiterator_test.c | 394 + lib/dns/tests/dbversion_test.c | 499 + lib/dns/tests/dh_test.c | 112 + lib/dns/tests/dispatch_test.c | 360 + lib/dns/tests/dnstap_test.c | 402 + lib/dns/tests/dnstest.c | 643 + lib/dns/tests/dnstest.h | 132 + lib/dns/tests/dst_test.c | 504 + lib/dns/tests/geoip_test.c | 433 + lib/dns/tests/keytable_test.c | 720 + lib/dns/tests/master_test.c | 633 + lib/dns/tests/mkraw.pl | 26 + lib/dns/tests/name_test.c | 796 + lib/dns/tests/nsec3_test.c | 196 + lib/dns/tests/nsec3param_test.c | 304 + lib/dns/tests/peer_test.c | 175 + lib/dns/tests/private_test.c | 236 + lib/dns/tests/rbt_serialize_test.c | 489 + lib/dns/tests/rbt_test.c | 1390 + lib/dns/tests/rbtdb_test.c | 423 + lib/dns/tests/rdata_test.c | 3229 +++ lib/dns/tests/rdataset_test.c | 146 + lib/dns/tests/rdatasetstats_test.c | 312 + lib/dns/tests/resolver_test.c | 228 + lib/dns/tests/result_test.c | 133 + lib/dns/tests/rsa_test.c | 242 + lib/dns/tests/sigs_test.c | 462 + lib/dns/tests/testdata/db/data.db | 22 + lib/dns/tests/testdata/dbiterator/zone1.data | 30 + lib/dns/tests/testdata/dbiterator/zone2.data | 319 + lib/dns/tests/testdata/diff/zone1.data | 13 + lib/dns/tests/testdata/diff/zone2.data | 14 + lib/dns/tests/testdata/diff/zone3.data | 12 + lib/dns/tests/testdata/dnstap/dnstap.saved | Bin 0 -> 30398 bytes lib/dns/tests/testdata/dnstap/dnstap.text | 96 + lib/dns/tests/testdata/dnstap/query.auth | 4 + lib/dns/tests/testdata/dnstap/query.recursive | 4 + lib/dns/tests/testdata/dnstap/response.auth | 19 + lib/dns/tests/testdata/dnstap/response.recursive | 19 + lib/dns/tests/testdata/dst/Ktest.+008+11349.key | 5 + .../tests/testdata/dst/Ktest.+008+11349.private | 13 + lib/dns/tests/testdata/dst/Ktest.+013+49130.key | 5 + .../tests/testdata/dst/Ktest.+013+49130.private | 6 + lib/dns/tests/testdata/dst/test1.data | 3077 +++ lib/dns/tests/testdata/dst/test1.ecdsa256sig | 1 + lib/dns/tests/testdata/dst/test1.rsasha256sig | 1 + lib/dns/tests/testdata/dst/test2.data | 3077 +++ lib/dns/tests/testdata/dstrandom/random.data | Bin 0 -> 4096 bytes lib/dns/tests/testdata/master/master1.data | 11 + lib/dns/tests/testdata/master/master10.data | 7 + lib/dns/tests/testdata/master/master11.data | 6 + lib/dns/tests/testdata/master/master12.data.in | 1 + lib/dns/tests/testdata/master/master13.data.in | 1 + lib/dns/tests/testdata/master/master14.data.in | 1 + lib/dns/tests/testdata/master/master15.data | 1609 ++ lib/dns/tests/testdata/master/master16.data | 1609 ++ lib/dns/tests/testdata/master/master17.data | 14 + lib/dns/tests/testdata/master/master18.data | 10 + lib/dns/tests/testdata/master/master2.data | 11 + lib/dns/tests/testdata/master/master3.data | 11 + lib/dns/tests/testdata/master/master4.data | 11 + lib/dns/tests/testdata/master/master5.data | 11 + lib/dns/tests/testdata/master/master6.data | 33 + lib/dns/tests/testdata/master/master7.data | 17 + lib/dns/tests/testdata/master/master8.data | 4 + lib/dns/tests/testdata/master/master9.data | 4 + lib/dns/tests/testdata/nsec3/1024.db | 16 + lib/dns/tests/testdata/nsec3/2048.db | 16 + lib/dns/tests/testdata/nsec3/4096.db | 16 + lib/dns/tests/testdata/nsec3/min-1024.db | 20 + lib/dns/tests/testdata/nsec3/min-2048.db | 18 + lib/dns/tests/testdata/nsec3param/nsec3.db.signed | 73 + lib/dns/tests/testdata/zt/zone1.db | 22 + lib/dns/tests/testkeys/Kexample.+008+20386.key | 5 + lib/dns/tests/testkeys/Kexample.+008+20386.private | 13 + lib/dns/tests/testkeys/Kexample.+008+37464.key | 5 + lib/dns/tests/testkeys/Kexample.+008+37464.private | 13 + lib/dns/tests/time_test.c | 218 + lib/dns/tests/tsig_test.c | 605 + lib/dns/tests/update_test.c | 381 + lib/dns/tests/zonemgr_test.c | 265 + lib/dns/tests/zt_test.c | 376 + lib/dns/time.c | 216 + lib/dns/timer.c | 54 + lib/dns/tkey.c | 1604 ++ lib/dns/tsec.c | 151 + lib/dns/tsig.c | 1902 ++ lib/dns/tsig_p.h | 43 + lib/dns/ttl.c | 225 + lib/dns/update.c | 2280 ++ lib/dns/validator.c | 3394 +++ lib/dns/version.c | 20 + lib/dns/view.c | 2642 ++ lib/dns/win32/DLLMain.c | 49 + lib/dns/win32/gen.vcxproj.filters.in | 27 + lib/dns/win32/gen.vcxproj.in | 134 + lib/dns/win32/gen.vcxproj.user | 3 + lib/dns/win32/libdns.def.in | 1548 ++ lib/dns/win32/libdns.vcxproj.filters.in | 668 + lib/dns/win32/libdns.vcxproj.in | 345 + lib/dns/win32/libdns.vcxproj.user | 3 + lib/dns/win32/version.c | 20 + lib/dns/xfrin.c | 1704 ++ lib/dns/zone.c | 23609 ++++++++++++++++ lib/dns/zone_p.h | 53 + lib/dns/zonekey.c | 54 + lib/dns/zoneverify.c | 2038 ++ lib/dns/zt.c | 617 + lib/irs/Kyuafile | 15 + lib/irs/Makefile.in | 90 + lib/irs/context.c | 334 + lib/irs/dnsconf.c | 291 + lib/irs/gai_strerror.c | 96 + lib/irs/getaddrinfo.c | 1365 + lib/irs/getnameinfo.c | 438 + lib/irs/include/.clang-format | 1 + lib/irs/include/Makefile.in | 19 + lib/irs/include/irs/Makefile.in | 46 + lib/irs/include/irs/context.h | 155 + lib/irs/include/irs/dnsconf.h | 92 + lib/irs/include/irs/netdb.h.in | 193 + lib/irs/include/irs/platform.h.in | 32 + lib/irs/include/irs/resconf.h | 118 + lib/irs/include/irs/types.h | 26 + lib/irs/include/irs/version.h | 18 + lib/irs/resconf.c | 689 + lib/irs/tests/Kyuafile | 15 + lib/irs/tests/Makefile.in | 51 + lib/irs/tests/resconf_test.c | 142 + lib/irs/tests/testdata/domain.conf | 12 + lib/irs/tests/testdata/nameserver-v4.conf | 12 + lib/irs/tests/testdata/nameserver-v6-scoped.conf | 12 + lib/irs/tests/testdata/nameserver-v6.conf | 12 + lib/irs/tests/testdata/options-bad-ndots.conf | 13 + lib/irs/tests/testdata/options-debug.conf | 12 + lib/irs/tests/testdata/options-empty.conf | 13 + lib/irs/tests/testdata/options-ndots.conf | 12 + lib/irs/tests/testdata/options-timeout.conf | 12 + lib/irs/tests/testdata/options-unknown.conf | 12 + lib/irs/tests/testdata/options.conf | 12 + lib/irs/tests/testdata/port.conf | 12 + lib/irs/tests/testdata/resolv.conf | 19 + lib/irs/tests/testdata/search.conf | 12 + lib/irs/tests/testdata/sortlist-v4.conf | 12 + lib/irs/tests/testdata/timeout.conf | 12 + lib/irs/tests/testdata/unknown.conf | 12 + lib/irs/version.c | 18 + lib/irs/win32/DLLMain.c | 49 + lib/irs/win32/Makefile.in | 19 + lib/irs/win32/include/.clang-format | 1 + lib/irs/win32/include/Makefile.in | 19 + lib/irs/win32/include/irs/Makefile.in | 28 + lib/irs/win32/include/irs/netdb.h | 207 + lib/irs/win32/include/irs/platform.h | 34 + lib/irs/win32/libirs.def | 27 + lib/irs/win32/libirs.vcxproj.filters.in | 69 + lib/irs/win32/libirs.vcxproj.in | 142 + lib/irs/win32/libirs.vcxproj.user | 3 + lib/irs/win32/resconf.c | 130 + lib/irs/win32/version.c | 18 + lib/isc/Kyuafile | 15 + lib/isc/Makefile.in | 144 + lib/isc/aes.c | 72 + lib/isc/app.c | 544 + lib/isc/assertions.c | 129 + lib/isc/astack.c | 85 + lib/isc/backtrace-emptytbl.c | 29 + lib/isc/backtrace.c | 304 + lib/isc/base32.c | 443 + lib/isc/base64.c | 270 + lib/isc/bind9.c | 27 + lib/isc/buffer.c | 542 + lib/isc/bufferlist.c | 56 + lib/isc/commandline.c | 265 + lib/isc/counter.c | 112 + lib/isc/crc64.c | 140 + lib/isc/entropy.c | 28 + lib/isc/entropy_private.h | 37 + lib/isc/error.c | 94 + lib/isc/event.c | 95 + lib/isc/fsaccess.c | 103 + lib/isc/hash.c | 153 + lib/isc/heap.c | 280 + lib/isc/hex.c | 212 + lib/isc/hmac.c | 146 + lib/isc/ht.c | 342 + lib/isc/httpd.c | 1347 + lib/isc/include/.clang-format | 1 + lib/isc/include/Makefile.in | 19 + lib/isc/include/isc/Makefile.in | 63 + lib/isc/include/isc/aes.h | 44 + lib/isc/include/isc/app.h | 283 + lib/isc/include/isc/assertions.h | 79 + lib/isc/include/isc/astack.h | 49 + lib/isc/include/isc/atomic.h | 73 + lib/isc/include/isc/backtrace.h | 127 + lib/isc/include/isc/barrier.h | 39 + lib/isc/include/isc/base32.h | 146 + lib/isc/include/isc/base64.h | 101 + lib/isc/include/isc/bind9.h | 29 + lib/isc/include/isc/buffer.h | 1103 + lib/isc/include/isc/bufferlist.h | 80 + lib/isc/include/isc/cmocka.h | 55 + lib/isc/include/isc/commandline.h | 59 + lib/isc/include/isc/counter.h | 87 + lib/isc/include/isc/crc64.h | 58 + lib/isc/include/isc/deprecated.h | 23 + lib/isc/include/isc/endian.h | 190 + lib/isc/include/isc/errno.h | 30 + lib/isc/include/isc/error.h | 57 + lib/isc/include/isc/event.h | 120 + lib/isc/include/isc/eventclass.h | 48 + lib/isc/include/isc/file.h | 400 + lib/isc/include/isc/formatcheck.h | 36 + lib/isc/include/isc/fsaccess.h | 174 + lib/isc/include/isc/fuzz.h | 26 + lib/isc/include/isc/hash.h | 66 + lib/isc/include/isc/heap.h | 164 + lib/isc/include/isc/hex.h | 101 + lib/isc/include/isc/hmac.h | 147 + lib/isc/include/isc/ht.h | 183 + lib/isc/include/isc/httpd.h | 85 + lib/isc/include/isc/interfaceiter.h | 130 + lib/isc/include/isc/iterated_hash.h | 38 + lib/isc/include/isc/lang.h | 27 + lib/isc/include/isc/lex.h | 447 + lib/isc/include/isc/lfsr.h | 124 + lib/isc/include/isc/lib.h | 47 + lib/isc/include/isc/likely.h | 33 + lib/isc/include/isc/list.h | 229 + lib/isc/include/isc/log.h | 848 + lib/isc/include/isc/magic.h | 37 + lib/isc/include/isc/managers.h | 29 + lib/isc/include/isc/md.h | 205 + lib/isc/include/isc/mem.h | 633 + lib/isc/include/isc/meminfo.h | 33 + lib/isc/include/isc/mutexblock.h | 57 + lib/isc/include/isc/netaddr.h | 199 + lib/isc/include/isc/netmgr.h | 540 + lib/isc/include/isc/netscope.h | 39 + lib/isc/include/isc/nonce.h | 33 + lib/isc/include/isc/os.h | 32 + lib/isc/include/isc/parseint.h | 60 + lib/isc/include/isc/platform.h.in | 100 + lib/isc/include/isc/pool.h | 141 + lib/isc/include/isc/portset.h | 138 + lib/isc/include/isc/print.h | 33 + lib/isc/include/isc/quota.h | 156 + lib/isc/include/isc/radix.h | 224 + lib/isc/include/isc/random.h | 65 + lib/isc/include/isc/ratelimiter.h | 148 + lib/isc/include/isc/refcount.h | 156 + lib/isc/include/isc/regex.h | 36 + lib/isc/include/isc/region.h | 98 + lib/isc/include/isc/resource.h | 90 + lib/isc/include/isc/result.h | 122 + lib/isc/include/isc/resultclass.h | 43 + lib/isc/include/isc/rwlock.h | 107 + lib/isc/include/isc/safe.h | 47 + lib/isc/include/isc/serial.h | 72 + lib/isc/include/isc/siphash.h | 37 + lib/isc/include/isc/sockaddr.h | 254 + lib/isc/include/isc/socket.h | 914 + lib/isc/include/isc/stats.h | 256 + lib/isc/include/isc/stdio.h | 74 + lib/isc/include/isc/strerr.h | 23 + lib/isc/include/isc/string.h | 43 + lib/isc/include/isc/symtab.h | 138 + lib/isc/include/isc/task.h | 721 + lib/isc/include/isc/taskpool.h | 138 + lib/isc/include/isc/timer.h | 323 + lib/isc/include/isc/tm.h | 42 + lib/isc/include/isc/types.h | 131 + lib/isc/include/isc/url.h | 82 + lib/isc/include/isc/utf8.h | 43 + lib/isc/include/isc/util.h | 445 + lib/isc/include/isc/version.h | 18 + lib/isc/include/pk11/Makefile.in | 40 + lib/isc/include/pk11/constants.h | 37 + lib/isc/include/pk11/internal.h | 49 + lib/isc/include/pk11/pk11.h | 290 + lib/isc/include/pk11/result.h | 48 + lib/isc/include/pk11/site.h | 16 + lib/isc/include/pkcs11/Makefile.in | 40 + lib/isc/include/pkcs11/pkcs11.h | 1655 ++ lib/isc/iterated_hash.c | 64 + lib/isc/lex.c | 1133 + lib/isc/lfsr.c | 153 + lib/isc/lib.c | 85 + lib/isc/lib_p.h | 20 + lib/isc/log.c | 1896 ++ lib/isc/managers.c | 95 + lib/isc/md.c | 175 + lib/isc/mem.c | 2450 ++ lib/isc/mem_p.h | 36 + lib/isc/mutexblock.c | 35 + lib/isc/netaddr.c | 479 + lib/isc/netmgr/Makefile.in | 41 + lib/isc/netmgr/netmgr-int.h | 1615 ++ lib/isc/netmgr/netmgr.c | 3396 +++ lib/isc/netmgr/tcp.c | 1456 + lib/isc/netmgr/tcpdns.c | 1505 ++ lib/isc/netmgr/udp.c | 1211 + lib/isc/netmgr/uv-compat.c | 152 + lib/isc/netmgr/uv-compat.h | 126 + lib/isc/netmgr/uverr2result.c | 104 + lib/isc/netmgr_p.h | 38 + lib/isc/netscope.c | 76 + lib/isc/nonce.c | 21 + lib/isc/openssl_shim.c | 231 + lib/isc/openssl_shim.h | 135 + lib/isc/parseint.c | 79 + lib/isc/pk11.c | 1112 + lib/isc/pk11_result.c | 73 + lib/isc/pool.c | 163 + lib/isc/portset.c | 135 + lib/isc/pthreads/Makefile.in | 32 + lib/isc/pthreads/condition.c | 72 + lib/isc/pthreads/include/.clang-format | 1 + lib/isc/pthreads/include/Makefile.in | 19 + lib/isc/pthreads/include/isc/Makefile.in | 36 + lib/isc/pthreads/include/isc/condition.h | 64 + lib/isc/pthreads/include/isc/mutex.h | 129 + lib/isc/pthreads/include/isc/once.h | 33 + lib/isc/pthreads/include/isc/thread.h | 74 + lib/isc/pthreads/mutex.c | 302 + lib/isc/pthreads/thread.c | 129 + lib/isc/quota.c | 198 + lib/isc/radix.c | 706 + lib/isc/random.c | 161 + lib/isc/ratelimiter.c | 372 + lib/isc/regex.c | 436 + lib/isc/region.c | 39 + lib/isc/result.c | 306 + lib/isc/rwlock.c | 646 + lib/isc/safe.c | 26 + lib/isc/serial.c | 55 + lib/isc/siphash.c | 235 + lib/isc/sockaddr.c | 513 + lib/isc/stats.c | 203 + lib/isc/string.c | 149 + lib/isc/symtab.c | 294 + lib/isc/task.c | 1486 + lib/isc/task_p.h | 106 + lib/isc/taskpool.c | 157 + lib/isc/tests/Kyuafile | 43 + lib/isc/tests/Makefile.in | 227 + lib/isc/tests/aes_test.c | 249 + lib/isc/tests/buffer_test.c | 351 + lib/isc/tests/counter_test.c | 105 + lib/isc/tests/crc64_test.c | 108 + lib/isc/tests/errno_test.c | 123 + lib/isc/tests/file_test.c | 154 + lib/isc/tests/hash_test.c | 114 + lib/isc/tests/heap_test.c | 115 + lib/isc/tests/hmac_test.c | 949 + lib/isc/tests/ht_test.c | 358 + lib/isc/tests/isctest.c | 173 + lib/isc/tests/isctest.h | 63 + lib/isc/tests/lex_test.c | 432 + lib/isc/tests/md_test.c | 587 + lib/isc/tests/mem_test.c | 477 + lib/isc/tests/netaddr_test.c | 159 + lib/isc/tests/netmgr_test.c | 2218 ++ lib/isc/tests/parse_test.c | 96 + lib/isc/tests/pool_test.c | 194 + lib/isc/tests/quota_test.c | 358 + lib/isc/tests/radix_test.c | 124 + lib/isc/tests/random_test.c | 894 + lib/isc/tests/regex_test.c | 2374 ++ lib/isc/tests/result_test.c | 132 + lib/isc/tests/safe_test.c | 107 + lib/isc/tests/siphash_test.c | 183 + lib/isc/tests/sockaddr_test.c | 188 + lib/isc/tests/socket_test.c | 833 + lib/isc/tests/stats_test.c | 141 + lib/isc/tests/symtab_test.c | 171 + lib/isc/tests/task_test.c | 1595 ++ lib/isc/tests/taskpool_test.c | 204 + lib/isc/tests/testdata/file/keep | 0 lib/isc/tests/time_test.c | 430 + lib/isc/tests/timer_test.c | 634 + lib/isc/tests/uv_wrap.h | 323 + lib/isc/timer.c | 753 + lib/isc/timer_p.h | 25 + lib/isc/tls.c | 161 + lib/isc/tls_p.h | 20 + lib/isc/tm.c | 469 + lib/isc/trampoline.c | 218 + lib/isc/trampoline_p.h | 90 + lib/isc/unix/Makefile.in | 48 + lib/isc/unix/dir.c | 268 + lib/isc/unix/errno.c | 24 + lib/isc/unix/errno2result.c | 131 + lib/isc/unix/errno2result.h | 37 + lib/isc/unix/file.c | 840 + lib/isc/unix/fsaccess.c | 87 + lib/isc/unix/ifiter_getifaddrs.c | 240 + lib/isc/unix/include/.clang-format | 1 + lib/isc/unix/include/Makefile.in | 19 + lib/isc/unix/include/isc/Makefile.in | 37 + lib/isc/unix/include/isc/align.h | 20 + lib/isc/unix/include/isc/dir.h | 75 + lib/isc/unix/include/isc/net.h | 310 + lib/isc/unix/include/isc/netdb.h | 51 + lib/isc/unix/include/isc/offset.h | 28 + lib/isc/unix/include/isc/stat.h | 47 + lib/isc/unix/include/isc/stdatomic.h | 224 + lib/isc/unix/include/isc/stdtime.h | 64 + lib/isc/unix/include/isc/syslog.h | 41 + lib/isc/unix/include/isc/time.h | 452 + lib/isc/unix/interfaceiter.c | 301 + lib/isc/unix/meminfo.c | 50 + lib/isc/unix/net.c | 860 + lib/isc/unix/os.c | 68 + lib/isc/unix/pk11_api.c | 708 + lib/isc/unix/resource.c | 219 + lib/isc/unix/socket.c | 5521 ++++ lib/isc/unix/socket_p.h | 27 + lib/isc/unix/stdio.c | 152 + lib/isc/unix/stdtime.c | 68 + lib/isc/unix/syslog.c | 73 + lib/isc/unix/time.c | 553 + lib/isc/url.c | 671 + lib/isc/utf8.c | 89 + lib/isc/version.c | 18 + lib/isc/win32/.dir-locals.el | 35 + lib/isc/win32/DLLMain.c | 52 + lib/isc/win32/Makefile.in | 36 + lib/isc/win32/condition.c | 255 + lib/isc/win32/dir.c | 314 + lib/isc/win32/errno.c | 21 + lib/isc/win32/errno2result.c | 118 + lib/isc/win32/errno2result.h | 35 + lib/isc/win32/file.c | 1003 + lib/isc/win32/fsaccess.c | 404 + lib/isc/win32/include/.clang-format | 1 + lib/isc/win32/include/Makefile.in | 19 + lib/isc/win32/include/isc/Makefile.in | 32 + lib/isc/win32/include/isc/align.h | 15 + lib/isc/win32/include/isc/bind_registry.h | 42 + lib/isc/win32/include/isc/bindevt.h | 83 + lib/isc/win32/include/isc/condition.h | 60 + lib/isc/win32/include/isc/dir.h | 73 + lib/isc/win32/include/isc/ipv6.h | 130 + lib/isc/win32/include/isc/mutex.h | 47 + lib/isc/win32/include/isc/net.h | 402 + lib/isc/win32/include/isc/netdb.h | 48 + lib/isc/win32/include/isc/ntgroups.h | 28 + lib/isc/win32/include/isc/ntpaths.h | 66 + lib/isc/win32/include/isc/offset.h | 26 + lib/isc/win32/include/isc/once.h | 40 + lib/isc/win32/include/isc/platform.h.in | 132 + lib/isc/win32/include/isc/stat.h | 58 + lib/isc/win32/include/isc/stdatomic.h | 595 + lib/isc/win32/include/isc/stdtime.h | 62 + lib/isc/win32/include/isc/syslog.h | 39 + lib/isc/win32/include/isc/thread.h | 103 + lib/isc/win32/include/isc/time.h | 468 + lib/isc/win32/include/isc/win32os.h | 41 + lib/isc/win32/interfaceiter.c | 550 + lib/isc/win32/ipv6.c | 18 + lib/isc/win32/libgen.h | 22 + lib/isc/win32/libisc.def.exclude | 42 + lib/isc/win32/libisc.def.in | 805 + lib/isc/win32/libisc.vcxproj.filters.in | 671 + lib/isc/win32/libisc.vcxproj.in | 483 + lib/isc/win32/libisc.vcxproj.user | 3 + lib/isc/win32/meminfo.c | 26 + lib/isc/win32/net.c | 301 + lib/isc/win32/netdb.h | 182 + lib/isc/win32/ntgroups.c | 215 + lib/isc/win32/ntpaths.c | 151 + lib/isc/win32/once.c | 43 + lib/isc/win32/os.c | 41 + lib/isc/win32/pk11_api.c | 706 + lib/isc/win32/resource.c | 66 + lib/isc/win32/socket.c | 3965 +++ lib/isc/win32/stdio.c | 158 + lib/isc/win32/stdtime.c | 43 + lib/isc/win32/syslog.c | 171 + lib/isc/win32/syslog.h | 70 + lib/isc/win32/thread.c | 82 + lib/isc/win32/time.c | 651 + lib/isc/win32/unistd.h | 55 + lib/isc/win32/version.c | 18 + lib/isc/win32/win32os.c | 113 + lib/isc/xoshiro128starstar.c | 63 + lib/isccc/Kyuafile | 15 + lib/isccc/Makefile.in | 81 + lib/isccc/alist.c | 320 + lib/isccc/base64.c | 75 + lib/isccc/cc.c | 1059 + lib/isccc/ccmsg.c | 231 + lib/isccc/include/.clang-format | 1 + lib/isccc/include/Makefile.in | 19 + lib/isccc/include/isccc/Makefile.in | 41 + lib/isccc/include/isccc/alist.h | 89 + lib/isccc/include/isccc/base64.h | 82 + lib/isccc/include/isccc/cc.h | 131 + lib/isccc/include/isccc/ccmsg.h | 146 + lib/isccc/include/isccc/events.h | 46 + lib/isccc/include/isccc/result.h | 56 + lib/isccc/include/isccc/sexpr.h | 122 + lib/isccc/include/isccc/symtab.h | 136 + lib/isccc/include/isccc/symtype.h | 40 + lib/isccc/include/isccc/types.h | 55 + lib/isccc/include/isccc/util.h | 229 + lib/isccc/include/isccc/version.h | 18 + lib/isccc/result.c | 76 + lib/isccc/sexpr.c | 317 + lib/isccc/symtab.c | 293 + lib/isccc/tests/Kyuafile | 15 + lib/isccc/tests/Makefile.in | 51 + lib/isccc/tests/result_test.c | 84 + lib/isccc/version.c | 18 + lib/isccc/win32/DLLMain.c | 49 + lib/isccc/win32/libisccc.def | 65 + lib/isccc/win32/libisccc.vcxproj.filters.in | 87 + lib/isccc/win32/libisccc.vcxproj.in | 148 + lib/isccc/win32/libisccc.vcxproj.user | 3 + lib/isccc/win32/version.c | 18 + lib/isccfg/Kyuafile | 15 + lib/isccfg/Makefile.in | 79 + lib/isccfg/aclconf.c | 934 + lib/isccfg/dnsconf.c | 58 + lib/isccfg/include/.clang-format | 1 + lib/isccfg/include/Makefile.in | 19 + lib/isccfg/include/isccfg/Makefile.in | 42 + lib/isccfg/include/isccfg/aclconf.h | 94 + lib/isccfg/include/isccfg/cfg.h | 626 + lib/isccfg/include/isccfg/dnsconf.h | 30 + lib/isccfg/include/isccfg/grammar.h | 620 + lib/isccfg/include/isccfg/kaspconf.h | 60 + lib/isccfg/include/isccfg/log.h | 49 + lib/isccfg/include/isccfg/namedconf.h | 57 + lib/isccfg/include/isccfg/version.h | 18 + lib/isccfg/kaspconf.c | 423 + lib/isccfg/log.c | 41 + lib/isccfg/namedconf.c | 3891 +++ lib/isccfg/parser.c | 4145 +++ lib/isccfg/tests/Kyuafile | 16 + lib/isccfg/tests/Makefile.in | 57 + lib/isccfg/tests/duration_test.c | 278 + lib/isccfg/tests/parser_test.c | 290 + lib/isccfg/version.c | 18 + lib/isccfg/win32/DLLMain.c | 51 + lib/isccfg/win32/libisccfg.def | 175 + lib/isccfg/win32/libisccfg.vcxproj.filters.in | 72 + lib/isccfg/win32/libisccfg.vcxproj.in | 143 + lib/isccfg/win32/libisccfg.vcxproj.user | 3 + lib/isccfg/win32/version.c | 18 + lib/ns/Kyuafile | 15 + lib/ns/Makefile.in | 89 + lib/ns/client.c | 3053 +++ lib/ns/hooks.c | 544 + lib/ns/include/.clang-format | 1 + lib/ns/include/Makefile.in | 19 + lib/ns/include/ns/Makefile.in | 37 + lib/ns/include/ns/client.h | 585 + lib/ns/include/ns/hooks.h | 420 + lib/ns/include/ns/interfacemgr.h | 202 + lib/ns/include/ns/lib.h | 37 + lib/ns/include/ns/listenlist.h | 101 + lib/ns/include/ns/log.h | 74 + lib/ns/include/ns/notify.h | 47 + lib/ns/include/ns/query.h | 235 + lib/ns/include/ns/server.h | 189 + lib/ns/include/ns/sortlist.h | 83 + lib/ns/include/ns/stats.h | 141 + lib/ns/include/ns/types.h | 35 + lib/ns/include/ns/update.h | 45 + lib/ns/include/ns/version.h | 18 + lib/ns/include/ns/xfrout.h | 33 + lib/ns/interfacemgr.c | 1263 + lib/ns/lib.c | 86 + lib/ns/listenlist.c | 130 + lib/ns/log.c | 64 + lib/ns/notify.c | 179 + lib/ns/query.c | 12013 +++++++++ lib/ns/server.c | 233 + lib/ns/sortlist.c | 167 + lib/ns/stats.c | 128 + lib/ns/tests/Kyuafile | 18 + lib/ns/tests/Makefile.in | 85 + lib/ns/tests/listenlist_test.c | 140 + lib/ns/tests/notify_test.c | 172 + lib/ns/tests/nstest.c | 1018 + lib/ns/tests/nstest.h | 165 + lib/ns/tests/plugin_test.c | 209 + lib/ns/tests/query_test.c | 632 + lib/ns/tests/testdata/notify/notify1.msg | 3 + lib/ns/tests/testdata/notify/zone1.db | 26 + lib/ns/tests/testdata/query/foo.db | 20 + lib/ns/update.c | 3696 +++ lib/ns/version.c | 18 + lib/ns/win32/DLLMain.c | 49 + lib/ns/win32/libns.def | 107 + lib/ns/win32/libns.vcxproj.filters | 114 + lib/ns/win32/libns.vcxproj.in | 156 + lib/ns/win32/libns.vcxproj.user | 3 + lib/ns/win32/version.c | 22 + lib/ns/xfrout.c | 1813 ++ lib/win32/bindevt/bindevt.c | 23 + lib/win32/bindevt/bindevt.mc | 41 + lib/win32/bindevt/bindevt.vcxproj.filters.in | 12 + lib/win32/bindevt/bindevt.vcxproj.in | 137 + lib/win32/bindevt/bindevt.vcxproj.user | 3 + ltmain.sh | 11251 ++++++++ m4/ax_check_compile_flag.m4 | 55 + m4/ax_check_link_flag.m4 | 55 + m4/ax_check_openssl.m4 | 117 + m4/ax_check_preproc_flag.m4 | 55 + m4/ax_gcc_func_attribute.m4 | 244 + m4/ax_posix_shell.m4 | 39 + m4/ax_pthread.m4 | 487 + m4/ax_restore_flags.m4 | 54 + m4/ax_save_flags.m4 | 73 + m4/compat.m4 | 28 + m4/libtool.m4 | 8394 ++++++ m4/ltoptions.m4 | 437 + m4/ltsugar.m4 | 124 + m4/ltversion.m4 | 23 + m4/lt~obsolete.m4 | 99 + make/Makefile.in | 22 + make/includes.in | 43 + make/mkdep.in | 148 + make/rules.in | 386 + mkinstalldirs | 38 + sonar-project.properties | 2 + srcid | 1 + unit/README | 8 + unit/gdb | 33 + unit/unittest.sh.in | 96 + util/bindkeys.pl | 49 + util/check-make-install.in | 62 + util/mksymtbl.pl | 99 + version | 11 + win32utils/Configure | 2778 ++ win32utils/GeoIP.diff | 345 + win32utils/bind9.sln.in | 772 + win32utils/build.txt | 293 + win32utils/readme1st.txt | 158 + 4505 files changed, 841749 insertions(+) create mode 100644 .clang-format create mode 100644 .clang-format.headers create mode 100644 .dir-locals.el create mode 100644 .gitattributes create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/sonarcloud.yml create mode 100644 .gitlab-ci.yml create mode 100644 .gitlab/issue_templates/Bug.md create mode 100644 .gitlab/issue_templates/Feature_Request.md create mode 100644 .gitlab/issue_templates/Release.md create mode 100644 .pylintrc create mode 100644 .readthedocs.yaml create mode 100644 .reuse/dep5 create mode 100644 .reuse/templates/isc.jinja2 create mode 100644 .tsan-suppress create mode 100644 .uncrustify.cfg create mode 100644 CHANGES create mode 100644 CODE_OF_CONDUCT create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING create mode 100644 CONTRIBUTING.md create mode 100644 COPYRIGHT create mode 100644 HISTORY create mode 100644 HISTORY.md create mode 100644 Kyuafile create mode 100644 LICENSE create mode 100644 LICENSES/Apache-2.0.txt create mode 100644 LICENSES/Autoconf-exception-3.0.txt create mode 100644 LICENSES/BSD-2-Clause.txt create mode 100644 LICENSES/BSD-3-Clause.txt create mode 100644 LICENSES/CC0-1.0.txt create mode 100644 LICENSES/FSFAP.txt create mode 100644 LICENSES/GPL-3.0-or-later.txt create mode 100644 LICENSES/ISC.txt create mode 100644 LICENSES/LLVM-exception.txt create mode 100644 LICENSES/MIT.txt create mode 100644 LICENSES/MPL-2.0.txt create mode 100644 Makefile.in create mode 100644 OPTIONS create mode 100644 OPTIONS.md create mode 100644 README create mode 100644 README.md create mode 100644 aclocal.m4 create mode 100755 autogen.sh create mode 100644 bin/Makefile.in create mode 100644 bin/check/Makefile.in create mode 100644 bin/check/check-tool.c create mode 100644 bin/check/check-tool.h create mode 100644 bin/check/named-checkconf.c create mode 100644 bin/check/named-checkconf.rst create mode 100644 bin/check/named-checkzone.c create mode 100644 bin/check/named-checkzone.rst create mode 100644 bin/check/named-compilezone.rst create mode 100644 bin/check/win32/checkconf.vcxproj.filters.in create mode 100644 bin/check/win32/checkconf.vcxproj.in create mode 100644 bin/check/win32/checkconf.vcxproj.user create mode 100644 bin/check/win32/checktool.vcxproj.filters.in create mode 100644 bin/check/win32/checktool.vcxproj.in create mode 100644 bin/check/win32/checktool.vcxproj.user create mode 100644 bin/check/win32/checkzone.vcxproj.filters.in create mode 100644 bin/check/win32/checkzone.vcxproj.in create mode 100644 bin/check/win32/checkzone.vcxproj.user create mode 100644 bin/confgen/Makefile.in create mode 100644 bin/confgen/ddns-confgen.c create mode 100644 bin/confgen/ddns-confgen.rst create mode 120000 bin/confgen/include/.clang-format create mode 100644 bin/confgen/include/confgen/os.h create mode 100644 bin/confgen/keygen.c create mode 100644 bin/confgen/keygen.h create mode 100644 bin/confgen/rndc-confgen.c create mode 100644 bin/confgen/rndc-confgen.rst create mode 100644 bin/confgen/tsig-keygen.rst create mode 100644 bin/confgen/unix/Makefile.in create mode 100644 bin/confgen/unix/os.c create mode 100644 bin/confgen/util.c create mode 100644 bin/confgen/util.h create mode 100644 bin/confgen/win32/confgentool.vcxproj.filters.in create mode 100644 bin/confgen/win32/confgentool.vcxproj.in create mode 100644 bin/confgen/win32/confgentool.vcxproj.user create mode 100644 bin/confgen/win32/ddnsconfgen.vcxproj.filters.in create mode 100644 bin/confgen/win32/ddnsconfgen.vcxproj.in create mode 100644 bin/confgen/win32/ddnsconfgen.vcxproj.user create mode 100644 bin/confgen/win32/os.c create mode 100644 bin/confgen/win32/rndcconfgen.vcxproj.filters.in create mode 100644 bin/confgen/win32/rndcconfgen.vcxproj.in create mode 100644 bin/confgen/win32/rndcconfgen.vcxproj.user create mode 100644 bin/delv/Makefile.in create mode 100644 bin/delv/delv.c create mode 100644 bin/delv/delv.rst create mode 100644 bin/delv/win32/delv.vcxproj.filters.in create mode 100644 bin/delv/win32/delv.vcxproj.in create mode 100644 bin/delv/win32/delv.vcxproj.user create mode 100644 bin/dig/Makefile.in create mode 100644 bin/dig/dig.c create mode 100644 bin/dig/dig.rst create mode 100644 bin/dig/dighost.c create mode 100644 bin/dig/host.c create mode 100644 bin/dig/host.rst create mode 120000 bin/dig/include/.clang-format create mode 100644 bin/dig/include/dig/dig.h create mode 100644 bin/dig/nslookup.c create mode 100644 bin/dig/nslookup.rst create mode 100644 bin/dig/win32/dig.vcxproj.filters.in create mode 100644 bin/dig/win32/dig.vcxproj.in create mode 100644 bin/dig/win32/dig.vcxproj.user create mode 100644 bin/dig/win32/dighost.vcxproj.filters.in create mode 100644 bin/dig/win32/dighost.vcxproj.in create mode 100644 bin/dig/win32/dighost.vcxproj.user create mode 100644 bin/dig/win32/host.vcxproj.filters.in create mode 100644 bin/dig/win32/host.vcxproj.in create mode 100644 bin/dig/win32/host.vcxproj.user create mode 100644 bin/dig/win32/nslookup.vcxproj.filters.in create mode 100644 bin/dig/win32/nslookup.vcxproj.in create mode 100644 bin/dig/win32/nslookup.vcxproj.user create mode 100644 bin/dnssec/Makefile.in create mode 100644 bin/dnssec/dnssec-cds.c create mode 100644 bin/dnssec/dnssec-cds.rst create mode 100644 bin/dnssec/dnssec-dsfromkey.c create mode 100644 bin/dnssec/dnssec-dsfromkey.rst create mode 100644 bin/dnssec/dnssec-importkey.c create mode 100644 bin/dnssec/dnssec-importkey.rst create mode 100644 bin/dnssec/dnssec-keyfromlabel.c create mode 100644 bin/dnssec/dnssec-keyfromlabel.rst create mode 100644 bin/dnssec/dnssec-keygen.c create mode 100644 bin/dnssec/dnssec-keygen.rst create mode 100644 bin/dnssec/dnssec-revoke.c create mode 100644 bin/dnssec/dnssec-revoke.rst create mode 100644 bin/dnssec/dnssec-settime.c create mode 100644 bin/dnssec/dnssec-settime.rst create mode 100644 bin/dnssec/dnssec-signzone.c create mode 100644 bin/dnssec/dnssec-signzone.rst create mode 100644 bin/dnssec/dnssec-verify.c create mode 100644 bin/dnssec/dnssec-verify.rst create mode 100644 bin/dnssec/dnssectool.c create mode 100644 bin/dnssec/dnssectool.h create mode 100644 bin/dnssec/win32/cds.vcxproj.filters.in create mode 100644 bin/dnssec/win32/cds.vcxproj.in create mode 100644 bin/dnssec/win32/cds.vcxproj.user create mode 100644 bin/dnssec/win32/dnssectool.vcxproj.filters.in create mode 100644 bin/dnssec/win32/dnssectool.vcxproj.in create mode 100644 bin/dnssec/win32/dnssectool.vcxproj.user create mode 100644 bin/dnssec/win32/dsfromkey.vcxproj.filters.in create mode 100644 bin/dnssec/win32/dsfromkey.vcxproj.in create mode 100644 bin/dnssec/win32/dsfromkey.vcxproj.user create mode 100644 bin/dnssec/win32/importkey.vcxproj.filters.in create mode 100644 bin/dnssec/win32/importkey.vcxproj.in create mode 100644 bin/dnssec/win32/importkey.vcxproj.user create mode 100644 bin/dnssec/win32/keyfromlabel.vcxproj.filters.in create mode 100644 bin/dnssec/win32/keyfromlabel.vcxproj.in create mode 100644 bin/dnssec/win32/keyfromlabel.vcxproj.user create mode 100644 bin/dnssec/win32/keygen.vcxproj.filters.in create mode 100644 bin/dnssec/win32/keygen.vcxproj.in create mode 100644 bin/dnssec/win32/keygen.vcxproj.user create mode 100644 bin/dnssec/win32/revoke.vcxproj.filters.in create mode 100644 bin/dnssec/win32/revoke.vcxproj.in create mode 100644 bin/dnssec/win32/revoke.vcxproj.user create mode 100644 bin/dnssec/win32/settime.vcxproj.filters.in create mode 100644 bin/dnssec/win32/settime.vcxproj.in create mode 100644 bin/dnssec/win32/settime.vcxproj.user create mode 100644 bin/dnssec/win32/signzone.vcxproj.filters.in create mode 100644 bin/dnssec/win32/signzone.vcxproj.in create mode 100644 bin/dnssec/win32/signzone.vcxproj.user create mode 100644 bin/dnssec/win32/verify.vcxproj.filters.in create mode 100644 bin/dnssec/win32/verify.vcxproj.in create mode 100644 bin/dnssec/win32/verify.vcxproj.user create mode 100644 bin/named/Makefile.in create mode 100644 bin/named/bind9.xsl create mode 100644 bin/named/bind9.xsl.h create mode 100644 bin/named/builtin.c create mode 100644 bin/named/config.c create mode 100644 bin/named/control.c create mode 100644 bin/named/controlconf.c create mode 100755 bin/named/convertxsl.pl create mode 100644 bin/named/fuzz.c create mode 100644 bin/named/geoip.c create mode 120000 bin/named/include/.clang-format create mode 100644 bin/named/include/dlz/dlz_dlopen_driver.h create mode 100644 bin/named/include/named/builtin.h create mode 100644 bin/named/include/named/config.h create mode 100644 bin/named/include/named/control.h create mode 100644 bin/named/include/named/fuzz.h create mode 100644 bin/named/include/named/geoip.h create mode 100644 bin/named/include/named/globals.h create mode 100644 bin/named/include/named/log.h create mode 100644 bin/named/include/named/logconf.h create mode 100644 bin/named/include/named/main.h create mode 100644 bin/named/include/named/server.h create mode 100644 bin/named/include/named/smf_globals.h create mode 100644 bin/named/include/named/statschannel.h create mode 100644 bin/named/include/named/tkeyconf.h create mode 100644 bin/named/include/named/tsigconf.h create mode 100644 bin/named/include/named/types.h create mode 100644 bin/named/include/named/zoneconf.h create mode 100644 bin/named/log.c create mode 100644 bin/named/logconf.c create mode 100644 bin/named/main.c create mode 100644 bin/named/named.conf.rst create mode 100644 bin/named/named.rst create mode 100644 bin/named/server.c create mode 100644 bin/named/statschannel.c create mode 100644 bin/named/tkeyconf.c create mode 100644 bin/named/tsigconf.c create mode 100644 bin/named/unix/Makefile.in create mode 100644 bin/named/unix/dlz_dlopen_driver.c create mode 120000 bin/named/unix/include/.clang-format create mode 100644 bin/named/unix/include/named/os.h create mode 100644 bin/named/unix/os.c create mode 100644 bin/named/win32/dlz_dlopen_driver.c create mode 120000 bin/named/win32/include/.clang-format create mode 100644 bin/named/win32/include/named/ntservice.h create mode 100644 bin/named/win32/include/named/os.h create mode 100644 bin/named/win32/named.vcxproj.filters.in create mode 100644 bin/named/win32/named.vcxproj.in create mode 100644 bin/named/win32/named.vcxproj.user create mode 100644 bin/named/win32/ntservice.c create mode 100644 bin/named/win32/os.c create mode 100644 bin/named/zoneconf.c create mode 100644 bin/nsupdate/Makefile.in create mode 100644 bin/nsupdate/nsupdate.c create mode 100644 bin/nsupdate/nsupdate.rst create mode 100644 bin/nsupdate/win32/nsupdate.vcxproj.filters.in create mode 100644 bin/nsupdate/win32/nsupdate.vcxproj.in create mode 100644 bin/nsupdate/win32/nsupdate.vcxproj.user create mode 100644 bin/pkcs11/Makefile.in create mode 100644 bin/pkcs11/pkcs11-destroy.c create mode 100644 bin/pkcs11/pkcs11-destroy.rst create mode 100644 bin/pkcs11/pkcs11-keygen.c create mode 100644 bin/pkcs11/pkcs11-keygen.rst create mode 100644 bin/pkcs11/pkcs11-list.c create mode 100644 bin/pkcs11/pkcs11-list.rst create mode 100644 bin/pkcs11/pkcs11-tokens.c create mode 100644 bin/pkcs11/pkcs11-tokens.rst create mode 100644 bin/pkcs11/win32/pk11destroy.vcxproj.filters.in create mode 100644 bin/pkcs11/win32/pk11destroy.vcxproj.in create mode 100644 bin/pkcs11/win32/pk11destroy.vcxproj.user create mode 100644 bin/pkcs11/win32/pk11keygen.vcxproj.filters.in create mode 100644 bin/pkcs11/win32/pk11keygen.vcxproj.in create mode 100644 bin/pkcs11/win32/pk11keygen.vcxproj.user create mode 100644 bin/pkcs11/win32/pk11list.vcxproj.filters.in create mode 100644 bin/pkcs11/win32/pk11list.vcxproj.in create mode 100644 bin/pkcs11/win32/pk11list.vcxproj.user create mode 100644 bin/pkcs11/win32/pk11tokens.vcxproj.filters.in create mode 100644 bin/pkcs11/win32/pk11tokens.vcxproj.in create mode 100644 bin/pkcs11/win32/pk11tokens.vcxproj.user create mode 100644 bin/plugins/Makefile.in create mode 100644 bin/plugins/filter-aaaa.c create mode 100644 bin/plugins/filter-aaaa.rst create mode 100644 bin/python/Makefile.in create mode 100644 bin/python/dnssec-checkds.py.in create mode 100644 bin/python/dnssec-checkds.rst create mode 100644 bin/python/dnssec-coverage.py.in create mode 100644 bin/python/dnssec-coverage.rst create mode 100644 bin/python/dnssec-keymgr.py.in create mode 100644 bin/python/dnssec-keymgr.rst create mode 100644 bin/python/isc/Makefile.in create mode 100644 bin/python/isc/__init__.py.in create mode 100644 bin/python/isc/checkds.py.in create mode 100644 bin/python/isc/coverage.py.in create mode 100644 bin/python/isc/dnskey.py.in create mode 100644 bin/python/isc/eventlist.py.in create mode 100644 bin/python/isc/keydict.py.in create mode 100644 bin/python/isc/keyevent.py.in create mode 100644 bin/python/isc/keymgr.py.in create mode 100644 bin/python/isc/keyseries.py.in create mode 100644 bin/python/isc/keyzone.py.in create mode 100644 bin/python/isc/policy.py.in create mode 100644 bin/python/isc/rndc.py.in create mode 100644 bin/python/isc/tests/Makefile.in create mode 100644 bin/python/isc/tests/dnskey_test.py.in create mode 100644 bin/python/isc/tests/policy_test.py.in create mode 100644 bin/python/isc/tests/test-policies/01-keysize.pol create mode 100644 bin/python/isc/tests/test-policies/02-prepublish.pol create mode 100644 bin/python/isc/tests/test-policies/03-postpublish.pol create mode 100644 bin/python/isc/tests/test-policies/04-combined-pre-post.pol create mode 100644 bin/python/isc/tests/test-policies/05-numeric-zone.pol create mode 100644 bin/python/isc/tests/testdata/Kexample.com.+007+35529.key create mode 100644 bin/python/isc/tests/testdata/Kexample.com.+007+35529.private create mode 100644 bin/python/isc/utils.py.in create mode 100644 bin/python/setup.py create mode 100644 bin/rndc/Makefile.in create mode 120000 bin/rndc/include/.clang-format create mode 100644 bin/rndc/include/rndc/os.h create mode 100644 bin/rndc/rndc.c create mode 100644 bin/rndc/rndc.conf create mode 100644 bin/rndc/rndc.conf.rst create mode 100644 bin/rndc/rndc.rst create mode 100644 bin/rndc/util.c create mode 100644 bin/rndc/util.h create mode 100644 bin/rndc/win32/rndc.vcxproj.filters.in create mode 100644 bin/rndc/win32/rndc.vcxproj.in create mode 100644 bin/rndc/win32/rndc.vcxproj.user create mode 100644 bin/rndc/win32/rndcutil.vcxproj.filters.in create mode 100644 bin/rndc/win32/rndcutil.vcxproj.in create mode 100644 bin/rndc/win32/rndcutil.vcxproj.user create mode 100644 bin/tests/Makefile.in create mode 100644 bin/tests/bigtest/README create mode 100644 bin/tests/bigtest/buildzones.sh create mode 100644 bin/tests/bigtest/rndc.key create mode 100644 bin/tests/bigtest/tests.sh create mode 100644 bin/tests/bigtest/zones create mode 100644 bin/tests/cfg_test.c create mode 100644 bin/tests/headerdep_test.sh.in create mode 100644 bin/tests/makejournal.c create mode 100644 bin/tests/named.conf create mode 100644 bin/tests/optional/Kchild.example.+005+33180.key create mode 100644 bin/tests/optional/Kchild.example.+005+33180.private create mode 100644 bin/tests/optional/Makefile.in create mode 100644 bin/tests/optional/adb_test.c create mode 100644 bin/tests/optional/backtrace_test.c create mode 100644 bin/tests/optional/byaddr_test.c create mode 100644 bin/tests/optional/byname_test.c create mode 100644 bin/tests/optional/db_test.c create mode 100644 bin/tests/optional/fsaccess_test.c create mode 100644 bin/tests/optional/gsstest.c create mode 100644 bin/tests/optional/inter_test.c create mode 100644 bin/tests/optional/lex_test.c create mode 100644 bin/tests/optional/lfsr_test.c create mode 100644 bin/tests/optional/log_test.c create mode 100644 bin/tests/optional/master_test.c create mode 100644 bin/tests/optional/mempool_test.c create mode 100644 bin/tests/optional/name_test.c create mode 100644 bin/tests/optional/nsecify.c create mode 100644 bin/tests/optional/ratelimiter_test.c create mode 100644 bin/tests/optional/rbt_test.c create mode 100644 bin/tests/optional/rbt_test.out create mode 100644 bin/tests/optional/rbt_test.txt create mode 100644 bin/tests/optional/rwlock_test.c create mode 100644 bin/tests/optional/serial_test.c create mode 100644 bin/tests/optional/shutdown_test.c create mode 100644 bin/tests/optional/sig0_test.c create mode 100644 bin/tests/optional/sock_test.c create mode 100644 bin/tests/optional/sym_test.c create mode 100644 bin/tests/optional/task_test.c create mode 100644 bin/tests/optional/timer_test.c create mode 100644 bin/tests/optional/zone_test.c create mode 100644 bin/tests/pkcs11/Makefile.in create mode 100644 bin/tests/pkcs11/README create mode 100644 bin/tests/pkcs11/benchmarks/Makefile.in create mode 100644 bin/tests/pkcs11/benchmarks/create.c create mode 100644 bin/tests/pkcs11/benchmarks/find.c create mode 100644 bin/tests/pkcs11/benchmarks/genrsa.c create mode 100644 bin/tests/pkcs11/benchmarks/login.c create mode 100644 bin/tests/pkcs11/benchmarks/privrsa.c create mode 100644 bin/tests/pkcs11/benchmarks/pubrsa.c create mode 100644 bin/tests/pkcs11/benchmarks/session.c create mode 100644 bin/tests/pkcs11/benchmarks/sha1.c create mode 100644 bin/tests/pkcs11/benchmarks/sign.c create mode 100644 bin/tests/pkcs11/benchmarks/verify.c create mode 100755 bin/tests/prepare-softhsm2.sh create mode 100644 bin/tests/startperf/README create mode 100644 bin/tests/startperf/clean.sh create mode 100644 bin/tests/startperf/makenames.pl create mode 100644 bin/tests/startperf/mkzonefile.pl create mode 100644 bin/tests/startperf/setup.sh create mode 100644 bin/tests/startperf/smallzone.db create mode 100644 bin/tests/system/Makefile.in create mode 100644 bin/tests/system/README create mode 100644 bin/tests/system/acl/clean.sh create mode 100644 bin/tests/system/acl/ns2/named1.conf.in create mode 100644 bin/tests/system/acl/ns2/named2.conf.in create mode 100644 bin/tests/system/acl/ns2/named3.conf.in create mode 100644 bin/tests/system/acl/ns2/named4.conf.in create mode 100644 bin/tests/system/acl/ns2/named5.conf.in create mode 100644 bin/tests/system/acl/ns3/example.db create mode 100644 bin/tests/system/acl/ns3/named.conf.in create mode 100644 bin/tests/system/acl/ns4/example.db create mode 100644 bin/tests/system/acl/ns4/existing.db create mode 100644 bin/tests/system/acl/ns4/named.conf.in create mode 100644 bin/tests/system/acl/setup.sh create mode 100644 bin/tests/system/acl/tests.sh create mode 100644 bin/tests/system/additional/clean.sh create mode 100644 bin/tests/system/additional/ns1/mx.db create mode 100644 bin/tests/system/additional/ns1/named.args create mode 100644 bin/tests/system/additional/ns1/named1.conf.in create mode 100644 bin/tests/system/additional/ns1/named2.conf.in create mode 100644 bin/tests/system/additional/ns1/named3.conf.in create mode 100644 bin/tests/system/additional/ns1/named4.conf.in create mode 100644 bin/tests/system/additional/ns1/naptr.db create mode 100644 bin/tests/system/additional/ns1/naptr2.db create mode 100644 bin/tests/system/additional/ns1/nid.db create mode 100644 bin/tests/system/additional/ns1/root.db create mode 100644 bin/tests/system/additional/ns1/rt.db create mode 100644 bin/tests/system/additional/ns1/rt2.db create mode 100644 bin/tests/system/additional/ns1/srv.db create mode 100644 bin/tests/system/additional/ns2/named.conf.in create mode 100644 bin/tests/system/additional/ns2/root.db create mode 100644 bin/tests/system/additional/ns3/ex.db create mode 100644 bin/tests/system/additional/ns3/ex2.db create mode 100644 bin/tests/system/additional/ns3/named.conf.in create mode 100644 bin/tests/system/additional/ns3/root.hint create mode 100644 bin/tests/system/additional/setup.sh create mode 100644 bin/tests/system/additional/tests.sh create mode 100644 bin/tests/system/addzone/clean.sh create mode 100644 bin/tests/system/addzone/ns1/inlinesec.db create mode 100644 bin/tests/system/addzone/ns1/named.conf.in create mode 100644 bin/tests/system/addzone/ns1/redirect.db.1 create mode 100644 bin/tests/system/addzone/ns1/redirect.db.2 create mode 100644 bin/tests/system/addzone/ns2/added.db create mode 100644 bin/tests/system/addzone/ns2/default.nzf.in create mode 100644 bin/tests/system/addzone/ns2/hints.db create mode 100644 bin/tests/system/addzone/ns2/inline.db create mode 100644 bin/tests/system/addzone/ns2/named1.conf.in create mode 100644 bin/tests/system/addzone/ns2/named2.conf.in create mode 100644 bin/tests/system/addzone/ns2/named3.conf.in create mode 100644 bin/tests/system/addzone/ns2/normal.db create mode 100644 bin/tests/system/addzone/ns2/previous.db create mode 100644 bin/tests/system/addzone/ns2/redirect.db.1 create mode 100644 bin/tests/system/addzone/ns2/redirect.db.2 create mode 100644 bin/tests/system/addzone/ns3/e.db create mode 100644 bin/tests/system/addzone/ns3/example.db create mode 100644 bin/tests/system/addzone/ns3/named1.conf.in create mode 100644 bin/tests/system/addzone/ns3/named2.conf.in create mode 100644 bin/tests/system/addzone/ns3/redirect.db.1 create mode 100644 bin/tests/system/addzone/ns3/redirect.db.2 create mode 100644 bin/tests/system/addzone/setup.sh create mode 100755 bin/tests/system/addzone/tests.sh create mode 100755 bin/tests/system/addzone/tests_rndc_deadlock.py create mode 100644 bin/tests/system/allow-query/clean.sh create mode 100644 bin/tests/system/allow-query/ns1/named.conf.in create mode 100644 bin/tests/system/allow-query/ns1/root.db create mode 100644 bin/tests/system/allow-query/ns2/generic.db create mode 100644 bin/tests/system/allow-query/ns2/named01.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named02.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named03.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named04.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named05.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named06.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named07.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named08.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named09.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named10.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named11.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named12.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named21.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named22.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named23.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named24.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named25.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named26.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named27.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named28.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named29.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named30.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named31.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named32.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named33.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named34.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named40.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named53.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named54.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named55.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named56.conf.in create mode 100644 bin/tests/system/allow-query/ns2/named57.conf.in create mode 100644 bin/tests/system/allow-query/ns3/named.args create mode 100644 bin/tests/system/allow-query/ns3/named1.conf.in create mode 100644 bin/tests/system/allow-query/ns3/named2.conf.in create mode 100644 bin/tests/system/allow-query/ns3/named3.conf.in create mode 100644 bin/tests/system/allow-query/ns3/named4.conf.in create mode 100644 bin/tests/system/allow-query/setup.sh create mode 100644 bin/tests/system/allow-query/tests.sh create mode 100644 bin/tests/system/ans.pl create mode 100644 bin/tests/system/auth/clean.sh create mode 100644 bin/tests/system/auth/ns1/chaos.db create mode 100644 bin/tests/system/auth/ns1/example.com.db create mode 100644 bin/tests/system/auth/ns1/example.net.db create mode 100644 bin/tests/system/auth/ns1/named.conf.in create mode 100644 bin/tests/system/auth/ns2/named.conf.in create mode 100644 bin/tests/system/auth/setup.sh create mode 100644 bin/tests/system/auth/tests.sh create mode 100644 bin/tests/system/autosign/clean.sh create mode 100644 bin/tests/system/autosign/ns1/keygen.sh create mode 100644 bin/tests/system/autosign/ns1/named.conf.in create mode 100644 bin/tests/system/autosign/ns1/root.db.in create mode 100644 bin/tests/system/autosign/ns2/Xbar.+013+59973.key create mode 100644 bin/tests/system/autosign/ns2/Xbar.+013+59973.private create mode 100644 bin/tests/system/autosign/ns2/Xbar.+013+60101.key create mode 100644 bin/tests/system/autosign/ns2/Xbar.+013+60101.private create mode 100644 bin/tests/system/autosign/ns2/bar.db.in create mode 100644 bin/tests/system/autosign/ns2/child.nsec3.example.db create mode 100644 bin/tests/system/autosign/ns2/child.optout.example.db create mode 100644 bin/tests/system/autosign/ns2/dst.example.db.in create mode 100644 bin/tests/system/autosign/ns2/example.db.in create mode 100644 bin/tests/system/autosign/ns2/insecure.secure.example.db create mode 100644 bin/tests/system/autosign/ns2/keygen.sh create mode 100644 bin/tests/system/autosign/ns2/named.conf.in create mode 100644 bin/tests/system/autosign/ns2/optout-with-ent.db.in create mode 100644 bin/tests/system/autosign/ns2/private.secure.example.db.in create mode 100644 bin/tests/system/autosign/ns3/autonsec3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/cdnskey-delete.example.db.in create mode 100644 bin/tests/system/autosign/ns3/cds-delete.example.db.in create mode 100644 bin/tests/system/autosign/ns3/delay.example.db create mode 100644 bin/tests/system/autosign/ns3/delzsk.example.db.in create mode 100644 bin/tests/system/autosign/ns3/dname-at-apex-nsec3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/inacksk2.example.db.in create mode 100644 bin/tests/system/autosign/ns3/inacksk3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/inaczsk.example.db.in create mode 100644 bin/tests/system/autosign/ns3/inaczsk2.example.db.in create mode 100644 bin/tests/system/autosign/ns3/inaczsk3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/insecure.example.db create mode 100644 bin/tests/system/autosign/ns3/jitter.nsec3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/keygen.sh create mode 100644 bin/tests/system/autosign/ns3/kskonly.example.db.in create mode 100644 bin/tests/system/autosign/ns3/named.conf.in create mode 100644 bin/tests/system/autosign/ns3/noksk.example.db.in create mode 100644 bin/tests/system/autosign/ns3/nozsk.example.db.in create mode 100644 bin/tests/system/autosign/ns3/nsec-only.example.db.in create mode 100644 bin/tests/system/autosign/ns3/nsec3-to-nsec.example.db.in create mode 100644 bin/tests/system/autosign/ns3/nsec3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/nsec3.nsec3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/nsec3.optout.example.db.in create mode 100644 bin/tests/system/autosign/ns3/oldsigs.example.db.in create mode 100644 bin/tests/system/autosign/ns3/optout.example.db.in create mode 100644 bin/tests/system/autosign/ns3/optout.nsec3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/optout.optout.example.db.in create mode 100644 bin/tests/system/autosign/ns3/rsasha256.example.db.in create mode 100644 bin/tests/system/autosign/ns3/rsasha512.example.db.in create mode 100644 bin/tests/system/autosign/ns3/secure-to-insecure.example.db.in create mode 100644 bin/tests/system/autosign/ns3/secure-to-insecure2.example.db.in create mode 100644 bin/tests/system/autosign/ns3/secure.example.db.in create mode 100644 bin/tests/system/autosign/ns3/secure.nsec3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/secure.optout.example.db.in create mode 100644 bin/tests/system/autosign/ns3/sync.example.db.in create mode 100644 bin/tests/system/autosign/ns3/ttl1.example.db.in create mode 100644 bin/tests/system/autosign/ns3/ttl2.example.db.in create mode 100644 bin/tests/system/autosign/ns3/ttl3.example.db.in create mode 100644 bin/tests/system/autosign/ns3/ttl4.example.db.in create mode 100644 bin/tests/system/autosign/ns4/named.conf.in create mode 100644 bin/tests/system/autosign/ns5/named.conf.in create mode 100644 bin/tests/system/autosign/setup.sh create mode 100755 bin/tests/system/autosign/tests.sh create mode 100644 bin/tests/system/builtin/clean.sh create mode 100644 bin/tests/system/builtin/ns1/named.conf.in create mode 100644 bin/tests/system/builtin/ns2/named.conf.in create mode 100644 bin/tests/system/builtin/ns3/named.conf.in create mode 100644 bin/tests/system/builtin/setup.sh create mode 100644 bin/tests/system/builtin/tests.sh create mode 100644 bin/tests/system/cacheclean/clean.sh create mode 100644 bin/tests/system/cacheclean/dig.batch create mode 100644 bin/tests/system/cacheclean/knowngood.dig.out create mode 100644 bin/tests/system/cacheclean/ns1/example.db create mode 100644 bin/tests/system/cacheclean/ns1/expire-test.db create mode 100644 bin/tests/system/cacheclean/ns1/flushtest.db create mode 100644 bin/tests/system/cacheclean/ns1/named.args create mode 100644 bin/tests/system/cacheclean/ns1/named.conf.in create mode 100644 bin/tests/system/cacheclean/ns2/named.args create mode 100644 bin/tests/system/cacheclean/ns2/named.conf.in create mode 100644 bin/tests/system/cacheclean/setup.sh create mode 100755 bin/tests/system/cacheclean/tests.sh create mode 100644 bin/tests/system/case/clean.sh create mode 100644 bin/tests/system/case/dynamic.good create mode 100644 bin/tests/system/case/ns1/dynamic.db.in create mode 100644 bin/tests/system/case/ns1/example.db create mode 100644 bin/tests/system/case/ns1/named.conf.in create mode 100644 bin/tests/system/case/ns2/named.conf.in create mode 100644 bin/tests/system/case/postns1.good create mode 100644 bin/tests/system/case/postupdate.good create mode 100644 bin/tests/system/case/setup.sh create mode 100644 bin/tests/system/case/tests.sh create mode 100644 bin/tests/system/catz/clean.sh create mode 100644 bin/tests/system/catz/ns1/catalog.example.db.in create mode 100644 bin/tests/system/catz/ns1/named.conf.in create mode 100644 bin/tests/system/catz/ns2/named1.conf.in create mode 100644 bin/tests/system/catz/ns2/named2.conf.in create mode 100644 bin/tests/system/catz/ns3/catalog.example.db.in create mode 100644 bin/tests/system/catz/ns3/dom5.example.db create mode 100644 bin/tests/system/catz/ns3/dom6.example.db create mode 100644 bin/tests/system/catz/ns3/named.conf.in create mode 100644 bin/tests/system/catz/ns4/catalog.example.db.in create mode 100644 bin/tests/system/catz/ns4/named.conf.in create mode 100644 bin/tests/system/catz/setup.sh create mode 100644 bin/tests/system/catz/tests.sh create mode 100644 bin/tests/system/cds/checkmtime.pl create mode 100644 bin/tests/system/cds/checktime.pl create mode 100644 bin/tests/system/cds/clean.sh create mode 100644 bin/tests/system/cds/mangle.pl create mode 100644 bin/tests/system/cds/setup.sh create mode 100644 bin/tests/system/cds/tests.sh create mode 100644 bin/tests/system/chain/README create mode 100644 bin/tests/system/chain/ans3/ans.pl create mode 100644 bin/tests/system/chain/ans4/README.anspy create mode 100755 bin/tests/system/chain/ans4/ans.py create mode 100755 bin/tests/system/chain/clean.sh create mode 100644 bin/tests/system/chain/ns1/named.conf.in create mode 100644 bin/tests/system/chain/ns1/root.db create mode 100644 bin/tests/system/chain/ns2/example.db create mode 100644 bin/tests/system/chain/ns2/generic.db create mode 100644 bin/tests/system/chain/ns2/named.conf.in create mode 100644 bin/tests/system/chain/ns2/sign.sh create mode 100644 bin/tests/system/chain/ns2/sub.db create mode 100644 bin/tests/system/chain/ns2/wildcard-secure.db create mode 100644 bin/tests/system/chain/ns2/wildcard.db create mode 100644 bin/tests/system/chain/ns5/named.conf.in create mode 100644 bin/tests/system/chain/ns5/sub.db create mode 100644 bin/tests/system/chain/ns7/named.conf.in create mode 100644 bin/tests/system/chain/ns7/root.hint create mode 100644 bin/tests/system/chain/prereq.sh create mode 100644 bin/tests/system/chain/setup.sh create mode 100644 bin/tests/system/chain/tests.sh create mode 100644 bin/tests/system/checkconf/altdb.conf create mode 100644 bin/tests/system/checkconf/altdlz.conf create mode 100644 bin/tests/system/checkconf/ancient.conf create mode 100644 bin/tests/system/checkconf/bad-acl.conf create mode 100644 bin/tests/system/checkconf/bad-also-notify.conf create mode 100644 bin/tests/system/checkconf/bad-catz-zone.conf create mode 100644 bin/tests/system/checkconf/bad-checknames-primary-dup-2.conf create mode 100644 bin/tests/system/checkconf/bad-checknames-primary-dup.conf create mode 100644 bin/tests/system/checkconf/bad-checknames-secondary-dup.conf create mode 100644 bin/tests/system/checkconf/bad-dnskey-validity.conf create mode 100644 bin/tests/system/checkconf/bad-dnssec.conf create mode 100644 bin/tests/system/checkconf/bad-duplicate-key.conf create mode 100644 bin/tests/system/checkconf/bad-duplicate-primaries-1.conf create mode 100644 bin/tests/system/checkconf/bad-duplicate-primaries-2.conf create mode 100644 bin/tests/system/checkconf/bad-duplicate-root-key.conf create mode 100644 bin/tests/system/checkconf/bad-geoip-use-ecs.conf create mode 100644 bin/tests/system/checkconf/bad-glue-cache-bogus.conf create mode 100644 bin/tests/system/checkconf/bad-hint.conf create mode 100644 bin/tests/system/checkconf/bad-in-view-dup.conf create mode 100644 bin/tests/system/checkconf/bad-inline-options.conf create mode 100644 bin/tests/system/checkconf/bad-inline-slave.conf create mode 100644 bin/tests/system/checkconf/bad-inline-view.conf create mode 100644 bin/tests/system/checkconf/bad-interface-interval.conf create mode 100644 bin/tests/system/checkconf/bad-ipv4-prefix-dotted1.conf create mode 100644 bin/tests/system/checkconf/bad-ipv4-prefix-dotted2.conf create mode 100644 bin/tests/system/checkconf/bad-ipv4-prefix2.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-define-default.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-define-insecure.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-define-none.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-duplicate.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-key1.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-key2.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-key3.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-key4.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-keydir1.conf.in create mode 100644 bin/tests/system/checkconf/bad-kasp-keydir2.conf.in create mode 100644 bin/tests/system/checkconf/bad-kasp-keydir3.conf.in create mode 100644 bin/tests/system/checkconf/bad-kasp-keydir4.conf.in create mode 100644 bin/tests/system/checkconf/bad-kasp-keydir5.conf.in create mode 100644 bin/tests/system/checkconf/bad-kasp-policy-undefined-inherited-view.conf create mode 100644 bin/tests/system/checkconf/bad-kasp-policy-undefined-inherited.conf create mode 100644 bin/tests/system/checkconf/bad-kasp10.conf create mode 100644 bin/tests/system/checkconf/bad-kasp11.conf create mode 100644 bin/tests/system/checkconf/bad-kasp12.conf create mode 100644 bin/tests/system/checkconf/bad-kasp13.conf create mode 100644 bin/tests/system/checkconf/bad-kasp2.conf create mode 100644 bin/tests/system/checkconf/bad-kasp3.conf create mode 100644 bin/tests/system/checkconf/bad-kasp4.conf create mode 100644 bin/tests/system/checkconf/bad-kasp6.conf create mode 100644 bin/tests/system/checkconf/bad-kasp7.conf create mode 100644 bin/tests/system/checkconf/bad-kasp8.conf create mode 100644 bin/tests/system/checkconf/bad-kasp9.conf create mode 100644 bin/tests/system/checkconf/bad-keep-response-order.conf create mode 100644 bin/tests/system/checkconf/bad-ksk-without-zsk.conf create mode 100644 bin/tests/system/checkconf/bad-lifetime.conf create mode 100644 bin/tests/system/checkconf/bad-lmdb-mapsize-bogus.conf create mode 100644 bin/tests/system/checkconf/bad-lmdb-mapsize-toolarge.conf create mode 100644 bin/tests/system/checkconf/bad-lmdb-mapsize-toosmall.conf create mode 100644 bin/tests/system/checkconf/bad-lmdb-mapsize-unlimited.conf create mode 100644 bin/tests/system/checkconf/bad-master-request-ixfr.conf create mode 100644 bin/tests/system/checkconf/bad-masters-dup.conf create mode 100644 bin/tests/system/checkconf/bad-maxcachettl.conf create mode 100644 bin/tests/system/checkconf/bad-maxncachettl-1.conf create mode 100644 bin/tests/system/checkconf/bad-maxncachettl-2.conf create mode 100644 bin/tests/system/checkconf/bad-maxncachettl-3.conf create mode 100644 bin/tests/system/checkconf/bad-maxncachettl-4.conf create mode 100644 bin/tests/system/checkconf/bad-maxratio1.conf create mode 100644 bin/tests/system/checkconf/bad-maxratio2.conf create mode 100644 bin/tests/system/checkconf/bad-maxttlmap.conf create mode 100644 bin/tests/system/checkconf/bad-mincachettl.conf create mode 100644 bin/tests/system/checkconf/bad-minncachettl.conf create mode 100644 bin/tests/system/checkconf/bad-mirror-allow-recursion-none.conf create mode 100644 bin/tests/system/checkconf/bad-mirror-explicit-notify-yes.conf create mode 100644 bin/tests/system/checkconf/bad-mirror-non-root-zone-without-masters.conf create mode 100644 bin/tests/system/checkconf/bad-mirror-recursion-no.conf create mode 100644 bin/tests/system/checkconf/bad-mirror-zonename.conf create mode 100644 bin/tests/system/checkconf/bad-noddns.conf create mode 100644 bin/tests/system/checkconf/bad-notify-source-v6.conf create mode 100644 bin/tests/system/checkconf/bad-notify-source.conf create mode 100644 bin/tests/system/checkconf/bad-options-also-notify.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-def-options.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-def-view.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-def-view2.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-def-zone.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-dup.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-dupdef.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-empty.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-empty2.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-mirror.conf create mode 100644 bin/tests/system/checkconf/bad-parental-agents-notfound.conf create mode 100644 bin/tests/system/checkconf/bad-parental-source-v6.conf create mode 100644 bin/tests/system/checkconf/bad-parental-source.conf create mode 100644 bin/tests/system/checkconf/bad-port.conf create mode 100644 bin/tests/system/checkconf/bad-primaries-key.conf create mode 100644 bin/tests/system/checkconf/bad-primaries-notfound.conf create mode 100644 bin/tests/system/checkconf/bad-printtime.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-acl.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-all-per-second.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-errors-per-second.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-ipv4-prefix-length.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-ipv6-prefix-length.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-max-table-size.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-nodata-per-second.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-nxdomains-per-second.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-qps-scale.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-referrals-per-second.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-responses-per-second.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-slip.conf create mode 100644 bin/tests/system/checkconf/bad-rate-limit-window.conf create mode 100644 bin/tests/system/checkconf/bad-root-mixed-key.conf create mode 100644 bin/tests/system/checkconf/bad-rpz-too-many-zones.conf create mode 100644 bin/tests/system/checkconf/bad-rpz-ttl.conf create mode 100644 bin/tests/system/checkconf/bad-rpz-update.conf create mode 100644 bin/tests/system/checkconf/bad-rpz-zone.conf create mode 100644 bin/tests/system/checkconf/bad-sharedwritable1.conf create mode 100644 bin/tests/system/checkconf/bad-sharedwritable2.conf create mode 100644 bin/tests/system/checkconf/bad-sharedzone1.conf create mode 100644 bin/tests/system/checkconf/bad-sharedzone2.conf create mode 100644 bin/tests/system/checkconf/bad-sharedzone3.conf create mode 100644 bin/tests/system/checkconf/bad-sig-validity.conf create mode 100644 bin/tests/system/checkconf/bad-static-initial-1.conf create mode 100644 bin/tests/system/checkconf/bad-static-initial-2.conf create mode 100644 bin/tests/system/checkconf/bad-static-initial-3.conf create mode 100644 bin/tests/system/checkconf/bad-static-initial-4.conf create mode 100644 bin/tests/system/checkconf/bad-stub-masters-dialup.conf create mode 100644 bin/tests/system/checkconf/bad-transfer-source-v6.conf create mode 100644 bin/tests/system/checkconf/bad-transfer-source.conf create mode 100644 bin/tests/system/checkconf/bad-tsig.conf create mode 100644 bin/tests/system/checkconf/bad-unpaired-keys.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy1.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy10.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy11.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy12.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy13.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy14.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy15.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy2.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy3.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy4.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy5.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy6.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy7.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy8.conf create mode 100644 bin/tests/system/checkconf/bad-update-policy9.conf create mode 100644 bin/tests/system/checkconf/bad-validation-auto-key.conf create mode 100644 bin/tests/system/checkconf/bad-view-also-notify.conf create mode 100644 bin/tests/system/checkconf/bad-zsk-without-ksk.conf create mode 100644 bin/tests/system/checkconf/check-dup-records-fail.conf create mode 100644 bin/tests/system/checkconf/check-dup-records.db create mode 100644 bin/tests/system/checkconf/check-missing-zone.conf create mode 100644 bin/tests/system/checkconf/check-mixed-keys.conf create mode 100644 bin/tests/system/checkconf/check-mx-cname-fail.conf create mode 100644 bin/tests/system/checkconf/check-mx-cname.db create mode 100644 bin/tests/system/checkconf/check-mx-fail.conf create mode 100644 bin/tests/system/checkconf/check-mx.db create mode 100644 bin/tests/system/checkconf/check-names-fail.conf create mode 100644 bin/tests/system/checkconf/check-names.db create mode 100644 bin/tests/system/checkconf/check-root-ksk-2010.conf create mode 100644 bin/tests/system/checkconf/check-root-ksk-2017.conf create mode 100644 bin/tests/system/checkconf/check-root-ksk-both.conf create mode 100644 bin/tests/system/checkconf/check-root-static-ds.conf create mode 100644 bin/tests/system/checkconf/check-root-static-key.conf create mode 100644 bin/tests/system/checkconf/check-root-trusted-key.conf create mode 100644 bin/tests/system/checkconf/check-srv-cname-fail.conf create mode 100644 bin/tests/system/checkconf/check-srv-cname.db create mode 100644 bin/tests/system/checkconf/check-wildcard-no.conf create mode 100644 bin/tests/system/checkconf/check-wildcard.conf create mode 100644 bin/tests/system/checkconf/check-wildcard.db create mode 100644 bin/tests/system/checkconf/clean.sh create mode 100644 bin/tests/system/checkconf/deprecated-masterfile-format-map.conf create mode 100644 bin/tests/system/checkconf/deprecated.conf create mode 100644 bin/tests/system/checkconf/dlz-bad.conf create mode 100644 bin/tests/system/checkconf/dnssec.1 create mode 100644 bin/tests/system/checkconf/dnssec.2 create mode 100644 bin/tests/system/checkconf/dnssec.3 create mode 100644 bin/tests/system/checkconf/dnssec.4 create mode 100644 bin/tests/system/checkconf/good-acl.conf create mode 100644 bin/tests/system/checkconf/good-allow-update-forwarding-view.conf create mode 100644 bin/tests/system/checkconf/good-allow-update-forwarding.conf create mode 100644 bin/tests/system/checkconf/good-allow-update-view.conf create mode 100644 bin/tests/system/checkconf/good-allow-update.conf create mode 100644 bin/tests/system/checkconf/good-class.conf create mode 100644 bin/tests/system/checkconf/good-dnskey-validity-3660.conf create mode 100644 bin/tests/system/checkconf/good-dnskey-validity-zero.conf create mode 100644 bin/tests/system/checkconf/good-ds-key-1.conf create mode 100644 bin/tests/system/checkconf/good-ds-key-2.conf create mode 100644 bin/tests/system/checkconf/good-dup-managed-key.conf create mode 100644 bin/tests/system/checkconf/good-dup-trusted-key.conf create mode 100644 bin/tests/system/checkconf/good-glue-cache.conf create mode 100644 bin/tests/system/checkconf/good-initial-ds.conf create mode 100644 bin/tests/system/checkconf/good-interface-interval.conf create mode 100644 bin/tests/system/checkconf/good-kasp.conf create mode 100644 bin/tests/system/checkconf/good-key-directory.conf create mode 100644 bin/tests/system/checkconf/good-lmdb-mapsize-largest.conf create mode 100644 bin/tests/system/checkconf/good-lmdb-mapsize-smallest.conf create mode 100644 bin/tests/system/checkconf/good-masterfile-format-raw.conf create mode 100644 bin/tests/system/checkconf/good-masterfile-format-text.conf create mode 100644 bin/tests/system/checkconf/good-masters-and-primaries.conf create mode 100644 bin/tests/system/checkconf/good-maxcachettl.conf create mode 100644 bin/tests/system/checkconf/good-maxncachettl.conf create mode 100644 bin/tests/system/checkconf/good-maxratio1.conf create mode 100644 bin/tests/system/checkconf/good-maxratio2.conf create mode 100644 bin/tests/system/checkconf/good-mincachettl.conf create mode 100644 bin/tests/system/checkconf/good-minncachettl.conf create mode 100644 bin/tests/system/checkconf/good-mirror-inherited-notify-yes.conf create mode 100644 bin/tests/system/checkconf/good-mirror-root-zone-without-masters.conf create mode 100644 bin/tests/system/checkconf/good-nested.conf create mode 100644 bin/tests/system/checkconf/good-notify-source-v6.conf create mode 100644 bin/tests/system/checkconf/good-notify-source.conf create mode 100644 bin/tests/system/checkconf/good-options-also-notify.conf create mode 100644 bin/tests/system/checkconf/good-parental-source-v6.conf create mode 100644 bin/tests/system/checkconf/good-parental-source.conf create mode 100644 bin/tests/system/checkconf/good-printtime.conf create mode 100644 bin/tests/system/checkconf/good-response-dot.conf create mode 100644 bin/tests/system/checkconf/good-rpz-ttl.conf create mode 100644 bin/tests/system/checkconf/good-rpz-update.conf create mode 100644 bin/tests/system/checkconf/good-rrset-order-none.conf create mode 100644 bin/tests/system/checkconf/good-static-ds.conf create mode 100644 bin/tests/system/checkconf/good-transfer-source-v6.conf create mode 100644 bin/tests/system/checkconf/good-transfer-source.conf create mode 100644 bin/tests/system/checkconf/good-update-policy1.conf create mode 100644 bin/tests/system/checkconf/good-update-policy10.conf create mode 100644 bin/tests/system/checkconf/good-update-policy11.conf create mode 100644 bin/tests/system/checkconf/good-update-policy12.conf create mode 100644 bin/tests/system/checkconf/good-update-policy2.conf create mode 100644 bin/tests/system/checkconf/good-update-policy3.conf create mode 100644 bin/tests/system/checkconf/good-update-policy4.conf create mode 100644 bin/tests/system/checkconf/good-update-policy5.conf create mode 100644 bin/tests/system/checkconf/good-update-policy6.conf create mode 100644 bin/tests/system/checkconf/good-update-policy7.conf create mode 100644 bin/tests/system/checkconf/good-update-policy8.conf create mode 100644 bin/tests/system/checkconf/good-update-policy9.conf create mode 100644 bin/tests/system/checkconf/good-view-also-notify.conf create mode 100644 bin/tests/system/checkconf/good.conf create mode 100644 bin/tests/system/checkconf/good.zonelist create mode 100644 bin/tests/system/checkconf/hint-nofile.conf create mode 100644 bin/tests/system/checkconf/in-view-good.conf create mode 100644 bin/tests/system/checkconf/inline-bad.conf create mode 100644 bin/tests/system/checkconf/inline-good.conf create mode 100644 bin/tests/system/checkconf/inline-no.conf create mode 100644 bin/tests/system/checkconf/kasp-and-other-dnssec-options.conf create mode 100644 bin/tests/system/checkconf/kasp-bad-keylen.conf create mode 100644 bin/tests/system/checkconf/kasp-bad-nsec3-alg.conf create mode 100644 bin/tests/system/checkconf/kasp-bad-nsec3-iter.conf create mode 100644 bin/tests/system/checkconf/kasp-bad-nsec3-salt.conf create mode 100644 bin/tests/system/checkconf/kasp-ignore-keylen.conf create mode 100644 bin/tests/system/checkconf/max-cache-size-good.conf create mode 100644 bin/tests/system/checkconf/max-ttl.conf create mode 100644 bin/tests/system/checkconf/maxttl-bad.conf create mode 100644 bin/tests/system/checkconf/maxttl-bad.db create mode 100644 bin/tests/system/checkconf/maxttl.db create mode 100644 bin/tests/system/checkconf/notify.conf create mode 100644 bin/tests/system/checkconf/portrange-good.conf create mode 100644 bin/tests/system/checkconf/range.conf create mode 100644 bin/tests/system/checkconf/servestale.stale-refresh-time.0.conf create mode 100644 bin/tests/system/checkconf/servestale.stale-refresh-time.29.conf create mode 100644 bin/tests/system/checkconf/shared.example.db create mode 100644 bin/tests/system/checkconf/tests.sh create mode 100644 bin/tests/system/checkconf/view-class-any1.conf create mode 100644 bin/tests/system/checkconf/view-class-any2.conf create mode 100644 bin/tests/system/checkconf/view-class-in1.conf create mode 100644 bin/tests/system/checkconf/view-class-in2.conf create mode 100644 bin/tests/system/checkconf/warn-dlv-auto.conf create mode 100644 bin/tests/system/checkconf/warn-dlv-dlv.example.com.conf create mode 100644 bin/tests/system/checkconf/warn-dlv-dlv.isc.org.conf create mode 100644 bin/tests/system/checkconf/warn-geoip-use-ecs.conf create mode 100644 bin/tests/system/checkconf/warn-kasp-max-zone-ttl.conf create mode 100644 bin/tests/system/checkconf/warn-keydir.conf create mode 100644 bin/tests/system/checkconf/warn-maxratio1.conf create mode 100644 bin/tests/system/checkconf/warn-notify-source.conf create mode 100644 bin/tests/system/checkconf/warn-parental-source.conf create mode 100644 bin/tests/system/checkconf/warn-transfer-source.conf create mode 100644 bin/tests/system/checkds/README create mode 100644 bin/tests/system/checkds/clean.sh create mode 100644 bin/tests/system/checkds/ns2/named.conf.in create mode 100644 bin/tests/system/checkds/ns2/setup.sh create mode 100644 bin/tests/system/checkds/ns2/template.db.in create mode 100644 bin/tests/system/checkds/ns4/named.conf.in create mode 100644 bin/tests/system/checkds/ns5/named.conf.in create mode 100644 bin/tests/system/checkds/ns5/setup.sh create mode 100644 bin/tests/system/checkds/ns5/template.db.in create mode 100644 bin/tests/system/checkds/ns6/named.conf.in create mode 100644 bin/tests/system/checkds/ns7/named.conf.in create mode 100644 bin/tests/system/checkds/ns9/named.conf.in create mode 100644 bin/tests/system/checkds/ns9/setup.sh create mode 100644 bin/tests/system/checkds/ns9/template.db.in create mode 100644 bin/tests/system/checkds/prereq.sh create mode 100644 bin/tests/system/checkds/setup.sh create mode 100755 bin/tests/system/checkds/tests_checkds.py create mode 100644 bin/tests/system/checkdstool/clean.sh create mode 100755 bin/tests/system/checkdstool/dig.bat create mode 100644 bin/tests/system/checkdstool/dig.pl create mode 100755 bin/tests/system/checkdstool/dig.sh create mode 100644 bin/tests/system/checkdstool/missing.example.dnskey.db create mode 100644 bin/tests/system/checkdstool/missing.example.ds.db create mode 100644 bin/tests/system/checkdstool/none.example.dnskey.db create mode 100644 bin/tests/system/checkdstool/none.example.ds.db create mode 100644 bin/tests/system/checkdstool/ok.example.dnskey.db create mode 100644 bin/tests/system/checkdstool/ok.example.ds.db create mode 100644 bin/tests/system/checkdstool/prep.example.db create mode 100644 bin/tests/system/checkdstool/prep.example.ds.db create mode 100644 bin/tests/system/checkdstool/tests.sh create mode 100644 bin/tests/system/checkdstool/wrong.example.dnskey.db create mode 100644 bin/tests/system/checkdstool/wrong.example.ds.db create mode 100644 bin/tests/system/checknames/clean.sh create mode 100644 bin/tests/system/checknames/ns1/fail.example.db.in create mode 100644 bin/tests/system/checknames/ns1/fail.update.db.in create mode 100644 bin/tests/system/checknames/ns1/ignore.example.db.in create mode 100644 bin/tests/system/checknames/ns1/ignore.update.db.in create mode 100644 bin/tests/system/checknames/ns1/named.conf.in create mode 100644 bin/tests/system/checknames/ns1/root.db create mode 100644 bin/tests/system/checknames/ns1/warn.example.db.in create mode 100644 bin/tests/system/checknames/ns1/warn.update.db.in create mode 100644 bin/tests/system/checknames/ns2/named.conf.in create mode 100644 bin/tests/system/checknames/ns2/root.hints create mode 100644 bin/tests/system/checknames/ns3/named.conf.in create mode 100644 bin/tests/system/checknames/ns3/root.hints create mode 100644 bin/tests/system/checknames/ns4/named.conf.in create mode 100644 bin/tests/system/checknames/ns4/primary-ignore.update.db.in create mode 100644 bin/tests/system/checknames/ns4/root.hints create mode 100644 bin/tests/system/checknames/ns5/master-ignore.update.db.in create mode 100644 bin/tests/system/checknames/ns5/named.conf.in create mode 100644 bin/tests/system/checknames/ns5/root.hints create mode 100644 bin/tests/system/checknames/setup.sh create mode 100644 bin/tests/system/checknames/tests.sh create mode 100644 bin/tests/system/checkzone/clean.sh create mode 100644 bin/tests/system/checkzone/setup.sh create mode 100644 bin/tests/system/checkzone/tests.sh create mode 100644 bin/tests/system/checkzone/zones/.gitattributes create mode 100644 bin/tests/system/checkzone/zones/bad-badclass.raw create mode 100644 bin/tests/system/checkzone/zones/bad-caa-rr.db create mode 100644 bin/tests/system/checkzone/zones/bad-cdnskey.db create mode 100644 bin/tests/system/checkzone/zones/bad-cds.db create mode 100644 bin/tests/system/checkzone/zones/bad-dhcid.db create mode 100644 bin/tests/system/checkzone/zones/bad-dns-sd-reverse.db create mode 100644 bin/tests/system/checkzone/zones/bad-ds.db create mode 100644 bin/tests/system/checkzone/zones/bad-eid.db create mode 100644 bin/tests/system/checkzone/zones/bad-generate-garbage.db create mode 100644 bin/tests/system/checkzone/zones/bad-generate-missing-brace.db create mode 100644 bin/tests/system/checkzone/zones/bad-generate-range.db create mode 100644 bin/tests/system/checkzone/zones/bad-generate-tkey.db create mode 100644 bin/tests/system/checkzone/zones/bad-nimloc.db create mode 100644 bin/tests/system/checkzone/zones/bad-nsap-empty.db create mode 100644 bin/tests/system/checkzone/zones/bad-nsap-odd-nibble.db create mode 100644 bin/tests/system/checkzone/zones/bad-nsec3-padded.db create mode 100644 bin/tests/system/checkzone/zones/bad-nsec3owner-padded.db create mode 100644 bin/tests/system/checkzone/zones/bad-svcb-mandatory.db create mode 100644 bin/tests/system/checkzone/zones/bad-svcb-servername.db create mode 100644 bin/tests/system/checkzone/zones/bad-svcb.db create mode 100644 bin/tests/system/checkzone/zones/bad-tkey.db create mode 100644 bin/tests/system/checkzone/zones/bad-tsig.db.in create mode 100644 bin/tests/system/checkzone/zones/bad-unspec.db create mode 100644 bin/tests/system/checkzone/zones/bad1.db create mode 100644 bin/tests/system/checkzone/zones/bad2.db create mode 100644 bin/tests/system/checkzone/zones/bad3.db create mode 100644 bin/tests/system/checkzone/zones/bad4.db create mode 100644 bin/tests/system/checkzone/zones/badttl.db create mode 100644 bin/tests/system/checkzone/zones/crashzone.db create mode 100644 bin/tests/system/checkzone/zones/delegating-ns-address-below-dname.db create mode 100644 bin/tests/system/checkzone/zones/generate-overflow.db create mode 100644 bin/tests/system/checkzone/zones/good-cdnskey.db create mode 100644 bin/tests/system/checkzone/zones/good-cds-unsigned.db create mode 100644 bin/tests/system/checkzone/zones/good-cds.db create mode 100644 bin/tests/system/checkzone/zones/good-dns-sd-reverse.db create mode 100644 bin/tests/system/checkzone/zones/good-gc-msdcs.db create mode 100644 bin/tests/system/checkzone/zones/good-generate-modifier.db create mode 100644 bin/tests/system/checkzone/zones/good-nsap.db create mode 100644 bin/tests/system/checkzone/zones/good-nsec3-nopadhash.db create mode 100644 bin/tests/system/checkzone/zones/good-occulted-ns-by-dname.db create mode 100644 bin/tests/system/checkzone/zones/good-occulted-ns-by-ns.db create mode 100644 bin/tests/system/checkzone/zones/good-spf-exception.db create mode 100644 bin/tests/system/checkzone/zones/good-svcb.db create mode 100644 bin/tests/system/checkzone/zones/good1.db create mode 100644 bin/tests/system/checkzone/zones/inherit.db create mode 100644 bin/tests/system/checkzone/zones/nowarn.inherited.owner.db create mode 100644 bin/tests/system/checkzone/zones/ns-address-below-dname.db create mode 100644 bin/tests/system/checkzone/zones/spf.db create mode 100644 bin/tests/system/checkzone/zones/test1.db create mode 100644 bin/tests/system/checkzone/zones/test2.db create mode 100644 bin/tests/system/checkzone/zones/warn.inherit.origin.db create mode 100644 bin/tests/system/checkzone/zones/warn.inherited.owner.db create mode 100644 bin/tests/system/ckdnsrps.sh create mode 100644 bin/tests/system/cleanall.sh create mode 100644 bin/tests/system/cleanpkcs11.sh create mode 100644 bin/tests/system/common/controls.conf.in create mode 100644 bin/tests/system/common/rndc.conf create mode 100644 bin/tests/system/common/rndc.key create mode 100644 bin/tests/system/common/root.hint create mode 100644 bin/tests/system/conf.sh.common create mode 100644 bin/tests/system/conf.sh.in create mode 100644 bin/tests/system/conf.sh.win32 create mode 100644 bin/tests/system/conftest.py create mode 100644 bin/tests/system/cookie/ans9/ans.py create mode 100644 bin/tests/system/cookie/bad-cookie-badaes.conf create mode 100644 bin/tests/system/cookie/bad-cookie-badhex.conf create mode 100644 bin/tests/system/cookie/bad-cookie-badsiphash24.conf create mode 100644 bin/tests/system/cookie/bad-cookie-toolong.conf create mode 100644 bin/tests/system/cookie/clean.sh create mode 100644 bin/tests/system/cookie/good-cookie-aes.conf create mode 100644 bin/tests/system/cookie/good-cookie-siphash24.conf create mode 100644 bin/tests/system/cookie/ns1/example.db create mode 100644 bin/tests/system/cookie/ns1/named.conf.in create mode 100644 bin/tests/system/cookie/ns1/root.hint create mode 100644 bin/tests/system/cookie/ns2/named.conf.in create mode 100644 bin/tests/system/cookie/ns2/root.db create mode 100644 bin/tests/system/cookie/ns3/named.conf.in create mode 100644 bin/tests/system/cookie/ns3/root.hint create mode 100644 bin/tests/system/cookie/ns4/named.conf.in create mode 100644 bin/tests/system/cookie/ns4/root.hint create mode 100644 bin/tests/system/cookie/ns5/named.conf.in create mode 100644 bin/tests/system/cookie/ns5/root.hint create mode 100644 bin/tests/system/cookie/ns6/named.conf.in create mode 100644 bin/tests/system/cookie/ns6/root.hint create mode 100644 bin/tests/system/cookie/ns7/named.conf.in create mode 100644 bin/tests/system/cookie/ns7/root.db create mode 100644 bin/tests/system/cookie/ns8/example.db create mode 100644 bin/tests/system/cookie/ns8/named.conf.in create mode 100644 bin/tests/system/cookie/prereq.sh create mode 100644 bin/tests/system/cookie/setup.sh create mode 100755 bin/tests/system/cookie/tests.sh create mode 100644 bin/tests/system/coverage/01-ksk-inactive/README create mode 100644 bin/tests/system/coverage/01-ksk-inactive/expect create mode 100644 bin/tests/system/coverage/02-zsk-inactive/README create mode 100644 bin/tests/system/coverage/02-zsk-inactive/expect create mode 100644 bin/tests/system/coverage/03-ksk-unpublished/README create mode 100644 bin/tests/system/coverage/03-ksk-unpublished/expect create mode 100644 bin/tests/system/coverage/04-zsk-unpublished/README create mode 100644 bin/tests/system/coverage/04-zsk-unpublished/expect create mode 100644 bin/tests/system/coverage/05-ksk-unpub-active/README create mode 100644 bin/tests/system/coverage/05-ksk-unpub-active/expect create mode 100644 bin/tests/system/coverage/06-zsk-unpub-active/README create mode 100644 bin/tests/system/coverage/06-zsk-unpub-active/expect create mode 100644 bin/tests/system/coverage/07-ksk-ttl/README create mode 100644 bin/tests/system/coverage/07-ksk-ttl/expect create mode 100644 bin/tests/system/coverage/08-zsk-ttl/README create mode 100644 bin/tests/system/coverage/08-zsk-ttl/expect create mode 100644 bin/tests/system/coverage/09-check-zsk/README create mode 100644 bin/tests/system/coverage/09-check-zsk/expect create mode 100644 bin/tests/system/coverage/10-check-ksk/README create mode 100644 bin/tests/system/coverage/10-check-ksk/expect create mode 100644 bin/tests/system/coverage/11-cutoff/README create mode 100644 bin/tests/system/coverage/11-cutoff/expect create mode 100644 bin/tests/system/coverage/12-ksk-deletion/expect create mode 100644 bin/tests/system/coverage/13-dotted-dotless/expect create mode 100644 bin/tests/system/coverage/clean.sh create mode 100644 bin/tests/system/coverage/setup.sh create mode 100644 bin/tests/system/coverage/tests.sh create mode 100644 bin/tests/system/database/clean.sh create mode 100644 bin/tests/system/database/ns1/named1.conf.in create mode 100644 bin/tests/system/database/ns1/named2.conf.in create mode 100644 bin/tests/system/database/setup.sh create mode 100644 bin/tests/system/database/tests.sh create mode 100644 bin/tests/system/dialup/clean.sh create mode 100644 bin/tests/system/dialup/ns1/example.db create mode 100644 bin/tests/system/dialup/ns1/named.conf.in create mode 100644 bin/tests/system/dialup/ns1/root.db create mode 100644 bin/tests/system/dialup/ns2/hint.db create mode 100644 bin/tests/system/dialup/ns2/named.conf.in create mode 100644 bin/tests/system/dialup/ns3/hint.db create mode 100644 bin/tests/system/dialup/ns3/named.conf.in create mode 100644 bin/tests/system/dialup/setup.sh create mode 100644 bin/tests/system/dialup/tests.sh create mode 100644 bin/tests/system/digcomp.pl create mode 100644 bin/tests/system/digdelv/ans4/startme create mode 100644 bin/tests/system/digdelv/ans5/ans.pl create mode 100755 bin/tests/system/digdelv/ans6/ans.pl create mode 100755 bin/tests/system/digdelv/ans7/ans.pl create mode 100644 bin/tests/system/digdelv/clean.sh create mode 100644 bin/tests/system/digdelv/ns1/named.conf.in create mode 100644 bin/tests/system/digdelv/ns1/root.db create mode 100644 bin/tests/system/digdelv/ns2/example.db.in create mode 100644 bin/tests/system/digdelv/ns2/named.conf.in create mode 100644 bin/tests/system/digdelv/ns2/sign.sh create mode 100644 bin/tests/system/digdelv/ns3/named.conf.in create mode 100644 bin/tests/system/digdelv/prereq.sh create mode 100644 bin/tests/system/digdelv/setup.sh create mode 100644 bin/tests/system/digdelv/tests.sh create mode 100644 bin/tests/system/digdelv/yamlget.py create mode 100644 bin/tests/system/ditch.pl create mode 100644 bin/tests/system/dlz/clean.sh create mode 100644 bin/tests/system/dlz/ns1/dns-root/com/broken/dns.d/@/DNAME=10=example.net.= create mode 100644 bin/tests/system/dlz/ns1/dns-root/com/broken/dns.d/@/NS=10=example.com.= create mode 100644 bin/tests/system/dlz/ns1/dns-root/com/broken/dns.d/@/SOA=10=ns.example.com.=root.example.com.=None=None=None=None=None= create mode 100644 bin/tests/system/dlz/ns1/dns-root/com/example/dns.d/@/DNAME=10=example.net.= create mode 100644 bin/tests/system/dlz/ns1/dns-root/com/example/dns.d/@/NS=10=example.com.= create mode 100644 bin/tests/system/dlz/ns1/dns-root/com/example/dns.d/@/SOA=10=ns.example.com.=root.example.com.=2010062900=0=0=0=10= create mode 100644 bin/tests/system/dlz/ns1/dns-root/com/example/xfr.d/10.53.0.1 create mode 100644 bin/tests/system/dlz/ns1/named.conf.in create mode 100644 bin/tests/system/dlz/prereq.sh create mode 100644 bin/tests/system/dlz/setup.sh create mode 100644 bin/tests/system/dlz/tests.sh create mode 100644 bin/tests/system/dlzexternal/Makefile.in create mode 100644 bin/tests/system/dlzexternal/clean.sh create mode 100644 bin/tests/system/dlzexternal/driver.c create mode 100644 bin/tests/system/dlzexternal/driver.h create mode 100644 bin/tests/system/dlzexternal/ns1/dlzs.conf.in create mode 100644 bin/tests/system/dlzexternal/ns1/named.conf.in create mode 100644 bin/tests/system/dlzexternal/ns1/root.db create mode 100644 bin/tests/system/dlzexternal/prereq.sh create mode 100644 bin/tests/system/dlzexternal/setup.sh create mode 100644 bin/tests/system/dlzexternal/tests.sh create mode 100644 bin/tests/system/dns64/clean.sh create mode 100644 bin/tests/system/dns64/conf/bad1.conf create mode 100644 bin/tests/system/dns64/conf/bad10.conf create mode 100644 bin/tests/system/dns64/conf/bad11.conf create mode 100644 bin/tests/system/dns64/conf/bad12.conf create mode 100644 bin/tests/system/dns64/conf/bad13.conf create mode 100644 bin/tests/system/dns64/conf/bad14.conf create mode 100644 bin/tests/system/dns64/conf/bad15.conf create mode 100644 bin/tests/system/dns64/conf/bad16.conf create mode 100644 bin/tests/system/dns64/conf/bad17.conf create mode 100644 bin/tests/system/dns64/conf/bad18.conf create mode 100644 bin/tests/system/dns64/conf/bad19.conf create mode 100644 bin/tests/system/dns64/conf/bad2.conf create mode 100644 bin/tests/system/dns64/conf/bad3.conf create mode 100644 bin/tests/system/dns64/conf/bad4.conf create mode 100644 bin/tests/system/dns64/conf/bad5.conf create mode 100644 bin/tests/system/dns64/conf/bad6.conf create mode 100644 bin/tests/system/dns64/conf/bad7.conf create mode 100644 bin/tests/system/dns64/conf/bad8.conf create mode 100644 bin/tests/system/dns64/conf/bad9.conf create mode 100644 bin/tests/system/dns64/conf/good1.conf create mode 100644 bin/tests/system/dns64/conf/good2.conf create mode 100644 bin/tests/system/dns64/conf/good3.conf create mode 100644 bin/tests/system/dns64/conf/good4.conf create mode 100644 bin/tests/system/dns64/conf/good5.conf create mode 100644 bin/tests/system/dns64/ns1/example.db create mode 100644 bin/tests/system/dns64/ns1/named.conf.in create mode 100644 bin/tests/system/dns64/ns1/root.db create mode 100644 bin/tests/system/dns64/ns1/sign.sh create mode 100644 bin/tests/system/dns64/ns2/named.conf.in create mode 100644 bin/tests/system/dns64/ns2/rpz.db create mode 100644 bin/tests/system/dns64/setup.sh create mode 100644 bin/tests/system/dns64/tests.sh create mode 100644 bin/tests/system/dnssec/README create mode 100644 bin/tests/system/dnssec/ans10/ans.py create mode 100644 bin/tests/system/dnssec/clean.sh create mode 100644 bin/tests/system/dnssec/dnssec_update_test.pl create mode 100644 bin/tests/system/dnssec/ns1/named.conf.in create mode 100644 bin/tests/system/dnssec/ns1/root.db.in create mode 100644 bin/tests/system/dnssec/ns1/sign.sh create mode 100644 bin/tests/system/dnssec/ns2/algroll.db.in create mode 100644 bin/tests/system/dnssec/ns2/badparam.db.in create mode 100644 bin/tests/system/dnssec/ns2/cdnskey-auto.secure.db.in create mode 100644 bin/tests/system/dnssec/ns2/cdnskey-kskonly.secure.db.in create mode 100644 bin/tests/system/dnssec/ns2/cdnskey-update.secure.db.in create mode 100644 bin/tests/system/dnssec/ns2/cdnskey.secure.db.in create mode 100644 bin/tests/system/dnssec/ns2/cds-auto.secure.db.in create mode 100644 bin/tests/system/dnssec/ns2/cds-kskonly.secure.db.in create mode 100644 bin/tests/system/dnssec/ns2/cds-update.secure.db.in create mode 100644 bin/tests/system/dnssec/ns2/cds.secure.db.in create mode 100644 bin/tests/system/dnssec/ns2/child.nsec3.example.db create mode 100644 bin/tests/system/dnssec/ns2/child.optout.example.db create mode 100644 bin/tests/system/dnssec/ns2/corp.db create mode 100644 bin/tests/system/dnssec/ns2/dst.example.db.in create mode 100644 bin/tests/system/dnssec/ns2/example.db.in create mode 100644 bin/tests/system/dnssec/ns2/hours-vs-days.db.in create mode 100644 bin/tests/system/dnssec/ns2/in-addr.arpa.db.in create mode 100644 bin/tests/system/dnssec/ns2/insecure.secure.example.db create mode 100644 bin/tests/system/dnssec/ns2/key.db.in create mode 100644 bin/tests/system/dnssec/ns2/named.conf.in create mode 100644 bin/tests/system/dnssec/ns2/private.secure.example.db.in create mode 100644 bin/tests/system/dnssec/ns2/rfc2335.example.db create mode 100644 bin/tests/system/dnssec/ns2/sign.sh create mode 100644 bin/tests/system/dnssec/ns2/single-nsec3.db.in create mode 100644 bin/tests/system/dnssec/ns2/template.secure.db.in create mode 100644 bin/tests/system/dnssec/ns2/too-many-iterations.db.in create mode 100644 bin/tests/system/dnssec/ns3/auto-nsec.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/auto-nsec3.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/bogus.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/dname-at-apex-nsec3.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/dnskey-nsec3-unknown.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/dnskey-unknown.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/dnskey-unsupported-2.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/dnskey-unsupported.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/dynamic.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/expired.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/expiring.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/future.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/generic.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/inline.example.db create mode 100644 bin/tests/system/dnssec/ns3/insecure.below-cname.example.db create mode 100644 bin/tests/system/dnssec/ns3/insecure.example.db create mode 100644 bin/tests/system/dnssec/ns3/insecure.nsec3.example.db create mode 100644 bin/tests/system/dnssec/ns3/insecure.optout.example.db create mode 100644 bin/tests/system/dnssec/ns3/insecure2.example.db create mode 100644 bin/tests/system/dnssec/ns3/key.db.in create mode 100644 bin/tests/system/dnssec/ns3/kskonly.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/lower.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/managed-future.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/multiple.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/named.conf.in create mode 100644 bin/tests/system/dnssec/ns3/nosign.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/nsec3-unknown.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/nsec3.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/nsec3.nsec3.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/nsec3.optout.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/occluded.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/optout-unknown.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/optout.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/optout.nsec3.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/optout.optout.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/publish-inactive.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/rsasha256.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/rsasha512.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/secure.below-cname.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/secure.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/secure.nsec3.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/secure.optout.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/siginterval.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/siginterval1.conf create mode 100644 bin/tests/system/dnssec/ns3/siginterval2.conf create mode 100644 bin/tests/system/dnssec/ns3/sign.sh create mode 100644 bin/tests/system/dnssec/ns3/split-dnssec.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/split-smart.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/ttlpatch.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/unsupported-algorithm.key create mode 100644 bin/tests/system/dnssec/ns3/update-nsec3.example.db.in create mode 100644 bin/tests/system/dnssec/ns3/upper.example.db.in create mode 100644 bin/tests/system/dnssec/ns4/managed-keys.bind.in create mode 100644 bin/tests/system/dnssec/ns4/named1.conf.in create mode 100644 bin/tests/system/dnssec/ns4/named2.conf.in create mode 100644 bin/tests/system/dnssec/ns4/named3.conf.in create mode 100644 bin/tests/system/dnssec/ns4/named4.conf.in create mode 100644 bin/tests/system/dnssec/ns4/named5.conf.in create mode 100644 bin/tests/system/dnssec/ns5/named1.conf.in create mode 100644 bin/tests/system/dnssec/ns5/named2.conf.in create mode 100644 bin/tests/system/dnssec/ns5/sign.sh create mode 100644 bin/tests/system/dnssec/ns6/named.args create mode 100644 bin/tests/system/dnssec/ns6/named.conf.in create mode 100644 bin/tests/system/dnssec/ns6/optout-tld.db.in create mode 100644 bin/tests/system/dnssec/ns6/sign.sh create mode 100644 bin/tests/system/dnssec/ns7/named.conf.in create mode 100644 bin/tests/system/dnssec/ns7/named.nosoa create mode 100644 bin/tests/system/dnssec/ns7/nosoa.secure.example.db create mode 100644 bin/tests/system/dnssec/ns7/sign.sh create mode 100644 bin/tests/system/dnssec/ns7/split-rrsig.db.in create mode 100644 bin/tests/system/dnssec/ns8/named.conf.in create mode 100644 bin/tests/system/dnssec/ns9/named.conf.in create mode 100755 bin/tests/system/dnssec/ntadiff.pl create mode 100644 bin/tests/system/dnssec/prereq.sh create mode 100644 bin/tests/system/dnssec/setup.sh create mode 100644 bin/tests/system/dnssec/signer/example.db.in create mode 100644 bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.key create mode 100644 bin/tests/system/dnssec/signer/general/Kexample.com.+008+15002.private create mode 100644 bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.key create mode 100644 bin/tests/system/dnssec/signer/general/Kexample.com.+008+63613.private create mode 100644 bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.key create mode 100644 bin/tests/system/dnssec/signer/general/Kexample.com.+010+18240.private create mode 100644 bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.key create mode 100644 bin/tests/system/dnssec/signer/general/Kexample.com.+010+28633.private create mode 100644 bin/tests/system/dnssec/signer/general/bogus-ksk.key create mode 100644 bin/tests/system/dnssec/signer/general/bogus-zsk.key create mode 100644 bin/tests/system/dnssec/signer/general/test1.zone create mode 100644 bin/tests/system/dnssec/signer/general/test2.zone create mode 100644 bin/tests/system/dnssec/signer/general/test3.zone create mode 100644 bin/tests/system/dnssec/signer/general/test4.zone create mode 100644 bin/tests/system/dnssec/signer/general/test5.zone create mode 100644 bin/tests/system/dnssec/signer/general/test6.zone create mode 100644 bin/tests/system/dnssec/signer/general/test7.zone create mode 100644 bin/tests/system/dnssec/signer/general/test8.zone create mode 100644 bin/tests/system/dnssec/signer/general/test9.zone create mode 100644 bin/tests/system/dnssec/signer/prepub.db.in create mode 100644 bin/tests/system/dnssec/signer/remove.db.in create mode 100644 bin/tests/system/dnssec/signer/remove2.db.in create mode 100644 bin/tests/system/dnssec/tests.sh create mode 100644 bin/tests/system/dnstap/README create mode 100644 bin/tests/system/dnstap/bad-fstrm-reopen-interval.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-buffer-hint-max.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-buffer-hint-min.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-flush-timeout-max.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-flush-timeout-min.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-input-queue-size-max.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-input-queue-size-min.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-input-queue-size-po2.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-output-notify-threshold.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-output-queue-size-max.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-output-queue-size-min.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-reopen-interval-max.conf create mode 100644 bin/tests/system/dnstap/bad-fstrm-set-reopen-interval-min.conf create mode 100644 bin/tests/system/dnstap/bad-missing-dnstap-output-view.conf create mode 100644 bin/tests/system/dnstap/bad-missing-dnstap-output.conf create mode 100644 bin/tests/system/dnstap/bad-size-version.conf create mode 100644 bin/tests/system/dnstap/clean.sh create mode 100644 bin/tests/system/dnstap/good-dnstap-in-options.conf create mode 100644 bin/tests/system/dnstap/good-dnstap-in-view.conf create mode 100644 bin/tests/system/dnstap/good-fstrm-reopen-interval.conf create mode 100644 bin/tests/system/dnstap/good-fstrm-set-buffer-hint.conf create mode 100644 bin/tests/system/dnstap/good-fstrm-set-flush-timeout.conf create mode 100644 bin/tests/system/dnstap/good-fstrm-set-input-queue-size.conf create mode 100644 bin/tests/system/dnstap/good-fstrm-set-output-notify-threshold.conf create mode 100644 bin/tests/system/dnstap/good-fstrm-set-output-queue-model-mpsc.conf create mode 100644 bin/tests/system/dnstap/good-fstrm-set-output-queue-model-spsc.conf create mode 100644 bin/tests/system/dnstap/good-fstrm-set-output-queue-size.conf create mode 100644 bin/tests/system/dnstap/good-fstrm-set-reopen-interval.conf create mode 100644 bin/tests/system/dnstap/good-size-unlimited.conf create mode 100644 bin/tests/system/dnstap/good-size-version.conf create mode 100644 bin/tests/system/dnstap/large-answer.fstrm create mode 100644 bin/tests/system/dnstap/ns1/named.conf.in create mode 100644 bin/tests/system/dnstap/ns1/root.db create mode 100644 bin/tests/system/dnstap/ns2/example.db.in create mode 100644 bin/tests/system/dnstap/ns2/named.conf.in create mode 100644 bin/tests/system/dnstap/ns3/named.args create mode 100644 bin/tests/system/dnstap/ns3/named.conf.in create mode 100644 bin/tests/system/dnstap/ns4/named.conf.in create mode 100644 bin/tests/system/dnstap/prereq.sh create mode 100644 bin/tests/system/dnstap/setup.sh create mode 100644 bin/tests/system/dnstap/tests.sh create mode 100644 bin/tests/system/dnstap/ydump.py create mode 100644 bin/tests/system/dscp/clean.sh create mode 100644 bin/tests/system/dscp/ns1/named.args create mode 100644 bin/tests/system/dscp/ns1/named.conf.in create mode 100644 bin/tests/system/dscp/ns1/root.db create mode 100644 bin/tests/system/dscp/ns2/named.args create mode 100644 bin/tests/system/dscp/ns2/named.conf.in create mode 100644 bin/tests/system/dscp/ns3/hint.db create mode 100644 bin/tests/system/dscp/ns3/named.args create mode 100644 bin/tests/system/dscp/ns3/named.conf.in create mode 100644 bin/tests/system/dscp/ns4/named.args create mode 100644 bin/tests/system/dscp/ns4/named.conf.in create mode 100644 bin/tests/system/dscp/ns4/root.db create mode 100644 bin/tests/system/dscp/ns5/named.args create mode 100644 bin/tests/system/dscp/ns5/named.conf.in create mode 100644 bin/tests/system/dscp/ns6/hint.db create mode 100644 bin/tests/system/dscp/ns6/named.args create mode 100644 bin/tests/system/dscp/ns6/named.conf.in create mode 100644 bin/tests/system/dscp/ns7/named.args create mode 100644 bin/tests/system/dscp/ns7/named.conf.in create mode 100644 bin/tests/system/dscp/setup.sh create mode 100644 bin/tests/system/dscp/tests.sh create mode 100644 bin/tests/system/dsdigest/clean.sh create mode 100644 bin/tests/system/dsdigest/ns1/named.conf.in create mode 100644 bin/tests/system/dsdigest/ns1/root.db.in create mode 100644 bin/tests/system/dsdigest/ns1/sign.sh create mode 100644 bin/tests/system/dsdigest/ns2/bad.db.in create mode 100644 bin/tests/system/dsdigest/ns2/good.db.in create mode 100644 bin/tests/system/dsdigest/ns2/named.conf.in create mode 100644 bin/tests/system/dsdigest/ns2/sign.sh create mode 100644 bin/tests/system/dsdigest/ns3/named.conf.in create mode 100644 bin/tests/system/dsdigest/ns4/named.conf.in create mode 100644 bin/tests/system/dsdigest/setup.sh create mode 100644 bin/tests/system/dsdigest/tests.sh create mode 100644 bin/tests/system/dupsigs/check_journal.pl create mode 100644 bin/tests/system/dupsigs/clean.sh create mode 100644 bin/tests/system/dupsigs/ns1/named.args create mode 100644 bin/tests/system/dupsigs/ns1/named.conf.in create mode 100644 bin/tests/system/dupsigs/ns1/reset_keys.sh create mode 100644 bin/tests/system/dupsigs/ns1/signing.test.db.in create mode 100644 bin/tests/system/dupsigs/setup.sh create mode 100644 bin/tests/system/dupsigs/tests.sh create mode 100644 bin/tests/system/dyndb/Makefile.in create mode 100644 bin/tests/system/dyndb/clean.sh create mode 100644 bin/tests/system/dyndb/driver/AUTHORS create mode 100644 bin/tests/system/dyndb/driver/Makefile.in create mode 100644 bin/tests/system/dyndb/driver/README create mode 100644 bin/tests/system/dyndb/driver/db.c create mode 100644 bin/tests/system/dyndb/driver/db.h create mode 100644 bin/tests/system/dyndb/driver/driver.c create mode 100644 bin/tests/system/dyndb/driver/instance.c create mode 100644 bin/tests/system/dyndb/driver/instance.h create mode 100644 bin/tests/system/dyndb/driver/lock.c create mode 100644 bin/tests/system/dyndb/driver/lock.h create mode 100644 bin/tests/system/dyndb/driver/log.c create mode 100644 bin/tests/system/dyndb/driver/log.h create mode 100644 bin/tests/system/dyndb/driver/syncptr.c create mode 100644 bin/tests/system/dyndb/driver/syncptr.h create mode 100644 bin/tests/system/dyndb/driver/util.h create mode 100644 bin/tests/system/dyndb/driver/zone.c create mode 100644 bin/tests/system/dyndb/driver/zone.h create mode 100644 bin/tests/system/dyndb/ns1/named.conf.in create mode 100644 bin/tests/system/dyndb/prereq.sh create mode 100644 bin/tests/system/dyndb/setup.sh create mode 100644 bin/tests/system/dyndb/tests.sh create mode 100644 bin/tests/system/ecdsa/clean.sh create mode 100644 bin/tests/system/ecdsa/ns1/named.conf.in create mode 100644 bin/tests/system/ecdsa/ns1/root.db.in create mode 100644 bin/tests/system/ecdsa/ns1/sign.sh create mode 100644 bin/tests/system/ecdsa/ns2/named.conf.in create mode 100644 bin/tests/system/ecdsa/ns3/named.conf.in create mode 100644 bin/tests/system/ecdsa/setup.sh create mode 100644 bin/tests/system/ecdsa/tests.sh create mode 100644 bin/tests/system/eddsa/clean.sh create mode 100644 bin/tests/system/eddsa/ns1/named.conf.in create mode 100644 bin/tests/system/eddsa/ns1/root.db.in create mode 100644 bin/tests/system/eddsa/ns1/sign.sh create mode 100644 bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.key create mode 100644 bin/tests/system/eddsa/ns2/Xexample.com.+015+03613.private create mode 100644 bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.key create mode 100644 bin/tests/system/eddsa/ns2/Xexample.com.+015+35217.private create mode 100644 bin/tests/system/eddsa/ns2/example.com.db.in create mode 100644 bin/tests/system/eddsa/ns2/named.conf.in create mode 100644 bin/tests/system/eddsa/ns2/sign.sh create mode 100644 bin/tests/system/eddsa/ns3/Xexample.com.+016+09713.key create mode 100644 bin/tests/system/eddsa/ns3/Xexample.com.+016+09713.private create mode 100644 bin/tests/system/eddsa/ns3/Xexample.com.+016+38353.key create mode 100644 bin/tests/system/eddsa/ns3/Xexample.com.+016+38353.private create mode 100644 bin/tests/system/eddsa/ns3/example.com.db.in create mode 100644 bin/tests/system/eddsa/ns3/named.conf.in create mode 100644 bin/tests/system/eddsa/ns3/sign.sh create mode 100644 bin/tests/system/eddsa/prereq.sh create mode 100644 bin/tests/system/eddsa/setup.sh create mode 100644 bin/tests/system/eddsa/tests.sh create mode 100644 bin/tests/system/ednscompliance/clean.sh create mode 100644 bin/tests/system/ednscompliance/ns1/named.conf.in create mode 100644 bin/tests/system/ednscompliance/ns1/root.db create mode 100644 bin/tests/system/ednscompliance/setup.sh create mode 100644 bin/tests/system/ednscompliance/tests.sh create mode 100644 bin/tests/system/emptyzones/clean.sh create mode 100644 bin/tests/system/emptyzones/ns1/empty.db create mode 100644 bin/tests/system/emptyzones/ns1/named1.conf.in create mode 100644 bin/tests/system/emptyzones/ns1/named2.conf.in create mode 100644 bin/tests/system/emptyzones/ns1/rfc1918.zones create mode 100644 bin/tests/system/emptyzones/ns1/root.hint create mode 100644 bin/tests/system/emptyzones/setup.sh create mode 100644 bin/tests/system/emptyzones/tests.sh create mode 100644 bin/tests/system/feature-test.c create mode 100644 bin/tests/system/fetchlimit/ans4/ans.pl create mode 100644 bin/tests/system/fetchlimit/clean.sh create mode 100644 bin/tests/system/fetchlimit/ns1/named.conf.in create mode 100644 bin/tests/system/fetchlimit/ns1/root.db create mode 100644 bin/tests/system/fetchlimit/ns2/example.db create mode 100644 bin/tests/system/fetchlimit/ns2/named.conf.in create mode 100644 bin/tests/system/fetchlimit/ns3/named.args create mode 100644 bin/tests/system/fetchlimit/ns3/named1.conf.in create mode 100644 bin/tests/system/fetchlimit/ns3/named2.conf.in create mode 100644 bin/tests/system/fetchlimit/ns3/named3.conf.in create mode 100644 bin/tests/system/fetchlimit/ns3/root.hint create mode 100644 bin/tests/system/fetchlimit/prereq.sh create mode 100644 bin/tests/system/fetchlimit/setup.sh create mode 100644 bin/tests/system/fetchlimit/tests.sh create mode 100644 bin/tests/system/filter-aaaa/clean.sh create mode 100644 bin/tests/system/filter-aaaa/conf/bad1.conf create mode 100644 bin/tests/system/filter-aaaa/conf/bad2.conf create mode 100644 bin/tests/system/filter-aaaa/conf/bad3.conf create mode 100644 bin/tests/system/filter-aaaa/conf/bad4.conf create mode 100644 bin/tests/system/filter-aaaa/conf/bad5.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good1.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good2.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good3.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good4.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good5.conf create mode 100644 bin/tests/system/filter-aaaa/ns1/named1.conf.in create mode 100644 bin/tests/system/filter-aaaa/ns1/named2.conf.in create mode 100644 bin/tests/system/filter-aaaa/ns1/root.db create mode 100755 bin/tests/system/filter-aaaa/ns1/sign.sh create mode 100644 bin/tests/system/filter-aaaa/ns1/signed.db.in create mode 100644 bin/tests/system/filter-aaaa/ns1/unsigned.db create mode 100644 bin/tests/system/filter-aaaa/ns2/hints create mode 100644 bin/tests/system/filter-aaaa/ns2/named1.conf.in create mode 100644 bin/tests/system/filter-aaaa/ns2/named2.conf.in create mode 100644 bin/tests/system/filter-aaaa/ns3/hints create mode 100644 bin/tests/system/filter-aaaa/ns3/named1.conf.in create mode 100644 bin/tests/system/filter-aaaa/ns3/named2.conf.in create mode 100644 bin/tests/system/filter-aaaa/ns4/named1.conf.in create mode 100644 bin/tests/system/filter-aaaa/ns4/named2.conf.in create mode 100644 bin/tests/system/filter-aaaa/ns4/root.db create mode 100755 bin/tests/system/filter-aaaa/ns4/sign.sh create mode 100644 bin/tests/system/filter-aaaa/ns4/signed.db.in create mode 100644 bin/tests/system/filter-aaaa/ns4/unsigned.db create mode 100644 bin/tests/system/filter-aaaa/ns5/hints create mode 100644 bin/tests/system/filter-aaaa/ns5/named.conf.in create mode 100644 bin/tests/system/filter-aaaa/prereq.sh create mode 100644 bin/tests/system/filter-aaaa/setup.sh create mode 100644 bin/tests/system/filter-aaaa/tests.sh create mode 100644 bin/tests/system/formerr/clean.sh create mode 100644 bin/tests/system/formerr/formerr.pl create mode 100644 bin/tests/system/formerr/nametoolong create mode 100644 bin/tests/system/formerr/noquestions create mode 100644 bin/tests/system/formerr/ns1/named.conf.in create mode 100644 bin/tests/system/formerr/ns1/root.db create mode 100644 bin/tests/system/formerr/setup.sh create mode 100644 bin/tests/system/formerr/tests.sh create mode 100644 bin/tests/system/formerr/twoquestions create mode 100644 bin/tests/system/forward/ans11/ans.py create mode 100644 bin/tests/system/forward/ans6/ans.pl create mode 100644 bin/tests/system/forward/clean.sh create mode 100644 bin/tests/system/forward/ns1/diditwork.net.db create mode 100644 bin/tests/system/forward/ns1/example.db create mode 100644 bin/tests/system/forward/ns1/named.conf.in create mode 100644 bin/tests/system/forward/ns1/net.example.lll create mode 100644 bin/tests/system/forward/ns1/root.db.in create mode 100644 bin/tests/system/forward/ns1/sign.sh create mode 100644 bin/tests/system/forward/ns1/sld.tld.db create mode 100644 bin/tests/system/forward/ns1/spoofed.net.db create mode 100644 bin/tests/system/forward/ns1/sub.local.net.db create mode 100644 bin/tests/system/forward/ns10/fakenet.zone create mode 100644 bin/tests/system/forward/ns10/fakenet2.zone create mode 100644 bin/tests/system/forward/ns10/fakesublocalnet.zone create mode 100644 bin/tests/system/forward/ns10/fakesublocaltld.zone create mode 100644 bin/tests/system/forward/ns10/named.conf.in create mode 100644 bin/tests/system/forward/ns10/net.example.lll create mode 100644 bin/tests/system/forward/ns10/spoofednet.zone create mode 100644 bin/tests/system/forward/ns2/example.db create mode 100644 bin/tests/system/forward/ns2/named.conf.in create mode 100644 bin/tests/system/forward/ns2/root.db create mode 100644 bin/tests/system/forward/ns2/tld.db create mode 100644 bin/tests/system/forward/ns3/named1.conf.in create mode 100644 bin/tests/system/forward/ns3/named2.conf.in create mode 100644 bin/tests/system/forward/ns3/root.db create mode 100644 bin/tests/system/forward/ns4/malicious.db create mode 100644 bin/tests/system/forward/ns4/named.conf.in create mode 100644 bin/tests/system/forward/ns4/root.db create mode 100644 bin/tests/system/forward/ns4/sibling.tld.db create mode 100644 bin/tests/system/forward/ns5/named.conf.in create mode 100644 bin/tests/system/forward/ns5/rebind.db create mode 100644 bin/tests/system/forward/ns5/root.db create mode 100644 bin/tests/system/forward/ns7/named.conf.in create mode 100644 bin/tests/system/forward/ns7/root.db create mode 100644 bin/tests/system/forward/ns8/named.conf.in create mode 100644 bin/tests/system/forward/ns8/root.db create mode 100644 bin/tests/system/forward/ns8/sub.local.tld.db create mode 100644 bin/tests/system/forward/ns9/local.net.db create mode 100644 bin/tests/system/forward/ns9/local.tld.db create mode 100644 bin/tests/system/forward/ns9/named1.conf.in create mode 100644 bin/tests/system/forward/ns9/named2.conf.in create mode 100644 bin/tests/system/forward/ns9/named3.conf.in create mode 100644 bin/tests/system/forward/ns9/named4.conf.in create mode 100644 bin/tests/system/forward/ns9/root.db create mode 100644 bin/tests/system/forward/prereq.sh create mode 100644 bin/tests/system/forward/rfc1918-inherited.conf create mode 100644 bin/tests/system/forward/rfc1918-notinherited.conf create mode 100644 bin/tests/system/forward/setup.sh create mode 100644 bin/tests/system/forward/tests.sh create mode 100644 bin/tests/system/forward/ula-inherited.conf create mode 100644 bin/tests/system/forward/ula-notinherited.conf create mode 100644 bin/tests/system/fromhex.pl create mode 100644 bin/tests/system/genzone.sh create mode 100644 bin/tests/system/geoip2/clean.sh create mode 100644 bin/tests/system/geoip2/conf/bad-areacode.conf create mode 100644 bin/tests/system/geoip2/conf/bad-dbname.conf create mode 100644 bin/tests/system/geoip2/conf/bad-netspeed.conf create mode 100644 bin/tests/system/geoip2/conf/bad-regiondb.conf create mode 100644 bin/tests/system/geoip2/conf/bad-threeletter.conf create mode 100644 bin/tests/system/geoip2/conf/good-options.conf create mode 100644 bin/tests/system/geoip2/data/GeoIP2-City.json create mode 100644 bin/tests/system/geoip2/data/GeoIP2-City.mmdb create mode 100644 bin/tests/system/geoip2/data/GeoIP2-Country.json create mode 100644 bin/tests/system/geoip2/data/GeoIP2-Country.mmdb create mode 100644 bin/tests/system/geoip2/data/GeoIP2-Domain.json create mode 100644 bin/tests/system/geoip2/data/GeoIP2-Domain.mmdb create mode 100644 bin/tests/system/geoip2/data/GeoIP2-ISP.json create mode 100644 bin/tests/system/geoip2/data/GeoIP2-ISP.mmdb create mode 100644 bin/tests/system/geoip2/data/GeoLite2-ASN.json create mode 100644 bin/tests/system/geoip2/data/GeoLite2-ASN.mmdb create mode 100644 bin/tests/system/geoip2/data/README.md create mode 100755 bin/tests/system/geoip2/data/write-test-data.pl create mode 100644 bin/tests/system/geoip2/ns2/example.db.in create mode 100644 bin/tests/system/geoip2/ns2/named1.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named10.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named11.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named12.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named2.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named3.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named4.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named5.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named6.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named7.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named8.conf.in create mode 100644 bin/tests/system/geoip2/ns2/named9.conf.in create mode 100644 bin/tests/system/geoip2/prereq.sh create mode 100644 bin/tests/system/geoip2/setup.sh create mode 100644 bin/tests/system/geoip2/tests.sh create mode 100755 bin/tests/system/get_algorithms.py create mode 100644 bin/tests/system/glue/clean.sh create mode 100644 bin/tests/system/glue/fi.good create mode 100644 bin/tests/system/glue/noglue.good create mode 100644 bin/tests/system/glue/ns1/named.conf.in create mode 100644 bin/tests/system/glue/ns1/net.db create mode 100644 bin/tests/system/glue/ns1/root-servers.nil.db create mode 100644 bin/tests/system/glue/ns1/root.db create mode 100644 bin/tests/system/glue/setup.sh create mode 100644 bin/tests/system/glue/tests.sh create mode 100644 bin/tests/system/idna/clean.sh create mode 100644 bin/tests/system/idna/ns1/named.conf.in create mode 100644 bin/tests/system/idna/ns1/root.db create mode 100644 bin/tests/system/idna/setup.sh create mode 100644 bin/tests/system/idna/tests.sh create mode 100644 bin/tests/system/ifconfig.bat create mode 100755 bin/tests/system/ifconfig.sh create mode 100644 bin/tests/system/inline/clean.sh create mode 100644 bin/tests/system/inline/ns1/named.conf.in create mode 100644 bin/tests/system/inline/ns1/root.db.in create mode 100644 bin/tests/system/inline/ns1/sign.sh create mode 100644 bin/tests/system/inline/ns2/bits.db.in create mode 100644 bin/tests/system/inline/ns2/named.conf.in create mode 100644 bin/tests/system/inline/ns2/nsec3-loop.db.in create mode 100644 bin/tests/system/inline/ns3/include.db.in create mode 100644 bin/tests/system/inline/ns3/master.db.in create mode 100644 bin/tests/system/inline/ns3/master2.db.in create mode 100644 bin/tests/system/inline/ns3/master3.db.in create mode 100644 bin/tests/system/inline/ns3/master4.db.in create mode 100644 bin/tests/system/inline/ns3/master5.db.in create mode 100644 bin/tests/system/inline/ns3/master6.db.in create mode 100644 bin/tests/system/inline/ns3/master7.db.in create mode 100644 bin/tests/system/inline/ns3/named.conf.in create mode 100755 bin/tests/system/inline/ns3/sign.sh create mode 100644 bin/tests/system/inline/ns4/named.conf.in create mode 100644 bin/tests/system/inline/ns4/noixfr.db.in create mode 100644 bin/tests/system/inline/ns5/named.conf.post create mode 100644 bin/tests/system/inline/ns5/named.conf.pre create mode 100644 bin/tests/system/inline/ns6/named.conf.in create mode 100644 bin/tests/system/inline/ns7/named.conf.in create mode 100755 bin/tests/system/inline/ns7/sign.sh create mode 100644 bin/tests/system/inline/ns8/example.com.db.in create mode 100644 bin/tests/system/inline/ns8/example.db.in create mode 100644 bin/tests/system/inline/ns8/example2.db.in create mode 100644 bin/tests/system/inline/ns8/example3.db.in create mode 100644 bin/tests/system/inline/ns8/named.conf.in create mode 100755 bin/tests/system/inline/ns8/sign.sh create mode 100644 bin/tests/system/inline/setup.sh create mode 100755 bin/tests/system/inline/tests.sh create mode 100755 bin/tests/system/inline/tests_signed_zone_files.py create mode 100644 bin/tests/system/integrity/clean.sh create mode 100644 bin/tests/system/integrity/ns1/mx-cname.db create mode 100644 bin/tests/system/integrity/ns1/named.conf.in create mode 100644 bin/tests/system/integrity/ns1/srv-cname.db create mode 100644 bin/tests/system/integrity/setup.sh create mode 100644 bin/tests/system/integrity/tests.sh create mode 100644 bin/tests/system/ixfr/ans2/startme create mode 100644 bin/tests/system/ixfr/clean.sh create mode 100644 bin/tests/system/ixfr/ixfr-stats.good create mode 100644 bin/tests/system/ixfr/ns1/named.conf.in create mode 100644 bin/tests/system/ixfr/ns1/startme create mode 100644 bin/tests/system/ixfr/ns3/named.conf.in create mode 100644 bin/tests/system/ixfr/ns4/named.conf.in create mode 100644 bin/tests/system/ixfr/ns5/named.conf.in create mode 100644 bin/tests/system/ixfr/prereq.sh create mode 100644 bin/tests/system/ixfr/setup.sh create mode 100644 bin/tests/system/ixfr/tests.sh create mode 100644 bin/tests/system/journal/clean.sh create mode 100644 bin/tests/system/journal/ns1/changed.ver1.jnl.saved create mode 100644 bin/tests/system/journal/ns1/changed.ver2.jnl.saved create mode 100644 bin/tests/system/journal/ns1/d1212.jnl.saved create mode 100644 bin/tests/system/journal/ns1/d2121.jnl.saved create mode 100644 bin/tests/system/journal/ns1/generic.db.in create mode 100644 bin/tests/system/journal/ns1/ixfr.db.in create mode 100644 bin/tests/system/journal/ns1/ixfr.ver1.jnl.saved create mode 100644 bin/tests/system/journal/ns1/managed-keys.bind.in create mode 100644 bin/tests/system/journal/ns1/managed-keys.bind.jnl.in create mode 100644 bin/tests/system/journal/ns1/maxjournal.jnl.saved create mode 100644 bin/tests/system/journal/ns1/maxjournal2.jnl.saved create mode 100644 bin/tests/system/journal/ns1/named.conf.in create mode 100644 bin/tests/system/journal/ns1/unchanged.ver1.jnl.saved create mode 100644 bin/tests/system/journal/ns1/unchanged.ver2.jnl.saved create mode 100644 bin/tests/system/journal/ns2/managed-keys.bind.in create mode 100644 bin/tests/system/journal/ns2/managed-keys.bind.jnl.in create mode 100644 bin/tests/system/journal/ns2/named.conf.in create mode 100644 bin/tests/system/journal/setup.sh create mode 100644 bin/tests/system/journal/tests.sh create mode 100644 bin/tests/system/kasp.sh create mode 100644 bin/tests/system/kasp/README create mode 100644 bin/tests/system/kasp/clean.sh create mode 100644 bin/tests/system/kasp/kasp.conf create mode 100644 bin/tests/system/kasp/ns2/named.conf.in create mode 100644 bin/tests/system/kasp/ns2/secondary.kasp.db.in create mode 100644 bin/tests/system/kasp/ns2/secondary.kasp.db.in2 create mode 100644 bin/tests/system/kasp/ns2/setup.sh create mode 100644 bin/tests/system/kasp/ns2/template.tld.db.in create mode 100644 bin/tests/system/kasp/ns3/ed25519.conf create mode 100644 bin/tests/system/kasp/ns3/ed448.conf create mode 100644 bin/tests/system/kasp/ns3/named-fips.conf.in create mode 100644 bin/tests/system/kasp/ns3/named.conf.in create mode 100644 bin/tests/system/kasp/ns3/policies/autosign.conf.in create mode 100644 bin/tests/system/kasp/ns3/policies/kasp-fips.conf.in create mode 100644 bin/tests/system/kasp/ns3/policies/kasp.conf.in create mode 100644 bin/tests/system/kasp/ns3/setup.sh create mode 100644 bin/tests/system/kasp/ns3/template.db.in create mode 100644 bin/tests/system/kasp/ns3/template2.db.in create mode 100644 bin/tests/system/kasp/ns4/example1.db.in create mode 100644 bin/tests/system/kasp/ns4/example2.db.in create mode 100644 bin/tests/system/kasp/ns4/named.conf.in create mode 100644 bin/tests/system/kasp/ns4/setup.sh create mode 100644 bin/tests/system/kasp/ns4/template.db.in create mode 100644 bin/tests/system/kasp/ns5/named.conf.in create mode 100644 bin/tests/system/kasp/ns5/setup.sh create mode 100644 bin/tests/system/kasp/ns5/template.db.in create mode 100644 bin/tests/system/kasp/ns6/example.db.in create mode 100644 bin/tests/system/kasp/ns6/example2.db.in create mode 100644 bin/tests/system/kasp/ns6/example3.db.in create mode 100644 bin/tests/system/kasp/ns6/named.conf.in create mode 100644 bin/tests/system/kasp/ns6/named2.conf.in create mode 100644 bin/tests/system/kasp/ns6/policies/csk1.conf.in create mode 100644 bin/tests/system/kasp/ns6/policies/csk2.conf.in create mode 100644 bin/tests/system/kasp/ns6/policies/kasp-fips.conf.in create mode 100644 bin/tests/system/kasp/ns6/policies/kasp.conf.in create mode 100644 bin/tests/system/kasp/ns6/setup.sh create mode 100644 bin/tests/system/kasp/ns6/template.db.in create mode 100644 bin/tests/system/kasp/prereq.sh create mode 100644 bin/tests/system/kasp/setup.sh create mode 100644 bin/tests/system/kasp/tests.sh create mode 100644 bin/tests/system/keepalive/clean.sh create mode 100644 bin/tests/system/keepalive/expected create mode 100644 bin/tests/system/keepalive/ns1/named.conf.in create mode 100644 bin/tests/system/keepalive/ns1/root.db create mode 100644 bin/tests/system/keepalive/ns2/example.db create mode 100644 bin/tests/system/keepalive/ns2/named.conf.in create mode 100644 bin/tests/system/keepalive/ns3/named.conf.in create mode 100644 bin/tests/system/keepalive/setup.sh create mode 100644 bin/tests/system/keepalive/tests.sh create mode 100644 bin/tests/system/keymgr/01-ksk-inactive/README create mode 100644 bin/tests/system/keymgr/01-ksk-inactive/expect create mode 100644 bin/tests/system/keymgr/02-zsk-inactive/README create mode 100644 bin/tests/system/keymgr/02-zsk-inactive/expect create mode 100644 bin/tests/system/keymgr/03-ksk-unpublished/README create mode 100644 bin/tests/system/keymgr/03-ksk-unpublished/expect create mode 100644 bin/tests/system/keymgr/04-zsk-unpublished/README create mode 100644 bin/tests/system/keymgr/04-zsk-unpublished/expect create mode 100644 bin/tests/system/keymgr/05-ksk-unpub-active/README create mode 100644 bin/tests/system/keymgr/05-ksk-unpub-active/expect create mode 100644 bin/tests/system/keymgr/06-zsk-unpub-active/README create mode 100644 bin/tests/system/keymgr/06-zsk-unpub-active/expect create mode 100644 bin/tests/system/keymgr/07-ksk-ttl/README create mode 100644 bin/tests/system/keymgr/07-ksk-ttl/expect create mode 100644 bin/tests/system/keymgr/08-zsk-ttl/README create mode 100644 bin/tests/system/keymgr/08-zsk-ttl/expect create mode 100644 bin/tests/system/keymgr/09-no-keys/README create mode 100644 bin/tests/system/keymgr/09-no-keys/expect create mode 100644 bin/tests/system/keymgr/10-change-roll/README create mode 100644 bin/tests/system/keymgr/10-change-roll/expect create mode 100644 bin/tests/system/keymgr/11-many-simul/README create mode 100644 bin/tests/system/keymgr/11-many-simul/expect create mode 100644 bin/tests/system/keymgr/12-many-active/README create mode 100644 bin/tests/system/keymgr/12-many-active/expect create mode 100644 bin/tests/system/keymgr/13-noroll/README create mode 100644 bin/tests/system/keymgr/13-noroll/expect create mode 100644 bin/tests/system/keymgr/14-wrongalg/README create mode 100644 bin/tests/system/keymgr/14-wrongalg/expect create mode 100644 bin/tests/system/keymgr/15-unspec/README create mode 100644 bin/tests/system/keymgr/15-unspec/expect create mode 100644 bin/tests/system/keymgr/16-wrongalg-unspec/README create mode 100644 bin/tests/system/keymgr/16-wrongalg-unspec/expect create mode 100644 bin/tests/system/keymgr/17-noforce/README create mode 100644 bin/tests/system/keymgr/17-noforce/expect create mode 100644 bin/tests/system/keymgr/18-nonstd-prepub/README create mode 100644 bin/tests/system/keymgr/18-nonstd-prepub/expect create mode 100644 bin/tests/system/keymgr/18-nonstd-prepub/policy.conf.in create mode 100644 bin/tests/system/keymgr/19-old-keys/README create mode 100644 bin/tests/system/keymgr/19-old-keys/expect create mode 100644 bin/tests/system/keymgr/19-old-keys/extra.sh create mode 100644 bin/tests/system/keymgr/19-old-keys/policy.conf.in create mode 100644 bin/tests/system/keymgr/clean.sh create mode 100644 bin/tests/system/keymgr/policy.conf.in create mode 100644 bin/tests/system/keymgr/policy.good create mode 100644 bin/tests/system/keymgr/policy.sample create mode 100644 bin/tests/system/keymgr/setup.sh create mode 100644 bin/tests/system/keymgr/testpolicy.py create mode 100644 bin/tests/system/keymgr/tests.sh create mode 100644 bin/tests/system/keymgr2kasp/README create mode 100644 bin/tests/system/keymgr2kasp/clean.sh create mode 100644 bin/tests/system/keymgr2kasp/ns3/kasp.conf.in create mode 100644 bin/tests/system/keymgr2kasp/ns3/named.conf.in create mode 100644 bin/tests/system/keymgr2kasp/ns3/named2.conf.in create mode 100644 bin/tests/system/keymgr2kasp/ns3/setup.sh create mode 100644 bin/tests/system/keymgr2kasp/ns3/template.db.in create mode 100644 bin/tests/system/keymgr2kasp/ns4/named.conf.in create mode 100644 bin/tests/system/keymgr2kasp/ns4/named2.conf.in create mode 100644 bin/tests/system/keymgr2kasp/ns4/setup.sh create mode 100644 bin/tests/system/keymgr2kasp/ns4/template.ext.db.in create mode 100644 bin/tests/system/keymgr2kasp/ns4/template.int.db.in create mode 100644 bin/tests/system/keymgr2kasp/setup.sh create mode 100644 bin/tests/system/keymgr2kasp/tests.sh create mode 100644 bin/tests/system/legacy/build.sh create mode 100644 bin/tests/system/legacy/clean.sh create mode 100644 bin/tests/system/legacy/ns1/named1.conf.in create mode 100644 bin/tests/system/legacy/ns1/named2.conf.in create mode 100644 bin/tests/system/legacy/ns1/root.db create mode 100644 bin/tests/system/legacy/ns1/trusted.conf create mode 100644 bin/tests/system/legacy/ns10/ednsrefused.db create mode 100644 bin/tests/system/legacy/ns10/named.conf.in create mode 100644 bin/tests/system/legacy/ns10/named.ednsrefused create mode 100644 bin/tests/system/legacy/ns2/dropedns.db create mode 100644 bin/tests/system/legacy/ns2/named.conf.in create mode 100644 bin/tests/system/legacy/ns2/named.dropedns create mode 100644 bin/tests/system/legacy/ns3/dropedns-notcp.db create mode 100644 bin/tests/system/legacy/ns3/named.conf.in create mode 100644 bin/tests/system/legacy/ns3/named.dropedns create mode 100644 bin/tests/system/legacy/ns3/named.notcp create mode 100644 bin/tests/system/legacy/ns4/named.args create mode 100644 bin/tests/system/legacy/ns4/named.conf.in create mode 100644 bin/tests/system/legacy/ns4/plain.db create mode 100644 bin/tests/system/legacy/ns5/named.args create mode 100644 bin/tests/system/legacy/ns5/named.conf.in create mode 100644 bin/tests/system/legacy/ns5/named.notcp create mode 100644 bin/tests/system/legacy/ns5/plain-notcp.db create mode 100644 bin/tests/system/legacy/ns6/edns512.db.in create mode 100644 bin/tests/system/legacy/ns6/edns512.db.signed create mode 100644 bin/tests/system/legacy/ns6/named.args create mode 100644 bin/tests/system/legacy/ns6/named.conf.in create mode 100755 bin/tests/system/legacy/ns6/sign.sh create mode 100644 bin/tests/system/legacy/ns7/edns512-notcp.db.in create mode 100644 bin/tests/system/legacy/ns7/edns512-notcp.db.signed create mode 100644 bin/tests/system/legacy/ns7/named.args create mode 100644 bin/tests/system/legacy/ns7/named.conf.in create mode 100644 bin/tests/system/legacy/ns7/named.notcp create mode 100755 bin/tests/system/legacy/ns7/sign.sh create mode 100644 bin/tests/system/legacy/ns8/ednsformerr.db create mode 100644 bin/tests/system/legacy/ns8/named.conf.in create mode 100644 bin/tests/system/legacy/ns8/named.ednsformerr create mode 100644 bin/tests/system/legacy/ns9/ednsnotimp.db create mode 100644 bin/tests/system/legacy/ns9/named.conf.in create mode 100644 bin/tests/system/legacy/ns9/named.ednsnotimp create mode 100644 bin/tests/system/legacy/setup.sh create mode 100755 bin/tests/system/legacy/tests.sh create mode 100644 bin/tests/system/limits/clean.sh create mode 100644 bin/tests/system/limits/knowngood.dig.out.1000 create mode 100644 bin/tests/system/limits/knowngood.dig.out.2000 create mode 100644 bin/tests/system/limits/knowngood.dig.out.3000 create mode 100644 bin/tests/system/limits/knowngood.dig.out.4000 create mode 100644 bin/tests/system/limits/knowngood.dig.out.a-maximum-rrset create mode 100644 bin/tests/system/limits/ns1/example.db create mode 100644 bin/tests/system/limits/ns1/named.conf.in create mode 100644 bin/tests/system/limits/ns1/root.db create mode 100644 bin/tests/system/limits/setup.sh create mode 100644 bin/tests/system/limits/tests.sh create mode 100644 bin/tests/system/logfileconfig/clean.sh create mode 100644 bin/tests/system/logfileconfig/named1.args create mode 100644 bin/tests/system/logfileconfig/named2.args create mode 100644 bin/tests/system/logfileconfig/ns1/named.dirconf.in create mode 100644 bin/tests/system/logfileconfig/ns1/named.iso8601-utc.in create mode 100644 bin/tests/system/logfileconfig/ns1/named.iso8601.in create mode 100644 bin/tests/system/logfileconfig/ns1/named.pipeconf.in create mode 100644 bin/tests/system/logfileconfig/ns1/named.plain.in create mode 100644 bin/tests/system/logfileconfig/ns1/named.plainconf.in create mode 100644 bin/tests/system/logfileconfig/ns1/named.symconf.in create mode 100644 bin/tests/system/logfileconfig/ns1/named.tsconf.in create mode 100644 bin/tests/system/logfileconfig/ns1/named.unlimited.in create mode 100644 bin/tests/system/logfileconfig/ns1/named.versconf.in create mode 100644 bin/tests/system/logfileconfig/setup.sh create mode 100644 bin/tests/system/logfileconfig/tests.sh create mode 100644 bin/tests/system/masterfile/clean.sh create mode 100644 bin/tests/system/masterfile/knowngood.dig.out create mode 100644 bin/tests/system/masterfile/ns1/include.db create mode 100644 bin/tests/system/masterfile/ns1/named.conf.in create mode 100644 bin/tests/system/masterfile/ns1/sub.db create mode 100644 bin/tests/system/masterfile/ns1/ttl1.db create mode 100644 bin/tests/system/masterfile/ns1/ttl2.db create mode 100644 bin/tests/system/masterfile/ns2/example.db create mode 100644 bin/tests/system/masterfile/ns2/named.conf.in create mode 100644 bin/tests/system/masterfile/setup.sh create mode 100644 bin/tests/system/masterfile/tests.sh create mode 100644 bin/tests/system/masterfile/zone/inheritownerafterinclude.db create mode 100644 bin/tests/system/masterfile/zone/inheritownerafterinclude.good create mode 100644 bin/tests/system/masterfile/zone/nameservers.db create mode 100755 bin/tests/system/masterformat/clean.sh create mode 100755 bin/tests/system/masterformat/ns1/compile.sh create mode 100644 bin/tests/system/masterformat/ns1/example.db create mode 100644 bin/tests/system/masterformat/ns1/large.db.in create mode 100644 bin/tests/system/masterformat/ns1/named.conf.in create mode 100644 bin/tests/system/masterformat/ns1/signed.db create mode 100644 bin/tests/system/masterformat/ns2/formerly-text.db.in create mode 100644 bin/tests/system/masterformat/ns2/named.conf.in create mode 100644 bin/tests/system/masterformat/ns3/named.conf.in create mode 100755 bin/tests/system/masterformat/setup.sh create mode 100755 bin/tests/system/masterformat/tests.sh create mode 100644 bin/tests/system/metadata/child.db create mode 100644 bin/tests/system/metadata/clean.sh create mode 100644 bin/tests/system/metadata/parent.db create mode 100644 bin/tests/system/metadata/setup.sh create mode 100644 bin/tests/system/metadata/tests.sh create mode 100644 bin/tests/system/mirror/README create mode 100644 bin/tests/system/mirror/clean.sh create mode 100644 bin/tests/system/mirror/ns1/named.conf.in create mode 100644 bin/tests/system/mirror/ns1/root.db.in create mode 100644 bin/tests/system/mirror/ns1/sign.sh create mode 100644 bin/tests/system/mirror/ns2/example.db.in create mode 100644 bin/tests/system/mirror/ns2/initially-unavailable.db.in create mode 100644 bin/tests/system/mirror/ns2/named.conf.in create mode 100644 bin/tests/system/mirror/ns2/sign.sh create mode 100644 bin/tests/system/mirror/ns2/sub.example.db.in create mode 100644 bin/tests/system/mirror/ns2/verify.db.in create mode 100644 bin/tests/system/mirror/ns3/named.args create mode 100644 bin/tests/system/mirror/ns3/named.conf.in create mode 100644 bin/tests/system/mirror/setup.sh create mode 100644 bin/tests/system/mirror/tests.sh create mode 100644 bin/tests/system/mkeys/README create mode 100644 bin/tests/system/mkeys/clean.sh create mode 100644 bin/tests/system/mkeys/ns1/named1.conf.in create mode 100644 bin/tests/system/mkeys/ns1/named2.conf.in create mode 100644 bin/tests/system/mkeys/ns1/named3.conf.in create mode 100644 bin/tests/system/mkeys/ns1/root.db create mode 100644 bin/tests/system/mkeys/ns1/sign.sh create mode 100644 bin/tests/system/mkeys/ns1/sub.tld.db create mode 100644 bin/tests/system/mkeys/ns1/tld.db create mode 100644 bin/tests/system/mkeys/ns1/unsupported.key create mode 100644 bin/tests/system/mkeys/ns2/named.args create mode 100644 bin/tests/system/mkeys/ns2/named.conf.in create mode 100644 bin/tests/system/mkeys/ns3/named.args create mode 100644 bin/tests/system/mkeys/ns3/named.conf.in create mode 100644 bin/tests/system/mkeys/ns4/named.conf.in create mode 100644 bin/tests/system/mkeys/ns4/sign.sh create mode 100644 bin/tests/system/mkeys/ns4/sub.foo.db create mode 100644 bin/tests/system/mkeys/ns5/foo.db create mode 100644 bin/tests/system/mkeys/ns5/named.conf.in create mode 100644 bin/tests/system/mkeys/ns5/named1.args create mode 100644 bin/tests/system/mkeys/ns5/named2.args create mode 100644 bin/tests/system/mkeys/ns6/named.args create mode 100644 bin/tests/system/mkeys/ns6/named.conf.in create mode 100644 bin/tests/system/mkeys/ns6/setup.sh create mode 100644 bin/tests/system/mkeys/ns6/unsupported-managed.key create mode 100644 bin/tests/system/mkeys/ns7/named.conf.in create mode 100644 bin/tests/system/mkeys/setup.sh create mode 100644 bin/tests/system/mkeys/tests.sh create mode 100644 bin/tests/system/names/clean.sh create mode 100644 bin/tests/system/names/ns1/example.db create mode 100644 bin/tests/system/names/ns1/named.conf.in create mode 100644 bin/tests/system/names/setup.sh create mode 100644 bin/tests/system/names/tests.sh create mode 100644 bin/tests/system/notify/clean.sh create mode 100644 bin/tests/system/notify/ns1/named.conf.in create mode 100644 bin/tests/system/notify/ns1/root.db create mode 100644 bin/tests/system/notify/ns2/example1.db create mode 100644 bin/tests/system/notify/ns2/example2.db create mode 100644 bin/tests/system/notify/ns2/example3.db create mode 100644 bin/tests/system/notify/ns2/example4.db create mode 100644 bin/tests/system/notify/ns2/generic.db create mode 100644 bin/tests/system/notify/ns2/named.conf.in create mode 100644 bin/tests/system/notify/ns3/named.conf.in create mode 100644 bin/tests/system/notify/ns4/named.conf.in create mode 100644 bin/tests/system/notify/ns4/named.port.in create mode 100644 bin/tests/system/notify/ns5/named.conf.in create mode 100644 bin/tests/system/notify/ns5/x21.db create mode 100644 bin/tests/system/notify/setup.sh create mode 100644 bin/tests/system/notify/tests.sh create mode 100644 bin/tests/system/nsec3/clean.sh create mode 100644 bin/tests/system/nsec3/ns2/named.conf.in create mode 100644 bin/tests/system/nsec3/ns2/setup.sh create mode 100644 bin/tests/system/nsec3/ns2/template.db.in create mode 100644 bin/tests/system/nsec3/ns3/named.conf.in create mode 100644 bin/tests/system/nsec3/ns3/named2.conf.in create mode 100644 bin/tests/system/nsec3/ns3/nsec3-fails-to-load.kasp.db.in create mode 100644 bin/tests/system/nsec3/ns3/setup.sh create mode 100644 bin/tests/system/nsec3/ns3/template.db.in create mode 100644 bin/tests/system/nsec3/setup.sh create mode 100644 bin/tests/system/nsec3/tests.sh create mode 100644 bin/tests/system/nslookup/clean.sh create mode 100644 bin/tests/system/nslookup/ns1/example.net.db create mode 100644 bin/tests/system/nslookup/ns1/named.conf.in create mode 100644 bin/tests/system/nslookup/setup.sh create mode 100644 bin/tests/system/nslookup/tests.sh create mode 100644 bin/tests/system/nsupdate/ans4/ans.pl create mode 100644 bin/tests/system/nsupdate/clean.sh create mode 100644 bin/tests/system/nsupdate/commandlist create mode 100644 bin/tests/system/nsupdate/knowngood.ns1.after create mode 100644 bin/tests/system/nsupdate/knowngood.ns1.afterstop create mode 100644 bin/tests/system/nsupdate/knowngood.ns1.before create mode 100644 bin/tests/system/nsupdate/krb/setup.sh create mode 100644 bin/tests/system/nsupdate/ns1/example1.db create mode 100644 bin/tests/system/nsupdate/ns1/many.test.db.in create mode 100644 bin/tests/system/nsupdate/ns1/max-ttl.db create mode 100644 bin/tests/system/nsupdate/ns1/maxjournal.db.in create mode 100644 bin/tests/system/nsupdate/ns1/named.conf.in create mode 100644 bin/tests/system/nsupdate/ns1/sample.db.in create mode 100644 bin/tests/system/nsupdate/ns10/dns.keytab create mode 100644 bin/tests/system/nsupdate/ns10/example.com.db.in create mode 100644 bin/tests/system/nsupdate/ns10/in-addr.db.in create mode 100644 bin/tests/system/nsupdate/ns10/machine.ccache create mode 100644 bin/tests/system/nsupdate/ns10/named.conf.in create mode 100644 bin/tests/system/nsupdate/ns2/named.conf.in create mode 100644 bin/tests/system/nsupdate/ns2/sample.db.in create mode 100644 bin/tests/system/nsupdate/ns3/delegation.test.db.in create mode 100644 bin/tests/system/nsupdate/ns3/dnskey.test.db.in create mode 100644 bin/tests/system/nsupdate/ns3/example.db.in create mode 100644 bin/tests/system/nsupdate/ns3/multisigner.test.db.in create mode 100644 bin/tests/system/nsupdate/ns3/named.conf.in create mode 100644 bin/tests/system/nsupdate/ns3/nsec3param.test.db.in create mode 100644 bin/tests/system/nsupdate/ns3/sign.sh create mode 100644 bin/tests/system/nsupdate/ns3/too-big.test.db.in create mode 100644 bin/tests/system/nsupdate/ns5/local.db.in create mode 100644 bin/tests/system/nsupdate/ns5/named.args create mode 100644 bin/tests/system/nsupdate/ns5/named.conf.in create mode 100644 bin/tests/system/nsupdate/ns6/in-addr.db.in create mode 100644 bin/tests/system/nsupdate/ns6/named.args create mode 100644 bin/tests/system/nsupdate/ns6/named.conf.in create mode 100644 bin/tests/system/nsupdate/ns7/dns.keytab create mode 100644 bin/tests/system/nsupdate/ns7/example.com.db.in create mode 100644 bin/tests/system/nsupdate/ns7/in-addr.db.in create mode 100644 bin/tests/system/nsupdate/ns7/machine.ccache create mode 100644 bin/tests/system/nsupdate/ns7/named.conf.in create mode 100644 bin/tests/system/nsupdate/ns8/dns-other-than-KRB5_KTNAME.keytab create mode 100644 bin/tests/system/nsupdate/ns8/example.com.db.in create mode 100644 bin/tests/system/nsupdate/ns8/in-addr.db.in create mode 100644 bin/tests/system/nsupdate/ns8/machine.ccache create mode 100644 bin/tests/system/nsupdate/ns8/named.conf.in create mode 100644 bin/tests/system/nsupdate/ns9/dns.keytab create mode 100644 bin/tests/system/nsupdate/ns9/example.com.db.in create mode 100644 bin/tests/system/nsupdate/ns9/in-addr.db.in create mode 100644 bin/tests/system/nsupdate/ns9/machine.ccache create mode 100644 bin/tests/system/nsupdate/ns9/named.conf.in create mode 100644 bin/tests/system/nsupdate/prereq.sh create mode 100644 bin/tests/system/nsupdate/setup.sh create mode 100755 bin/tests/system/nsupdate/tests.sh create mode 100644 bin/tests/system/nsupdate/update_test.pl create mode 100644 bin/tests/system/nsupdate/verylarge.in create mode 100644 bin/tests/system/nzd2nzf/clean.sh create mode 100644 bin/tests/system/nzd2nzf/ns1/added.db create mode 100644 bin/tests/system/nzd2nzf/ns1/named.conf.in create mode 100644 bin/tests/system/nzd2nzf/prereq.sh create mode 100644 bin/tests/system/nzd2nzf/setup.sh create mode 100644 bin/tests/system/nzd2nzf/tests.sh create mode 100644 bin/tests/system/org.isc.bind.system create mode 100644 bin/tests/system/org.isc.bind.system.plist create mode 100644 bin/tests/system/packet.pl create mode 100644 bin/tests/system/padding/clean.sh create mode 100644 bin/tests/system/padding/ns1/named.conf.in create mode 100644 bin/tests/system/padding/ns1/root.db create mode 100644 bin/tests/system/padding/ns2/example.db create mode 100644 bin/tests/system/padding/ns2/named.conf.in create mode 100644 bin/tests/system/padding/ns3/named.conf.in create mode 100644 bin/tests/system/padding/ns4/named.conf.in create mode 100644 bin/tests/system/padding/setup.sh create mode 100644 bin/tests/system/padding/tests.sh create mode 100644 bin/tests/system/parallel.sh create mode 100644 bin/tests/system/pending/clean.sh create mode 100644 bin/tests/system/pending/ns1/named.conf.in create mode 100644 bin/tests/system/pending/ns1/root.db.in create mode 100644 bin/tests/system/pending/ns1/sign.sh create mode 100644 bin/tests/system/pending/ns2/example.com.db.in create mode 100644 bin/tests/system/pending/ns2/example.db.in create mode 100644 bin/tests/system/pending/ns2/forgery.db create mode 100644 bin/tests/system/pending/ns2/named.conf.in create mode 100644 bin/tests/system/pending/ns2/sign.sh create mode 100644 bin/tests/system/pending/ns3/hostile.db create mode 100644 bin/tests/system/pending/ns3/mail.example.db create mode 100644 bin/tests/system/pending/ns3/named.conf.in create mode 100644 bin/tests/system/pending/ns4/named.conf.in create mode 100644 bin/tests/system/pending/setup.sh create mode 100644 bin/tests/system/pending/tests.sh create mode 100644 bin/tests/system/pipelined/Makefile.in create mode 100644 bin/tests/system/pipelined/ans5/ans.py create mode 100644 bin/tests/system/pipelined/clean.sh create mode 100644 bin/tests/system/pipelined/input create mode 100644 bin/tests/system/pipelined/inputb create mode 100644 bin/tests/system/pipelined/ns1/named.conf.in create mode 100644 bin/tests/system/pipelined/ns1/root.db create mode 100644 bin/tests/system/pipelined/ns2/examplea.db create mode 100644 bin/tests/system/pipelined/ns2/named.conf.in create mode 100644 bin/tests/system/pipelined/ns3/exampleb.db create mode 100644 bin/tests/system/pipelined/ns3/named.conf.in create mode 100644 bin/tests/system/pipelined/ns4/named.conf.in create mode 100644 bin/tests/system/pipelined/pipequeries.c create mode 100644 bin/tests/system/pipelined/prereq.sh create mode 100644 bin/tests/system/pipelined/ref create mode 100644 bin/tests/system/pipelined/refb create mode 100644 bin/tests/system/pipelined/setup.sh create mode 100644 bin/tests/system/pipelined/tests.sh create mode 100644 bin/tests/system/pkcs11/2037-pk11_numbits-crash-test.pkt create mode 100644 bin/tests/system/pkcs11/clean.sh create mode 100644 bin/tests/system/pkcs11/ns1/example.db.in create mode 100644 bin/tests/system/pkcs11/ns1/named.conf.in create mode 100644 bin/tests/system/pkcs11/setup.sh create mode 100644 bin/tests/system/pkcs11/tests.sh create mode 100644 bin/tests/system/pkcs11/usepkcs11 create mode 100644 bin/tests/system/pytest_custom_markers.py create mode 100755 bin/tests/system/qmin/ans2/ans.py create mode 100755 bin/tests/system/qmin/ans3/ans.py create mode 100755 bin/tests/system/qmin/ans4/ans.py create mode 100644 bin/tests/system/qmin/clean.sh create mode 100644 bin/tests/system/qmin/ns1/named.conf.in create mode 100644 bin/tests/system/qmin/ns1/root.db create mode 100644 bin/tests/system/qmin/ns5/named.conf.in create mode 100644 bin/tests/system/qmin/ns6/named.conf.in create mode 100644 bin/tests/system/qmin/ns7/named.conf.in create mode 100644 bin/tests/system/qmin/prereq.sh create mode 100644 bin/tests/system/qmin/setup.sh create mode 100755 bin/tests/system/qmin/tests.sh create mode 100644 bin/tests/system/reclimit/README create mode 100644 bin/tests/system/reclimit/ans2/ans.pl create mode 100644 bin/tests/system/reclimit/ans4/ans.pl create mode 100644 bin/tests/system/reclimit/ans7/ans.pl create mode 100644 bin/tests/system/reclimit/clean.sh create mode 100644 bin/tests/system/reclimit/ns1/named.conf.in create mode 100644 bin/tests/system/reclimit/ns1/root.db create mode 100644 bin/tests/system/reclimit/ns3/hints.db create mode 100644 bin/tests/system/reclimit/ns3/named1.conf.in create mode 100644 bin/tests/system/reclimit/ns3/named2.conf.in create mode 100644 bin/tests/system/reclimit/ns3/named3.conf.in create mode 100644 bin/tests/system/reclimit/ns3/named4.conf.in create mode 100644 bin/tests/system/reclimit/prereq.sh create mode 100644 bin/tests/system/reclimit/setup.sh create mode 100644 bin/tests/system/reclimit/tests.sh create mode 100644 bin/tests/system/redirect/clean.sh create mode 100644 bin/tests/system/redirect/conf/bad1.conf create mode 100644 bin/tests/system/redirect/conf/bad2.conf create mode 100644 bin/tests/system/redirect/conf/bad3.conf create mode 100644 bin/tests/system/redirect/conf/good1.conf create mode 100644 bin/tests/system/redirect/conf/good2.conf create mode 100644 bin/tests/system/redirect/conf/good3.conf create mode 100644 bin/tests/system/redirect/conf/good4.conf create mode 100644 bin/tests/system/redirect/ns1/example.db create mode 100644 bin/tests/system/redirect/ns1/named.conf.in create mode 100644 bin/tests/system/redirect/ns1/redirect.db create mode 100644 bin/tests/system/redirect/ns1/root.db create mode 100644 bin/tests/system/redirect/ns1/sign.sh create mode 100644 bin/tests/system/redirect/ns2/example.db.in create mode 100644 bin/tests/system/redirect/ns2/named.conf.in create mode 100644 bin/tests/system/redirect/ns2/redirect.db.in create mode 100644 bin/tests/system/redirect/ns3/example.db create mode 100644 bin/tests/system/redirect/ns3/named.conf.in create mode 100644 bin/tests/system/redirect/ns3/redirect.db create mode 100644 bin/tests/system/redirect/ns3/root.db create mode 100644 bin/tests/system/redirect/ns3/sign.sh create mode 100644 bin/tests/system/redirect/ns4/example.db.in create mode 100644 bin/tests/system/redirect/ns4/named.conf.in create mode 100644 bin/tests/system/redirect/ns4/root.hint create mode 100644 bin/tests/system/redirect/ns5/named.conf.in create mode 100644 bin/tests/system/redirect/ns5/root.db.in create mode 100644 bin/tests/system/redirect/ns5/sign.sh create mode 100644 bin/tests/system/redirect/ns5/signed.db.in create mode 100644 bin/tests/system/redirect/ns5/unsigned.db create mode 100644 bin/tests/system/redirect/ns6/named.conf.in create mode 100644 bin/tests/system/redirect/ns6/root.db create mode 100644 bin/tests/system/redirect/setup.sh create mode 100644 bin/tests/system/redirect/tests.sh create mode 100644 bin/tests/system/resolve.c create mode 100644 bin/tests/system/resolver/ans2/ans.pl create mode 100644 bin/tests/system/resolver/ans3/ans.pl create mode 100644 bin/tests/system/resolver/ans8/ans.pl create mode 100644 bin/tests/system/resolver/clean.sh create mode 100644 bin/tests/system/resolver/ns1/chaostest.db create mode 100644 bin/tests/system/resolver/ns1/named.conf.in create mode 100644 bin/tests/system/resolver/ns1/root.hint create mode 100644 bin/tests/system/resolver/ns4/broken.db create mode 100644 bin/tests/system/resolver/ns4/child.server.db create mode 100644 bin/tests/system/resolver/ns4/moves.db create mode 100644 bin/tests/system/resolver/ns4/named.conf.in create mode 100644 bin/tests/system/resolver/ns4/named.noaa create mode 100644 bin/tests/system/resolver/ns4/root.db create mode 100644 bin/tests/system/resolver/ns4/sourcens.db create mode 100644 bin/tests/system/resolver/ns4/tld1.db create mode 100644 bin/tests/system/resolver/ns4/tld2.db create mode 100644 bin/tests/system/resolver/ns4/v4only.net.db create mode 100644 bin/tests/system/resolver/ns5/child.server.db create mode 100644 bin/tests/system/resolver/ns5/moves.db create mode 100644 bin/tests/system/resolver/ns5/named.conf.in create mode 100644 bin/tests/system/resolver/ns5/root.hint create mode 100644 bin/tests/system/resolver/ns6/broken.db create mode 100644 bin/tests/system/resolver/ns6/delegation-only.db create mode 100644 bin/tests/system/resolver/ns6/ds.example.net.db.in create mode 100644 bin/tests/system/resolver/ns6/example.net.db.in create mode 100644 bin/tests/system/resolver/ns6/fetch.tld.db create mode 100644 bin/tests/system/resolver/ns6/keygen.sh create mode 100644 bin/tests/system/resolver/ns6/moves.db create mode 100644 bin/tests/system/resolver/ns6/named.conf.in create mode 100644 bin/tests/system/resolver/ns6/no-edns-version.tld.db create mode 100644 bin/tests/system/resolver/ns6/redirect.com.db create mode 100644 bin/tests/system/resolver/ns6/root.db create mode 100644 bin/tests/system/resolver/ns6/targetns.db create mode 100644 bin/tests/system/resolver/ns6/tld1.db create mode 100644 bin/tests/system/resolver/ns6/to-be-removed.tld.db.in create mode 100644 bin/tests/system/resolver/ns7/all-cnames.db create mode 100644 bin/tests/system/resolver/ns7/edns-version.tld.db create mode 100644 bin/tests/system/resolver/ns7/named1.conf.in create mode 100644 bin/tests/system/resolver/ns7/named2.conf.in create mode 100644 bin/tests/system/resolver/ns7/root.hint create mode 100644 bin/tests/system/resolver/ns7/server.db.in create mode 100644 bin/tests/system/resolver/ns7/sub.tld1.db create mode 100644 bin/tests/system/resolver/ns7/tld2.db create mode 100644 bin/tests/system/resolver/ns9/named.args create mode 100644 bin/tests/system/resolver/ns9/named.conf.in create mode 100644 bin/tests/system/resolver/ns9/named.ipv6-only create mode 100644 bin/tests/system/resolver/ns9/root.hint create mode 100644 bin/tests/system/resolver/prereq.sh create mode 100644 bin/tests/system/resolver/setup.sh create mode 100755 bin/tests/system/resolver/tests.sh create mode 100644 bin/tests/system/rndc/Makefile.in create mode 100644 bin/tests/system/rndc/clean.sh create mode 100644 bin/tests/system/rndc/gencheck.c create mode 100644 bin/tests/system/rndc/ns2/incl.db create mode 100644 bin/tests/system/rndc/ns2/named.conf.in create mode 100644 bin/tests/system/rndc/ns2/secondkey.conf create mode 100644 bin/tests/system/rndc/ns3/named.conf.in create mode 100644 bin/tests/system/rndc/ns4/named.conf.in create mode 100644 bin/tests/system/rndc/ns5/named.conf.in create mode 100644 bin/tests/system/rndc/ns6/named.args create mode 100644 bin/tests/system/rndc/ns6/named.conf.in create mode 100644 bin/tests/system/rndc/ns7/include.db.in create mode 100644 bin/tests/system/rndc/ns7/include2.db.in create mode 100644 bin/tests/system/rndc/ns7/named.conf.in create mode 100644 bin/tests/system/rndc/ns7/test.db.in create mode 100644 bin/tests/system/rndc/setup.sh create mode 100644 bin/tests/system/rndc/tests.sh create mode 100644 bin/tests/system/rootkeysentinel/clean.sh create mode 100644 bin/tests/system/rootkeysentinel/ns1/named.conf.in create mode 100644 bin/tests/system/rootkeysentinel/ns1/root.db.in create mode 100644 bin/tests/system/rootkeysentinel/ns1/sign.sh create mode 100644 bin/tests/system/rootkeysentinel/ns2/example.db.in create mode 100644 bin/tests/system/rootkeysentinel/ns2/named.conf.in create mode 100644 bin/tests/system/rootkeysentinel/ns2/sign.sh create mode 100644 bin/tests/system/rootkeysentinel/ns3/hint.db create mode 100644 bin/tests/system/rootkeysentinel/ns3/named.conf.in create mode 100644 bin/tests/system/rootkeysentinel/ns4/hint.db create mode 100644 bin/tests/system/rootkeysentinel/ns4/named.conf.in create mode 100644 bin/tests/system/rootkeysentinel/setup.sh create mode 100644 bin/tests/system/rootkeysentinel/tests.sh create mode 100644 bin/tests/system/rpz/Makefile.in create mode 100644 bin/tests/system/rpz/README create mode 100644 bin/tests/system/rpz/clean.sh create mode 100644 bin/tests/system/rpz/dnsrps.c create mode 100644 bin/tests/system/rpz/dnsrpzd-license.conf create mode 100644 bin/tests/system/rpz/dnsrpzd.conf.in create mode 100644 bin/tests/system/rpz/ns1/named.conf.in create mode 100644 bin/tests/system/rpz/ns1/root.db create mode 100644 bin/tests/system/rpz/ns10/hints create mode 100644 bin/tests/system/rpz/ns10/named.conf.in create mode 100644 bin/tests/system/rpz/ns10/stub.db create mode 100644 bin/tests/system/rpz/ns2/base-tld2s.db create mode 100644 bin/tests/system/rpz/ns2/bl.tld2.db.in create mode 100644 bin/tests/system/rpz/ns2/blv2.tld2.db.in create mode 100644 bin/tests/system/rpz/ns2/blv3.tld2.db.in create mode 100644 bin/tests/system/rpz/ns2/hints create mode 100644 bin/tests/system/rpz/ns2/named.conf.in create mode 100644 bin/tests/system/rpz/ns2/stub.db create mode 100644 bin/tests/system/rpz/ns2/tld2.db create mode 100644 bin/tests/system/rpz/ns3/base.db create mode 100644 bin/tests/system/rpz/ns3/broken.db.in create mode 100644 bin/tests/system/rpz/ns3/crash1 create mode 100644 bin/tests/system/rpz/ns3/crash2 create mode 100644 bin/tests/system/rpz/ns3/hints create mode 100644 bin/tests/system/rpz/ns3/manual-update-rpz-2.db.in create mode 100644 bin/tests/system/rpz/ns3/manual-update-rpz.db.in create mode 100644 bin/tests/system/rpz/ns3/mixed-case-rpz-1.db.in create mode 100644 bin/tests/system/rpz/ns3/mixed-case-rpz-2.db.in create mode 100644 bin/tests/system/rpz/ns3/named.conf.in create mode 100644 bin/tests/system/rpz/ns4/hints create mode 100644 bin/tests/system/rpz/ns4/named.conf.in create mode 100644 bin/tests/system/rpz/ns4/tld4.db create mode 100644 bin/tests/system/rpz/ns5/empty.db.in create mode 100644 bin/tests/system/rpz/ns5/expire.conf.in create mode 100644 bin/tests/system/rpz/ns5/fast-expire.db.in create mode 100644 bin/tests/system/rpz/ns5/hints create mode 100644 bin/tests/system/rpz/ns5/named.args create mode 100644 bin/tests/system/rpz/ns5/named.conf.in create mode 100644 bin/tests/system/rpz/ns5/tld5.db create mode 100644 bin/tests/system/rpz/ns6/bl.tld2s.db.in create mode 100644 bin/tests/system/rpz/ns6/hints create mode 100644 bin/tests/system/rpz/ns6/named.conf.in create mode 100644 bin/tests/system/rpz/ns7/hints create mode 100644 bin/tests/system/rpz/ns7/named.conf.in create mode 100644 bin/tests/system/rpz/ns8/hints create mode 100644 bin/tests/system/rpz/ns8/manual-update-rpz.db.in create mode 100644 bin/tests/system/rpz/ns8/named.conf.in create mode 100644 bin/tests/system/rpz/ns9/hints create mode 100644 bin/tests/system/rpz/ns9/named.conf.in create mode 100644 bin/tests/system/rpz/ns9/rpz.db create mode 100644 bin/tests/system/rpz/qperf.sh create mode 100644 bin/tests/system/rpz/setup.sh create mode 100644 bin/tests/system/rpz/test1 create mode 100644 bin/tests/system/rpz/test2 create mode 100644 bin/tests/system/rpz/test3 create mode 100644 bin/tests/system/rpz/test4 create mode 100644 bin/tests/system/rpz/test4a create mode 100644 bin/tests/system/rpz/test5 create mode 100644 bin/tests/system/rpz/test6 create mode 100644 bin/tests/system/rpz/tests.sh create mode 100644 bin/tests/system/rpzrecurse/README create mode 100644 bin/tests/system/rpzrecurse/ans5/ans.pl create mode 100644 bin/tests/system/rpzrecurse/clean.sh create mode 100644 bin/tests/system/rpzrecurse/ns1/db.l0 create mode 100644 bin/tests/system/rpzrecurse/ns1/db.l1.l0 create mode 100644 bin/tests/system/rpzrecurse/ns1/example.com.db create mode 100644 bin/tests/system/rpzrecurse/ns1/example.db create mode 100644 bin/tests/system/rpzrecurse/ns1/named.conf.in create mode 100644 bin/tests/system/rpzrecurse/ns1/root.db create mode 100644 bin/tests/system/rpzrecurse/ns1/test1.example.net.db create mode 100644 bin/tests/system/rpzrecurse/ns1/test2.example.net.db create mode 100644 bin/tests/system/rpzrecurse/ns2/db.clientip1 create mode 100644 bin/tests/system/rpzrecurse/ns2/db.clientip2 create mode 100644 bin/tests/system/rpzrecurse/ns2/db.clientip21 create mode 100644 bin/tests/system/rpzrecurse/ns2/db.given create mode 100644 bin/tests/system/rpzrecurse/ns2/db.invalidprefixlength create mode 100644 bin/tests/system/rpzrecurse/ns2/db.log1 create mode 100644 bin/tests/system/rpzrecurse/ns2/db.log2 create mode 100644 bin/tests/system/rpzrecurse/ns2/db.log3 create mode 100644 bin/tests/system/rpzrecurse/ns2/db.passthru create mode 100644 bin/tests/system/rpzrecurse/ns2/db.wildcard1 create mode 100644 bin/tests/system/rpzrecurse/ns2/db.wildcard2a create mode 100644 bin/tests/system/rpzrecurse/ns2/db.wildcard2b create mode 100644 bin/tests/system/rpzrecurse/ns2/db.wildcard3 create mode 100644 bin/tests/system/rpzrecurse/ns2/named.clientip.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/named.clientip2.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/named.conf.header.in create mode 100644 bin/tests/system/rpzrecurse/ns2/named.default.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/named.invalidprefixlength.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/named.log.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/named.max.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/named.wildcard1.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/named.wildcard2.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/named.wildcard3.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/named.wildcard4.conf create mode 100644 bin/tests/system/rpzrecurse/ns2/root.hint create mode 100644 bin/tests/system/rpzrecurse/ns3/example.db create mode 100644 bin/tests/system/rpzrecurse/ns3/named1.conf.in create mode 100644 bin/tests/system/rpzrecurse/ns3/named2.conf.in create mode 100644 bin/tests/system/rpzrecurse/ns3/policy.db create mode 100644 bin/tests/system/rpzrecurse/ns3/root.db create mode 100644 bin/tests/system/rpzrecurse/ns4/child.example.db create mode 100644 bin/tests/system/rpzrecurse/ns4/named.conf.in create mode 100644 bin/tests/system/rpzrecurse/prereq.sh create mode 100644 bin/tests/system/rpzrecurse/setup.sh create mode 100755 bin/tests/system/rpzrecurse/testgen.pl create mode 100644 bin/tests/system/rpzrecurse/tests.sh create mode 100644 bin/tests/system/rrchecker/classlist.good create mode 100644 bin/tests/system/rrchecker/clean.sh create mode 100644 bin/tests/system/rrchecker/privatelist.good create mode 100644 bin/tests/system/rrchecker/tests.sh create mode 100644 bin/tests/system/rrchecker/typelist.good create mode 100644 bin/tests/system/rrl/broken.conf.in create mode 100644 bin/tests/system/rrl/clean.sh create mode 100644 bin/tests/system/rrl/ns1/named.conf.in create mode 100644 bin/tests/system/rrl/ns1/root.db create mode 100644 bin/tests/system/rrl/ns2/hints create mode 100644 bin/tests/system/rrl/ns2/named.conf.in create mode 100644 bin/tests/system/rrl/ns2/tld2.db create mode 100644 bin/tests/system/rrl/ns3/hints create mode 100644 bin/tests/system/rrl/ns3/named.conf.in create mode 100644 bin/tests/system/rrl/ns3/tld3.db create mode 100644 bin/tests/system/rrl/ns4/hints create mode 100644 bin/tests/system/rrl/ns4/named.conf.in create mode 100644 bin/tests/system/rrl/ns4/tld4.db create mode 100644 bin/tests/system/rrl/setup.sh create mode 100644 bin/tests/system/rrl/tests.sh create mode 100644 bin/tests/system/rrsetorder/clean.sh create mode 100644 bin/tests/system/rrsetorder/dig.out.fixed.good create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good1 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good10 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good11 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good12 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good13 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good14 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good15 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good16 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good17 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good18 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good19 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good2 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good20 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good21 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good22 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good23 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good24 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good3 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good4 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good5 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good6 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good7 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good8 create mode 100644 bin/tests/system/rrsetorder/dig.out.random.good9 create mode 100644 bin/tests/system/rrsetorder/ns1/named.conf.in create mode 100644 bin/tests/system/rrsetorder/ns1/root.db create mode 100644 bin/tests/system/rrsetorder/ns2/named.conf.in create mode 100644 bin/tests/system/rrsetorder/ns3/named.conf.in create mode 100644 bin/tests/system/rrsetorder/ns4/named.conf.in create mode 100644 bin/tests/system/rrsetorder/ns5/named.conf.in create mode 100644 bin/tests/system/rrsetorder/setup.sh create mode 100644 bin/tests/system/rrsetorder/tests.sh create mode 100644 bin/tests/system/rsabigexponent/Makefile.in create mode 100644 bin/tests/system/rsabigexponent/README.md create mode 100644 bin/tests/system/rsabigexponent/bigkey.c create mode 100644 bin/tests/system/rsabigexponent/clean.sh create mode 100644 bin/tests/system/rsabigexponent/conf/bad01.conf create mode 100644 bin/tests/system/rsabigexponent/conf/bad02.conf create mode 100644 bin/tests/system/rsabigexponent/conf/bad03.conf create mode 100644 bin/tests/system/rsabigexponent/conf/good01.conf create mode 100644 bin/tests/system/rsabigexponent/conf/good02.conf create mode 100644 bin/tests/system/rsabigexponent/conf/good03.conf create mode 100644 bin/tests/system/rsabigexponent/ns1/named.conf.in create mode 100644 bin/tests/system/rsabigexponent/ns1/root.db.in create mode 100755 bin/tests/system/rsabigexponent/ns1/sign.sh create mode 100644 bin/tests/system/rsabigexponent/ns2/Xexample.+008+51650.key create mode 100644 bin/tests/system/rsabigexponent/ns2/Xexample.+008+51650.private create mode 100644 bin/tests/system/rsabigexponent/ns2/Xexample.+008+52810.key create mode 100644 bin/tests/system/rsabigexponent/ns2/Xexample.+008+52810.private create mode 100644 bin/tests/system/rsabigexponent/ns2/dsset-example.in create mode 100644 bin/tests/system/rsabigexponent/ns2/example.db.bad create mode 100644 bin/tests/system/rsabigexponent/ns2/example.db.in create mode 100644 bin/tests/system/rsabigexponent/ns2/named.conf.in create mode 100755 bin/tests/system/rsabigexponent/ns2/sign.sh create mode 100644 bin/tests/system/rsabigexponent/ns3/named.conf.in create mode 100644 bin/tests/system/rsabigexponent/prereq.sh create mode 100644 bin/tests/system/rsabigexponent/setup.sh create mode 100644 bin/tests/system/rsabigexponent/tests.sh create mode 100644 bin/tests/system/run.gdb create mode 100755 bin/tests/system/run.sh create mode 100755 bin/tests/system/runall.sh create mode 100755 bin/tests/system/runsequential.sh create mode 100644 bin/tests/system/runtime/README create mode 100644 bin/tests/system/runtime/clean.sh create mode 100644 bin/tests/system/runtime/ctrl-chars create mode 100644 bin/tests/system/runtime/long-cmd-line create mode 100644 bin/tests/system/runtime/ns2/named-alt1.conf.in create mode 100644 bin/tests/system/runtime/ns2/named-alt2.conf.in create mode 100644 bin/tests/system/runtime/ns2/named-alt3.conf.in create mode 100644 bin/tests/system/runtime/ns2/named-alt4.conf.in create mode 100644 bin/tests/system/runtime/ns2/named-alt5.conf.in create mode 100644 bin/tests/system/runtime/ns2/named-alt6.conf.in create mode 100644 bin/tests/system/runtime/ns2/named-alt7.conf.in create mode 100644 bin/tests/system/runtime/ns2/named-alt9.conf.in create mode 100644 bin/tests/system/runtime/ns2/named1.conf.in create mode 100644 bin/tests/system/runtime/setup.sh create mode 100644 bin/tests/system/runtime/tests.sh create mode 100644 bin/tests/system/send.pl create mode 100644 bin/tests/system/serve-stale/ans2/ans.pl create mode 100644 bin/tests/system/serve-stale/clean.sh create mode 100644 bin/tests/system/serve-stale/ns1/named1.conf.in create mode 100644 bin/tests/system/serve-stale/ns1/named2.conf.in create mode 100644 bin/tests/system/serve-stale/ns1/named3.conf.in create mode 100644 bin/tests/system/serve-stale/ns1/root.db create mode 100644 bin/tests/system/serve-stale/ns1/stale.test.db create mode 100644 bin/tests/system/serve-stale/ns3/named1.conf.in create mode 100644 bin/tests/system/serve-stale/ns3/named2.conf.in create mode 100644 bin/tests/system/serve-stale/ns3/named3.conf.in create mode 100644 bin/tests/system/serve-stale/ns3/named4.conf.in create mode 100644 bin/tests/system/serve-stale/ns3/named5.conf.in create mode 100644 bin/tests/system/serve-stale/ns3/named6.conf.in create mode 100644 bin/tests/system/serve-stale/ns3/named7.conf.in create mode 100644 bin/tests/system/serve-stale/ns3/named8.conf.in create mode 100644 bin/tests/system/serve-stale/ns3/root.db create mode 100644 bin/tests/system/serve-stale/ns4/named.conf.in create mode 100644 bin/tests/system/serve-stale/ns5/named.conf.in create mode 100644 bin/tests/system/serve-stale/prereq.sh create mode 100644 bin/tests/system/serve-stale/setup.sh create mode 100755 bin/tests/system/serve-stale/tests.sh create mode 100644 bin/tests/system/setup.sh create mode 100644 bin/tests/system/sfcache/README create mode 100644 bin/tests/system/sfcache/clean.sh create mode 100644 bin/tests/system/sfcache/ns1/named.conf.in create mode 100644 bin/tests/system/sfcache/ns1/root.db.in create mode 100644 bin/tests/system/sfcache/ns1/sign.sh create mode 100644 bin/tests/system/sfcache/ns2/example.db.in create mode 100644 bin/tests/system/sfcache/ns2/named.conf.in create mode 100644 bin/tests/system/sfcache/ns2/sign.sh create mode 100644 bin/tests/system/sfcache/ns5/named.conf.in create mode 100644 bin/tests/system/sfcache/ns5/sign.sh create mode 100644 bin/tests/system/sfcache/setup.sh create mode 100644 bin/tests/system/sfcache/tests.sh create mode 100644 bin/tests/system/shutdown/clean.sh create mode 100644 bin/tests/system/shutdown/ns1/named.conf.in create mode 100644 bin/tests/system/shutdown/ns1/root.db create mode 100644 bin/tests/system/shutdown/ns2/named.conf.in create mode 100644 bin/tests/system/shutdown/ns2/test.db create mode 100755 bin/tests/system/shutdown/prereq.sh create mode 100644 bin/tests/system/shutdown/resolver/named.conf.in create mode 100644 bin/tests/system/shutdown/resolver/root.db create mode 100644 bin/tests/system/shutdown/setup.sh create mode 100755 bin/tests/system/shutdown/tests_shutdown.py create mode 100644 bin/tests/system/smartsign/child.db create mode 100644 bin/tests/system/smartsign/clean.sh create mode 100644 bin/tests/system/smartsign/parent.db create mode 100644 bin/tests/system/smartsign/tests.sh create mode 100644 bin/tests/system/sortlist/clean.sh create mode 100644 bin/tests/system/sortlist/ns1/example.db create mode 100644 bin/tests/system/sortlist/ns1/named.conf.in create mode 100644 bin/tests/system/sortlist/ns1/root.db create mode 100644 bin/tests/system/sortlist/setup.sh create mode 100644 bin/tests/system/sortlist/tests.sh create mode 100644 bin/tests/system/spf/clean.sh create mode 100644 bin/tests/system/spf/ns1/named.conf.in create mode 100644 bin/tests/system/spf/ns1/spf.db create mode 100644 bin/tests/system/spf/setup.sh create mode 100644 bin/tests/system/spf/tests.sh create mode 100755 bin/tests/system/start.pl create mode 100755 bin/tests/system/start.sh create mode 100755 bin/tests/system/staticstub/clean.sh create mode 100644 bin/tests/system/staticstub/conf/bad01.conf create mode 100644 bin/tests/system/staticstub/conf/bad02.conf create mode 100644 bin/tests/system/staticstub/conf/bad03.conf create mode 100644 bin/tests/system/staticstub/conf/bad04.conf create mode 100644 bin/tests/system/staticstub/conf/bad05.conf create mode 100644 bin/tests/system/staticstub/conf/bad06.conf create mode 100644 bin/tests/system/staticstub/conf/bad07.conf create mode 100644 bin/tests/system/staticstub/conf/bad08.conf create mode 100644 bin/tests/system/staticstub/conf/bad09.conf create mode 100644 bin/tests/system/staticstub/conf/bad10.conf create mode 100644 bin/tests/system/staticstub/conf/bad11.conf create mode 100644 bin/tests/system/staticstub/conf/good01.conf create mode 100644 bin/tests/system/staticstub/conf/good02.conf create mode 100644 bin/tests/system/staticstub/conf/good03.conf create mode 100644 bin/tests/system/staticstub/conf/good04.conf create mode 100644 bin/tests/system/staticstub/conf/good05.conf create mode 100644 bin/tests/system/staticstub/knowngood.dig.out.rec create mode 100644 bin/tests/system/staticstub/ns1/named.conf.in create mode 100644 bin/tests/system/staticstub/ns1/root.db create mode 100644 bin/tests/system/staticstub/ns2/named.conf.in create mode 100644 bin/tests/system/staticstub/ns3/example.db.in create mode 100644 bin/tests/system/staticstub/ns3/example.org.db create mode 100644 bin/tests/system/staticstub/ns3/named.conf.in create mode 100755 bin/tests/system/staticstub/ns3/sign.sh create mode 100644 bin/tests/system/staticstub/ns3/undelegated.db.in create mode 100644 bin/tests/system/staticstub/ns4/example.com.db create mode 100644 bin/tests/system/staticstub/ns4/example.info.db create mode 100644 bin/tests/system/staticstub/ns4/example.org.db create mode 100644 bin/tests/system/staticstub/ns4/named.conf.in create mode 100755 bin/tests/system/staticstub/ns4/sign.sh create mode 100644 bin/tests/system/staticstub/ns4/sub.example.db.in create mode 100755 bin/tests/system/staticstub/setup.sh create mode 100755 bin/tests/system/staticstub/tests.sh create mode 100644 bin/tests/system/statistics/ans4/ans.pl create mode 100644 bin/tests/system/statistics/clean.sh create mode 100644 bin/tests/system/statistics/ns1/named.conf.in create mode 100644 bin/tests/system/statistics/ns1/root.db create mode 100644 bin/tests/system/statistics/ns1/zone.db create mode 100644 bin/tests/system/statistics/ns2/example.db create mode 100644 bin/tests/system/statistics/ns2/internal.db create mode 100644 bin/tests/system/statistics/ns2/named.conf.in create mode 100644 bin/tests/system/statistics/ns2/named2.conf.in create mode 100644 bin/tests/system/statistics/ns3/internal.db create mode 100644 bin/tests/system/statistics/ns3/named.conf.in create mode 100644 bin/tests/system/statistics/ns3/root.hint create mode 100644 bin/tests/system/statistics/prereq.sh create mode 100644 bin/tests/system/statistics/setup.sh create mode 100644 bin/tests/system/statistics/tests.sh create mode 100644 bin/tests/system/statschannel/clean.sh create mode 100644 bin/tests/system/statschannel/conftest.py create mode 100644 bin/tests/system/statschannel/fetch.pl create mode 100644 bin/tests/system/statschannel/generic.py create mode 100644 bin/tests/system/statschannel/generic_dnspython.py create mode 100644 bin/tests/system/statschannel/mem-xml.pl create mode 100644 bin/tests/system/statschannel/ns1/example.db create mode 100644 bin/tests/system/statschannel/ns1/named.conf.in create mode 100644 bin/tests/system/statschannel/ns2/dnssec.db.in create mode 100644 bin/tests/system/statschannel/ns2/example.db create mode 100644 bin/tests/system/statschannel/ns2/manykeys.db.in create mode 100644 bin/tests/system/statschannel/ns2/named.conf.in create mode 100644 bin/tests/system/statschannel/ns2/named2.conf.in create mode 100644 bin/tests/system/statschannel/ns2/sign.sh create mode 100644 bin/tests/system/statschannel/ns3/named.conf.in create mode 100644 bin/tests/system/statschannel/prereq.sh create mode 100644 bin/tests/system/statschannel/server-json.pl create mode 100644 bin/tests/system/statschannel/server-xml.pl create mode 100644 bin/tests/system/statschannel/setup.sh create mode 100644 bin/tests/system/statschannel/tests.sh create mode 100755 bin/tests/system/statschannel/tests_json.py create mode 100755 bin/tests/system/statschannel/tests_xml.py create mode 100644 bin/tests/system/statschannel/traffic-json.pl create mode 100644 bin/tests/system/statschannel/traffic-xml.pl create mode 100644 bin/tests/system/statschannel/traffic.expect.1 create mode 100644 bin/tests/system/statschannel/traffic.expect.2 create mode 100644 bin/tests/system/statschannel/traffic.expect.4 create mode 100644 bin/tests/system/statschannel/traffic.expect.5 create mode 100644 bin/tests/system/statschannel/traffic.expect.6 create mode 100644 bin/tests/system/statschannel/zones-json.pl create mode 100644 bin/tests/system/statschannel/zones-xml.pl create mode 100644 bin/tests/system/stop.pl create mode 100755 bin/tests/system/stop.sh create mode 100644 bin/tests/system/stopall.sh create mode 100644 bin/tests/system/stress/clean.sh create mode 100644 bin/tests/system/stress/ns2/named.conf.in create mode 100644 bin/tests/system/stress/ns2/zone.template.db create mode 100644 bin/tests/system/stress/ns3/named.conf.in create mode 100644 bin/tests/system/stress/ns4/named.conf.in create mode 100644 bin/tests/system/stress/prereq.sh create mode 100644 bin/tests/system/stress/setup.sh create mode 100644 bin/tests/system/stress/tests_stress_update.py create mode 100644 bin/tests/system/stub/clean.sh create mode 100644 bin/tests/system/stub/knowngood.dig.out.norec create mode 100644 bin/tests/system/stub/knowngood.dig.out.rec create mode 100644 bin/tests/system/stub/ns1/named.conf.in create mode 100644 bin/tests/system/stub/ns1/root.db create mode 100644 bin/tests/system/stub/ns2/child.example.db create mode 100644 bin/tests/system/stub/ns2/named.conf.in create mode 100644 bin/tests/system/stub/ns3/example.db create mode 100644 bin/tests/system/stub/ns3/named.conf.in create mode 100644 bin/tests/system/stub/ns4/example.db create mode 100644 bin/tests/system/stub/ns4/named.conf.in create mode 100644 bin/tests/system/stub/ns5/named.conf.in create mode 100644 bin/tests/system/stub/setup.sh create mode 100644 bin/tests/system/stub/tests.sh create mode 100644 bin/tests/system/synthfromdnssec/clean.sh create mode 100644 bin/tests/system/synthfromdnssec/ns1/dnamed.db.in create mode 100644 bin/tests/system/synthfromdnssec/ns1/example.db.in create mode 100644 bin/tests/system/synthfromdnssec/ns1/named.conf.in create mode 100644 bin/tests/system/synthfromdnssec/ns1/root.db.in create mode 100644 bin/tests/system/synthfromdnssec/ns1/sign.sh create mode 100644 bin/tests/system/synthfromdnssec/ns2/named.conf.in create mode 100644 bin/tests/system/synthfromdnssec/ns2/root.hints create mode 100644 bin/tests/system/synthfromdnssec/ns3/named.conf.in create mode 100644 bin/tests/system/synthfromdnssec/ns3/redirect.db create mode 100644 bin/tests/system/synthfromdnssec/ns3/root.hints create mode 100644 bin/tests/system/synthfromdnssec/ns4/named.conf.in create mode 100644 bin/tests/system/synthfromdnssec/ns4/root.hints create mode 100644 bin/tests/system/synthfromdnssec/ns5/named.conf.in create mode 100644 bin/tests/system/synthfromdnssec/ns5/root.hints create mode 100644 bin/tests/system/synthfromdnssec/setup.sh create mode 100644 bin/tests/system/synthfromdnssec/tests.sh create mode 100755 bin/tests/system/system-test-driver.sh create mode 100644 bin/tests/system/tcp/1996-alloc_dnsbuf-crash-test.pkt create mode 100644 bin/tests/system/tcp/ans6/ans.py create mode 100644 bin/tests/system/tcp/clean.sh create mode 100644 bin/tests/system/tcp/ns1/named.conf.in create mode 100644 bin/tests/system/tcp/ns1/root.db create mode 100644 bin/tests/system/tcp/ns2/example.db create mode 100644 bin/tests/system/tcp/ns2/named.conf.in create mode 100644 bin/tests/system/tcp/ns3/named.conf.in create mode 100644 bin/tests/system/tcp/ns4/named.conf.in create mode 100644 bin/tests/system/tcp/ns5/named.conf.in create mode 100644 bin/tests/system/tcp/ns7/named.conf.in create mode 100644 bin/tests/system/tcp/ns7/named.dropedns create mode 100644 bin/tests/system/tcp/ns7/root.db create mode 100644 bin/tests/system/tcp/prereq.sh create mode 100644 bin/tests/system/tcp/setup.sh create mode 100644 bin/tests/system/tcp/tests.sh create mode 100644 bin/tests/system/tcp/tests_tcp.py create mode 100755 bin/tests/system/testcrypto.sh create mode 100755 bin/tests/system/testsock.pl create mode 100644 bin/tests/system/testsock6.pl create mode 100644 bin/tests/system/testsummary.sh create mode 100644 bin/tests/system/timeouts/clean.sh create mode 100644 bin/tests/system/timeouts/ns1/example.db create mode 100644 bin/tests/system/timeouts/ns1/named.args create mode 100644 bin/tests/system/timeouts/ns1/named.conf.in create mode 100644 bin/tests/system/timeouts/ns1/root.db create mode 100644 bin/tests/system/timeouts/prereq.sh create mode 100644 bin/tests/system/timeouts/setup.sh create mode 100644 bin/tests/system/timeouts/tests_tcp_timeouts.py create mode 100644 bin/tests/system/tkey/Makefile.in create mode 100644 bin/tests/system/tkey/clean.sh create mode 100644 bin/tests/system/tkey/keycreate.c create mode 100644 bin/tests/system/tkey/keydelete.c create mode 100644 bin/tests/system/tkey/ns1/example.db create mode 100644 bin/tests/system/tkey/ns1/named.conf.in create mode 100644 bin/tests/system/tkey/ns1/setup.sh create mode 100644 bin/tests/system/tkey/setup.sh create mode 100644 bin/tests/system/tkey/tests.sh create mode 100644 bin/tests/system/tools/clean.sh create mode 100644 bin/tests/system/tools/setup.sh create mode 100644 bin/tests/system/tools/tests.sh create mode 100644 bin/tests/system/tsig/ans2/ans.pl create mode 100644 bin/tests/system/tsig/badlocation create mode 100644 bin/tests/system/tsig/badtime create mode 100644 bin/tests/system/tsig/clean.sh create mode 100644 bin/tests/system/tsig/ns1/example.db create mode 100644 bin/tests/system/tsig/ns1/named.conf.in create mode 100644 bin/tests/system/tsig/prereq.sh create mode 100644 bin/tests/system/tsig/setup.sh create mode 100644 bin/tests/system/tsig/tests.sh create mode 100644 bin/tests/system/tsiggss/authsock.pl create mode 100644 bin/tests/system/tsiggss/clean.sh create mode 100644 bin/tests/system/tsiggss/ns1/administrator.ccache create mode 100644 bin/tests/system/tsiggss/ns1/dns.keytab create mode 100644 bin/tests/system/tsiggss/ns1/example.nil.db.in create mode 100644 bin/tests/system/tsiggss/ns1/named.conf.in create mode 100644 bin/tests/system/tsiggss/ns1/testdenied.ccache create mode 100644 bin/tests/system/tsiggss/prereq.sh create mode 100644 bin/tests/system/tsiggss/setup.sh create mode 100644 bin/tests/system/tsiggss/tests.sh create mode 100755 bin/tests/system/tsiggss/tests_isc_spnego_flaws.py create mode 100644 bin/tests/system/ttl/clean.sh create mode 100644 bin/tests/system/ttl/ns1/max-example.db create mode 100644 bin/tests/system/ttl/ns1/min-example.db create mode 100644 bin/tests/system/ttl/ns1/named.conf.in create mode 100644 bin/tests/system/ttl/ns2/hints.db create mode 100644 bin/tests/system/ttl/ns2/named.conf.in create mode 100644 bin/tests/system/ttl/prereq.sh create mode 100644 bin/tests/system/ttl/setup.sh create mode 100644 bin/tests/system/ttl/tests_cache_ttl.py create mode 100644 bin/tests/system/unknown/clean.sh create mode 100644 bin/tests/system/unknown/large.out create mode 100644 bin/tests/system/unknown/ns1/broken1.db create mode 100644 bin/tests/system/unknown/ns1/broken2.db create mode 100644 bin/tests/system/unknown/ns1/broken3.db create mode 100644 bin/tests/system/unknown/ns1/broken4.db create mode 100644 bin/tests/system/unknown/ns1/broken5.db create mode 100644 bin/tests/system/unknown/ns1/class10.hints create mode 100644 bin/tests/system/unknown/ns1/example-class10.db create mode 100644 bin/tests/system/unknown/ns1/example-in.db create mode 100644 bin/tests/system/unknown/ns1/large.db create mode 100644 bin/tests/system/unknown/ns1/named.conf.in create mode 100644 bin/tests/system/unknown/ns2/named.conf.in create mode 100644 bin/tests/system/unknown/ns3/named.conf.in create mode 100644 bin/tests/system/unknown/ns3/sign.sh create mode 100644 bin/tests/system/unknown/setup.sh create mode 100644 bin/tests/system/unknown/tests.sh create mode 100644 bin/tests/system/unknown/zones/nan.bad create mode 100644 bin/tests/system/upforwd/ans4/ans.pl create mode 100644 bin/tests/system/upforwd/clean.sh create mode 100644 bin/tests/system/upforwd/knowngood.after1 create mode 100644 bin/tests/system/upforwd/knowngood.after2 create mode 100644 bin/tests/system/upforwd/knowngood.before create mode 100644 bin/tests/system/upforwd/knowngood.ns2.before create mode 100644 bin/tests/system/upforwd/ns1/example1.db create mode 100644 bin/tests/system/upforwd/ns1/named.conf.in create mode 100644 bin/tests/system/upforwd/ns2/named.conf.in create mode 100644 bin/tests/system/upforwd/ns3/named1.conf.in create mode 100644 bin/tests/system/upforwd/ns3/named2.conf.in create mode 100644 bin/tests/system/upforwd/ns3/nomaster.db create mode 100644 bin/tests/system/upforwd/prereq.sh create mode 100644 bin/tests/system/upforwd/setup.sh create mode 100644 bin/tests/system/upforwd/tests.sh create mode 100644 bin/tests/system/verify/clean.sh create mode 100644 bin/tests/system/verify/setup.sh create mode 100644 bin/tests/system/verify/tests.sh create mode 100644 bin/tests/system/verify/zones/genzones.sh create mode 100644 bin/tests/system/verify/zones/unsigned.db create mode 100644 bin/tests/system/views/clean.sh create mode 100644 bin/tests/system/views/ns1/named.conf.in create mode 100644 bin/tests/system/views/ns1/root.db create mode 100644 bin/tests/system/views/ns2/1.10.in-addr.arpa.db create mode 100644 bin/tests/system/views/ns2/clone.db create mode 100644 bin/tests/system/views/ns2/example1.db create mode 100644 bin/tests/system/views/ns2/example2.db create mode 100644 bin/tests/system/views/ns2/external/inline.db create mode 100644 bin/tests/system/views/ns2/internal.db create mode 100644 bin/tests/system/views/ns2/internal/inline.db create mode 100644 bin/tests/system/views/ns2/named1.conf.in create mode 100644 bin/tests/system/views/ns2/named2.conf.in create mode 100644 bin/tests/system/views/ns2/named3.conf.in create mode 100644 bin/tests/system/views/ns3/child.clone.db create mode 100644 bin/tests/system/views/ns3/internal.db create mode 100644 bin/tests/system/views/ns3/named1.conf.in create mode 100644 bin/tests/system/views/ns3/named2.conf.in create mode 100644 bin/tests/system/views/ns5/child.clone.db create mode 100644 bin/tests/system/views/ns5/named.conf.in create mode 100644 bin/tests/system/views/setup.sh create mode 100644 bin/tests/system/views/tests.sh create mode 100644 bin/tests/system/wildcard/clean.sh create mode 100644 bin/tests/system/wildcard/ns1/allwild.db.in create mode 100644 bin/tests/system/wildcard/ns1/dlv.db.in create mode 100644 bin/tests/system/wildcard/ns1/example.db.in create mode 100644 bin/tests/system/wildcard/ns1/named.conf.in create mode 100644 bin/tests/system/wildcard/ns1/nsec.db.in create mode 100644 bin/tests/system/wildcard/ns1/nsec3.db.in create mode 100644 bin/tests/system/wildcard/ns1/private.nsec.db.in create mode 100644 bin/tests/system/wildcard/ns1/private.nsec3.db.in create mode 100644 bin/tests/system/wildcard/ns1/root.db.in create mode 100755 bin/tests/system/wildcard/ns1/sign.sh create mode 100644 bin/tests/system/wildcard/ns2/named.conf.in create mode 100644 bin/tests/system/wildcard/ns3/named.conf.in create mode 100644 bin/tests/system/wildcard/ns4/named.conf.in create mode 100644 bin/tests/system/wildcard/ns5/named.conf.in create mode 100644 bin/tests/system/wildcard/setup.sh create mode 100644 bin/tests/system/wildcard/tests.sh create mode 100755 bin/tests/system/wildcard/tests_wildcard.py create mode 100644 bin/tests/system/win32/bigkey.vcxproj.filters.in create mode 100644 bin/tests/system/win32/bigkey.vcxproj.in create mode 100644 bin/tests/system/win32/bigkey.vcxproj.user create mode 100644 bin/tests/system/win32/feature-test.vcxproj.filters.in create mode 100644 bin/tests/system/win32/feature-test.vcxproj.in create mode 100644 bin/tests/system/win32/feature-test.vcxproj.user create mode 100644 bin/tests/system/win32/gencheck.vcxproj.filters.in create mode 100644 bin/tests/system/win32/gencheck.vcxproj.in create mode 100644 bin/tests/system/win32/gencheck.vcxproj.user create mode 100644 bin/tests/system/win32/keycreate.vcxproj.filters.in create mode 100644 bin/tests/system/win32/keycreate.vcxproj.in create mode 100644 bin/tests/system/win32/keycreate.vcxproj.user create mode 100644 bin/tests/system/win32/keydelete.vcxproj.filters.in create mode 100644 bin/tests/system/win32/keydelete.vcxproj.in create mode 100644 bin/tests/system/win32/keydelete.vcxproj.user create mode 100644 bin/tests/system/win32/pipequeries.vcxproj.filters.in create mode 100644 bin/tests/system/win32/pipequeries.vcxproj.in create mode 100644 bin/tests/system/win32/pipequeries.vcxproj.user create mode 100644 bin/tests/system/win32/resolve.vcxproj.filters.in create mode 100644 bin/tests/system/win32/resolve.vcxproj.in create mode 100644 bin/tests/system/win32/resolve.vcxproj.user create mode 100644 bin/tests/system/xfer/ans5/badkeydata create mode 100644 bin/tests/system/xfer/ans5/badmessageid create mode 100644 bin/tests/system/xfer/ans5/goodaxfr create mode 100644 bin/tests/system/xfer/ans5/partial create mode 100644 bin/tests/system/xfer/ans5/soamismatch create mode 100644 bin/tests/system/xfer/ans5/unknownkey create mode 100644 bin/tests/system/xfer/ans5/unsigned create mode 100644 bin/tests/system/xfer/ans5/wrongkey create mode 100644 bin/tests/system/xfer/axfr-stats.good create mode 100644 bin/tests/system/xfer/clean.sh create mode 100644 bin/tests/system/xfer/dig1.good create mode 100644 bin/tests/system/xfer/dig2.good create mode 100644 bin/tests/system/xfer/knowngood.mapped create mode 100644 bin/tests/system/xfer/ns1/axfr-too-big.db create mode 100644 bin/tests/system/xfer/ns1/ixfr-too-big.db.in create mode 100644 bin/tests/system/xfer/ns1/named.conf.in create mode 100644 bin/tests/system/xfer/ns1/root.db create mode 100644 bin/tests/system/xfer/ns1/xfer-stats.db create mode 100644 bin/tests/system/xfer/ns2/mapped.db.in create mode 100644 bin/tests/system/xfer/ns2/named.conf.in create mode 100644 bin/tests/system/xfer/ns2/sec.db.in create mode 100644 bin/tests/system/xfer/ns3/named.conf.in create mode 100644 bin/tests/system/xfer/ns4/named.conf.base create mode 100644 bin/tests/system/xfer/ns4/root.db.in create mode 100644 bin/tests/system/xfer/ns6/named.conf.in create mode 100644 bin/tests/system/xfer/ns7/named.conf.in create mode 100644 bin/tests/system/xfer/ns8/example.db create mode 100644 bin/tests/system/xfer/ns8/named.conf.in create mode 100644 bin/tests/system/xfer/prereq.sh create mode 100644 bin/tests/system/xfer/setup.sh create mode 100755 bin/tests/system/xfer/tests.sh create mode 100644 bin/tests/system/xferquota/clean.sh create mode 100644 bin/tests/system/xferquota/ns1/changing1.db create mode 100644 bin/tests/system/xferquota/ns1/changing2.db create mode 100644 bin/tests/system/xferquota/ns1/named.conf.in create mode 100644 bin/tests/system/xferquota/ns1/root.db create mode 100644 bin/tests/system/xferquota/ns2/example.db create mode 100644 bin/tests/system/xferquota/ns2/named.conf.in create mode 100644 bin/tests/system/xferquota/setup.pl create mode 100644 bin/tests/system/xferquota/setup.sh create mode 100755 bin/tests/system/xferquota/tests.sh create mode 100644 bin/tests/system/zero/ans5/ans.pl create mode 100644 bin/tests/system/zero/clean.sh create mode 100644 bin/tests/system/zero/ns1/named.conf.in create mode 100644 bin/tests/system/zero/ns1/root.db create mode 100644 bin/tests/system/zero/ns2/named.args create mode 100644 bin/tests/system/zero/ns2/named.conf.in create mode 100644 bin/tests/system/zero/ns2/tld.db create mode 100644 bin/tests/system/zero/ns3/named.args create mode 100644 bin/tests/system/zero/ns3/named.conf.in create mode 100644 bin/tests/system/zero/ns3/root.hint create mode 100644 bin/tests/system/zero/ns4/named.args create mode 100644 bin/tests/system/zero/ns4/named.conf.in create mode 100644 bin/tests/system/zero/ns4/one.tld.db create mode 100644 bin/tests/system/zero/prereq.sh create mode 100644 bin/tests/system/zero/setup.sh create mode 100644 bin/tests/system/zero/tests.sh create mode 100644 bin/tests/system/zonechecks/a.db create mode 100644 bin/tests/system/zonechecks/aaaa.db create mode 100644 bin/tests/system/zonechecks/bigserial.db create mode 100644 bin/tests/system/zonechecks/clean.sh create mode 100644 bin/tests/system/zonechecks/cname.db create mode 100644 bin/tests/system/zonechecks/dname.db create mode 100644 bin/tests/system/zonechecks/noaddress.db create mode 100644 bin/tests/system/zonechecks/ns1/named.conf.in create mode 100644 bin/tests/system/zonechecks/ns2/named.conf.in create mode 100644 bin/tests/system/zonechecks/nxdomain.db create mode 100644 bin/tests/system/zonechecks/setup.sh create mode 100644 bin/tests/system/zonechecks/tests.sh create mode 100644 bin/tests/testdata/wire/wire_test.data create mode 100644 bin/tests/testdata/wire/wire_test.data2 create mode 100644 bin/tests/testdata/wire/wire_test.data3 create mode 100644 bin/tests/testdata/wire/wire_test.data4 create mode 100644 bin/tests/win32/backtrace_test.vcxproj.filters.in create mode 100644 bin/tests/win32/backtrace_test.vcxproj.in create mode 100644 bin/tests/win32/backtrace_test.vcxproj.user create mode 100644 bin/tests/win32/inter_test.vcxproj.filters.in create mode 100644 bin/tests/win32/inter_test.vcxproj.in create mode 100644 bin/tests/win32/inter_test.vcxproj.user create mode 100644 bin/tests/win32/makejournal.vcxproj.filters.in create mode 100644 bin/tests/win32/makejournal.vcxproj.in create mode 100644 bin/tests/win32/makejournal.vcxproj.user create mode 100644 bin/tests/win32/rwlock_test.vcxproj.filters.in create mode 100644 bin/tests/win32/rwlock_test.vcxproj.in create mode 100644 bin/tests/win32/rwlock_test.vcxproj.user create mode 100644 bin/tests/win32/shutdown_test.vcxproj.filters.in create mode 100644 bin/tests/win32/shutdown_test.vcxproj.in create mode 100644 bin/tests/win32/shutdown_test.vcxproj.user create mode 100644 bin/tests/win32/sock_test.vcxproj.filters.in create mode 100644 bin/tests/win32/sock_test.vcxproj.in create mode 100644 bin/tests/win32/sock_test.vcxproj.user create mode 100644 bin/tests/win32/task_test.vcxproj.filters.in create mode 100644 bin/tests/win32/task_test.vcxproj.in create mode 100644 bin/tests/win32/task_test.vcxproj.user create mode 100644 bin/tests/win32/timer_test.vcxproj.filters.in create mode 100644 bin/tests/win32/timer_test.vcxproj.in create mode 100644 bin/tests/win32/timer_test.vcxproj.user create mode 100644 bin/tests/wire_test.c create mode 100644 bin/tools/Makefile.in create mode 100644 bin/tools/arpaname.c create mode 100644 bin/tools/arpaname.rst create mode 100644 bin/tools/dnstap-read.c create mode 100644 bin/tools/dnstap-read.rst create mode 100644 bin/tools/mdig.c create mode 100644 bin/tools/mdig.rst create mode 100644 bin/tools/named-journalprint.c create mode 100644 bin/tools/named-journalprint.rst create mode 100644 bin/tools/named-nzd2nzf.c create mode 100644 bin/tools/named-nzd2nzf.rst create mode 100644 bin/tools/named-rrchecker.c create mode 100644 bin/tools/named-rrchecker.rst create mode 100644 bin/tools/nsec3hash.c create mode 100644 bin/tools/nsec3hash.rst create mode 100644 bin/tools/win32/arpaname.vcxproj.filters.in create mode 100644 bin/tools/win32/arpaname.vcxproj.in create mode 100644 bin/tools/win32/arpaname.vcxproj.user create mode 100644 bin/tools/win32/journalprint.vcxproj.filters.in create mode 100644 bin/tools/win32/journalprint.vcxproj.in create mode 100644 bin/tools/win32/journalprint.vcxproj.user create mode 100644 bin/tools/win32/mdig.vcxproj.filters.in create mode 100644 bin/tools/win32/mdig.vcxproj.in create mode 100644 bin/tools/win32/mdig.vcxproj.user create mode 100644 bin/tools/win32/nsec3hash.vcxproj.filters.in create mode 100644 bin/tools/win32/nsec3hash.vcxproj.in create mode 100644 bin/tools/win32/nsec3hash.vcxproj.user create mode 100644 bin/tools/win32/rrchecker.vcxproj.filters.in create mode 100644 bin/tools/win32/rrchecker.vcxproj.in create mode 100644 bin/tools/win32/rrchecker.vcxproj.user create mode 100644 bin/win32/BINDInstall/AccountInfo.cpp create mode 100644 bin/win32/BINDInstall/AccountInfo.h create mode 100644 bin/win32/BINDInstall/BINDInstall.cpp create mode 100644 bin/win32/BINDInstall/BINDInstall.h create mode 100644 bin/win32/BINDInstall/BINDInstall.rc create mode 100644 bin/win32/BINDInstall/BINDInstall.vcxproj.filters.in create mode 100644 bin/win32/BINDInstall/BINDInstall.vcxproj.in create mode 100644 bin/win32/BINDInstall/BINDInstall.vcxproj.user create mode 100644 bin/win32/BINDInstall/BINDInstallDlg.cpp create mode 100644 bin/win32/BINDInstall/BINDInstallDlg.h create mode 100644 bin/win32/BINDInstall/DirBrowse.cpp create mode 100644 bin/win32/BINDInstall/DirBrowse.h create mode 100644 bin/win32/BINDInstall/StdAfx.cpp create mode 100644 bin/win32/BINDInstall/StdAfx.h create mode 100644 bin/win32/BINDInstall/VersionInfo.cpp create mode 100644 bin/win32/BINDInstall/VersionInfo.h create mode 100644 bin/win32/BINDInstall/res/BINDInstall.ico create mode 100644 bin/win32/BINDInstall/res/BINDInstall.rc2 create mode 100644 bin/win32/BINDInstall/resource.h create mode 100644 bind.keys create mode 100644 bind.keys.h create mode 100644 cocci/UV_RUNTIME_CHECK.spatch create mode 100644 cocci/config-h.spatch create mode 100644 cocci/dns_message_create.spatch create mode 100644 cocci/dns_message_destroy.spatch create mode 100644 cocci/dns_name_copy-with-result.spatch create mode 100644 cocci/dns_name_copy.spatch create mode 100644 cocci/dns_name_copynf.spatch create mode 100644 cocci/dns_name_dup.disabled create mode 100644 cocci/dns_rbtnodechain_init.disabled create mode 100644 cocci/isc_buffer_allocate_never_fail.spatch create mode 100644 cocci/isc_event_allocat_never_fail.spatch create mode 100644 cocci/isc_mem_allocate_never_fail.spatch create mode 100644 cocci/isc_mem_create_never_fail.disabled create mode 100644 cocci/isc_mem_get_never_fail.spatch create mode 100644 cocci/isc_mem_putanddetach.spatch create mode 100644 cocci/isc_mem_strdup_never_fail.spatch create mode 100644 cocci/isc_mempool_create_cannot_fail.cocci create mode 100644 cocci/memcpy.spatch create mode 100644 cocci/null-the-pointer-early.disabled create mode 100644 cocci/return-void-from-void.spatch create mode 100644 cocci/unreachable.spatch create mode 100755 config.guess create mode 100644 config.h.in create mode 100644 config.h.win32 create mode 100755 config.sub create mode 100644 config.threads.in create mode 100755 configure create mode 100644 configure.ac create mode 100644 contrib/README create mode 100755 contrib/dane/mkdane.sh create mode 100644 contrib/dane/tlsa6698.pem create mode 100644 contrib/dlz/bin/dlzbdb/Makefile.in create mode 100644 contrib/dlz/bin/dlzbdb/dlzbdb.c create mode 100644 contrib/dlz/config.dlz.in create mode 100644 contrib/dlz/drivers/dlz_bdb_driver.c create mode 100644 contrib/dlz/drivers/dlz_bdbhpt_driver.c create mode 100644 contrib/dlz/drivers/dlz_dlopen_driver.c create mode 100644 contrib/dlz/drivers/dlz_drivers.c create mode 100644 contrib/dlz/drivers/dlz_filesystem_driver.c create mode 100644 contrib/dlz/drivers/dlz_ldap_driver.c create mode 100644 contrib/dlz/drivers/dlz_mysql_driver.c create mode 100644 contrib/dlz/drivers/dlz_odbc_driver.c create mode 100644 contrib/dlz/drivers/dlz_postgres_driver.c create mode 100644 contrib/dlz/drivers/dlz_stub_driver.c create mode 120000 contrib/dlz/drivers/include/.clang-format create mode 100644 contrib/dlz/drivers/include/dlz/dlz_bdb_driver.h create mode 100644 contrib/dlz/drivers/include/dlz/dlz_bdbhpt_driver.h create mode 100644 contrib/dlz/drivers/include/dlz/dlz_dlopen_driver.h create mode 100644 contrib/dlz/drivers/include/dlz/dlz_drivers.h create mode 100644 contrib/dlz/drivers/include/dlz/dlz_filesystem_driver.h create mode 100644 contrib/dlz/drivers/include/dlz/dlz_ldap_driver.h create mode 100644 contrib/dlz/drivers/include/dlz/dlz_mysql_driver.h create mode 100644 contrib/dlz/drivers/include/dlz/dlz_odbc_driver.h create mode 100644 contrib/dlz/drivers/include/dlz/dlz_postgres_driver.h create mode 100644 contrib/dlz/drivers/include/dlz/dlz_stub_driver.h create mode 100644 contrib/dlz/drivers/include/dlz/sdlz_helper.h create mode 100644 contrib/dlz/drivers/rules.in create mode 100644 contrib/dlz/drivers/sdlz_helper.c create mode 100644 contrib/dlz/example/Makefile create mode 100644 contrib/dlz/example/README create mode 100644 contrib/dlz/example/dlz_example.c create mode 100644 contrib/dlz/example/named.conf create mode 100644 contrib/dlz/example/win32/DLLMain.c create mode 100644 contrib/dlz/example/win32/dxdriver.def create mode 100644 contrib/dlz/example/win32/dxdriver.dsp create mode 100644 contrib/dlz/example/win32/dxdriver.dsw create mode 100644 contrib/dlz/example/win32/dxdriver.mak create mode 100644 contrib/dlz/modules/bdbhpt/Makefile create mode 100644 contrib/dlz/modules/bdbhpt/README.md create mode 100644 contrib/dlz/modules/bdbhpt/dlz_bdbhpt_dynamic.c create mode 100644 contrib/dlz/modules/bdbhpt/testing/README create mode 100755 contrib/dlz/modules/bdbhpt/testing/bdbhpt-populate.pl create mode 100644 contrib/dlz/modules/bdbhpt/testing/dns-data.txt create mode 100644 contrib/dlz/modules/bdbhpt/testing/named.conf create mode 100644 contrib/dlz/modules/common/dlz_dbi.c create mode 100644 contrib/dlz/modules/filesystem/Makefile create mode 100644 contrib/dlz/modules/filesystem/dir.c create mode 100644 contrib/dlz/modules/filesystem/dir.h create mode 100644 contrib/dlz/modules/filesystem/dlz_filesystem_dynamic.c create mode 120000 contrib/dlz/modules/include/.clang-format create mode 100644 contrib/dlz/modules/include/dlz_dbi.h create mode 100644 contrib/dlz/modules/include/dlz_list.h create mode 100644 contrib/dlz/modules/include/dlz_minimal.h create mode 100644 contrib/dlz/modules/include/dlz_pthread.h create mode 100644 contrib/dlz/modules/ldap/Makefile create mode 100644 contrib/dlz/modules/ldap/dlz_ldap_dynamic.c create mode 100644 contrib/dlz/modules/ldap/testing/README create mode 100644 contrib/dlz/modules/ldap/testing/dlz.schema create mode 100644 contrib/dlz/modules/ldap/testing/example.ldif create mode 100644 contrib/dlz/modules/ldap/testing/named.conf create mode 100644 contrib/dlz/modules/ldap/testing/slapd.conf create mode 100644 contrib/dlz/modules/mysql/Makefile.in create mode 100644 contrib/dlz/modules/mysql/dlz_mysql_dynamic.c create mode 100644 contrib/dlz/modules/mysql/testing/README create mode 100644 contrib/dlz/modules/mysql/testing/dlz.data create mode 100644 contrib/dlz/modules/mysql/testing/dlz.schema create mode 100644 contrib/dlz/modules/mysql/testing/named.conf create mode 100644 contrib/dlz/modules/mysqldyn/Makefile.in create mode 100644 contrib/dlz/modules/mysqldyn/README create mode 100644 contrib/dlz/modules/mysqldyn/dlz_mysqldyn_mod.c create mode 100644 contrib/dlz/modules/mysqldyn/testing/README create mode 100644 contrib/dlz/modules/mysqldyn/testing/dlz.data create mode 100644 contrib/dlz/modules/mysqldyn/testing/dlz.schema create mode 100644 contrib/dlz/modules/mysqldyn/testing/named.conf create mode 100644 contrib/dlz/modules/perl/Makefile create mode 100644 contrib/dlz/modules/perl/README create mode 100644 contrib/dlz/modules/perl/dlz_perl_callback.xs create mode 100644 contrib/dlz/modules/perl/dlz_perl_callback_clientinfo.xs create mode 100644 contrib/dlz/modules/perl/dlz_perl_driver.c create mode 100644 contrib/dlz/modules/perl/dlz_perl_driver.h create mode 100644 contrib/dlz/modules/perl/testing/dlz_perl_example.pm create mode 100644 contrib/dlz/modules/perl/testing/named.conf create mode 100644 contrib/dlz/modules/sqlite3/Makefile create mode 100644 contrib/dlz/modules/sqlite3/dlz_sqlite3_dynamic.c create mode 100644 contrib/dlz/modules/sqlite3/testing/README create mode 100644 contrib/dlz/modules/sqlite3/testing/dlz.data create mode 100644 contrib/dlz/modules/sqlite3/testing/dlz.schema create mode 100644 contrib/dlz/modules/sqlite3/testing/named.conf create mode 100644 contrib/dlz/modules/wildcard/Makefile create mode 100644 contrib/dlz/modules/wildcard/README create mode 100644 contrib/dlz/modules/wildcard/dlz_wildcard_dynamic.c create mode 100644 contrib/dlz/modules/wildcard/testing/named.conf create mode 100644 contrib/dnspriv/README.md create mode 100644 contrib/dnspriv/named.conf create mode 100644 contrib/dnspriv/nginx.conf create mode 100644 contrib/kasp/README create mode 100644 contrib/kasp/kasp.xml create mode 100644 contrib/kasp/kasp2policy.py create mode 100644 contrib/kasp/policy.good create mode 100644 contrib/scripts/catzhash.py create mode 100644 contrib/scripts/check-secure-delegation.pl.in create mode 100644 contrib/scripts/check5011.pl create mode 100644 contrib/scripts/dnssec-keyset.sh create mode 100644 contrib/scripts/named-bootconf.sh create mode 100644 contrib/scripts/nanny.pl create mode 100644 contrib/scripts/zone-edit.sh.in create mode 100644 dangerfile.py create mode 100644 doc/Makefile.in create mode 100644 doc/arm/.gitattributes create mode 100644 doc/arm/Makefile.in create mode 100644 doc/arm/_static/custom.css create mode 100644 doc/arm/advanced.rst create mode 100644 doc/arm/build.rst create mode 100644 doc/arm/catz.rst create mode 100644 doc/arm/conf.py create mode 100644 doc/arm/configuration.rst create mode 100644 doc/arm/dlz.rst create mode 100644 doc/arm/dnssec-guide.rst create mode 100644 doc/arm/dnssec.inc.rst create mode 100644 doc/arm/dyndb.rst create mode 100644 doc/arm/general.rst create mode 100644 doc/arm/history.rst create mode 100644 doc/arm/index.rst create mode 100644 doc/arm/introduction.rst create mode 100644 doc/arm/isc-logo.pdf create mode 100644 doc/arm/logging-categories.rst create mode 100644 doc/arm/managed-keys.rst create mode 100644 doc/arm/manpages.rst create mode 100644 doc/arm/notes.rst create mode 100644 doc/arm/pkcs11.rst create mode 100644 doc/arm/platforms.rst create mode 100644 doc/arm/plugins.rst create mode 100644 doc/arm/reference.rst create mode 100644 doc/arm/requirements.rst create mode 100644 doc/arm/requirements.txt create mode 100644 doc/arm/security.rst create mode 100644 doc/arm/troubleshooting.rst create mode 100644 doc/dnssec-guide/advanced-discussions.rst create mode 100644 doc/dnssec-guide/commonly-asked-questions.rst create mode 100644 doc/dnssec-guide/getting-started.rst create mode 100644 doc/dnssec-guide/img/add-ds-1.png create mode 100644 doc/dnssec-guide/img/add-ds-2.png create mode 100644 doc/dnssec-guide/img/add-ds-3.png create mode 100644 doc/dnssec-guide/img/add-ds-4.png create mode 100644 doc/dnssec-guide/img/add-ds-5.png create mode 100644 doc/dnssec-guide/img/add-ds-6.png create mode 100644 doc/dnssec-guide/img/dnssec-12-steps.png create mode 100644 doc/dnssec-guide/img/dnssec-8-steps.png create mode 100644 doc/dnssec-guide/img/dnssec-inline-signing-1.png create mode 100644 doc/dnssec-guide/img/dnssec-inline-signing-2.png create mode 100644 doc/dnssec-guide/img/dnsviz-example-small.png create mode 100644 doc/dnssec-guide/img/remove-ds-1.png create mode 100644 doc/dnssec-guide/img/remove-ds-2.png create mode 100644 doc/dnssec-guide/img/remove-ds-3.png create mode 100644 doc/dnssec-guide/img/signature-generation.png create mode 100644 doc/dnssec-guide/img/signature-verification.png create mode 100644 doc/dnssec-guide/img/unsign-1.png create mode 100644 doc/dnssec-guide/img/unsign-2.png create mode 100644 doc/dnssec-guide/img/unsign-3.png create mode 100644 doc/dnssec-guide/img/unsign-4.png create mode 100644 doc/dnssec-guide/img/verisign-dnssec-debugger-example.png create mode 100644 doc/dnssec-guide/introduction.rst create mode 100644 doc/dnssec-guide/preface.rst create mode 100644 doc/dnssec-guide/recipes.rst create mode 100644 doc/dnssec-guide/signing.rst create mode 100644 doc/dnssec-guide/troubleshooting.rst create mode 100644 doc/dnssec-guide/validation.rst create mode 100644 doc/doxygen/Doxyfile.in create mode 100644 doc/doxygen/Makefile.in create mode 100644 doc/doxygen/doxygen-input-filter.in create mode 100644 doc/doxygen/isc-footer.html create mode 100644 doc/doxygen/isc-header.html create mode 100644 doc/doxygen/mainpage create mode 100644 doc/man/Makefile.in create mode 100644 doc/man/arpaname.1in create mode 100644 doc/man/arpaname.rst create mode 100644 doc/man/conf.py create mode 100644 doc/man/ddns-confgen.8in create mode 100644 doc/man/ddns-confgen.rst create mode 100644 doc/man/delv.1in create mode 100644 doc/man/delv.rst create mode 100644 doc/man/dig.1in create mode 100644 doc/man/dig.rst create mode 100644 doc/man/dnssec-cds.8in create mode 100644 doc/man/dnssec-cds.rst create mode 100644 doc/man/dnssec-checkds.8in create mode 100644 doc/man/dnssec-checkds.rst create mode 100644 doc/man/dnssec-coverage.8in create mode 100644 doc/man/dnssec-coverage.rst create mode 100644 doc/man/dnssec-dsfromkey.8in create mode 100644 doc/man/dnssec-dsfromkey.rst create mode 100644 doc/man/dnssec-importkey.8in create mode 100644 doc/man/dnssec-importkey.rst create mode 100644 doc/man/dnssec-keyfromlabel.8in create mode 100644 doc/man/dnssec-keyfromlabel.rst create mode 100644 doc/man/dnssec-keygen.8in create mode 100644 doc/man/dnssec-keygen.rst create mode 100644 doc/man/dnssec-keymgr.8in create mode 100644 doc/man/dnssec-keymgr.rst create mode 100644 doc/man/dnssec-revoke.8in create mode 100644 doc/man/dnssec-revoke.rst create mode 100644 doc/man/dnssec-settime.8in create mode 100644 doc/man/dnssec-settime.rst create mode 100644 doc/man/dnssec-signzone.8in create mode 100644 doc/man/dnssec-signzone.rst create mode 100644 doc/man/dnssec-verify.8in create mode 100644 doc/man/dnssec-verify.rst create mode 100644 doc/man/dnstap-read.1in create mode 100644 doc/man/dnstap-read.rst create mode 100644 doc/man/filter-aaaa.8in create mode 100644 doc/man/filter-aaaa.rst create mode 100644 doc/man/host.1in create mode 100644 doc/man/host.rst create mode 100644 doc/man/index.rst create mode 100644 doc/man/mdig.1in create mode 100644 doc/man/mdig.rst create mode 100644 doc/man/named-checkconf.8in create mode 100644 doc/man/named-checkconf.rst create mode 100644 doc/man/named-checkzone.8in create mode 100644 doc/man/named-checkzone.rst create mode 100644 doc/man/named-compilezone.8in create mode 100644 doc/man/named-compilezone.rst create mode 100644 doc/man/named-journalprint.8in create mode 100644 doc/man/named-journalprint.rst create mode 100644 doc/man/named-nzd2nzf.8in create mode 100644 doc/man/named-nzd2nzf.rst create mode 100644 doc/man/named-rrchecker.1in create mode 100644 doc/man/named-rrchecker.rst create mode 100644 doc/man/named.8in create mode 100644 doc/man/named.conf.5in create mode 100644 doc/man/named.conf.rst create mode 100644 doc/man/named.rst create mode 100644 doc/man/nsec3hash.8in create mode 100644 doc/man/nsec3hash.rst create mode 100644 doc/man/nslookup.1in create mode 100644 doc/man/nslookup.rst create mode 100644 doc/man/nsupdate.1in create mode 100644 doc/man/nsupdate.rst create mode 100644 doc/man/pkcs11-destroy.8in create mode 100644 doc/man/pkcs11-destroy.rst create mode 100644 doc/man/pkcs11-keygen.8in create mode 100644 doc/man/pkcs11-keygen.rst create mode 100644 doc/man/pkcs11-list.8in create mode 100644 doc/man/pkcs11-list.rst create mode 100644 doc/man/pkcs11-tokens.8in create mode 100644 doc/man/pkcs11-tokens.rst create mode 100644 doc/man/rndc-confgen.8in create mode 100644 doc/man/rndc-confgen.rst create mode 100644 doc/man/rndc.8in create mode 100644 doc/man/rndc.conf.5in create mode 100644 doc/man/rndc.conf.rst create mode 100644 doc/man/rndc.rst create mode 100644 doc/man/tsig-keygen.8in create mode 100644 doc/man/tsig-keygen.rst create mode 100644 doc/misc/Makefile.in create mode 100644 doc/misc/acl.grammar.rst create mode 100644 doc/misc/controls.grammar.rst create mode 100644 doc/misc/delegation-only.zoneopt create mode 100644 doc/misc/delegation-only.zoneopt.rst create mode 100644 doc/misc/dnssec-policy.default.conf create mode 100644 doc/misc/dnssec-policy.grammar.rst create mode 100644 doc/misc/format-options.pl create mode 100644 doc/misc/forward.zoneopt create mode 100644 doc/misc/forward.zoneopt.rst create mode 100644 doc/misc/hint.zoneopt create mode 100644 doc/misc/hint.zoneopt.rst create mode 100644 doc/misc/in-view.zoneopt create mode 100644 doc/misc/in-view.zoneopt.rst create mode 100644 doc/misc/key.grammar.rst create mode 100644 doc/misc/logging.grammar.rst create mode 100644 doc/misc/managed-keys.grammar.rst create mode 100644 doc/misc/master.zoneopt create mode 100644 doc/misc/master.zoneopt.rst create mode 100644 doc/misc/mirror.zoneopt create mode 100644 doc/misc/mirror.zoneopt.rst create mode 100644 doc/misc/options create mode 100644 doc/misc/options.active create mode 100644 doc/misc/options.grammar.rst create mode 100644 doc/misc/parental-agents.grammar.rst create mode 100644 doc/misc/primaries.grammar.rst create mode 100644 doc/misc/redirect.zoneopt create mode 100644 doc/misc/redirect.zoneopt.rst create mode 100644 doc/misc/rst-grammars.pl create mode 100644 doc/misc/rst-options.pl create mode 100644 doc/misc/rst-zoneopt.pl create mode 100644 doc/misc/server.grammar.rst create mode 100644 doc/misc/slave.zoneopt create mode 100644 doc/misc/slave.zoneopt.rst create mode 100644 doc/misc/sort-options.pl create mode 100644 doc/misc/static-stub.zoneopt create mode 100644 doc/misc/static-stub.zoneopt.rst create mode 100644 doc/misc/statistics-channels.grammar.rst create mode 100644 doc/misc/stub.zoneopt create mode 100644 doc/misc/stub.zoneopt.rst create mode 100644 doc/misc/trust-anchors.grammar.rst create mode 100644 doc/misc/trusted-keys.grammar.rst create mode 100644 doc/notes/notes-9.16.0.rst create mode 100644 doc/notes/notes-9.16.1.rst create mode 100644 doc/notes/notes-9.16.10.rst create mode 100644 doc/notes/notes-9.16.11.rst create mode 100644 doc/notes/notes-9.16.12.rst create mode 100644 doc/notes/notes-9.16.13.rst create mode 100644 doc/notes/notes-9.16.14.rst create mode 100644 doc/notes/notes-9.16.15.rst create mode 100644 doc/notes/notes-9.16.16.rst create mode 100644 doc/notes/notes-9.16.17.rst create mode 100644 doc/notes/notes-9.16.18.rst create mode 100644 doc/notes/notes-9.16.19.rst create mode 100644 doc/notes/notes-9.16.2.rst create mode 100644 doc/notes/notes-9.16.20.rst create mode 100644 doc/notes/notes-9.16.21.rst create mode 100644 doc/notes/notes-9.16.22.rst create mode 100644 doc/notes/notes-9.16.23.rst create mode 100644 doc/notes/notes-9.16.24.rst create mode 100644 doc/notes/notes-9.16.25.rst create mode 100644 doc/notes/notes-9.16.26.rst create mode 100644 doc/notes/notes-9.16.27.rst create mode 100644 doc/notes/notes-9.16.28.rst create mode 100644 doc/notes/notes-9.16.29.rst create mode 100644 doc/notes/notes-9.16.3.rst create mode 100644 doc/notes/notes-9.16.30.rst create mode 100644 doc/notes/notes-9.16.31.rst create mode 100644 doc/notes/notes-9.16.32.rst create mode 100644 doc/notes/notes-9.16.33.rst create mode 100644 doc/notes/notes-9.16.34.rst create mode 100644 doc/notes/notes-9.16.35.rst create mode 100644 doc/notes/notes-9.16.36.rst create mode 100644 doc/notes/notes-9.16.37.rst create mode 100644 doc/notes/notes-9.16.38.rst create mode 100644 doc/notes/notes-9.16.39.rst create mode 100644 doc/notes/notes-9.16.4.rst create mode 100644 doc/notes/notes-9.16.40.rst create mode 100644 doc/notes/notes-9.16.41.rst create mode 100644 doc/notes/notes-9.16.42.rst create mode 100644 doc/notes/notes-9.16.43.rst create mode 100644 doc/notes/notes-9.16.44.rst create mode 100644 doc/notes/notes-9.16.5.rst create mode 100644 doc/notes/notes-9.16.6.rst create mode 100644 doc/notes/notes-9.16.7.rst create mode 100644 doc/notes/notes-9.16.8.rst create mode 100644 doc/notes/notes-9.16.9.rst create mode 100644 doc/notes/notes-known-issues.rst create mode 100644 fuzz/FUZZING.md create mode 100644 fuzz/Makefile.in create mode 100644 fuzz/dns_master_load.in/generate-counter-overflow.db create mode 100644 fuzz/dns_name_fromtext_target.c create mode 100644 fuzz/dns_name_fromtext_target.in/example.com create mode 100644 fuzz/dns_rdata_fromtext.in/svbc-max-token create mode 100644 fuzz/dns_rdata_fromwire_text.c create mode 100644 fuzz/dns_rdata_fromwire_text.in/cdnskey create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-0 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-1 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-10 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-100 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-101 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-102 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-103 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-104 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-105 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-106 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-107 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-108 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-109 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-11 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-110 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-111 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-112 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-113 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-114 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-115 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-116 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-117 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-118 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-119 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-12 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-120 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-121 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-122 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-123 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-124 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-125 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-126 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-127 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-128 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-129 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-13 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-130 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-131 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-132 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-133 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-134 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-135 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-136 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-137 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-138 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-139 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-14 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-140 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-141 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-142 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-143 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-15 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-16 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-17 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-18 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-19 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-2 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-20 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-21 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-22 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-23 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-24 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-25 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-26 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-27 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-28 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-29 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-3 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-30 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-31 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-32 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-33 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-34 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-35 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-36 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-37 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-38 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-39 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-4 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-40 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-41 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-42 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-43 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-44 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-45 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-46 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-47 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-48 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-49 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-5 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-50 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-51 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-52 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-53 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-54 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-55 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-56 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-57 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-58 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-59 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-6 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-60 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-61 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-62 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-63 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-64 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-65 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-66 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-67 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-68 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-69 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-7 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-70 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-71 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-72 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-73 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-74 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-75 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-76 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-77 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-78 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-79 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-8 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-80 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-81 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-82 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-83 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-84 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-85 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-86 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-87 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-88 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-89 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-9 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-90 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-91 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-92 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-93 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-94 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-95 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-96 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-97 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-98 create mode 100644 fuzz/dns_rdata_fromwire_text.in/input-99 create mode 100644 fuzz/dns_rdata_fromwire_text.in/smimea create mode 100644 fuzz/dns_rdata_fromwire_text.in/sshfp create mode 100644 fuzz/dns_rdata_fromwire_text.in/svcb create mode 100644 fuzz/fuzz.h create mode 100644 fuzz/main.c create mode 100755 install-sh create mode 100644 lib/Kyuafile create mode 100644 lib/Makefile.in create mode 100644 lib/bind9/Makefile.in create mode 100644 lib/bind9/check.c create mode 100644 lib/bind9/getaddresses.c create mode 120000 lib/bind9/include/.clang-format create mode 100644 lib/bind9/include/Makefile.in create mode 100644 lib/bind9/include/bind9/Makefile.in create mode 100644 lib/bind9/include/bind9/check.h create mode 100644 lib/bind9/include/bind9/getaddresses.h create mode 100644 lib/bind9/include/bind9/version.h create mode 100644 lib/bind9/version.c create mode 100644 lib/bind9/win32/DLLMain.c create mode 100644 lib/bind9/win32/libbind9.def create mode 100644 lib/bind9/win32/libbind9.vcxproj.filters.in create mode 100644 lib/bind9/win32/libbind9.vcxproj.in create mode 100644 lib/bind9/win32/libbind9.vcxproj.user create mode 100644 lib/bind9/win32/version.c create mode 100644 lib/dns/Kyuafile create mode 100644 lib/dns/Makefile.in create mode 100644 lib/dns/acl.c create mode 100644 lib/dns/adb.c create mode 100644 lib/dns/badcache.c create mode 100644 lib/dns/byaddr.c create mode 100644 lib/dns/cache.c create mode 100644 lib/dns/callbacks.c create mode 100644 lib/dns/catz.c create mode 100644 lib/dns/client.c create mode 100644 lib/dns/clientinfo.c create mode 100644 lib/dns/compress.c create mode 100644 lib/dns/db.c create mode 100644 lib/dns/dbiterator.c create mode 100644 lib/dns/dbtable.c create mode 100644 lib/dns/diff.c create mode 100644 lib/dns/dispatch.c create mode 100644 lib/dns/dlz.c create mode 100644 lib/dns/dns64.c create mode 100644 lib/dns/dnsrps.c create mode 100644 lib/dns/dnssec.c create mode 100644 lib/dns/dnstap.c create mode 100644 lib/dns/dnstap.proto create mode 100644 lib/dns/ds.c create mode 100644 lib/dns/dst_api.c create mode 100644 lib/dns/dst_internal.h create mode 100644 lib/dns/dst_openssl.h create mode 100644 lib/dns/dst_parse.c create mode 100644 lib/dns/dst_parse.h create mode 100644 lib/dns/dst_pkcs11.h create mode 100644 lib/dns/dst_result.c create mode 100644 lib/dns/dyndb.c create mode 100644 lib/dns/ecdb.c create mode 100644 lib/dns/ecs.c create mode 100644 lib/dns/fixedname.c create mode 100644 lib/dns/forward.c create mode 100644 lib/dns/gen-unix.h create mode 100644 lib/dns/gen-win32.h create mode 100644 lib/dns/gen.c create mode 100644 lib/dns/geoip2.c create mode 100644 lib/dns/gssapi_link.c create mode 100644 lib/dns/gssapictx.c create mode 100644 lib/dns/hmac_link.c create mode 120000 lib/dns/include/.clang-format create mode 100644 lib/dns/include/Makefile.in create mode 100644 lib/dns/include/dns/Makefile.in create mode 100644 lib/dns/include/dns/acl.h create mode 100644 lib/dns/include/dns/adb.h create mode 100644 lib/dns/include/dns/badcache.h create mode 100644 lib/dns/include/dns/bit.h create mode 100644 lib/dns/include/dns/byaddr.h create mode 100644 lib/dns/include/dns/cache.h create mode 100644 lib/dns/include/dns/callbacks.h create mode 100644 lib/dns/include/dns/catz.h create mode 100644 lib/dns/include/dns/cert.h create mode 100644 lib/dns/include/dns/client.h create mode 100644 lib/dns/include/dns/clientinfo.h create mode 100644 lib/dns/include/dns/compress.h create mode 100644 lib/dns/include/dns/db.h create mode 100644 lib/dns/include/dns/dbiterator.h create mode 100644 lib/dns/include/dns/dbtable.h create mode 100644 lib/dns/include/dns/diff.h create mode 100644 lib/dns/include/dns/dispatch.h create mode 100644 lib/dns/include/dns/dlz.h create mode 100644 lib/dns/include/dns/dlz_dlopen.h create mode 100644 lib/dns/include/dns/dns64.h create mode 100644 lib/dns/include/dns/dnsrps.h create mode 100644 lib/dns/include/dns/dnssec.h create mode 100644 lib/dns/include/dns/dnstap.h create mode 100644 lib/dns/include/dns/ds.h create mode 100644 lib/dns/include/dns/dsdigest.h create mode 100644 lib/dns/include/dns/dyndb.h create mode 100644 lib/dns/include/dns/ecdb.h create mode 100644 lib/dns/include/dns/ecs.h create mode 100644 lib/dns/include/dns/edns.h create mode 100644 lib/dns/include/dns/events.h create mode 100644 lib/dns/include/dns/fixedname.h create mode 100644 lib/dns/include/dns/forward.h create mode 100644 lib/dns/include/dns/geoip.h create mode 100644 lib/dns/include/dns/ipkeylist.h create mode 100644 lib/dns/include/dns/iptable.h create mode 100644 lib/dns/include/dns/journal.h create mode 100644 lib/dns/include/dns/kasp.h create mode 100644 lib/dns/include/dns/keydata.h create mode 100644 lib/dns/include/dns/keyflags.h create mode 100644 lib/dns/include/dns/keymgr.h create mode 100644 lib/dns/include/dns/keytable.h create mode 100644 lib/dns/include/dns/keyvalues.h create mode 100644 lib/dns/include/dns/lib.h create mode 100644 lib/dns/include/dns/librpz.h create mode 100644 lib/dns/include/dns/lmdb.h create mode 100644 lib/dns/include/dns/log.h create mode 100644 lib/dns/include/dns/lookup.h create mode 100644 lib/dns/include/dns/master.h create mode 100644 lib/dns/include/dns/masterdump.h create mode 100644 lib/dns/include/dns/message.h create mode 100644 lib/dns/include/dns/name.h create mode 100644 lib/dns/include/dns/ncache.h create mode 100644 lib/dns/include/dns/nsec.h create mode 100644 lib/dns/include/dns/nsec3.h create mode 100644 lib/dns/include/dns/nta.h create mode 100644 lib/dns/include/dns/opcode.h create mode 100644 lib/dns/include/dns/order.h create mode 100644 lib/dns/include/dns/peer.h create mode 100644 lib/dns/include/dns/portlist.h create mode 100644 lib/dns/include/dns/private.h create mode 100644 lib/dns/include/dns/rbt.h create mode 100644 lib/dns/include/dns/rcode.h create mode 100644 lib/dns/include/dns/rdata.h create mode 100644 lib/dns/include/dns/rdataclass.h create mode 100644 lib/dns/include/dns/rdatalist.h create mode 100644 lib/dns/include/dns/rdataset.h create mode 100644 lib/dns/include/dns/rdatasetiter.h create mode 100644 lib/dns/include/dns/rdataslab.h create mode 100644 lib/dns/include/dns/rdatatype.h create mode 100644 lib/dns/include/dns/request.h create mode 100644 lib/dns/include/dns/resolver.h create mode 100644 lib/dns/include/dns/result.h create mode 100644 lib/dns/include/dns/rootns.h create mode 100644 lib/dns/include/dns/rpz.h create mode 100644 lib/dns/include/dns/rriterator.h create mode 100644 lib/dns/include/dns/rrl.h create mode 100644 lib/dns/include/dns/sdb.h create mode 100644 lib/dns/include/dns/sdlz.h create mode 100644 lib/dns/include/dns/secalg.h create mode 100644 lib/dns/include/dns/secproto.h create mode 100644 lib/dns/include/dns/soa.h create mode 100644 lib/dns/include/dns/ssu.h create mode 100644 lib/dns/include/dns/stats.h create mode 100644 lib/dns/include/dns/tcpmsg.h create mode 100644 lib/dns/include/dns/time.h create mode 100644 lib/dns/include/dns/timer.h create mode 100644 lib/dns/include/dns/tkey.h create mode 100644 lib/dns/include/dns/tsec.h create mode 100644 lib/dns/include/dns/tsig.h create mode 100644 lib/dns/include/dns/ttl.h create mode 100644 lib/dns/include/dns/types.h create mode 100644 lib/dns/include/dns/update.h create mode 100644 lib/dns/include/dns/validator.h create mode 100644 lib/dns/include/dns/version.h create mode 100644 lib/dns/include/dns/view.h create mode 100644 lib/dns/include/dns/xfrin.h create mode 100644 lib/dns/include/dns/zone.h create mode 100644 lib/dns/include/dns/zonekey.h create mode 100644 lib/dns/include/dns/zoneverify.h create mode 100644 lib/dns/include/dns/zt.h create mode 100644 lib/dns/include/dst/Makefile.in create mode 100644 lib/dns/include/dst/dst.h create mode 100644 lib/dns/include/dst/gssapi.h create mode 100644 lib/dns/include/dst/result.h create mode 100644 lib/dns/ipkeylist.c create mode 100644 lib/dns/iptable.c create mode 100644 lib/dns/journal.c create mode 100644 lib/dns/kasp.c create mode 100644 lib/dns/key.c create mode 100644 lib/dns/keydata.c create mode 100644 lib/dns/keymgr.c create mode 100644 lib/dns/keytable.c create mode 100644 lib/dns/lib.c create mode 100644 lib/dns/log.c create mode 100644 lib/dns/lookup.c create mode 100644 lib/dns/mapapi create mode 100644 lib/dns/master.c create mode 100644 lib/dns/masterdump.c create mode 100644 lib/dns/message.c create mode 100644 lib/dns/name.c create mode 100644 lib/dns/ncache.c create mode 100644 lib/dns/nsec.c create mode 100644 lib/dns/nsec3.c create mode 100644 lib/dns/nta.c create mode 100644 lib/dns/openssl_link.c create mode 100644 lib/dns/openssldh_link.c create mode 100644 lib/dns/opensslecdsa_link.c create mode 100644 lib/dns/openssleddsa_link.c create mode 100644 lib/dns/opensslrsa_link.c create mode 100644 lib/dns/order.c create mode 100644 lib/dns/peer.c create mode 100644 lib/dns/pkcs11.c create mode 100644 lib/dns/pkcs11ecdsa_link.c create mode 100644 lib/dns/pkcs11eddsa_link.c create mode 100644 lib/dns/pkcs11rsa_link.c create mode 100644 lib/dns/portlist.c create mode 100644 lib/dns/private.c create mode 100644 lib/dns/rbt.c create mode 100644 lib/dns/rbtdb.c create mode 100644 lib/dns/rbtdb.h create mode 100644 lib/dns/rcode.c create mode 100644 lib/dns/rdata.c create mode 100644 lib/dns/rdata/any_255/tsig_250.c create mode 100644 lib/dns/rdata/any_255/tsig_250.h create mode 100644 lib/dns/rdata/ch_3/a_1.c create mode 100644 lib/dns/rdata/ch_3/a_1.h create mode 100644 lib/dns/rdata/generic/afsdb_18.c create mode 100644 lib/dns/rdata/generic/afsdb_18.h create mode 100644 lib/dns/rdata/generic/amtrelay_260.c create mode 100644 lib/dns/rdata/generic/amtrelay_260.h create mode 100644 lib/dns/rdata/generic/avc_258.c create mode 100644 lib/dns/rdata/generic/avc_258.h create mode 100644 lib/dns/rdata/generic/caa_257.c create mode 100644 lib/dns/rdata/generic/caa_257.h create mode 100644 lib/dns/rdata/generic/cdnskey_60.c create mode 100644 lib/dns/rdata/generic/cdnskey_60.h create mode 100644 lib/dns/rdata/generic/cds_59.c create mode 100644 lib/dns/rdata/generic/cds_59.h create mode 100644 lib/dns/rdata/generic/cert_37.c create mode 100644 lib/dns/rdata/generic/cert_37.h create mode 100644 lib/dns/rdata/generic/cname_5.c create mode 100644 lib/dns/rdata/generic/cname_5.h create mode 100644 lib/dns/rdata/generic/csync_62.c create mode 100644 lib/dns/rdata/generic/csync_62.h create mode 100644 lib/dns/rdata/generic/dlv_32769.c create mode 100644 lib/dns/rdata/generic/dlv_32769.h create mode 100644 lib/dns/rdata/generic/dname_39.c create mode 100644 lib/dns/rdata/generic/dname_39.h create mode 100644 lib/dns/rdata/generic/dnskey_48.c create mode 100644 lib/dns/rdata/generic/dnskey_48.h create mode 100644 lib/dns/rdata/generic/doa_259.c create mode 100644 lib/dns/rdata/generic/doa_259.h create mode 100644 lib/dns/rdata/generic/ds_43.c create mode 100644 lib/dns/rdata/generic/ds_43.h create mode 100644 lib/dns/rdata/generic/eui48_108.c create mode 100644 lib/dns/rdata/generic/eui48_108.h create mode 100644 lib/dns/rdata/generic/eui64_109.c create mode 100644 lib/dns/rdata/generic/eui64_109.h create mode 100644 lib/dns/rdata/generic/gpos_27.c create mode 100644 lib/dns/rdata/generic/gpos_27.h create mode 100644 lib/dns/rdata/generic/hinfo_13.c create mode 100644 lib/dns/rdata/generic/hinfo_13.h create mode 100644 lib/dns/rdata/generic/hip_55.c create mode 100644 lib/dns/rdata/generic/hip_55.h create mode 100644 lib/dns/rdata/generic/ipseckey_45.c create mode 100644 lib/dns/rdata/generic/ipseckey_45.h create mode 100644 lib/dns/rdata/generic/isdn_20.c create mode 100644 lib/dns/rdata/generic/isdn_20.h create mode 100644 lib/dns/rdata/generic/key_25.c create mode 100644 lib/dns/rdata/generic/key_25.h create mode 100644 lib/dns/rdata/generic/keydata_65533.c create mode 100644 lib/dns/rdata/generic/keydata_65533.h create mode 100644 lib/dns/rdata/generic/l32_105.c create mode 100644 lib/dns/rdata/generic/l32_105.h create mode 100644 lib/dns/rdata/generic/l64_106.c create mode 100644 lib/dns/rdata/generic/l64_106.h create mode 100644 lib/dns/rdata/generic/loc_29.c create mode 100644 lib/dns/rdata/generic/loc_29.h create mode 100644 lib/dns/rdata/generic/lp_107.c create mode 100644 lib/dns/rdata/generic/lp_107.h create mode 100644 lib/dns/rdata/generic/mb_7.c create mode 100644 lib/dns/rdata/generic/mb_7.h create mode 100644 lib/dns/rdata/generic/md_3.c create mode 100644 lib/dns/rdata/generic/md_3.h create mode 100644 lib/dns/rdata/generic/mf_4.c create mode 100644 lib/dns/rdata/generic/mf_4.h create mode 100644 lib/dns/rdata/generic/mg_8.c create mode 100644 lib/dns/rdata/generic/mg_8.h create mode 100644 lib/dns/rdata/generic/minfo_14.c create mode 100644 lib/dns/rdata/generic/minfo_14.h create mode 100644 lib/dns/rdata/generic/mr_9.c create mode 100644 lib/dns/rdata/generic/mr_9.h create mode 100644 lib/dns/rdata/generic/mx_15.c create mode 100644 lib/dns/rdata/generic/mx_15.h create mode 100644 lib/dns/rdata/generic/naptr_35.c create mode 100644 lib/dns/rdata/generic/naptr_35.h create mode 100644 lib/dns/rdata/generic/nid_104.c create mode 100644 lib/dns/rdata/generic/nid_104.h create mode 100644 lib/dns/rdata/generic/ninfo_56.c create mode 100644 lib/dns/rdata/generic/ninfo_56.h create mode 100644 lib/dns/rdata/generic/ns_2.c create mode 100644 lib/dns/rdata/generic/ns_2.h create mode 100644 lib/dns/rdata/generic/nsec3_50.c create mode 100644 lib/dns/rdata/generic/nsec3_50.h create mode 100644 lib/dns/rdata/generic/nsec3param_51.c create mode 100644 lib/dns/rdata/generic/nsec3param_51.h create mode 100644 lib/dns/rdata/generic/nsec_47.c create mode 100644 lib/dns/rdata/generic/nsec_47.h create mode 100644 lib/dns/rdata/generic/null_10.c create mode 100644 lib/dns/rdata/generic/null_10.h create mode 100644 lib/dns/rdata/generic/nxt_30.c create mode 100644 lib/dns/rdata/generic/nxt_30.h create mode 100644 lib/dns/rdata/generic/openpgpkey_61.c create mode 100644 lib/dns/rdata/generic/openpgpkey_61.h create mode 100644 lib/dns/rdata/generic/opt_41.c create mode 100644 lib/dns/rdata/generic/opt_41.h create mode 100644 lib/dns/rdata/generic/proforma.c create mode 100644 lib/dns/rdata/generic/proforma.h create mode 100644 lib/dns/rdata/generic/ptr_12.c create mode 100644 lib/dns/rdata/generic/ptr_12.h create mode 100644 lib/dns/rdata/generic/rkey_57.c create mode 100644 lib/dns/rdata/generic/rkey_57.h create mode 100644 lib/dns/rdata/generic/rp_17.c create mode 100644 lib/dns/rdata/generic/rp_17.h create mode 100644 lib/dns/rdata/generic/rrsig_46.c create mode 100644 lib/dns/rdata/generic/rrsig_46.h create mode 100644 lib/dns/rdata/generic/rt_21.c create mode 100644 lib/dns/rdata/generic/rt_21.h create mode 100644 lib/dns/rdata/generic/sig_24.c create mode 100644 lib/dns/rdata/generic/sig_24.h create mode 100644 lib/dns/rdata/generic/sink_40.c create mode 100644 lib/dns/rdata/generic/sink_40.h create mode 100644 lib/dns/rdata/generic/smimea_53.c create mode 100644 lib/dns/rdata/generic/smimea_53.h create mode 100644 lib/dns/rdata/generic/soa_6.c create mode 100644 lib/dns/rdata/generic/soa_6.h create mode 100644 lib/dns/rdata/generic/spf_99.c create mode 100644 lib/dns/rdata/generic/spf_99.h create mode 100644 lib/dns/rdata/generic/sshfp_44.c create mode 100644 lib/dns/rdata/generic/sshfp_44.h create mode 100644 lib/dns/rdata/generic/ta_32768.c create mode 100644 lib/dns/rdata/generic/ta_32768.h create mode 100644 lib/dns/rdata/generic/talink_58.c create mode 100644 lib/dns/rdata/generic/talink_58.h create mode 100644 lib/dns/rdata/generic/tkey_249.c create mode 100644 lib/dns/rdata/generic/tkey_249.h create mode 100644 lib/dns/rdata/generic/tlsa_52.c create mode 100644 lib/dns/rdata/generic/tlsa_52.h create mode 100644 lib/dns/rdata/generic/txt_16.c create mode 100644 lib/dns/rdata/generic/txt_16.h create mode 100644 lib/dns/rdata/generic/uri_256.c create mode 100644 lib/dns/rdata/generic/uri_256.h create mode 100644 lib/dns/rdata/generic/x25_19.c create mode 100644 lib/dns/rdata/generic/x25_19.h create mode 100644 lib/dns/rdata/generic/zonemd_63.c create mode 100644 lib/dns/rdata/generic/zonemd_63.h create mode 100644 lib/dns/rdata/hs_4/a_1.c create mode 100644 lib/dns/rdata/hs_4/a_1.h create mode 100644 lib/dns/rdata/in_1/a6_38.c create mode 100644 lib/dns/rdata/in_1/a6_38.h create mode 100644 lib/dns/rdata/in_1/a_1.c create mode 100644 lib/dns/rdata/in_1/a_1.h create mode 100644 lib/dns/rdata/in_1/aaaa_28.c create mode 100644 lib/dns/rdata/in_1/aaaa_28.h create mode 100644 lib/dns/rdata/in_1/apl_42.c create mode 100644 lib/dns/rdata/in_1/apl_42.h create mode 100644 lib/dns/rdata/in_1/atma_34.c create mode 100644 lib/dns/rdata/in_1/atma_34.h create mode 100644 lib/dns/rdata/in_1/dhcid_49.c create mode 100644 lib/dns/rdata/in_1/dhcid_49.h create mode 100644 lib/dns/rdata/in_1/eid_31.c create mode 100644 lib/dns/rdata/in_1/eid_31.h create mode 100644 lib/dns/rdata/in_1/https_65.c create mode 100644 lib/dns/rdata/in_1/https_65.h create mode 100644 lib/dns/rdata/in_1/kx_36.c create mode 100644 lib/dns/rdata/in_1/kx_36.h create mode 100644 lib/dns/rdata/in_1/nimloc_32.c create mode 100644 lib/dns/rdata/in_1/nimloc_32.h create mode 100644 lib/dns/rdata/in_1/nsap-ptr_23.c create mode 100644 lib/dns/rdata/in_1/nsap-ptr_23.h create mode 100644 lib/dns/rdata/in_1/nsap_22.c create mode 100644 lib/dns/rdata/in_1/nsap_22.h create mode 100644 lib/dns/rdata/in_1/px_26.c create mode 100644 lib/dns/rdata/in_1/px_26.h create mode 100644 lib/dns/rdata/in_1/srv_33.c create mode 100644 lib/dns/rdata/in_1/srv_33.h create mode 100644 lib/dns/rdata/in_1/svcb_64.c create mode 100644 lib/dns/rdata/in_1/svcb_64.h create mode 100644 lib/dns/rdata/in_1/wks_11.c create mode 100644 lib/dns/rdata/in_1/wks_11.h create mode 100644 lib/dns/rdata/rdatastructpre.h create mode 100644 lib/dns/rdata/rdatastructsuf.h create mode 100644 lib/dns/rdatalist.c create mode 100644 lib/dns/rdatalist_p.h create mode 100644 lib/dns/rdataset.c create mode 100644 lib/dns/rdatasetiter.c create mode 100644 lib/dns/rdataslab.c create mode 100644 lib/dns/request.c create mode 100644 lib/dns/resolver.c create mode 100644 lib/dns/result.c create mode 100644 lib/dns/rootns.c create mode 100644 lib/dns/rpz.c create mode 100644 lib/dns/rriterator.c create mode 100644 lib/dns/rrl.c create mode 100644 lib/dns/sdb.c create mode 100644 lib/dns/sdlz.c create mode 100644 lib/dns/soa.c create mode 100644 lib/dns/ssu.c create mode 100644 lib/dns/ssu_external.c create mode 100644 lib/dns/stats.c create mode 100644 lib/dns/tcpmsg.c create mode 100644 lib/dns/tests/Kdh.+002+18602.key create mode 100644 lib/dns/tests/Krsa.+008+29238.key create mode 100644 lib/dns/tests/Kyuafile create mode 100644 lib/dns/tests/Makefile.in create mode 100644 lib/dns/tests/acl_test.c create mode 100644 lib/dns/tests/comparekeys/Kexample-d.+008+53461.key create mode 100644 lib/dns/tests/comparekeys/Kexample-d.+008+53461.private create mode 100644 lib/dns/tests/comparekeys/Kexample-e.+008+53973.key create mode 100644 lib/dns/tests/comparekeys/Kexample-e.+008+53973.private create mode 100644 lib/dns/tests/comparekeys/Kexample-n.+008+37464.key create mode 100644 lib/dns/tests/comparekeys/Kexample-n.+008+37464.private create mode 100644 lib/dns/tests/comparekeys/Kexample-p.+008+53461.key create mode 100644 lib/dns/tests/comparekeys/Kexample-p.+008+53461.private create mode 100644 lib/dns/tests/comparekeys/Kexample-private.+002+65316.key create mode 100644 lib/dns/tests/comparekeys/Kexample-private.+002+65316.private create mode 100644 lib/dns/tests/comparekeys/Kexample-q.+008+53461.key create mode 100644 lib/dns/tests/comparekeys/Kexample-q.+008+53461.private create mode 100644 lib/dns/tests/comparekeys/Kexample.+002+65316.key create mode 100644 lib/dns/tests/comparekeys/Kexample.+002+65316.private create mode 100644 lib/dns/tests/comparekeys/Kexample.+008+53461.key create mode 100644 lib/dns/tests/comparekeys/Kexample.+008+53461.private create mode 100644 lib/dns/tests/comparekeys/Kexample.+013+19786.key create mode 100644 lib/dns/tests/comparekeys/Kexample.+013+19786.private create mode 100644 lib/dns/tests/comparekeys/Kexample.+015+63663.key create mode 100644 lib/dns/tests/comparekeys/Kexample.+015+63663.private create mode 100644 lib/dns/tests/comparekeys/Kexample2.+002+19823.key create mode 100644 lib/dns/tests/comparekeys/Kexample2.+002+19823.private create mode 100644 lib/dns/tests/comparekeys/Kexample2.+008+37993.key create mode 100644 lib/dns/tests/comparekeys/Kexample2.+008+37993.private create mode 100644 lib/dns/tests/comparekeys/Kexample2.+013+16384.key create mode 100644 lib/dns/tests/comparekeys/Kexample2.+013+16384.private create mode 100644 lib/dns/tests/comparekeys/Kexample2.+015+37529.key create mode 100644 lib/dns/tests/comparekeys/Kexample2.+015+37529.private create mode 100644 lib/dns/tests/comparekeys/Kexample3.+002+17187.key create mode 100644 lib/dns/tests/comparekeys/Kexample3.+002+17187.private create mode 100644 lib/dns/tests/db_test.c create mode 100644 lib/dns/tests/dbdiff_test.c create mode 100644 lib/dns/tests/dbiterator_test.c create mode 100644 lib/dns/tests/dbversion_test.c create mode 100644 lib/dns/tests/dh_test.c create mode 100644 lib/dns/tests/dispatch_test.c create mode 100644 lib/dns/tests/dnstap_test.c create mode 100644 lib/dns/tests/dnstest.c create mode 100644 lib/dns/tests/dnstest.h create mode 100644 lib/dns/tests/dst_test.c create mode 100644 lib/dns/tests/geoip_test.c create mode 100644 lib/dns/tests/keytable_test.c create mode 100644 lib/dns/tests/master_test.c create mode 100644 lib/dns/tests/mkraw.pl create mode 100644 lib/dns/tests/name_test.c create mode 100644 lib/dns/tests/nsec3_test.c create mode 100644 lib/dns/tests/nsec3param_test.c create mode 100644 lib/dns/tests/peer_test.c create mode 100644 lib/dns/tests/private_test.c create mode 100644 lib/dns/tests/rbt_serialize_test.c create mode 100644 lib/dns/tests/rbt_test.c create mode 100644 lib/dns/tests/rbtdb_test.c create mode 100644 lib/dns/tests/rdata_test.c create mode 100644 lib/dns/tests/rdataset_test.c create mode 100644 lib/dns/tests/rdatasetstats_test.c create mode 100644 lib/dns/tests/resolver_test.c create mode 100644 lib/dns/tests/result_test.c create mode 100644 lib/dns/tests/rsa_test.c create mode 100644 lib/dns/tests/sigs_test.c create mode 100644 lib/dns/tests/testdata/db/data.db create mode 100644 lib/dns/tests/testdata/dbiterator/zone1.data create mode 100644 lib/dns/tests/testdata/dbiterator/zone2.data create mode 100644 lib/dns/tests/testdata/diff/zone1.data create mode 100644 lib/dns/tests/testdata/diff/zone2.data create mode 100644 lib/dns/tests/testdata/diff/zone3.data create mode 100644 lib/dns/tests/testdata/dnstap/dnstap.saved create mode 100644 lib/dns/tests/testdata/dnstap/dnstap.text create mode 100644 lib/dns/tests/testdata/dnstap/query.auth create mode 100644 lib/dns/tests/testdata/dnstap/query.recursive create mode 100644 lib/dns/tests/testdata/dnstap/response.auth create mode 100644 lib/dns/tests/testdata/dnstap/response.recursive create mode 100644 lib/dns/tests/testdata/dst/Ktest.+008+11349.key create mode 100644 lib/dns/tests/testdata/dst/Ktest.+008+11349.private create mode 100644 lib/dns/tests/testdata/dst/Ktest.+013+49130.key create mode 100644 lib/dns/tests/testdata/dst/Ktest.+013+49130.private create mode 100644 lib/dns/tests/testdata/dst/test1.data create mode 100644 lib/dns/tests/testdata/dst/test1.ecdsa256sig create mode 100644 lib/dns/tests/testdata/dst/test1.rsasha256sig create mode 100644 lib/dns/tests/testdata/dst/test2.data create mode 100644 lib/dns/tests/testdata/dstrandom/random.data create mode 100644 lib/dns/tests/testdata/master/master1.data create mode 100644 lib/dns/tests/testdata/master/master10.data create mode 100644 lib/dns/tests/testdata/master/master11.data create mode 100644 lib/dns/tests/testdata/master/master12.data.in create mode 100644 lib/dns/tests/testdata/master/master13.data.in create mode 100644 lib/dns/tests/testdata/master/master14.data.in create mode 100644 lib/dns/tests/testdata/master/master15.data create mode 100644 lib/dns/tests/testdata/master/master16.data create mode 100644 lib/dns/tests/testdata/master/master17.data create mode 100644 lib/dns/tests/testdata/master/master18.data create mode 100644 lib/dns/tests/testdata/master/master2.data create mode 100644 lib/dns/tests/testdata/master/master3.data create mode 100644 lib/dns/tests/testdata/master/master4.data create mode 100644 lib/dns/tests/testdata/master/master5.data create mode 100644 lib/dns/tests/testdata/master/master6.data create mode 100644 lib/dns/tests/testdata/master/master7.data create mode 100644 lib/dns/tests/testdata/master/master8.data create mode 100644 lib/dns/tests/testdata/master/master9.data create mode 100644 lib/dns/tests/testdata/nsec3/1024.db create mode 100644 lib/dns/tests/testdata/nsec3/2048.db create mode 100644 lib/dns/tests/testdata/nsec3/4096.db create mode 100644 lib/dns/tests/testdata/nsec3/min-1024.db create mode 100644 lib/dns/tests/testdata/nsec3/min-2048.db create mode 100644 lib/dns/tests/testdata/nsec3param/nsec3.db.signed create mode 100644 lib/dns/tests/testdata/zt/zone1.db create mode 100644 lib/dns/tests/testkeys/Kexample.+008+20386.key create mode 100644 lib/dns/tests/testkeys/Kexample.+008+20386.private create mode 100644 lib/dns/tests/testkeys/Kexample.+008+37464.key create mode 100644 lib/dns/tests/testkeys/Kexample.+008+37464.private create mode 100644 lib/dns/tests/time_test.c create mode 100644 lib/dns/tests/tsig_test.c create mode 100644 lib/dns/tests/update_test.c create mode 100644 lib/dns/tests/zonemgr_test.c create mode 100644 lib/dns/tests/zt_test.c create mode 100644 lib/dns/time.c create mode 100644 lib/dns/timer.c create mode 100644 lib/dns/tkey.c create mode 100644 lib/dns/tsec.c create mode 100644 lib/dns/tsig.c create mode 100644 lib/dns/tsig_p.h create mode 100644 lib/dns/ttl.c create mode 100644 lib/dns/update.c create mode 100644 lib/dns/validator.c create mode 100644 lib/dns/version.c create mode 100644 lib/dns/view.c create mode 100644 lib/dns/win32/DLLMain.c create mode 100644 lib/dns/win32/gen.vcxproj.filters.in create mode 100644 lib/dns/win32/gen.vcxproj.in create mode 100644 lib/dns/win32/gen.vcxproj.user create mode 100644 lib/dns/win32/libdns.def.in create mode 100644 lib/dns/win32/libdns.vcxproj.filters.in create mode 100644 lib/dns/win32/libdns.vcxproj.in create mode 100644 lib/dns/win32/libdns.vcxproj.user create mode 100644 lib/dns/win32/version.c create mode 100644 lib/dns/xfrin.c create mode 100644 lib/dns/zone.c create mode 100644 lib/dns/zone_p.h create mode 100644 lib/dns/zonekey.c create mode 100644 lib/dns/zoneverify.c create mode 100644 lib/dns/zt.c create mode 100644 lib/irs/Kyuafile create mode 100644 lib/irs/Makefile.in create mode 100644 lib/irs/context.c create mode 100644 lib/irs/dnsconf.c create mode 100644 lib/irs/gai_strerror.c create mode 100644 lib/irs/getaddrinfo.c create mode 100644 lib/irs/getnameinfo.c create mode 120000 lib/irs/include/.clang-format create mode 100644 lib/irs/include/Makefile.in create mode 100644 lib/irs/include/irs/Makefile.in create mode 100644 lib/irs/include/irs/context.h create mode 100644 lib/irs/include/irs/dnsconf.h create mode 100644 lib/irs/include/irs/netdb.h.in create mode 100644 lib/irs/include/irs/platform.h.in create mode 100644 lib/irs/include/irs/resconf.h create mode 100644 lib/irs/include/irs/types.h create mode 100644 lib/irs/include/irs/version.h create mode 100644 lib/irs/resconf.c create mode 100644 lib/irs/tests/Kyuafile create mode 100644 lib/irs/tests/Makefile.in create mode 100644 lib/irs/tests/resconf_test.c create mode 100644 lib/irs/tests/testdata/domain.conf create mode 100644 lib/irs/tests/testdata/nameserver-v4.conf create mode 100644 lib/irs/tests/testdata/nameserver-v6-scoped.conf create mode 100644 lib/irs/tests/testdata/nameserver-v6.conf create mode 100644 lib/irs/tests/testdata/options-bad-ndots.conf create mode 100644 lib/irs/tests/testdata/options-debug.conf create mode 100644 lib/irs/tests/testdata/options-empty.conf create mode 100644 lib/irs/tests/testdata/options-ndots.conf create mode 100644 lib/irs/tests/testdata/options-timeout.conf create mode 100644 lib/irs/tests/testdata/options-unknown.conf create mode 100644 lib/irs/tests/testdata/options.conf create mode 100644 lib/irs/tests/testdata/port.conf create mode 100644 lib/irs/tests/testdata/resolv.conf create mode 100644 lib/irs/tests/testdata/search.conf create mode 100644 lib/irs/tests/testdata/sortlist-v4.conf create mode 100644 lib/irs/tests/testdata/timeout.conf create mode 100644 lib/irs/tests/testdata/unknown.conf create mode 100644 lib/irs/version.c create mode 100644 lib/irs/win32/DLLMain.c create mode 100644 lib/irs/win32/Makefile.in create mode 120000 lib/irs/win32/include/.clang-format create mode 100644 lib/irs/win32/include/Makefile.in create mode 100644 lib/irs/win32/include/irs/Makefile.in create mode 100644 lib/irs/win32/include/irs/netdb.h create mode 100644 lib/irs/win32/include/irs/platform.h create mode 100644 lib/irs/win32/libirs.def create mode 100644 lib/irs/win32/libirs.vcxproj.filters.in create mode 100644 lib/irs/win32/libirs.vcxproj.in create mode 100644 lib/irs/win32/libirs.vcxproj.user create mode 100644 lib/irs/win32/resconf.c create mode 100644 lib/irs/win32/version.c create mode 100644 lib/isc/Kyuafile create mode 100644 lib/isc/Makefile.in create mode 100644 lib/isc/aes.c create mode 100644 lib/isc/app.c create mode 100644 lib/isc/assertions.c create mode 100644 lib/isc/astack.c create mode 100644 lib/isc/backtrace-emptytbl.c create mode 100644 lib/isc/backtrace.c create mode 100644 lib/isc/base32.c create mode 100644 lib/isc/base64.c create mode 100644 lib/isc/bind9.c create mode 100644 lib/isc/buffer.c create mode 100644 lib/isc/bufferlist.c create mode 100644 lib/isc/commandline.c create mode 100644 lib/isc/counter.c create mode 100644 lib/isc/crc64.c create mode 100644 lib/isc/entropy.c create mode 100644 lib/isc/entropy_private.h create mode 100644 lib/isc/error.c create mode 100644 lib/isc/event.c create mode 100644 lib/isc/fsaccess.c create mode 100644 lib/isc/hash.c create mode 100644 lib/isc/heap.c create mode 100644 lib/isc/hex.c create mode 100644 lib/isc/hmac.c create mode 100644 lib/isc/ht.c create mode 100644 lib/isc/httpd.c create mode 120000 lib/isc/include/.clang-format create mode 100644 lib/isc/include/Makefile.in create mode 100644 lib/isc/include/isc/Makefile.in create mode 100644 lib/isc/include/isc/aes.h create mode 100644 lib/isc/include/isc/app.h create mode 100644 lib/isc/include/isc/assertions.h create mode 100644 lib/isc/include/isc/astack.h create mode 100644 lib/isc/include/isc/atomic.h create mode 100644 lib/isc/include/isc/backtrace.h create mode 100644 lib/isc/include/isc/barrier.h create mode 100644 lib/isc/include/isc/base32.h create mode 100644 lib/isc/include/isc/base64.h create mode 100644 lib/isc/include/isc/bind9.h create mode 100644 lib/isc/include/isc/buffer.h create mode 100644 lib/isc/include/isc/bufferlist.h create mode 100644 lib/isc/include/isc/cmocka.h create mode 100644 lib/isc/include/isc/commandline.h create mode 100644 lib/isc/include/isc/counter.h create mode 100644 lib/isc/include/isc/crc64.h create mode 100644 lib/isc/include/isc/deprecated.h create mode 100644 lib/isc/include/isc/endian.h create mode 100644 lib/isc/include/isc/errno.h create mode 100644 lib/isc/include/isc/error.h create mode 100644 lib/isc/include/isc/event.h create mode 100644 lib/isc/include/isc/eventclass.h create mode 100644 lib/isc/include/isc/file.h create mode 100644 lib/isc/include/isc/formatcheck.h create mode 100644 lib/isc/include/isc/fsaccess.h create mode 100644 lib/isc/include/isc/fuzz.h create mode 100644 lib/isc/include/isc/hash.h create mode 100644 lib/isc/include/isc/heap.h create mode 100644 lib/isc/include/isc/hex.h create mode 100644 lib/isc/include/isc/hmac.h create mode 100644 lib/isc/include/isc/ht.h create mode 100644 lib/isc/include/isc/httpd.h create mode 100644 lib/isc/include/isc/interfaceiter.h create mode 100644 lib/isc/include/isc/iterated_hash.h create mode 100644 lib/isc/include/isc/lang.h create mode 100644 lib/isc/include/isc/lex.h create mode 100644 lib/isc/include/isc/lfsr.h create mode 100644 lib/isc/include/isc/lib.h create mode 100644 lib/isc/include/isc/likely.h create mode 100644 lib/isc/include/isc/list.h create mode 100644 lib/isc/include/isc/log.h create mode 100644 lib/isc/include/isc/magic.h create mode 100644 lib/isc/include/isc/managers.h create mode 100644 lib/isc/include/isc/md.h create mode 100644 lib/isc/include/isc/mem.h create mode 100644 lib/isc/include/isc/meminfo.h create mode 100644 lib/isc/include/isc/mutexblock.h create mode 100644 lib/isc/include/isc/netaddr.h create mode 100644 lib/isc/include/isc/netmgr.h create mode 100644 lib/isc/include/isc/netscope.h create mode 100644 lib/isc/include/isc/nonce.h create mode 100644 lib/isc/include/isc/os.h create mode 100644 lib/isc/include/isc/parseint.h create mode 100644 lib/isc/include/isc/platform.h.in create mode 100644 lib/isc/include/isc/pool.h create mode 100644 lib/isc/include/isc/portset.h create mode 100644 lib/isc/include/isc/print.h create mode 100644 lib/isc/include/isc/quota.h create mode 100644 lib/isc/include/isc/radix.h create mode 100644 lib/isc/include/isc/random.h create mode 100644 lib/isc/include/isc/ratelimiter.h create mode 100644 lib/isc/include/isc/refcount.h create mode 100644 lib/isc/include/isc/regex.h create mode 100644 lib/isc/include/isc/region.h create mode 100644 lib/isc/include/isc/resource.h create mode 100644 lib/isc/include/isc/result.h create mode 100644 lib/isc/include/isc/resultclass.h create mode 100644 lib/isc/include/isc/rwlock.h create mode 100644 lib/isc/include/isc/safe.h create mode 100644 lib/isc/include/isc/serial.h create mode 100644 lib/isc/include/isc/siphash.h create mode 100644 lib/isc/include/isc/sockaddr.h create mode 100644 lib/isc/include/isc/socket.h create mode 100644 lib/isc/include/isc/stats.h create mode 100644 lib/isc/include/isc/stdio.h create mode 100644 lib/isc/include/isc/strerr.h create mode 100644 lib/isc/include/isc/string.h create mode 100644 lib/isc/include/isc/symtab.h create mode 100644 lib/isc/include/isc/task.h create mode 100644 lib/isc/include/isc/taskpool.h create mode 100644 lib/isc/include/isc/timer.h create mode 100644 lib/isc/include/isc/tm.h create mode 100644 lib/isc/include/isc/types.h create mode 100644 lib/isc/include/isc/url.h create mode 100644 lib/isc/include/isc/utf8.h create mode 100644 lib/isc/include/isc/util.h create mode 100644 lib/isc/include/isc/version.h create mode 100644 lib/isc/include/pk11/Makefile.in create mode 100644 lib/isc/include/pk11/constants.h create mode 100644 lib/isc/include/pk11/internal.h create mode 100644 lib/isc/include/pk11/pk11.h create mode 100644 lib/isc/include/pk11/result.h create mode 100644 lib/isc/include/pk11/site.h create mode 100644 lib/isc/include/pkcs11/Makefile.in create mode 100644 lib/isc/include/pkcs11/pkcs11.h create mode 100644 lib/isc/iterated_hash.c create mode 100644 lib/isc/lex.c create mode 100644 lib/isc/lfsr.c create mode 100644 lib/isc/lib.c create mode 100644 lib/isc/lib_p.h create mode 100644 lib/isc/log.c create mode 100644 lib/isc/managers.c create mode 100644 lib/isc/md.c create mode 100644 lib/isc/mem.c create mode 100644 lib/isc/mem_p.h create mode 100644 lib/isc/mutexblock.c create mode 100644 lib/isc/netaddr.c create mode 100644 lib/isc/netmgr/Makefile.in create mode 100644 lib/isc/netmgr/netmgr-int.h create mode 100644 lib/isc/netmgr/netmgr.c create mode 100644 lib/isc/netmgr/tcp.c create mode 100644 lib/isc/netmgr/tcpdns.c create mode 100644 lib/isc/netmgr/udp.c create mode 100644 lib/isc/netmgr/uv-compat.c create mode 100644 lib/isc/netmgr/uv-compat.h create mode 100644 lib/isc/netmgr/uverr2result.c create mode 100644 lib/isc/netmgr_p.h create mode 100644 lib/isc/netscope.c create mode 100644 lib/isc/nonce.c create mode 100644 lib/isc/openssl_shim.c create mode 100644 lib/isc/openssl_shim.h create mode 100644 lib/isc/parseint.c create mode 100644 lib/isc/pk11.c create mode 100644 lib/isc/pk11_result.c create mode 100644 lib/isc/pool.c create mode 100644 lib/isc/portset.c create mode 100644 lib/isc/pthreads/Makefile.in create mode 100644 lib/isc/pthreads/condition.c create mode 120000 lib/isc/pthreads/include/.clang-format create mode 100644 lib/isc/pthreads/include/Makefile.in create mode 100644 lib/isc/pthreads/include/isc/Makefile.in create mode 100644 lib/isc/pthreads/include/isc/condition.h create mode 100644 lib/isc/pthreads/include/isc/mutex.h create mode 100644 lib/isc/pthreads/include/isc/once.h create mode 100644 lib/isc/pthreads/include/isc/thread.h create mode 100644 lib/isc/pthreads/mutex.c create mode 100644 lib/isc/pthreads/thread.c create mode 100644 lib/isc/quota.c create mode 100644 lib/isc/radix.c create mode 100644 lib/isc/random.c create mode 100644 lib/isc/ratelimiter.c create mode 100644 lib/isc/regex.c create mode 100644 lib/isc/region.c create mode 100644 lib/isc/result.c create mode 100644 lib/isc/rwlock.c create mode 100644 lib/isc/safe.c create mode 100644 lib/isc/serial.c create mode 100644 lib/isc/siphash.c create mode 100644 lib/isc/sockaddr.c create mode 100644 lib/isc/stats.c create mode 100644 lib/isc/string.c create mode 100644 lib/isc/symtab.c create mode 100644 lib/isc/task.c create mode 100644 lib/isc/task_p.h create mode 100644 lib/isc/taskpool.c create mode 100644 lib/isc/tests/Kyuafile create mode 100644 lib/isc/tests/Makefile.in create mode 100644 lib/isc/tests/aes_test.c create mode 100644 lib/isc/tests/buffer_test.c create mode 100644 lib/isc/tests/counter_test.c create mode 100644 lib/isc/tests/crc64_test.c create mode 100644 lib/isc/tests/errno_test.c create mode 100644 lib/isc/tests/file_test.c create mode 100644 lib/isc/tests/hash_test.c create mode 100644 lib/isc/tests/heap_test.c create mode 100644 lib/isc/tests/hmac_test.c create mode 100644 lib/isc/tests/ht_test.c create mode 100644 lib/isc/tests/isctest.c create mode 100644 lib/isc/tests/isctest.h create mode 100644 lib/isc/tests/lex_test.c create mode 100644 lib/isc/tests/md_test.c create mode 100644 lib/isc/tests/mem_test.c create mode 100644 lib/isc/tests/netaddr_test.c create mode 100644 lib/isc/tests/netmgr_test.c create mode 100644 lib/isc/tests/parse_test.c create mode 100644 lib/isc/tests/pool_test.c create mode 100644 lib/isc/tests/quota_test.c create mode 100644 lib/isc/tests/radix_test.c create mode 100644 lib/isc/tests/random_test.c create mode 100644 lib/isc/tests/regex_test.c create mode 100644 lib/isc/tests/result_test.c create mode 100644 lib/isc/tests/safe_test.c create mode 100644 lib/isc/tests/siphash_test.c create mode 100644 lib/isc/tests/sockaddr_test.c create mode 100644 lib/isc/tests/socket_test.c create mode 100644 lib/isc/tests/stats_test.c create mode 100644 lib/isc/tests/symtab_test.c create mode 100644 lib/isc/tests/task_test.c create mode 100644 lib/isc/tests/taskpool_test.c create mode 100644 lib/isc/tests/testdata/file/keep create mode 100644 lib/isc/tests/time_test.c create mode 100644 lib/isc/tests/timer_test.c create mode 100644 lib/isc/tests/uv_wrap.h create mode 100644 lib/isc/timer.c create mode 100644 lib/isc/timer_p.h create mode 100644 lib/isc/tls.c create mode 100644 lib/isc/tls_p.h create mode 100644 lib/isc/tm.c create mode 100644 lib/isc/trampoline.c create mode 100644 lib/isc/trampoline_p.h create mode 100644 lib/isc/unix/Makefile.in create mode 100644 lib/isc/unix/dir.c create mode 100644 lib/isc/unix/errno.c create mode 100644 lib/isc/unix/errno2result.c create mode 100644 lib/isc/unix/errno2result.h create mode 100644 lib/isc/unix/file.c create mode 100644 lib/isc/unix/fsaccess.c create mode 100644 lib/isc/unix/ifiter_getifaddrs.c create mode 120000 lib/isc/unix/include/.clang-format create mode 100644 lib/isc/unix/include/Makefile.in create mode 100644 lib/isc/unix/include/isc/Makefile.in create mode 100644 lib/isc/unix/include/isc/align.h create mode 100644 lib/isc/unix/include/isc/dir.h create mode 100644 lib/isc/unix/include/isc/net.h create mode 100644 lib/isc/unix/include/isc/netdb.h create mode 100644 lib/isc/unix/include/isc/offset.h create mode 100644 lib/isc/unix/include/isc/stat.h create mode 100644 lib/isc/unix/include/isc/stdatomic.h create mode 100644 lib/isc/unix/include/isc/stdtime.h create mode 100644 lib/isc/unix/include/isc/syslog.h create mode 100644 lib/isc/unix/include/isc/time.h create mode 100644 lib/isc/unix/interfaceiter.c create mode 100644 lib/isc/unix/meminfo.c create mode 100644 lib/isc/unix/net.c create mode 100644 lib/isc/unix/os.c create mode 100644 lib/isc/unix/pk11_api.c create mode 100644 lib/isc/unix/resource.c create mode 100644 lib/isc/unix/socket.c create mode 100644 lib/isc/unix/socket_p.h create mode 100644 lib/isc/unix/stdio.c create mode 100644 lib/isc/unix/stdtime.c create mode 100644 lib/isc/unix/syslog.c create mode 100644 lib/isc/unix/time.c create mode 100644 lib/isc/url.c create mode 100644 lib/isc/utf8.c create mode 100644 lib/isc/version.c create mode 100644 lib/isc/win32/.dir-locals.el create mode 100644 lib/isc/win32/DLLMain.c create mode 100644 lib/isc/win32/Makefile.in create mode 100644 lib/isc/win32/condition.c create mode 100644 lib/isc/win32/dir.c create mode 100644 lib/isc/win32/errno.c create mode 100644 lib/isc/win32/errno2result.c create mode 100644 lib/isc/win32/errno2result.h create mode 100644 lib/isc/win32/file.c create mode 100644 lib/isc/win32/fsaccess.c create mode 120000 lib/isc/win32/include/.clang-format create mode 100644 lib/isc/win32/include/Makefile.in create mode 100644 lib/isc/win32/include/isc/Makefile.in create mode 100644 lib/isc/win32/include/isc/align.h create mode 100644 lib/isc/win32/include/isc/bind_registry.h create mode 100644 lib/isc/win32/include/isc/bindevt.h create mode 100644 lib/isc/win32/include/isc/condition.h create mode 100644 lib/isc/win32/include/isc/dir.h create mode 100644 lib/isc/win32/include/isc/ipv6.h create mode 100644 lib/isc/win32/include/isc/mutex.h create mode 100644 lib/isc/win32/include/isc/net.h create mode 100644 lib/isc/win32/include/isc/netdb.h create mode 100644 lib/isc/win32/include/isc/ntgroups.h create mode 100644 lib/isc/win32/include/isc/ntpaths.h create mode 100644 lib/isc/win32/include/isc/offset.h create mode 100644 lib/isc/win32/include/isc/once.h create mode 100644 lib/isc/win32/include/isc/platform.h.in create mode 100644 lib/isc/win32/include/isc/stat.h create mode 100644 lib/isc/win32/include/isc/stdatomic.h create mode 100644 lib/isc/win32/include/isc/stdtime.h create mode 100644 lib/isc/win32/include/isc/syslog.h create mode 100644 lib/isc/win32/include/isc/thread.h create mode 100644 lib/isc/win32/include/isc/time.h create mode 100644 lib/isc/win32/include/isc/win32os.h create mode 100644 lib/isc/win32/interfaceiter.c create mode 100644 lib/isc/win32/ipv6.c create mode 100644 lib/isc/win32/libgen.h create mode 100644 lib/isc/win32/libisc.def.exclude create mode 100644 lib/isc/win32/libisc.def.in create mode 100644 lib/isc/win32/libisc.vcxproj.filters.in create mode 100644 lib/isc/win32/libisc.vcxproj.in create mode 100644 lib/isc/win32/libisc.vcxproj.user create mode 100644 lib/isc/win32/meminfo.c create mode 100644 lib/isc/win32/net.c create mode 100644 lib/isc/win32/netdb.h create mode 100644 lib/isc/win32/ntgroups.c create mode 100644 lib/isc/win32/ntpaths.c create mode 100644 lib/isc/win32/once.c create mode 100644 lib/isc/win32/os.c create mode 100644 lib/isc/win32/pk11_api.c create mode 100644 lib/isc/win32/resource.c create mode 100644 lib/isc/win32/socket.c create mode 100644 lib/isc/win32/stdio.c create mode 100644 lib/isc/win32/stdtime.c create mode 100644 lib/isc/win32/syslog.c create mode 100644 lib/isc/win32/syslog.h create mode 100644 lib/isc/win32/thread.c create mode 100644 lib/isc/win32/time.c create mode 100644 lib/isc/win32/unistd.h create mode 100644 lib/isc/win32/version.c create mode 100644 lib/isc/win32/win32os.c create mode 100644 lib/isc/xoshiro128starstar.c create mode 100644 lib/isccc/Kyuafile create mode 100644 lib/isccc/Makefile.in create mode 100644 lib/isccc/alist.c create mode 100644 lib/isccc/base64.c create mode 100644 lib/isccc/cc.c create mode 100644 lib/isccc/ccmsg.c create mode 120000 lib/isccc/include/.clang-format create mode 100644 lib/isccc/include/Makefile.in create mode 100644 lib/isccc/include/isccc/Makefile.in create mode 100644 lib/isccc/include/isccc/alist.h create mode 100644 lib/isccc/include/isccc/base64.h create mode 100644 lib/isccc/include/isccc/cc.h create mode 100644 lib/isccc/include/isccc/ccmsg.h create mode 100644 lib/isccc/include/isccc/events.h create mode 100644 lib/isccc/include/isccc/result.h create mode 100644 lib/isccc/include/isccc/sexpr.h create mode 100644 lib/isccc/include/isccc/symtab.h create mode 100644 lib/isccc/include/isccc/symtype.h create mode 100644 lib/isccc/include/isccc/types.h create mode 100644 lib/isccc/include/isccc/util.h create mode 100644 lib/isccc/include/isccc/version.h create mode 100644 lib/isccc/result.c create mode 100644 lib/isccc/sexpr.c create mode 100644 lib/isccc/symtab.c create mode 100644 lib/isccc/tests/Kyuafile create mode 100644 lib/isccc/tests/Makefile.in create mode 100644 lib/isccc/tests/result_test.c create mode 100644 lib/isccc/version.c create mode 100644 lib/isccc/win32/DLLMain.c create mode 100644 lib/isccc/win32/libisccc.def create mode 100644 lib/isccc/win32/libisccc.vcxproj.filters.in create mode 100644 lib/isccc/win32/libisccc.vcxproj.in create mode 100644 lib/isccc/win32/libisccc.vcxproj.user create mode 100644 lib/isccc/win32/version.c create mode 100644 lib/isccfg/Kyuafile create mode 100644 lib/isccfg/Makefile.in create mode 100644 lib/isccfg/aclconf.c create mode 100644 lib/isccfg/dnsconf.c create mode 120000 lib/isccfg/include/.clang-format create mode 100644 lib/isccfg/include/Makefile.in create mode 100644 lib/isccfg/include/isccfg/Makefile.in create mode 100644 lib/isccfg/include/isccfg/aclconf.h create mode 100644 lib/isccfg/include/isccfg/cfg.h create mode 100644 lib/isccfg/include/isccfg/dnsconf.h create mode 100644 lib/isccfg/include/isccfg/grammar.h create mode 100644 lib/isccfg/include/isccfg/kaspconf.h create mode 100644 lib/isccfg/include/isccfg/log.h create mode 100644 lib/isccfg/include/isccfg/namedconf.h create mode 100644 lib/isccfg/include/isccfg/version.h create mode 100644 lib/isccfg/kaspconf.c create mode 100644 lib/isccfg/log.c create mode 100644 lib/isccfg/namedconf.c create mode 100644 lib/isccfg/parser.c create mode 100644 lib/isccfg/tests/Kyuafile create mode 100644 lib/isccfg/tests/Makefile.in create mode 100644 lib/isccfg/tests/duration_test.c create mode 100644 lib/isccfg/tests/parser_test.c create mode 100644 lib/isccfg/version.c create mode 100644 lib/isccfg/win32/DLLMain.c create mode 100644 lib/isccfg/win32/libisccfg.def create mode 100644 lib/isccfg/win32/libisccfg.vcxproj.filters.in create mode 100644 lib/isccfg/win32/libisccfg.vcxproj.in create mode 100644 lib/isccfg/win32/libisccfg.vcxproj.user create mode 100644 lib/isccfg/win32/version.c create mode 100644 lib/ns/Kyuafile create mode 100644 lib/ns/Makefile.in create mode 100644 lib/ns/client.c create mode 100644 lib/ns/hooks.c create mode 120000 lib/ns/include/.clang-format create mode 100644 lib/ns/include/Makefile.in create mode 100644 lib/ns/include/ns/Makefile.in create mode 100644 lib/ns/include/ns/client.h create mode 100644 lib/ns/include/ns/hooks.h create mode 100644 lib/ns/include/ns/interfacemgr.h create mode 100644 lib/ns/include/ns/lib.h create mode 100644 lib/ns/include/ns/listenlist.h create mode 100644 lib/ns/include/ns/log.h create mode 100644 lib/ns/include/ns/notify.h create mode 100644 lib/ns/include/ns/query.h create mode 100644 lib/ns/include/ns/server.h create mode 100644 lib/ns/include/ns/sortlist.h create mode 100644 lib/ns/include/ns/stats.h create mode 100644 lib/ns/include/ns/types.h create mode 100644 lib/ns/include/ns/update.h create mode 100644 lib/ns/include/ns/version.h create mode 100644 lib/ns/include/ns/xfrout.h create mode 100644 lib/ns/interfacemgr.c create mode 100644 lib/ns/lib.c create mode 100644 lib/ns/listenlist.c create mode 100644 lib/ns/log.c create mode 100644 lib/ns/notify.c create mode 100644 lib/ns/query.c create mode 100644 lib/ns/server.c create mode 100644 lib/ns/sortlist.c create mode 100644 lib/ns/stats.c create mode 100644 lib/ns/tests/Kyuafile create mode 100644 lib/ns/tests/Makefile.in create mode 100644 lib/ns/tests/listenlist_test.c create mode 100644 lib/ns/tests/notify_test.c create mode 100644 lib/ns/tests/nstest.c create mode 100644 lib/ns/tests/nstest.h create mode 100644 lib/ns/tests/plugin_test.c create mode 100644 lib/ns/tests/query_test.c create mode 100644 lib/ns/tests/testdata/notify/notify1.msg create mode 100644 lib/ns/tests/testdata/notify/zone1.db create mode 100644 lib/ns/tests/testdata/query/foo.db create mode 100644 lib/ns/update.c create mode 100644 lib/ns/version.c create mode 100644 lib/ns/win32/DLLMain.c create mode 100644 lib/ns/win32/libns.def create mode 100644 lib/ns/win32/libns.vcxproj.filters create mode 100644 lib/ns/win32/libns.vcxproj.in create mode 100644 lib/ns/win32/libns.vcxproj.user create mode 100644 lib/ns/win32/version.c create mode 100644 lib/ns/xfrout.c create mode 100644 lib/win32/bindevt/bindevt.c create mode 100644 lib/win32/bindevt/bindevt.mc create mode 100644 lib/win32/bindevt/bindevt.vcxproj.filters.in create mode 100644 lib/win32/bindevt/bindevt.vcxproj.in create mode 100644 lib/win32/bindevt/bindevt.vcxproj.user create mode 100755 ltmain.sh create mode 100644 m4/ax_check_compile_flag.m4 create mode 100644 m4/ax_check_link_flag.m4 create mode 100644 m4/ax_check_openssl.m4 create mode 100644 m4/ax_check_preproc_flag.m4 create mode 100644 m4/ax_gcc_func_attribute.m4 create mode 100644 m4/ax_posix_shell.m4 create mode 100644 m4/ax_pthread.m4 create mode 100644 m4/ax_restore_flags.m4 create mode 100644 m4/ax_save_flags.m4 create mode 100644 m4/compat.m4 create mode 100644 m4/libtool.m4 create mode 100644 m4/ltoptions.m4 create mode 100644 m4/ltsugar.m4 create mode 100644 m4/ltversion.m4 create mode 100644 m4/lt~obsolete.m4 create mode 100644 make/Makefile.in create mode 100644 make/includes.in create mode 100644 make/mkdep.in create mode 100644 make/rules.in create mode 100644 mkinstalldirs create mode 100644 sonar-project.properties create mode 100644 srcid create mode 100644 unit/README create mode 100755 unit/gdb create mode 100755 unit/unittest.sh.in create mode 100755 util/bindkeys.pl create mode 100644 util/check-make-install.in create mode 100755 util/mksymtbl.pl create mode 100644 version create mode 100644 win32utils/Configure create mode 100644 win32utils/GeoIP.diff create mode 100644 win32utils/bind9.sln.in create mode 100644 win32utils/build.txt create mode 100644 win32utils/readme1st.txt diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..7137d8e --- /dev/null +++ b/.clang-format @@ -0,0 +1,76 @@ +BasedOnStyle: LLVM +IndentWidth: 8 +UseTab: Always +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterEnum: false + AfterStruct: false + AfterUnion: false + AfterControlStatement: MultiLine + AfterFunction: false # should also be MultiLine, but not yet supported + AfterExternBlock: false + BeforeElse: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true +AllowShortIfStatementsOnASingleLine: false +IndentCaseLabels: false +AlwaysBreakAfterReturnType: All +Cpp11BracedListStyle: false +ColumnLimit: 80 +AlignAfterOpenBracket: Align +AlignConsecutiveBitFields: true +AlignConsecutiveDeclarations: false +AlignConsecutiveMacros: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AlwaysBreakBeforeMultilineStrings: false +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +AlignEscapedNewlines: Left +DerivePointerAlignment: false +PointerAlignment: Right +PointerBindsToType: false +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 1 + - Regex: '".*"' + Priority: 9 +IndentExternBlock: NoIndent +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +PenaltyBreakAssignment: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 80 +PenaltyExcessCharacter: 100 +Standard: Cpp11 +ContinuationIndentWidth: 8 diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..1fe69da --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,120 @@ +;;; Directory Local Variables +;;; For more information see (info "(emacs) Directory Variables") + +((c-mode . + ((eval . + (set (make-local-variable 'directory-of-current-dir-locals-file) + (file-name-directory (locate-dominating-file default-directory ".dir-locals.el")) + ) + ) + (eval . + (set (make-local-variable 'include-directories) + (list + + ;; top directory + (expand-file-name + (concat directory-of-current-dir-locals-file "./")) + + ;; libisc + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/isc/unix/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/isc/pthreads/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/isc/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/isc")) + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/isc/netmgr")) + + ;; libdns + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/dns/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/dns")) + + ;; libisccc + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/isccc/include")) + + ;; libisccfg + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/isccfg/include")) + + ;; libns + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/ns/include")) + + ;; libirs + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/irs/include")) + + ;; libbind9 + (expand-file-name + (concat directory-of-current-dir-locals-file "lib/bind9/include")) + + ;; bin + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/check")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/confgen/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/confgen")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/confgen/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/dig/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/named/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/named/unix/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/rndc/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/dnssec/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/named/include")) + (expand-file-name + (concat directory-of-current-dir-locals-file "bin/rndc/include")) + + (expand-file-name "/usr/include/libxml2") + (expand-file-name "/usr/include/json-c") + + (expand-file-name "/usr/local/opt/openssl@1.1/include") + (expand-file-name "/usr/local/opt/libxml2/include/libxml2") + (expand-file-name "/usr/local/opt/json-c/include/json-c/") + (expand-file-name "/usr/local/include") + ) + ) + ) + + (eval setq flycheck-clang-include-path include-directories) + (eval setq flycheck-cppcheck-include-path include-directories) + (eval setq flycheck-gcc-include-path include-directories) + (eval setq flycheck-clang-args + (list + "-include" + (expand-file-name + (concat directory-of-current-dir-locals-file "config.h")) + ) + ) + (eval setq flycheck-gcc-args + (list + "-include" + (expand-file-name + (concat directory-of-current-dir-locals-file "config.h")) + ) + ) + (eval setq flycheck-cppcheck-args + (list + "--enable=all" + "--suppress=missingIncludeSystem" + "--suppress=nullPointerRedundantCheck" + (concat "--suppressions-list=" (expand-file-name + (concat directory-of-current-dir-locals-file "util/suppressions.txt"))) + (concat "-include=" (expand-file-name + (concat directory-of-current-dir-locals-file "config.h"))) + ) + ) + ) + )) diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3003b4d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +*.sln.in eol=crlf +*.vcxproj.* eol=crlf + +/fuzz/dns_rdata_fromwire_text.in/input-* -text + +.gitignore export-ignore +/conftools export-ignore +/doc/design export-ignore +/doc/dev export-ignore +/util/** export-ignore +/util/bindkeys.pl -export-ignore +/util/check-make-install.in -export-ignore +/util/mksymtbl.pl -export-ignore diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..03c997e --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,55 @@ +name: "CodeQL" + +on: + push: + branches: [ "bind-9.16", "bind-9.18", "main" ] + schedule: + - cron: '39 8 * * 3' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install build dependencies + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libuv1-dev libssl-dev libnghttp2-dev libxml2-dev liblmdb-dev libjson-c-dev pkg-config autoconf automake autotools-dev libtool-bin libjemalloc-dev libedit-dev libcap-dev libidn2-dev libkrb5-dev libmaxminddb-dev zlib1g-dev python3-ply + version: 1.0 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # â„¹ï¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml new file mode 100644 index 0000000..c9babfb --- /dev/null +++ b/.github/workflows/sonarcloud.yml @@ -0,0 +1,50 @@ +name: SonarCloud + +on: + push: + branches: [ "bind-9.16", "bind-9.18", "main" ] + schedule: + - cron: '39 8 * * 3' + +jobs: + build: + name: Build and analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp' ] + + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install build dependencies + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libuv1-dev libssl-dev libnghttp2-dev libxml2-dev liblmdb-dev libjson-c-dev pkg-config autoconf automake autotools-dev libtool-bin libjemalloc-dev libedit-dev libcap-dev libidn2-dev libkrb5-dev libmaxminddb-dev zlib1g-dev python3-ply + version: 1.0 + + - name: Install sonar-scanner and build-wrapper + uses: SonarSource/sonarcloud-github-c-cpp@v1 + + - name: Run build-wrapper + run: | + autoreconf -fi + ./configure + build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make clean all + + - name: Run sonar-scanner + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..e02d2d2 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,1800 @@ +variables: + # Not normally needed, but may be if some script uses `apt-get install`. + DEBIAN_FRONTEND: noninteractive + # Locale settings do not affect the build, but might affect tests. + LC_ALL: C + + CI_REGISTRY_IMAGE: registry.gitlab.isc.org/isc-projects/images/bind9 + CCACHE_DIR: "/ccache" + SOFTHSM2_CONF: "/var/tmp/softhsm2/softhsm2.conf" + + # VirtualBox driver needs to set build_dir to "/builds" in gitlab-runner.toml + KYUA_RESULT: "$CI_PROJECT_DIR/kyua.results" + + GIT_DEPTH: 1 + GIT_CLEAN_FLAGS: -ffdxq + + # The following values may be overwritten in GitLab's CI/CD Variables Settings. + BUILD_PARALLEL_JOBS: 6 + TEST_PARALLEL_JOBS: 4 + + CONFIGURE: ./configure + CLANG_VERSION: 16 + CLANG: "clang-${CLANG_VERSION}" + SCAN_BUILD: "scan-build-${CLANG_VERSION}" + LLVM_SYMBOLIZER: "/usr/lib/llvm-${CLANG_VERSION}/bin/llvm-symbolizer" + ASAN_SYMBOLIZER_PATH: "/usr/lib/llvm-${CLANG_VERSION}/bin/llvm-symbolizer" + CLANG_FORMAT: "clang-format-${CLANG_VERSION}" + + CFLAGS_COMMON: -fno-omit-frame-pointer -fno-optimize-sibling-calls -O1 -g -Wall -Wextra + + # Pass run-time flags to AddressSanitizer to get core dumps on error. + ASAN_OPTIONS: abort_on_error=1:disable_coredump=0:unmap_shadow_on_exit=1 + + TSAN_OPTIONS_COMMON: "disable_coredump=0 second_deadlock_stack=1 atexit_sleep_ms=1000 history_size=7 log_exe_name=true log_path=tsan" + TSAN_SUPPRESSIONS: "suppressions=${CI_PROJECT_DIR}/.tsan-suppress" + TSAN_OPTIONS_DEBIAN: "${TSAN_OPTIONS_COMMON} ${TSAN_SUPPRESSIONS} external_symbolizer_path=${LLVM_SYMBOLIZER}" + TSAN_OPTIONS_FEDORA: "${TSAN_OPTIONS_COMMON} ${TSAN_SUPPRESSIONS} external_symbolizer_path=/usr/bin/llvm-symbolizer" + + UBSAN_OPTIONS: "halt_on_error=1:abort_on_error=1:disable_coredump=0" + + TARBALL_COMPRESSOR: xz + TARBALL_EXTENSION: xz + + INSTALL_PATH: "${CI_PROJECT_DIR}/.local" + + # Disable pytest's "cacheprovider" plugin to prevent it from creating + # cross-testrun files as there is no need to use that feature in CI. + PYTEST_ADDOPTS: "-p no:cacheprovider" + + # Default platforms to run "stress" tests on + BIND_STRESS_TEST_OS: linux + BIND_STRESS_TEST_ARCH: amd64 + +default: + # Allow all running CI jobs to be automatically canceled when a new + # version of a branch is pushed. + # + # See: https://docs.gitlab.com/ee/ci/pipelines/settings.html#auto-cancel-redundant-pipelines + interruptible: true + +stages: + - precheck + - build + - unit + - system + - performance + - docs + - postcheck + - release + +### Runner Tag Templates + +.libvirt-amd64: &libvirt_amd64 + tags: + - libvirt + - amd64 + +# Jobs with these tags do not run on AWS but on permanent OVH systems. + +.linux-respdiff-amd64: &linux_respdiff_amd64 + tags: + - linux + - ovh + - amd64 + +# Autoscaling GitLab Runner on AWS EC2 + +.linux-amd64: &linux_amd64 + tags: + - linux + - aws + - runner-manager + - amd64 + +# Stress-testing runners + +.linux-stress-amd64: &linux_stress_amd64 + tags: + - amd64 + - aws + - linux-stress + - stress + +.linux-stress-arm64: &linux_stress_arm64 + tags: + - aarch64 + - aws + - linux-stress + - stress + +.freebsd-stress-amd64: &freebsd_stress_amd64 + tags: + - amd64 + - aws + - bsd-stress + - stress + +.windows-amd64: &windows_amd64 + tags: + - windows + - amd64 + +### Docker Image Templates + +# Alpine Linux + +.alpine-3.18-amd64: &alpine_3_18_amd64_image + image: "$CI_REGISTRY_IMAGE:alpine-3.18-amd64" + <<: *linux_amd64 + +# Oracle Linux + +.oraclelinux-7-amd64: &oraclelinux_7_amd64_image + image: "$CI_REGISTRY_IMAGE:oraclelinux-7-amd64" + <<: *linux_amd64 + +.oraclelinux-8-amd64: &oraclelinux_8_amd64_image + image: "$CI_REGISTRY_IMAGE:oraclelinux-8-amd64" + <<: *linux_amd64 + +.oraclelinux-9-amd64: &oraclelinux_9_amd64_image + image: "$CI_REGISTRY_IMAGE:oraclelinux-9-amd64" + <<: *linux_amd64 + +# Debian + +.debian-buster-amd64: &debian_buster_amd64_image + image: "$CI_REGISTRY_IMAGE:debian-buster-amd64" + <<: *linux_amd64 + +.debian-bullseye-amd64: &debian_bullseye_amd64_image + image: "$CI_REGISTRY_IMAGE:debian-bullseye-amd64" + <<: *linux_amd64 + +.respdiff-debian-bookworm-amd64: &respdiff_debian_bookworm_amd64_image + image: "$CI_REGISTRY_IMAGE:debian-bookworm-amd64" + <<: *linux_respdiff_amd64 + +.debian-bookworm-amd64: &debian_bookworm_amd64_image + image: "$CI_REGISTRY_IMAGE:debian-bookworm-amd64" + <<: *linux_amd64 + +.tsan-debian-bookworm-amd64: &tsan_debian_bookworm_amd64_image + image: "$CI_REGISTRY_IMAGE:tsan-debian-bookworm-amd64" + <<: *linux_amd64 + +.debian-bookworm-amd64cross32: &debian_bookworm_amd64cross32_image + image: "$CI_REGISTRY_IMAGE:debian-bookworm-amd64cross32" + <<: *linux_amd64 + +.debian-sid-amd64: &debian_sid_amd64_image + image: "$CI_REGISTRY_IMAGE:debian-sid-amd64" + <<: *linux_amd64 + +# openSUSE Tumbleweed + +.tumbleweed-latest-amd64: &tumbleweed_latest_amd64_image + image: "$CI_REGISTRY_IMAGE:tumbleweed-latest-amd64" + <<: *linux_amd64 + +# Fedora + +.tsan-fedora-38-amd64: &tsan_fedora_38_amd64_image + image: "$CI_REGISTRY_IMAGE:tsan-fedora-38-amd64" + <<: *linux_amd64 + +.fedora-38-amd64: &fedora_38_amd64_image + image: "$CI_REGISTRY_IMAGE:fedora-38-amd64" + <<: *linux_amd64 + +.fedora-38-arm64: &fedora_38_arm64_image + image: "$CI_REGISTRY_IMAGE:fedora-38-arm64" + <<: *linux_stress_arm64 + +# Ubuntu + +.ubuntu-bionic-amd64: &ubuntu_bionic_amd64_image + image: "$CI_REGISTRY_IMAGE:ubuntu-bionic-amd64" + <<: *linux_amd64 + +.ubuntu-focal-amd64: &ubuntu_focal_amd64_image + image: "$CI_REGISTRY_IMAGE:ubuntu-focal-amd64" + <<: *linux_amd64 + +.ubuntu-jammy-amd64: &ubuntu_jammy_amd64_image + image: "$CI_REGISTRY_IMAGE:ubuntu-jammy-amd64" + <<: *linux_amd64 + +# Windows + +.windows-server-2016-amd64: &windows_server_2016_amd64_image + image: "$CI_REGISTRY_IMAGE:windows-server-2016-amd64" + <<: *windows_amd64 + +# Base image +# This is a meta image that is used as a base for non-specific jobs + +.base: &base_image + <<: *debian_bookworm_amd64_image + +### QCOW2 Image Templates + +.freebsd-12-amd64: &freebsd_12_amd64_image + image: "freebsd-12.4-x86_64" + <<: *libvirt_amd64 + +.freebsd-13-amd64: &freebsd_13_amd64_image + image: "freebsd-13.2-x86_64" + <<: *libvirt_amd64 + +.openbsd-amd64: &openbsd_amd64_image + image: "openbsd-7.3-x86_64" + <<: *libvirt_amd64 + +### Job Templates + +.api-schedules-tags-triggers-web-triggering-rules: &api_schedules_tags_triggers_web_triggering_rules + only: + - api + - schedules + - tags + - triggers + - web + +.api-schedules-triggers-web-triggering-rules: &api_schedules_triggers_web_triggering_rules + only: + - api + - schedules + - triggers + - web + +.default-triggering-rules: &default_triggering_rules + only: + - api + - merge_requests + - schedules + - tags + - triggers + - web + +.precheck: &precheck_job + <<: *default_triggering_rules + <<: *base_image + stage: precheck + +.autoconf: &autoconf_job + <<: *default_triggering_rules + <<: *base_image + stage: precheck + script: + - autoreconf2.69 -fi + artifacts: + untracked: true + +.configure: &configure + - ${CONFIGURE} + --disable-maintainer-mode + --enable-developer + --with-libtool + --disable-static + --enable-option-checking=fatal + --enable-dnstap + --with-cmocka + --with-libxml2 + --with-json-c + --without-make-clean + $EXTRA_CONFIGURE + || (test -s config.log && cat config.log; exit 1) + +.parse_tsan: &parse_tsan + - find -name 'tsan.*' -exec python3 util/parse_tsan.py {} \; + +.build: &build_job + <<: *default_triggering_rules + stage: build + before_script: + - test -w "${CCACHE_DIR}" && export PATH="/usr/lib/ccache:${PATH}" + - test -n "${OOT_BUILD_WORKSPACE}" && mkdir "${OOT_BUILD_WORKSPACE}" && cd "${OOT_BUILD_WORKSPACE}" + script: + - *configure + - test -n "${SKIP_MAKE_DEPEND}" || make -j${BUILD_PARALLEL_JOBS:-1} depend 2>&1 | tee make-depend.log + - test -n "${SKIP_MAKE_DEPEND}" || ( ! grep -F "error:" make-depend.log ) + - make -j${BUILD_PARALLEL_JOBS:-1} -k all V=1 + - test -z "${BUILD_CONTRIB}" || for DIR in contrib/dlz/modules/*; do test -f "${DIR}/Makefile" && make -C "${DIR}"; done + - test -z "${RUN_MAKE_INSTALL}" || make DESTDIR="${INSTALL_PATH}" install + - test -z "${RUN_MAKE_INSTALL}" -o -z "${BUILD_CONTRIB}" || for DIR in contrib/dlz/modules/*; do test -f "${DIR}/Makefile" && make -C "${DIR}" DESTDIR="${INSTALL_PATH}" install; done + - test -z "${RUN_MAKE_INSTALL}" || DESTDIR="${INSTALL_PATH}" sh util/check-make-install + - if [[ "${CFLAGS}" == *"-fsanitize=address"* ]]; then ( ! grep -F AddressSanitizer config.log ); fi + - test -z "${CROSS_COMPILATION}" || grep -F -A 1 "checking whether we are cross compiling" config.log | grep -q "result.*yes" + - test -z "${CROSS_COMPILATION}" || file lib/dns/gen | grep -F -q "ELF 64-bit LSB" + - test -z "${CROSS_COMPILATION}" || ( ! git ls-files -z --others --exclude lib/dns/gen | xargs -0 file | grep "ELF 64-bit LSB" ) + needs: + - job: autoreconf + artifacts: true + artifacts: + untracked: true + when: always + +.windows_build: &windows_build_job + stage: build + script: + - 'Push-Location "C:/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Auxiliary/Build"' + - '& cmd.exe /C "vcvarsall.bat x64 & set" | Foreach-Object { if ($_ -match "(.*?)=(.*)") { Set-Item -force -path "Env:\$($matches[1])" -value "$($matches[2])" } }' + - 'Pop-Location' + - 'Set-Location win32utils' + - '& "C:/Strawberry/perl/bin/perl.exe" Configure + "with-tools-version=15.0" + "with-platform-toolset=v141" + "with-platform-version=10.0.17763.0" + "with-vcredist=C:/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Redist/MSVC/14.16.27012/vcredist_x64.exe" + "with-openssl=C:/OpenSSL" + "with-libxml2=C:/libxml2" + "with-libuv=C:/libuv" + "without-python" + "with-system-tests" + x64' + - 'Set-Item -path "Env:CL" -value "/MP$([Math]::Truncate($BUILD_PARALLEL_JOBS/2))"' + - '& msbuild.exe /maxCpuCount:2 /t:Build /p:Configuration=$VSCONF bind9.sln' + needs: [] + artifacts: + untracked: true + +.setup_interfaces: &setup_interfaces + - if [ "$(id -u)" -eq "0" ]; then + sh -x bin/tests/system/ifconfig.sh up; + else + sudo sh -x bin/tests/system/ifconfig.sh up; + fi + +.setup_softhsm: &setup_softhsm + - export SLOT=$(sh -x bin/tests/prepare-softhsm2.sh) + - test -n "${SLOT}" && test "${SLOT}" -gt 0 + +cross-version-config-tests: + stage: system + <<: *base_image + <<: *default_triggering_rules + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON}" + # Disable option checking to prevent problems with new default options in + # the &configure anchor. + EXTRA_CONFIGURE: "--disable-option-checking" + script: + # Exclude the dyndb test from the system test as the sample library can't + # locate the libdns library from the BIND 9 baseline version. + - sed -i '/^dyndb \\$/d' bin/tests/system/conf.sh.common + - *configure + - *setup_interfaces + - make -j${BUILD_PARALLEL_JOBS:-1} + - export BIND_BRANCH=16 + # When testing a .0 release, compare it against the previous development + # release (e.g., 9.19.0 and 9.18.0 should both be compared against 9.17.22). + - if [ "$(sed -n -E "s|^m4_define\(\[bind_VERSION_PATCH\], ([0-9]+)\)dnl$|\1|p" configure.ac)" = "0" ]; then export BIND_BRANCH=$((BIND_BRANCH - 1 - (BIND_BRANCH % 2))); fi + - BASELINE="$(curl -s "https://gitlab.isc.org/api/v4/projects/1/repository/tags?search=^v9.${BIND_BRANCH}&order_by=version" | jq -r ".[0].name")" + - git clone --branch "${BASELINE}" --depth 1 https://gitlab.isc.org/isc-projects/bind9.git "bind-${BASELINE}" + - cd "bind-${BASELINE}" + - autoreconf2.69 -fi + - *configure + - make -j${BUILD_PARALLEL_JOBS:-1} + - cd bin/tests/system + # Neutralize shell and pytests; in effect, "nsX" servers are just started + # and stopped, thus configuration checked. + - truncate --size=0 */tests{.sh,*.py} + # Run the setup phase of all system tests in the most recently tagged BIND 9 + # release using the binaries built for the current BIND 9 version. This + # intends to detect obvious backward compatibility issues with the latter. + - sed -i -E "s|(export TOP)=.*|\1=${CI_PROJECT_DIR}|" conf.sh + - make -j${TEST_PARALLEL_JOBS:-1} -k check V=1 + needs: + - job: autoreconf + artifacts: true + artifacts: + paths: + - bind-* + untracked: true + expire_in: "1 day" + when: on_failure + +.system_test_common: &system_test_common + <<: *default_triggering_rules + stage: system + before_script: + - *setup_interfaces + - *setup_softhsm + script: + - ( cd bin/tests/system && make -j${TEST_PARALLEL_JOBS:-1} -k test V=1 ) + - test -s bin/tests/system/systests.output + - if git rev-parse > /dev/null 2>&1; then ( ! grep "^I:.*:file.*not removed$" bin/tests/system/systests.output ); fi + - '( ! grep -F "grep: warning:" bin/tests/system/systests.output )' + +.system_test: &system_test_job + <<: *system_test_common + artifacts: + untracked: true + when: on_failure + +.system_test_gcov: &system_test_gcov_job + <<: *system_test_common + artifacts: + untracked: true + when: always + +.system_test_tsan: &system_test_tsan_job + <<: *system_test_common + after_script: + - *parse_tsan + artifacts: + untracked: true + when: on_failure + +.kyua_report: &kyua_report_html + - kyua --logfile /dev/null report-html + --force + --results-file "$KYUA_RESULT" + --results-filter "" + --output kyua_html > /dev/null + +.windows_system_test: &windows_system_test_job + stage: system + script: + - 'Push-Location bin/tests/system' + - '$ifIndex = Get-NetIPInterface -AddressFamily IPv4 -InterfaceMetric 75 | Select-Object -ExpandProperty ifIndex' + - '& C:/tools/cygwin/bin/sed.exe -i "s/^exit.*/netsh interface ipv4 set dnsservers $ifIndex dhcp/; s/\(name\|interface\)=Loopback/$ifIndex/;" ifconfig.bat' + - '& C:/tools/cygwin/bin/sed.exe -i "s/kill -f/kill -W/;" conf.sh stop.pl' + - '& cmd.exe /C ifconfig.bat up; ""' + - 'Start-Sleep 2' + - '$Env:Path = "C:/tools/cygwin/bin;$Env:Path"' + - '& sh.exe runall.sh $TEST_PARALLEL_JOBS' + - 'If (Test-Path C:/CrashDumps/*) { dir C:/CrashDumps; Throw }' + artifacts: + untracked: true + when: on_failure + +.unit_test_common: &unit_test_common + <<: *default_triggering_rules + stage: unit + before_script: + - *setup_softhsm + script: + - make unit + after_script: + - *kyua_report_html + +.unit_test: &unit_test_job + <<: *unit_test_common + artifacts: + untracked: true + when: on_failure + +.unit_test_gcov: &unit_test_gcov_job + <<: *unit_test_common + artifacts: + untracked: true + when: always + +.unit_test_tsan: &unit_test_tsan_job + <<: *unit_test_common + after_script: + - *kyua_report_html + - *parse_tsan + artifacts: + untracked: true + when: on_failure + +.respdiff: &respdiff_job + stage: system + before_script: + - *configure + - make -j${BUILD_PARALLEL_JOBS:-1} V=1 + - *setup_interfaces + - git clone --depth 1 https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.isc.org/isc-private/bind-qa.git + - cd bind-qa/bind9/respdiff + needs: [] + artifacts: + paths: + - bind-qa/bind9/respdiff + exclude: + - bind-qa/bind9/respdiff/rspworkdir/data.mdb # Exclude a 10 GB file. + untracked: true + when: always + +### Job Definitions + +# Jobs in the precheck stage + +autoreconf: + <<: *autoconf_job + +misc: + <<: *precheck_job + script: + - sh util/check-ans-prereq.sh + - sh util/checklibs.sh > checklibs.out + - sh util/tabify-changes < CHANGES > CHANGES.tmp + - diff -urNap CHANGES CHANGES.tmp + - perl util/check-changes CHANGES + - sh util/check-line-length.sh CHANGES + - test ! -f CHANGES.SE || sh util/tabify-changes < CHANGES.SE > CHANGES.tmp + - test ! -f CHANGES.SE || diff -urNap CHANGES.SE CHANGES.tmp + - test ! -f CHANGES.SE || perl util/check-changes master=0 CHANGES.SE + - test ! -f CHANGES.SE || sh util/check-line-length.sh CHANGES.SE + - rm CHANGES.tmp + - xmllint --noout --nonet `git ls-files '*.xml' '*.docbook'` + - sh util/check-win32util-configure + - sh util/check-categories.sh + - sh util/xmllint-html.sh + needs: [] + artifacts: + paths: + - checklibs.out + when: on_failure + +black: + <<: *precheck_job + needs: [] + script: + - black $(git ls-files '*.py' '*.py.in') + - git diff > black.patch + - if test "$(git status --porcelain | grep -Ev '\?\?' | wc -l)" -gt "0"; then git status --short; exit 1; fi + artifacts: + paths: + - black.patch + expire_in: "1 week" + when: on_failure + +clang-format: + <<: *precheck_job + needs: [] + script: + - if [ -r .clang-format ]; then "${CLANG_FORMAT}" -i -style=file $(git ls-files '*.c' '*.h'); fi + - git diff > clang-format.patch + - if test "$(git status --porcelain | grep -Ev '\?\?' | wc -l)" -gt "0"; then git status --short; exit 1; fi + artifacts: + paths: + - clang-format.patch + expire_in: "1 week" + when: on_failure + +coccinelle: + <<: *precheck_job + needs: [] + script: + - util/check-cocci + - if test "$(git status --porcelain | grep -Ev '\?\?' | wc -l)" -gt "0"; then git status --short; exit 1; fi + +reuse: + <<: *precheck_job + needs: [] + image: + name: docker.io/fsfe/reuse:latest + entrypoint: [""] + script: + - reuse lint + +danger: + <<: *precheck_job + needs: [] + script: + - danger-python ci -f + only: + refs: + - merge_requests + variables: + - $DANGER_GITLAB_API_TOKEN + +pylint: + <<: *default_triggering_rules + <<: *base_image + stage: postcheck + needs: + - job: autoreconf + artifacts: true + script: + - *configure + - export PYTHONPATH="$PYTHONPATH:$CI_PROJECT_DIR/bin/python" + - pylint --rcfile $CI_PROJECT_DIR/.pylintrc $(git ls-files '*.py' | grep -vE '(ans\.py|dangerfile\.py|^bin/tests/system/)') + # Ignore Pylint wrong-import-position error in system test to enable use of pytest.importorskip + - pylint --rcfile $CI_PROJECT_DIR/.pylintrc --disable=wrong-import-position $(git ls-files 'bin/tests/system/*.py' | grep -vE 'ans\.py') + +checkbashisms: + <<: *precheck_job + needs: [] + script: + - checkbashisms $(find . -path './.git' -prune -o -type f -exec sh -c 'head -n 1 "{}" | grep -qsF "#!/bin/sh"' \; -print | sed -e '/^\.\/install-sh$/d') + +tarball-create: + stage: precheck + <<: *base_image + <<: *default_triggering_rules + script: + - source version + - export BIND9_VERSION="${MAJORVER}.${MINORVER}${PATCHVER:+.}${PATCHVER}${RELEASETYPE}${RELEASEVER}${EXTENSIONS}" + - export BIND_DIRECTORY="bind-${BIND9_VERSION}" + - git archive --prefix="${BIND_DIRECTORY}/" --output="${BIND_DIRECTORY}.tar" HEAD + - mkdir "${BIND_DIRECTORY}" + - echo "SRCID=$(git rev-list --max-count=1 HEAD | cut -b1-7)" > "${BIND_DIRECTORY}/srcid" + - tar --append --file="${BIND_DIRECTORY}.tar" "${BIND_DIRECTORY}/srcid" + - sphinx-build -b man -d "${BIND_DIRECTORY}/tmp/.doctrees/" -W -a -v -c doc/man/ -D version="@BIND9_VERSION@" -D today="@RELEASE_DATE@" -D release="@BIND9_VERSIONSTRING@" doc/man "${BIND_DIRECTORY}/doc/man" + - rm -rf "${BIND_DIRECTORY}/tmp/.doctrees/" + - for man in "${BIND_DIRECTORY}/doc/man/"*; do mv "$man" "$man"in; done + - tar --append --file="${BIND_DIRECTORY}.tar" "${BIND_DIRECTORY}/doc/man/"*in + - ${TARBALL_COMPRESSOR} "${BIND_DIRECTORY}.tar" + artifacts: + paths: + - bind-*.tar.${TARBALL_EXTENSION} + +# Jobs for doc builds on Debian 12 "bookworm" (amd64) + +docs: + <<: *default_triggering_rules + <<: *base_image + stage: docs + before_script: + - test -w "${CCACHE_DIR}" && export PATH="/usr/lib/ccache:${PATH}" + - test -n "${OOT_BUILD_WORKSPACE}" && mkdir "${OOT_BUILD_WORKSPACE}" && cd "${OOT_BUILD_WORKSPACE}" + script: + - *configure + - make maintainer-clean + - autoreconf2.69 -fi + - *configure + - make -j${BUILD_PARALLEL_JOBS:-1} all V=1 + - make -j${BUILD_PARALLEL_JOBS:-1} doc V=1 + - if test "$(git status --porcelain | grep -Ev '\?\?' | grep -v -F -e aclocal.m4 -e configure -e ltmain.sh -e m4/ | wc -l)" -gt "0"; then git status --short; exit 1; fi + - qpdf --check doc/arm/_build/latex/Bv9ARM.pdf + - find doc/man/ -maxdepth 1 -name "*.[0-9]" -exec mandoc -T lint "{}" \; | ( ! grep -v -e "skipping paragraph macro. sp after" -e "unknown font, skipping request. ft C" -e "input text line longer than 80 bytes" ) + needs: + - job: autoreconf + artifacts: true + artifacts: + paths: + - doc/arm/ + - doc/man/ + - doc/misc/ + when: always + +# Jobs for regular GCC builds on Alpine Linux 3.18 (amd64) + +gcc:alpine3.18:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON}" + <<: *alpine_3_18_amd64_image + <<: *build_job + +system:gcc:alpine3.18:amd64: + <<: *alpine_3_18_amd64_image + <<: *system_test_job + needs: + - job: gcc:alpine3.18:amd64 + artifacts: true + +unit:gcc:alpine3.18:amd64: + <<: *alpine_3_18_amd64_image + <<: *unit_test_job + needs: + - job: gcc:alpine3.18:amd64 + artifacts: true + +# Jobs for regular GCC builds on Oracle Linux 7 (amd64) + +gcc:oraclelinux7:amd64: + variables: + CC: gcc + # -Wno-address suppresses isc_buffer macro warnings + CFLAGS: "${CFLAGS_COMMON} -Wno-address" + EXTRA_CONFIGURE: "--with-libidn2" + <<: *oraclelinux_7_amd64_image + <<: *build_job + +system:gcc:oraclelinux7:amd64: + <<: *oraclelinux_7_amd64_image + <<: *system_test_job + needs: + - job: gcc:oraclelinux7:amd64 + artifacts: true + +unit:gcc:oraclelinux7:amd64: + <<: *oraclelinux_7_amd64_image + <<: *unit_test_job + needs: + - job: gcc:oraclelinux7:amd64 + artifacts: true + +# Jobs for regular GCC builds on Oracle Linux 8 (amd64) + +gcc:oraclelinux8:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON}" + EXTRA_CONFIGURE: "--enable-buffer-useinline --with-libidn2" + <<: *oraclelinux_8_amd64_image + <<: *build_job + +system:gcc:oraclelinux8:amd64: + <<: *oraclelinux_8_amd64_image + <<: *system_test_job + needs: + - job: gcc:oraclelinux8:amd64 + artifacts: true + +unit:gcc:oraclelinux8:amd64: + <<: *oraclelinux_8_amd64_image + <<: *unit_test_job + needs: + - job: gcc:oraclelinux8:amd64 + artifacts: true + +# Jobs for regular GCC builds on Oracle Linux 9 (amd64) + +gcc:oraclelinux9:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON}" + EXTRA_CONFIGURE: "--with-libidn2 --disable-developer" + <<: *oraclelinux_9_amd64_image + <<: *build_job + +system:gcc:oraclelinux9:amd64: + <<: *oraclelinux_9_amd64_image + <<: *system_test_job + needs: + - job: gcc:oraclelinux9:amd64 + artifacts: true + +unit:gcc:oraclelinux9:amd64: + <<: *oraclelinux_9_amd64_image + <<: *unit_test_job + needs: + - job: gcc:oraclelinux9:amd64 + artifacts: true + +gcc:tarball:nosphinx: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON}" + EXTRA_CONFIGURE: "--with-libidn2 --disable-developer" + RUN_MAKE_INSTALL: 1 + <<: *oraclelinux_9_amd64_image + <<: *build_job + before_script: + - (! command -v sphinx-build >/dev/null) + - tar --extract --file bind-*.tar.${TARBALL_EXTENSION} + - rm -f bind-*.tar.${TARBALL_EXTENSION} + - cd bind-* + needs: + - job: tarball-create + artifacts: true + +# Jobs for regular GCC builds on Debian 10 "buster" (amd64) + +gcc:buster:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON}" + EXTRA_CONFIGURE: "--with-libidn2" + <<: *debian_buster_amd64_image + <<: *build_job + <<: *api_schedules_tags_triggers_web_triggering_rules + +system:gcc:buster:amd64: + <<: *debian_buster_amd64_image + <<: *system_test_job + <<: *api_schedules_tags_triggers_web_triggering_rules + needs: + - job: gcc:buster:amd64 + artifacts: true + +unit:gcc:buster:amd64: + <<: *debian_buster_amd64_image + <<: *unit_test_job + <<: *api_schedules_tags_triggers_web_triggering_rules + needs: + - job: gcc:buster:amd64 + artifacts: true + +# Jobs for Debian 11 "bullseye" (amd64) + +clang:bullseye:amd64: + variables: + CC: ${CLANG} + CFLAGS: "${CFLAGS_COMMON} -Wenum-conversion" + <<: *debian_bullseye_amd64_image + <<: *build_job + +system:clang:bullseye:amd64: + <<: *debian_bullseye_amd64_image + <<: *system_test_job + needs: + - job: clang:bullseye:amd64 + artifacts: true + +unit:clang:bullseye:amd64: + <<: *debian_bullseye_amd64_image + <<: *unit_test_job + needs: + - job: clang:bullseye:amd64 + artifacts: true + +gcc:bullseye:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON}" + EXTRA_CONFIGURE: "--with-libidn2" + <<: *debian_bullseye_amd64_image + <<: *build_job + +system:gcc:bullseye:amd64: + <<: *debian_bullseye_amd64_image + <<: *system_test_job + needs: + - job: gcc:bullseye:amd64 + artifacts: true + +unit:gcc:bullseye:amd64: + <<: *debian_bullseye_amd64_image + <<: *unit_test_job + needs: + - job: gcc:bullseye:amd64 + artifacts: true + +# Jobs for regular GCC builds on Debian 12 "bookworm" (amd64) + +gcc:bookworm:amd64: + variables: + BUILD_CONTRIB: 1 + CC: gcc + CFLAGS: "${CFLAGS_COMMON} --coverage -O0" + EXTRA_CONFIGURE: "--with-libidn2" + LDFLAGS: "--coverage" + RUN_MAKE_INSTALL: 1 + <<: *debian_bookworm_amd64_image + <<: *build_job + +system:gcc:bookworm:amd64: + <<: *debian_bookworm_amd64_image + <<: *system_test_gcov_job + variables: + CI_ENABLE_ALL_TESTS: 1 + needs: + - job: unit:gcc:bookworm:amd64 + artifacts: true + +unit:gcc:bookworm:amd64: + <<: *debian_bookworm_amd64_image + <<: *unit_test_gcov_job + variables: + CI_ENABLE_ALL_TESTS: 1 + needs: + - job: gcc:bookworm:amd64 + artifacts: true + +# Build job for cross-compiled GCC builds on 64-bit Debian 12 "bookworm" +# (amd64) with 32-bit BIND 9. + +gcc:bookworm:amd64cross32: + variables: + BUILD_CC: gcc + BUILD_CFLAGS: "${CFLAGS_COMMON}" + CFLAGS: "${CFLAGS_COMMON}" + CROSS_COMPILATION: 1 + EXTRA_CONFIGURE: "--build=x86_64-linux-gnu --host=i686-linux-gnu --with-libidn2" + <<: *debian_bookworm_amd64cross32_image + <<: *build_job + +# Jobs for scan-build builds on Debian 12 "bookworm" (amd64) + +.scan_build: &scan_build + - ${SCAN_BUILD} --html-title="BIND 9 ($CI_COMMIT_SHORT_SHA)" + --keep-cc + --status-bugs + --keep-going + -o scan-build.reports make -j${BUILD_PARALLEL_JOBS:-1} all V=1 + +scan-build: + <<: *default_triggering_rules + <<: *base_image + stage: postcheck + variables: + CC: "${CLANG}" + CFLAGS: "${CFLAGS_COMMON}" + CONFIGURE: "${SCAN_BUILD} ./configure" + EXTRA_CONFIGURE: "--with-libidn2" + script: + - *configure + - *scan_build + needs: + - job: autoreconf + artifacts: true + artifacts: + paths: + - scan-build.reports/ + when: on_failure + +# Jobs for regular GCC builds on Debian "sid" (amd64) +# Also tests configration option: --without-lmdb. + +gcc:sid:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -O3" + EXTRA_CONFIGURE: "--with-libidn2 --without-lmdb" + RUN_MAKE_INSTALL: 1 + <<: *debian_sid_amd64_image + <<: *build_job + +system:gcc:sid:amd64: + <<: *debian_sid_amd64_image + <<: *system_test_job + needs: + - job: gcc:sid:amd64 + artifacts: true + +unit:gcc:sid:amd64: + <<: *debian_sid_amd64_image + <<: *unit_test_job + needs: + - job: gcc:sid:amd64 + artifacts: true + +# Job for out-of-tree GCC build on Debian 12 "bookworm" (amd64) +# Also tests configration option: --with-lmdb. + +gcc:out-of-tree: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + CONFIGURE: ../configure + EXTRA_CONFIGURE: "--with-libidn2 --with-lmdb" + SKIP_MAKE_DEPEND: 1 + RUN_MAKE_INSTALL: 1 + OOT_BUILD_WORKSPACE: workspace + <<: *base_image + <<: *build_job + +# Jobs for tarball GCC builds on Debian 12 "bookworm" (amd64) + +gcc:tarball: + variables: + CC: gcc + EXTRA_CONFIGURE: "--with-libidn2" + RUN_MAKE_INSTALL: 1 + <<: *base_image + <<: *build_job + before_script: + - tar --extract --file bind-*.tar.${TARBALL_EXTENSION} + - rm -f bind-*.tar.${TARBALL_EXTENSION} + - cd bind-* + needs: + - job: tarball-create + artifacts: true + +system:gcc:tarball: + <<: *base_image + <<: *system_test_job + <<: *api_schedules_tags_triggers_web_triggering_rules + before_script: + - cd bind-* + - *setup_interfaces + needs: + - job: gcc:tarball + artifacts: true + +unit:gcc:tarball: + <<: *base_image + <<: *unit_test_job + <<: *api_schedules_tags_triggers_web_triggering_rules + before_script: + - cd bind-* + needs: + - job: gcc:tarball + artifacts: true + +# Jobs for debug GCC builds on openSUSE Tumbleweed (amd64) + +gcc:tumbleweed:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -DDEBUG" + EXTRA_CONFIGURE: "--with-libidn2" + <<: *tumbleweed_latest_amd64_image + <<: *build_job + +system:gcc:tumbleweed:amd64: + <<: *tumbleweed_latest_amd64_image + <<: *system_test_job + needs: + - job: gcc:tumbleweed:amd64 + artifacts: true + +unit:gcc:tumbleweed:amd64: + <<: *tumbleweed_latest_amd64_image + <<: *unit_test_job + needs: + - job: gcc:tumbleweed:amd64 + artifacts: true + +# Jobs for regular GCC builds on Ubuntu 18.04 Bionic Beaver (amd64) + +gcc:bionic:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -O2" + EXTRA_CONFIGURE: "--disable-dnstap --with-gssapi --without-cmocka" + <<: *ubuntu_bionic_amd64_image + <<: *build_job + <<: *api_schedules_tags_triggers_web_triggering_rules + +system:gcc:bionic:amd64: + <<: *ubuntu_bionic_amd64_image + <<: *system_test_job + <<: *api_schedules_tags_triggers_web_triggering_rules + needs: + - job: gcc:bionic:amd64 + artifacts: true + +# Jobs for regular GCC builds on Ubuntu 20.04 Focal Fossa (amd64) + +gcc:focal:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + EXTRA_CONFIGURE: "--with-libidn2 --with-gssapi=/usr --disable-geoip" + <<: *ubuntu_focal_amd64_image + <<: *build_job + +system:gcc:focal:amd64: + <<: *ubuntu_focal_amd64_image + <<: *system_test_job + needs: + - job: gcc:focal:amd64 + artifacts: true + +unit:gcc:focal:amd64: + <<: *ubuntu_focal_amd64_image + <<: *unit_test_job + needs: + - job: gcc:focal:amd64 + artifacts: true + +# Jobs for regular GCC builds on Ubuntu 22.04 Jammy Jellyfish (amd64) + +gcc:jammy:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON}" + EXTRA_CONFIGURE: "--with-libidn2" + <<: *ubuntu_jammy_amd64_image + <<: *build_job + +system:gcc:jammy:amd64: + <<: *ubuntu_jammy_amd64_image + <<: *system_test_job + needs: + - job: gcc:jammy:amd64 + artifacts: true + +unit:gcc:jammy:amd64: + <<: *ubuntu_jammy_amd64_image + <<: *unit_test_job + needs: + - job: gcc:jammy:amd64 + artifacts: true + +# Jobs for ASAN builds on Fedora 38 (amd64) + +gcc:asan: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0" + LDFLAGS: "-fsanitize=address,undefined" + EXTRA_CONFIGURE: "--with-libidn2" + <<: *fedora_38_amd64_image + <<: *build_job + +system:gcc:asan: + <<: *fedora_38_amd64_image + <<: *system_test_job + needs: + - job: gcc:asan + artifacts: true + +unit:gcc:asan: + <<: *fedora_38_amd64_image + <<: *unit_test_job + needs: + - job: gcc:asan + artifacts: true + +clang:asan: + variables: + CC: ${CLANG} + CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0" + LDFLAGS: "-fsanitize=address,undefined" + EXTRA_CONFIGURE: "--with-libidn2" + <<: *base_image + <<: *build_job + +system:clang:asan: + <<: *base_image + <<: *system_test_job + needs: + - job: clang:asan + artifacts: true + +unit:clang:asan: + <<: *base_image + <<: *unit_test_job + needs: + - job: clang:asan + artifacts: true + +# Jobs for TSAN builds on Fedora 38 (amd64) + +gcc:tsan: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -fsanitize=thread -DISC_MEM_USE_INTERNAL_MALLOC=0" + LDFLAGS: "-fsanitize=thread" + EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock" + <<: *tsan_fedora_38_amd64_image + <<: *build_job + +system:gcc:tsan: + variables: + TSAN_OPTIONS: "${TSAN_OPTIONS_FEDORA}" + <<: *tsan_fedora_38_amd64_image + <<: *system_test_tsan_job + needs: + - job: gcc:tsan + artifacts: true + +unit:gcc:tsan: + variables: + TSAN_OPTIONS: "${TSAN_OPTIONS_FEDORA}" + <<: *tsan_fedora_38_amd64_image + <<: *unit_test_tsan_job + needs: + - job: gcc:tsan + artifacts: true + +clang:tsan: + <<: *tsan_debian_bookworm_amd64_image + <<: *build_job + variables: + CC: "${CLANG}" + CFLAGS: "${CFLAGS_COMMON} -fsanitize=thread -DISC_MEM_USE_INTERNAL_MALLOC=0" + LDFLAGS: "-fsanitize=thread" + EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock" + +system:clang:tsan: + variables: + TSAN_OPTIONS: "${TSAN_OPTIONS_DEBIAN}" + <<: *tsan_debian_bookworm_amd64_image + <<: *system_test_tsan_job + needs: + - job: clang:tsan + artifacts: true + +unit:clang:tsan: + variables: + TSAN_OPTIONS: "${TSAN_OPTIONS_DEBIAN}" + <<: *tsan_debian_bookworm_amd64_image + <<: *unit_test_tsan_job + needs: + - job: clang:tsan + artifacts: true + +# Jobs for Clang builds on Debian 12 "bookworm" (amd64) + +clang:bookworm:amd64: + variables: + BUILD_CONTRIB: 1 + CC: ${CLANG} + CFLAGS: "${CFLAGS_COMMON} -Wenum-conversion" + EXTRA_CONFIGURE: "--with-python=python3" + RUN_MAKE_INSTALL: 1 + <<: *debian_bookworm_amd64_image + <<: *build_job + +system:clang:bookworm:amd64: + <<: *debian_bookworm_amd64_image + <<: *system_test_job + needs: + - job: clang:bookworm:amd64 + artifacts: true + +unit:clang:bookworm:amd64: + <<: *debian_bookworm_amd64_image + <<: *unit_test_job + needs: + - job: clang:bookworm:amd64 + artifacts: true + +# Jobs for PKCS#11-enabled builds + +clang:softhsm2.6: + variables: + CC: "${CLANG}" + CFLAGS: "${CFLAGS_COMMON} -O1" + EXTRA_CONFIGURE: "--with-libidn2 --enable-native-pkcs11 --with-pkcs11=/usr/lib/softhsm/libsofthsm2.so" + <<: *debian_bullseye_amd64_image + <<: *build_job + +system:clang:softhsm2.6: + variables: + DISABLE_ALGORITHM_SUPPORT_CHECKING: 1 + <<: *debian_bullseye_amd64_image + <<: *system_test_job + needs: + - job: clang:softhsm2.6 + artifacts: true + +unit:clang:softhsm2.6: + <<: *debian_bullseye_amd64_image + <<: *unit_test_job + needs: + - job: clang:softhsm2.6 + artifacts: true + +gcc:softhsm2.6: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -O1" + EXTRA_CONFIGURE: "--with-libidn2 --enable-native-pkcs11 --with-pkcs11=/usr/lib/softhsm/libsofthsm2.so" + <<: *debian_bookworm_amd64_image + <<: *build_job + +system:gcc:softhsm2.6: + variables: + DISABLE_ALGORITHM_SUPPORT_CHECKING: 1 + <<: *debian_bookworm_amd64_image + <<: *system_test_job + needs: + - job: gcc:softhsm2.6 + artifacts: true + +unit:gcc:softhsm2.6: + <<: *debian_bookworm_amd64_image + <<: *unit_test_job + needs: + - job: gcc:softhsm2.6 + artifacts: true + +# Jobs for Clang builds on FreeBSD 12 (amd64) + +clang:freebsd12:amd64: + variables: + CFLAGS: "${CFLAGS_COMMON}" + EXTRA_CONFIGURE: "--with-gssapi=krb5-config" + USER: gitlab-runner + <<: *freebsd_12_amd64_image + <<: *build_job + +system:clang:freebsd12:amd64: + <<: *freebsd_12_amd64_image + <<: *system_test_job + variables: + USER: gitlab-runner + needs: + - job: clang:freebsd12:amd64 + artifacts: true + +unit:clang:freebsd12:amd64: + <<: *freebsd_12_amd64_image + <<: *unit_test_job + needs: + - job: clang:freebsd12:amd64 + artifacts: true + +# Jobs for Clang builds on FreeBSD 13 (amd64) + +clang:freebsd13:amd64: + variables: + CFLAGS: "${CFLAGS_COMMON}" + EXTRA_CONFIGURE: "--with-gssapi=/usr/bin/krb5-config" + USER: gitlab-runner + <<: *freebsd_13_amd64_image + <<: *build_job + +system:clang:freebsd13:amd64: + <<: *freebsd_13_amd64_image + <<: *system_test_job + variables: + USER: gitlab-runner + needs: + - job: clang:freebsd13:amd64 + artifacts: true + +unit:clang:freebsd13:amd64: + <<: *freebsd_13_amd64_image + <<: *unit_test_job + needs: + - job: clang:freebsd13:amd64 + artifacts: true + +# Jobs for Clang builds on OpenBSD (amd64) + +clang:openbsd:amd64: + variables: + CC: clang + USER: gitlab-runner + EXTRA_CONFIGURE: "--disable-dnstap" + <<: *openbsd_amd64_image + <<: *build_job + +system:clang:openbsd:amd64: + <<: *openbsd_amd64_image + <<: *system_test_job + <<: *api_schedules_triggers_web_triggering_rules + variables: + USER: gitlab-runner + needs: + - job: clang:openbsd:amd64 + artifacts: true + allow_failure: true + +# Jobs with libtool disabled + +nolibtool:sid:amd64: + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON}" + EXTRA_CONFIGURE: "--with-libidn2 --without-libtool --with-dlopen" + <<: *debian_sid_amd64_image + <<: *build_job + +system:nolibtool:sid:amd64: + <<: *debian_sid_amd64_image + <<: *system_test_job + needs: + - job: nolibtool:sid:amd64 + artifacts: true + +unit:nolibtool:sid:amd64: + <<: *debian_sid_amd64_image + <<: *unit_test_job + needs: + - job: nolibtool:sid:amd64 + artifacts: true + +# Jobs for Visual Studio 2017 builds on Windows (amd64) + +msvc:windows:amd64: + <<: *windows_server_2016_amd64_image + <<: *windows_build_job + <<: *default_triggering_rules + variables: + VSCONF: Release + +system:msvc:windows:amd64: + <<: *windows_server_2016_amd64_image + <<: *windows_system_test_job + <<: *default_triggering_rules + variables: + VSCONF: Release + needs: + - job: msvc:windows:amd64 + artifacts: true + +msvc-debug:windows:amd64: + <<: *windows_server_2016_amd64_image + <<: *windows_build_job + <<: *api_schedules_tags_triggers_web_triggering_rules + variables: + VSCONF: Debug + +system:msvc-debug:windows:amd64: + <<: *windows_server_2016_amd64_image + <<: *windows_system_test_job + <<: *api_schedules_tags_triggers_web_triggering_rules + variables: + VSCONF: Debug + needs: + - job: msvc-debug:windows:amd64 + artifacts: true + +# Job producing a release tarball + +release: + <<: *base_image + stage: release + script: + # Determine BIND version + - source version + - export BIND_DIRECTORY="bind-${MAJORVER}.${MINORVER}.${PATCHVER}${RELEASETYPE}${RELEASEVER}" + # Remove redundant files and system test utilities from Windows build artifacts + - find Build/Release/ -name "*.pdb" -print -delete + - find Build/Debug/ \( -name "*.bsc" -o -name "*.idb" \) -print -delete + - find Build/ -regextype posix-extended -regex "Build/.*/($(find bin/tests/ -type f | sed -nE "s|^bin/tests(/system)?/win32/(.*)\.vcxproj$|\2|p" | paste -d"|" -s))\..*" -print -delete + # Create Windows zips + - openssl dgst -sha256 "${BIND_DIRECTORY}.tar.${TARBALL_EXTENSION}" | tee Build/Release/SHA256 Build/Debug/SHA256 + - cp "doc/arm/_build/latex/Bv9ARM.pdf" Build/Release/ + - cp "doc/arm/_build/latex/Bv9ARM.pdf" Build/Debug/ + - ( cd Build/Release; zip "../../BIND${BIND_DIRECTORY#bind-}.x64.zip" * ) + - ( cd Build/Debug; zip "../../BIND${BIND_DIRECTORY#bind-}.debug.x64.zip" * ) + # Prepare release tarball contents (tarballs + zips + documentation) + - mkdir -p release/doc/arm + - pushd release + - mv "../${BIND_DIRECTORY}.tar.${TARBALL_EXTENSION}" ../BIND*.zip . + - tar --extract --file="${BIND_DIRECTORY}.tar.${TARBALL_EXTENSION}" + - mv "${BIND_DIRECTORY}"/{CHANGES*,COPYRIGHT,LICENSE,README,srcid} . + - rm -rf "${BIND_DIRECTORY}" + - mv "../doc/arm/_build/html" doc/arm/ + - mv "../doc/arm/_build/latex/Bv9ARM.pdf" doc/arm/ + - echo 'Redirect' > "RELEASE-NOTES-${BIND_DIRECTORY}.html" + - popd + # Create release tarball + - tar --create --file="${CI_COMMIT_TAG}.tar.gz" --gzip release/ + needs: + - job: tarball-create + artifacts: true + - job: msvc:windows:amd64 + artifacts: true + - job: msvc-debug:windows:amd64 + artifacts: true + - job: docs + artifacts: true + only: + - tags + artifacts: + paths: + - "*.tar.gz" + expire_in: never + +# Coverity Scan analysis upload + +.coverity_prep: &coverity_prep + - curl --output /tmp/cov-analysis-linux64.md5 https://scan.coverity.com/download/linux64 + --form project=$COVERITY_SCAN_PROJECT_NAME + --form token=$COVERITY_SCAN_TOKEN + --form md5=1 + - curl --output /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64 + --form project=$COVERITY_SCAN_PROJECT_NAME + --form token=$COVERITY_SCAN_TOKEN + - test "$(md5sum /tmp/cov-analysis-linux64.tgz | awk '{ print $1 }')" = "$(cat /tmp/cov-analysis-linux64.md5)" + - tar --extract --gzip --file=/tmp/cov-analysis-linux64.tgz --directory=/tmp + - test -d /tmp/cov-analysis-linux64-* + +.coverity_build: &coverity_build + - /tmp/cov-analysis-linux64-*/bin/cov-build --dir /tmp/cov-int --fs-capture-search . sh -c 'make -j${BUILD_PARALLEL_JOBS:-1} -k all V=1' + - tar --create --gzip --file=/tmp/cov-int.tar.gz --directory /tmp cov-int + - curl -v https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME + --form token=$COVERITY_SCAN_TOKEN + --form email=bind-changes@isc.org + --form file=@/tmp/cov-int.tar.gz + --form version="$(git rev-parse --short HEAD)" + --form description="$(git rev-parse --short HEAD) / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID" 2>&1 + | tee curl-response.txt + - grep -q 'Build successfully submitted' curl-response.txt + +coverity: + <<: *base_image + stage: postcheck + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + EXTRA_CONFIGURE: "--with-libidn2" + script: + - *coverity_prep + - *configure + - *coverity_build + after_script: + - mv -v /tmp/cov-int.tar.gz ${CI_PROJECT_DIR}/ + needs: + - job: autoreconf + artifacts: true + artifacts: + paths: + - curl-response.txt + - cov-int.tar.gz + expire_in: "1 week" + when: on_failure + only: + variables: + - $COVERITY_SCAN_PROJECT_NAME + - $COVERITY_SCAN_TOKEN + +# Respdiff tests + +respdiff-short: + <<: *respdiff_job + <<: *default_triggering_rules + <<: *debian_bookworm_amd64_image + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + MAX_DISAGREEMENTS_PERCENTAGE: "0.1" + script: + - bash respdiff.sh -s named -q "${PWD}/10k_a.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named" + +respdiff-short:asan: + <<: *respdiff_job + <<: *default_triggering_rules + <<: *debian_bookworm_amd64_image + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0" + LDFLAGS: "-fsanitize=address,undefined" + MAX_DISAGREEMENTS_PERCENTAGE: "0.1" + script: + - bash respdiff.sh -s named -q "${PWD}/10k_a.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named" + +respdiff-short:tsan: + <<: *respdiff_job + <<: *default_triggering_rules + <<: *tsan_debian_bookworm_amd64_image + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og -fsanitize=thread -DISC_MEM_USE_INTERNAL_MALLOC=0" + LDFLAGS: "-fsanitize=thread" + EXTRA_CONFIGURE: "--enable-pthread-rwlock" + MAX_DISAGREEMENTS_PERCENTAGE: "0.1" + TSAN_OPTIONS: "${TSAN_OPTIONS_DEBIAN}" + RESPDIFF_JOBS: 32 + script: + - bash respdiff.sh -s named -q "${PWD}/10k_a.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named" + after_script: + - *parse_tsan + +respdiff-long: + <<: *respdiff_job + <<: *api_schedules_tags_triggers_web_triggering_rules + <<: *respdiff_debian_bookworm_amd64_image + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + MAX_DISAGREEMENTS_PERCENTAGE: "0.1" + script: + - bash respdiff.sh -s named -q "${PWD}/100k_mixed.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named" + +respdiff-long:asan: + <<: *respdiff_job + <<: *api_schedules_tags_triggers_web_triggering_rules + <<: *debian_bookworm_amd64_image + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0" + LDFLAGS: "-fsanitize=address,undefined" + MAX_DISAGREEMENTS_PERCENTAGE: "0.1" + script: + - bash respdiff.sh -s named -q "${PWD}/100k_mixed.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named" + +respdiff-long:tsan: + <<: *respdiff_job + <<: *api_schedules_tags_triggers_web_triggering_rules + <<: *tsan_debian_bookworm_amd64_image + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og -fsanitize=thread -DISC_MEM_USE_INTERNAL_MALLOC=0" + LDFLAGS: "-fsanitize=thread" + EXTRA_CONFIGURE: "--enable-pthread-rwlock" + MAX_DISAGREEMENTS_PERCENTAGE: "0.1" + TSAN_OPTIONS: "${TSAN_OPTIONS_DEBIAN}" + RESPDIFF_JOBS: 32 + script: + - bash respdiff.sh -s named -q "${PWD}/100k_mixed.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named" + after_script: + - *parse_tsan + +respdiff-long-third-party: + <<: *respdiff_job + <<: *api_schedules_tags_triggers_web_triggering_rules + <<: *debian_bookworm_amd64_image + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + MAX_DISAGREEMENTS_PERCENTAGE: "0.2" + script: + - bash respdiff.sh -s third_party -q "${PWD}/100k_mixed.txt" -c 1 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" + +# "Stress" tests + +# Parallel build in the "make" step is avoided since multiple jobs can be +# executed concurrently on the same runner. This may present problems when one +# job runs a performance-sensitive task of replying to queries while another +# takes all cores to build BIND. +.stress: &stress_job + stage: performance + script: + - *configure + - *setup_interfaces + - *setup_softhsm + - make -k all V=1 + - make DESTDIR="${INSTALL_PATH}" install + - git clone --depth 1 https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.isc.org/isc-private/bind-qa.git + - cd bind-qa/bind9/stress + - LD_LIBRARY_PATH="${INSTALL_PATH}/usr/local/lib" BIND_INSTALL_PATH="${INSTALL_PATH}/usr/local" WORKSPACE="${CI_PROJECT_DIR}" bash stress.sh + needs: + - job: autoreconf + artifacts: true + artifacts: + untracked: true + expire_in: "1 week" + when: always + timeout: 2h + +stress:authoritative:fedora:38:amd64: + <<: *fedora_38_amd64_image + <<: *linux_stress_amd64 + <<: *stress_job + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + FLAME: /usr/bin/flame + MODE: authoritative + RATE: 10000 + RUN_TIME: 1 + only: + variables: + - $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /authoritative/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i) + +stress:recursive:fedora:38:amd64: + <<: *fedora_38_amd64_image + <<: *linux_stress_amd64 + <<: *stress_job + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + FLAME: /usr/bin/flame + MODE: recursive + RATE: 10000 + RUN_TIME: 1 + only: + variables: + - $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /recursive/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i) + +stress:rpz:fedora:38:amd64: + <<: *fedora_38_amd64_image + <<: *linux_stress_amd64 + <<: *stress_job + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + FLAME: /usr/bin/flame + MODE: rpz + RATE: 1500 + RUN_TIME: 1 + only: + variables: + - $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /rpz/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i) + +stress:authoritative:fedora:38:arm64: + <<: *fedora_38_arm64_image + <<: *linux_stress_arm64 + <<: *stress_job + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + FLAME: /usr/bin/flame + MODE: authoritative + RATE: 10000 + RUN_TIME: 1 + only: + variables: + - $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /authoritative/i && $BIND_STRESS_TEST_ARCH =~ /arm64/i) + +stress:recursive:fedora:38:arm64: + <<: *fedora_38_arm64_image + <<: *linux_stress_arm64 + <<: *stress_job + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + FLAME: /usr/bin/flame + MODE: recursive + RATE: 10000 + RUN_TIME: 1 + only: + variables: + - $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /recursive/i && $BIND_STRESS_TEST_ARCH =~ /arm64/i) + +stress:rpz:fedora:38:arm64: + <<: *fedora_38_arm64_image + <<: *linux_stress_arm64 + <<: *stress_job + variables: + CC: gcc + CFLAGS: "${CFLAGS_COMMON} -Og" + FLAME: /usr/bin/flame + MODE: rpz + RATE: 1500 + RUN_TIME: 1 + only: + variables: + - $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /rpz/i && $BIND_STRESS_TEST_ARCH =~ /arm64/i) + +stress:authoritative:freebsd12:amd64: + <<: *freebsd_12_amd64_image + <<: *freebsd_stress_amd64 + <<: *stress_job + variables: + CC: clang + CFLAGS: "${CFLAGS_COMMON} -Og" + FLAME: /usr/local/bin/flame + MODE: authoritative + RATE: 10000 + RUN_TIME: 1 + only: + variables: + - $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /freebsd/i && $BIND_STRESS_TEST_MODE =~ /authoritative/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i) + +stress:recursive:freebsd12:amd64: + <<: *freebsd_12_amd64_image + <<: *freebsd_stress_amd64 + <<: *stress_job + variables: + CC: clang + CFLAGS: "${CFLAGS_COMMON} -Og" + FLAME: /usr/local/bin/flame + MODE: recursive + RATE: 10000 + RUN_TIME: 1 + only: + variables: + - $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /freebsd/i && $BIND_STRESS_TEST_MODE =~ /recursive/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i) + +stress:rpz:freebsd12:amd64: + <<: *freebsd_12_amd64_image + <<: *freebsd_stress_amd64 + <<: *stress_job + variables: + CC: clang + CFLAGS: "${CFLAGS_COMMON} -Og" + FLAME: /usr/local/bin/flame + MODE: rpz + RATE: 1500 + RUN_TIME: 1 + only: + variables: + - $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /freebsd/i && $BIND_STRESS_TEST_MODE =~ /rpz/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i) + +gcov: + <<: *base_image + <<: *default_triggering_rules + stage: postcheck + needs: + - job: system:gcc:bookworm:amd64 + artifacts: true + script: + # The "a-conftest.gcno" file is result of the ./configure step and + # should be removed as it does not belong to the BIND 9 code base. + - rm a-conftest.gcno + # Generate XML file in the Cobertura XML format suitable for use by GitLab + # for the purpose of displaying code coverage information in the diff view + # of a given merge request. + - gcovr --exclude-directories bin/tests --exclude-directories doc --exclude-directories fuzz --exclude tests --cobertura-pretty -o coverage.xml + - gcovr --exclude-directories bin/tests --exclude-directories doc --exclude-directories fuzz --exclude tests --html-details -o coverage.html + - gcovr --exclude-directories bin/tests --exclude-directories doc --exclude-directories fuzz --exclude tests --txt -o coverage.txt + - tail -n 3 coverage.txt + artifacts: + paths: + - coverage*.html + - coverage.css + - coverage.txt + - coverage.xml + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml + +# Pairwise testing of ./configure options + +pairwise: + <<: *base_image + stage: build + needs: + - job: autoreconf + artifacts: true + script: + - util/pairwise-testing.sh + artifacts: + paths: + - pairwise-commands.txt + - pairwise-model.txt + - pairwise-output.*.txt + when: on_failure + only: + variables: + - $PAIRWISE_TESTING diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md new file mode 100644 index 0000000..b2f43e8 --- /dev/null +++ b/.gitlab/issue_templates/Bug.md @@ -0,0 +1,46 @@ + + +### Summary + +(Summarize the bug encountered concisely.) + +### BIND version used + +(Paste the output of `named -V`.) + +### Steps to reproduce + +(How one can reproduce the issue - this is very important.) + +### What is the current *bug* behavior? + +(What actually happens.) + +### What is the expected *correct* behavior? + +(What you should see instead.) + +### Relevant configuration files + +(Paste any relevant configuration files - please use code blocks (```) +to format console output. If submitting the contents of your +configuration file in a non-confidential Issue, it is advisable to +obscure key secrets: this can be done automatically by using +`named-checkconf -px`.) + +### Relevant logs and/or screenshots + +(Paste any relevant logs - please use code blocks (```) to format console +output, logs, and code, as it's very hard to read otherwise.) + +### Possible fixes + +(If you can, link to the line of code that might be responsible for the +problem.) + +/label ~bug diff --git a/.gitlab/issue_templates/Feature_Request.md b/.gitlab/issue_templates/Feature_Request.md new file mode 100644 index 0000000..9ad28f4 --- /dev/null +++ b/.gitlab/issue_templates/Feature_Request.md @@ -0,0 +1,11 @@ +### Description + +(Describe the problem, use cases, benefits, and/or goals.) + +### Request + +(Describe the solution you'd like to see.) + +### Links / references + +/label ~"feature request" diff --git a/.gitlab/issue_templates/Release.md b/.gitlab/issue_templates/Release.md new file mode 100644 index 0000000..a00afa6 --- /dev/null +++ b/.gitlab/issue_templates/Release.md @@ -0,0 +1,65 @@ +## Release Schedule + +**Tagging Deadline:** + +**Public Release:** + +## Release Checklist + +## 2 Working Days Before the Tagging Deadline + + - [ ] ***(QA)*** Check whether all issues assigned to the release milestone are resolved[^1]. + - [ ] ***(QA)*** Ensure that there are no outstanding merge requests in the private repository[^1] (Subscription Edition only). + - [ ] ***(QA)*** Ensure all merge requests marked for backporting have been indeed backported. + +## Before the Tagging Deadline + + - [ ] ***(QA)*** Inform Support/Marketing of impending release (and give estimated release dates). + - [ ] ***(QA)*** Check Perflab to ensure there has been no unexplained drop in performance for the versions being released. + - [ ] ***(SwEng)*** Update API files for libraries with new version information. + - [ ] ***(SwEng)*** Change software version and library versions in `configure.ac` (new major release only). + - [ ] ***(SwEng)*** Rebuild `configure` using Autoconf on `docs.isc.org`. + - [ ] ***(SwEng)*** Update `CHANGES`. + - [ ] ***(SwEng)*** Update `CHANGES.SE` (Subscription Edition only). + - [ ] ***(SwEng)*** Update `README.md`. + - [ ] ***(SwEng)*** Update `version`. + - [ ] ***(SwEng)*** Build documentation on `docs.isc.org`. + - [ ] ***(QA)*** Check that all the above steps were performed correctly. + - [ ] ***(QA)*** Check that the contents of release notes match the merge requests comprising the releases. + - [ ] ***(QA)*** Check that the formatting is correct for text, PDF, and HTML versions of release notes. + - [ ] ***(SwEng)*** Tag the releases[^2]. (Tags may only be pushed to the public repository for releases which are *not* security releases.) + - [ ] ***(SwEng)*** If this is the first tag for a release (e.g. beta), create a release branch named `release_v9_X_Y` to allow development to continue on the maintenance branch whilst release engineering continues. + +## Before the ASN Deadline (for ASN Releases) or the Public Release Date (for Regular Releases) + + - [ ] ***(QA)*** Verify GitLab CI results for the tags created and prepare a QA report for the releases to be published. + - [ ] ***(QA)*** Request signatures for the tarballs, providing their location and checksums. + - [ ] ***(Signers)*** Validate tarball checksums, sign tarballs, and upload signatures. + - [ ] ***(QA)*** Verify tarball signatures and check tarball checksums again. + - [ ] ***(Support)*** Pre-publish ASN and/or Subscription Edition tarballs so that packages can be built. + - [ ] ***(QA)*** Build and test ASN and/or Subscription Edition packages. + - [ ] ***(QA)*** Notify Support that the releases have been prepared. + - [ ] ***(Support)*** Send out ASNs (if applicable). + +## On the Day of Public Release + + - [ ] ***(Support)*** Wait for clearance from Security Officer to proceed with the public release (if applicable). + - [ ] ***(Support)*** Place tarballs in public location on FTP site. + - [ ] ***(Support)*** Publish links to downloads on ISC website. + - [ ] ***(Support)*** Write release email to *bind-announce*. + - [ ] ***(Support)*** Write email to *bind-users* (if a major release). + - [ ] ***(Support)*** Update tickets in case of waiting support customers. + - [ ] ***(QA)*** Build and test any outstanding private packages. + - [ ] ***(QA)*** Build public packages (`*.deb`, RPMs). + - [ ] ***(QA)*** Inform Marketing of the release. + - [ ] ***(QA)*** Update the internal [BIND release dates wiki page](https://wiki.isc.org/bin/view/Main/BindReleaseDates) when public announcement has been made. + - [ ] ***(Marketing)*** Post short note to Twitter. + - [ ] ***(Marketing)*** Update [Wikipedia entry for BIND](https://en.wikipedia.org/wiki/BIND). + - [ ] ***(Marketing)*** Write blog article (if a major release). + - [ ] ***(QA)*** Ensure all new tags are annotated and signed. + - [ ] ***(SwEng)*** Push tags for the published releases to the public repository. + - [ ] ***(SwEng)*** Merge the automatically prepared `prep 9.X.Y` commit which updates `version` and documentation on the release branch into the relevant maintenance branch (`v9_X`). + +[^1]: If not, use the time remaining until the tagging deadline to ensure all outstanding issues are either resolved or moved to a different milestone. + +[^2]: Preferred command line: `git tag -u -a -s -m "BIND 9.X.Y[alphatag]" v9_X_Y[alphatag]`, where `[alphatag]` is an optional string such as `b1`, `rc1`, etc. diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..f9b1110 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,9 @@ +[MASTER] +disable= + C0103, # invalid-name + C0114, # missing-module-docstring + C0115, # missing-class-docstring + C0116, # missing-function-docstring + C0209, # consider-using-f-string + C0415, # import-outside-toplevel + R0801, # duplicate-code diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..5ea7be0 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,20 @@ +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in doc/arm/ with Sphinx +sphinx: + configuration: doc/arm/conf.py + +# Build all formats +formats: all + +# Explicitly set the version of Python and its requirements +python: + install: + - requirements: doc/arm/requirements.txt diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 0000000..e26b02d --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,233 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: BIND 9 +Upstream-Contact: Internet Systems Consortium, Inc. ("ISC") +Source: https://gitlab.isc.org/isc-projects/bind9/ + +# +# Build system, data files from tests, and misc cruft +# +Files: **/README + **/*.after* + **/*.bad + **/*.batch + **/*.before* + **/*.ccache + **/*.good + **/*.key + **/*.pem + **/*.private + **/*.raw + **/*.saved + **/*.zonelist + **/*dig.out* + **/Makefile + **/Makefile.* + **/expect + **/testdata/* + .github/* + .gitlab/* + AUTHORS + CHANGES + COPYRIGHT + CODE_OF_CONDUCT + CONTRIBUTING + HISTORY + Kyuafile + Makefile + Makefile.* + OPTIONS + README + bin/named/bind9.xsl + bin/named/bind9.xsl.h + bin/tests/bigtest/zones + bin/tests/optional/rbt_test.out + bin/tests/system/checkdstool/dig.bat + bin/tests/system/checkdstool/*.db + bin/tests/system/checkzone/zones/bad-caa-rr.db + bin/tests/system/checkzone/zones/bad1.db + bin/tests/system/checkzone/zones/crashzone.db + bin/tests/system/dnstap/large-answer.fstrm + bin/tests/system/formerr/nametoolong + bin/tests/system/formerr/noquestions + bin/tests/system/formerr/twoquestions + bin/tests/system/journal/ns1/managed-keys.bind.in + bin/tests/system/journal/ns1/managed-keys.bind.jnl.in + bin/tests/system/journal/ns2/managed-keys.bind.in + bin/tests/system/journal/ns2/managed-keys.bind.jnl.in + bin/tests/system/keepalive/expected + bin/tests/system/legacy/ns6/edns512.db.signed + bin/tests/system/legacy/ns7/edns512-notcp.db.signed + bin/tests/system/notify/ns4/named.port.in + bin/tests/system/nsupdate/commandlist + bin/tests/system/nsupdate/verylarge.in + bin/tests/system/org.isc.bind.system.plist + bin/tests/system/pipelined/input + bin/tests/system/pipelined/inputb + bin/tests/system/pipelined/ref + bin/tests/system/pipelined/refb + bin/tests/system/pkcs11/2037-pk11_numbits-crash-test.pkt + bin/tests/system/pkcs11/usepkcs11 + bin/tests/system/rsabigexponent/ns2/dsset-example.in + bin/tests/system/run.gdb + bin/tests/system/runtime/ctrl-chars + bin/tests/system/runtime/long-cmd-line + bin/tests/system/statschannel/traffic.expect.1 + bin/tests/system/statschannel/traffic.expect.2 + bin/tests/system/statschannel/traffic.expect.4 + bin/tests/system/statschannel/traffic.expect.5 + bin/tests/system/statschannel/traffic.expect.6 + bin/tests/system/tcp/1996-alloc_dnsbuf-crash-test.pkt + bin/tests/system/tsig/badlocation + bin/tests/system/tsig/badtime + bin/tests/system/unknown/large.out + bin/tests/system/xfer/ans5/badkeydata + bin/tests/system/xfer/ans5/badmessageid + bin/tests/system/xfer/ans5/goodaxfr + bin/tests/system/xfer/ans5/partial + bin/tests/system/xfer/ans5/soamismatch + bin/tests/system/xfer/ans5/unknownkey + bin/tests/system/xfer/ans5/unsigned + bin/tests/system/xfer/ans5/wrongkey + bin/tests/system/xfer/ans5/wrongname + bin/tests/system/xfer/knowngood.mapped + bind.keys + cocci/*.cocci + cocci/*.disabled + cocci/*.spatch + doc/arm/isc-logo.pdf + doc/arm/requirements.txt + doc/man/*.1in + doc/man/*.5in + doc/man/*.8in + fuzz/*.in/* +Copyright: Internet Systems Consortium, Inc. ("ISC") +License: MPL-2.0 + +# +# Libtool Files +# +Files: aclocal.m4 + ltmain.sh + m4/libtool.m4 + m4/ltoptions.m4 + m4/ltsugar.m4 + m4/ltversion.m4 + m4/ltversion.m4 + m4/lt~obsolete.m4 +Copyright: Free Software Foundation, Inc. +License: GPL-3.0-or-later WITH Autoconf-exception-3.0 + +# +# DNSSEC Guide images +# +Files: doc/dnssec-guide/img/*.png +Copyright: Internet Systems Consortium, Inc. ("ISC") +License: MPL-2.0 + +# +# DLZ Modules +# +Files: contrib/dlz/modules/*/testing/* +Copyright: Internet Systems Consortium, Inc. ("ISC") + Stichting NLnet, Netherlands +License: ISC and MPL-2.0 + +# +# Stuff that's basically uncopyrightable (configuration, generated files), +# use CC0-1.0 for clarity that we don't care +# +Files: **/.clang-format + **/.clang-format.headers + **/.dir-locals.el + **/.gitattributes + **/.gitignore + **/named*.args + **/named.dropedns + **/named.ednsformerr + **/named.ednsnotimp + **/named.ednsrefused + **/named.maxudp1460 + **/named.maxudp512 + **/named.noaa + **/named.noedns + **/named.nosoa + **/named.notcp + **/startme + .clang-format + .clang-format.headers + .dir-locals.el + .gitattributes + .gitignore + .gitlab-ci.yml + .lgtm.yml + .pylintrc + .readthedocs.yaml + .tsan-suppress + .uncrustify.cfg + config.guess + config.h.in + config.h.win32 + config.threads.in + config.sub + configure + bin/tests/system/dlz/ns1/dns-root/* + doc/misc/*.zoneopt + doc/misc/options + doc/misc/options.active + install-sh + lib/dns/mapapi + mkinstalldirs + util/suppressions.txt + version + sonar-project.properties +Copyright: Internet Systems Consortium, Inc. ("ISC") +License: CC0-1.0 + +# +# geoip2 test files (mmdb is generated from json) +# +Files: bin/tests/system/geoip2/data/*.json + bin/tests/system/geoip2/data/*.mmdb +Copyright: Internet Systems Consortium, Inc. ("ISC") +License: CC0-1.0 + +# +# files that may be left over from other branches. +# +# in a newly cloned branch or after running "git clean", these +# files don't exist, but they can be left lying around after +# checking out an older branch. we explicitly ignore them so they +# won't clutter up the output when running "reuse lint" by hand +# in a working source tree. +# +Files: **/platform.h + bin/tests/system/*.log + bin/tests/system/*.trs + fuzz/*.log + fuzz/*.trs + lib/*/tests/*.log + lib/*/tests/*.trs +Copyright: Internet Systems Consortium, Inc. ("ISC") +License: CC0-1.0 + +# +# Windows build system +# +Files: **/*.def + **/*.def.in + **/*.sln + **/*.sln.in + **/*.vcxproj.filters + **/*.vcxproj.filters.in + **/*.vcxproj + **/*.vcxproj.in + **/*.vcxproj.user + bin/win32/BINDInstall/BINDInstall.rc + bin/win32/BINDInstall/res/BINDInstall.ico + bin/win32/BINDInstall/res/BINDInstall.rc2 + contrib/dlz/example/win32/dxdriver.dsp + contrib/dlz/example/win32/dxdriver.dsw + contrib/dlz/example/win32/dxdriver.mak + win32utils/GeoIP.diff +Copyright: Internet Systems Consortium, Inc. ("ISC") +License: CC0-1.0 diff --git a/.reuse/templates/isc.jinja2 b/.reuse/templates/isc.jinja2 new file mode 100644 index 0000000..3f29bd1 --- /dev/null +++ b/.reuse/templates/isc.jinja2 @@ -0,0 +1,16 @@ +{% for copyright_line in copyright_lines %} +{{ copyright_line }} +{% endfor %} + +{% for expression in spdx_expressions %} +SPDX-License-Identifier: {{ expression }} +{% endfor %} + +{% if "MPL-2.0" in spdx_expressions %} +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, you can obtain one at https://mozilla.org/MPL/2.0/. + +See the COPYRIGHT file distributed with this work for additional +information regarding copyright ownership. +{% endif %} diff --git a/.tsan-suppress b/.tsan-suppress new file mode 100644 index 0000000..b12e038 --- /dev/null +++ b/.tsan-suppress @@ -0,0 +1,2 @@ +# Uninstrumented library. +called_from_lib:libfstrm.so diff --git a/.uncrustify.cfg b/.uncrustify.cfg new file mode 100644 index 0000000..012c070 --- /dev/null +++ b/.uncrustify.cfg @@ -0,0 +1,1434 @@ +# Uncrustify 0.59 + +# +# General options +# + +# The type of line endings +newlines = auto # auto/lf/crlf/cr + +# The original size of tabs in the input +input_tab_size = 8 # number + +# The size of tabs in the output (only used if align_with_tabs=true) +output_tab_size = 8 # number + +# The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn) +string_escape_char = 92 # number + +# Alternate string escape char for Pawn. Only works right before the quote char. +string_escape_char2 = 0 # number + +# Allow interpreting '>=' and '>>=' as part of a template in 'void f(list>=val);'. +# If true (default), 'assert(x<0 && y>=3)' will be broken. +# Improvements to template detection may make this option obsolete. +tok_split_gte = false # false/true + +# Control what to do with the UTF-8 BOM (recommend 'remove') +utf8_bom = ignore # ignore/add/remove/force + +# If the file only contains chars between 128 and 255 and is not UTF-8, then output as UTF-8 +utf8_byte = false # false/true + +# Force the output encoding to UTF-8 +utf8_force = false # false/true + +# +# Indenting +# + +# The number of columns to indent per level. +# Usually 2, 3, 4, or 8. +indent_columns = 8 # number + +# The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents. +# For FreeBSD, this is set to 4. +indent_continue = 0 # number + +# How to use tabs when indenting code +# 0=spaces only +# 1=indent with tabs to brace level, align with spaces +# 2=indent and align with tabs, using spaces when not on a tabstop +indent_with_tabs = 2 # number + +# Comments that are not a brace level are indented with tabs on a tabstop. +# Requires indent_with_tabs=2. If false, will use spaces. +indent_cmt_with_tabs = false # false/true + +# Whether to indent strings broken by '\' so that they line up +indent_align_string = false # false/true + +# The number of spaces to indent multi-line XML strings. +# Requires indent_align_string=True +indent_xml_string = 0 # number + +# Spaces to indent '{' from level +indent_brace = 0 # number + +# Whether braces are indented to the body level +indent_braces = false # false/true + +# Disabled indenting function braces if indent_braces is true +indent_braces_no_func = false # false/true + +# Disabled indenting class braces if indent_braces is true +indent_braces_no_class = false # false/true + +# Disabled indenting struct braces if indent_braces is true +indent_braces_no_struct = false # false/true + +# Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. +indent_brace_parent = false # false/true + +# Whether the 'namespace' body is indented +indent_namespace = false # false/true + +# The number of spaces to indent a namespace block +indent_namespace_level = 0 # number + +# If the body of the namespace is longer than this number, it won't be indented. +# Requires indent_namespace=true. Default=0 (no limit) +indent_namespace_limit = 0 # number + +# Whether the 'extern "C"' body is indented +indent_extern = false # false/true + +# Whether the 'class' body is indented +indent_class = false # false/true + +# Whether to indent the stuff after a leading class colon +indent_class_colon = false # false/true + +# Additional indenting for constructor initializer list +indent_ctor_init = 0 # number + +# False=treat 'else\nif' as 'else if' for indenting purposes +# True=indent the 'if' one level +indent_else_if = false # false/true + +# Amount to indent variable declarations after a open brace. neg=relative, pos=absolute +indent_var_def_blk = 0 # number + +# Indent continued variable declarations instead of aligning. +indent_var_def_cont = false # false/true + +# True: indent continued function call parameters one indent level +# False: align parameters under the open paren +indent_func_call_param = false # false/true + +# Same as indent_func_call_param, but for function defs +indent_func_def_param = false # false/true + +# Same as indent_func_call_param, but for function protos +indent_func_proto_param = false # false/true + +# Same as indent_func_call_param, but for class declarations +indent_func_class_param = false # false/true + +# Same as indent_func_call_param, but for class variable constructors +indent_func_ctor_var_param = false # false/true + +# Same as indent_func_call_param, but for templates +indent_template_param = false # false/true + +# Double the indent for indent_func_xxx_param options +indent_func_param_double = false # false/true + +# Indentation column for standalone 'const' function decl/proto qualifier +indent_func_const = 0 # number + +# Indentation column for standalone 'throw' function decl/proto qualifier +indent_func_throw = 0 # number + +# The number of spaces to indent a continued '->' or '.' +# Usually set to 0, 1, or indent_columns. +indent_member = 0 # number + +# Spaces to indent single line ('//') comments on lines before code +indent_sing_line_comments = 0 # number + +# If set, will indent trailing single line ('//') comments relative +# to the code instead of trying to keep the same absolute column +indent_relative_single_line_comments = false # false/true + +# Spaces to indent 'case' from 'switch' +# Usually 0 or indent_columns. +indent_switch_case = 0 # number + +# Spaces to shift the 'case' line, without affecting any other lines +# Usually 0. +indent_case_shift = 0 # number + +# Spaces to indent '{' from 'case'. +# By default, the brace will appear under the 'c' in case. +# Usually set to 0 or indent_columns. +indent_case_brace = 0 # number + +# Whether to indent comments found in first column +indent_col1_comment = false # false/true + +# How to indent goto labels +# >0 : absolute column where 1 is the leftmost column +# <=0 : subtract from brace indent +indent_label = 2 # number + +# Same as indent_label, but for access specifiers that are followed by a colon +indent_access_spec = 1 # number + +# Indent the code after an access specifier by one level. +# If set, this option forces 'indent_access_spec=0' +indent_access_spec_body = false # false/true + +# If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended) +indent_paren_nl = false # false/true + +# Controls the indent of a close paren after a newline. +# 0: Indent to body level +# 1: Align under the open paren +# 2: Indent to the brace level +indent_paren_close = 0 # number + +# Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren +indent_comma_paren = false # false/true + +# Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren +indent_bool_paren = false # false/true + +# If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones +indent_first_bool_expr = false # false/true + +# If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended) +indent_square_nl = false # false/true + +# Don't change the relative indent of ESQL/C 'EXEC SQL' bodies +indent_preserve_sql = false # false/true + +# Align continued statements at the '='. Default=True +# If FALSE or the '=' is followed by a newline, the next line is indent one tab. +indent_align_assign = true # false/true + +# +# Spacing options +# + +# Add or remove space around arithmetic operator '+', '-', '/', '*', etc +sp_arith = add # ignore/add/remove/force + +# Add or remove space around assignment operator '=', '+=', etc +sp_assign = add # ignore/add/remove/force + +# Add or remove space around assignment operator '=' in a prototype +sp_assign_default = add # ignore/add/remove/force + +# Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign. +sp_before_assign = ignore # ignore/add/remove/force + +# Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign. +sp_after_assign = ignore # ignore/add/remove/force + +# Add or remove space around assignment '=' in enum +sp_enum_assign = ignore # ignore/add/remove/force + +# Add or remove space before assignment '=' in enum. Overrides sp_enum_assign. +sp_enum_before_assign = ignore # ignore/add/remove/force + +# Add or remove space after assignment '=' in enum. Overrides sp_enum_assign. +sp_enum_after_assign = ignore # ignore/add/remove/force + +# Add or remove space around preprocessor '##' concatenation operator. Default=Add +sp_pp_concat = add # ignore/add/remove/force + +# Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator. Default=Add +sp_pp_stringify = add # ignore/add/remove/force + +# Add or remove space around boolean operators '&&' and '||' +sp_bool = add # ignore/add/remove/force + +# Add or remove space around compare operator '<', '>', '==', etc +sp_compare = add # ignore/add/remove/force + +# Add or remove space inside '(' and ')' +sp_inside_paren = ignore # ignore/add/remove/force + +# Add or remove space between nested parens +sp_paren_paren = ignore # ignore/add/remove/force + +# Whether to balance spaces inside nested parens +sp_balance_nested_parens = false # false/true + +# Add or remove space between ')' and '{' +sp_paren_brace = ignore # ignore/add/remove/force + +# Add or remove space before pointer star '*' +sp_before_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space before pointer star '*' that isn't followed by a variable name +# If set to 'ignore', sp_before_ptr_star is used instead. +sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space between pointer stars '*' +sp_between_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space after pointer star '*', if followed by a word. +sp_after_ptr_star = remove # ignore/add/remove/force + +# Add or remove space after a pointer star '*', if followed by a func proto/def. +sp_after_ptr_star_func = ignore # ignore/add/remove/force + +# Add or remove space before a pointer star '*', if followed by a func proto/def. +sp_before_ptr_star_func = ignore # ignore/add/remove/force + +# Add or remove space before a reference sign '&' +sp_before_byref = ignore # ignore/add/remove/force + +# Add or remove space before a reference sign '&' that isn't followed by a variable name +# If set to 'ignore', sp_before_byref is used instead. +sp_before_unnamed_byref = ignore # ignore/add/remove/force + +# Add or remove space after reference sign '&', if followed by a word. +sp_after_byref = remove # ignore/add/remove/force + +# Add or remove space after a reference sign '&', if followed by a func proto/def. +sp_after_byref_func = ignore # ignore/add/remove/force + +# Add or remove space before a reference sign '&', if followed by a func proto/def. +sp_before_byref_func = ignore # ignore/add/remove/force + +# Add or remove space between type and word. Default=Force +sp_after_type = force # ignore/add/remove/force + +# Add or remove space in 'template <' vs 'template<'. +# If set to ignore, sp_before_angle is used. +sp_template_angle = ignore # ignore/add/remove/force + +# Add or remove space before '<>' +sp_before_angle = ignore # ignore/add/remove/force + +# Add or remove space inside '<' and '>' +sp_inside_angle = ignore # ignore/add/remove/force + +# Add or remove space after '<>' +sp_after_angle = ignore # ignore/add/remove/force + +# Add or remove space between '<>' and '(' as found in 'new List();' +sp_angle_paren = ignore # ignore/add/remove/force + +# Add or remove space between '<>' and a word as in 'List m;' +sp_angle_word = ignore # ignore/add/remove/force + +# Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add +sp_angle_shift = add # ignore/add/remove/force + +# Add or remove space before '(' of 'if', 'for', 'switch', and 'while' +sp_before_sparen = add # ignore/add/remove/force + +# Add or remove space inside if-condition '(' and ')' +sp_inside_sparen = remove # ignore/add/remove/force + +# Add or remove space before if-condition ')'. Overrides sp_inside_sparen. +sp_inside_sparen_close = remove # ignore/add/remove/force + +# Add or remove space after ')' of 'if', 'for', 'switch', and 'while' +sp_after_sparen = add # ignore/add/remove/force + +# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while' +sp_sparen_brace = add # ignore/add/remove/force + +# Add or remove space between 'invariant' and '(' in the D language. +sp_invariant_paren = ignore # ignore/add/remove/force + +# Add or remove space after the ')' in 'invariant (C) c' in the D language. +sp_after_invariant_paren = ignore # ignore/add/remove/force + +# Add or remove space before empty statement ';' on 'if', 'for' and 'while' +sp_special_semi = remove # ignore/add/remove/force + +# Add or remove space before ';'. Default=Remove +sp_before_semi = remove # ignore/add/remove/force + +# Add or remove space before ';' in non-empty 'for' statements +sp_before_semi_for = ignore # ignore/add/remove/force + +# Add or remove space before a semicolon of an empty part of a for statement. +sp_before_semi_for_empty = ignore # ignore/add/remove/force + +# Add or remove space after ';', except when followed by a comment. Default=Add +sp_after_semi = ignore # ignore/add/remove/force + +# Add or remove space after ';' in non-empty 'for' statements. Default=Force +sp_after_semi_for = ignore # ignore/add/remove/force + +# Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; ). +sp_after_semi_for_empty = ignore # ignore/add/remove/force + +# Add or remove space before '[' (except '[]') +sp_before_square = ignore # ignore/add/remove/force + +# Add or remove space before '[]' +sp_before_squares = ignore # ignore/add/remove/force + +# Add or remove space inside a non-empty '[' and ']' +sp_inside_square = ignore # ignore/add/remove/force + +# Add or remove space after ',' +sp_after_comma = add # ignore/add/remove/force + +# Add or remove space before ',' +sp_before_comma = remove # ignore/add/remove/force + +# Add or remove space between an open paren and comma: '(,' vs '( ,' +sp_paren_comma = force # ignore/add/remove/force + +# Add or remove space before the variadic '...' when preceded by a non-punctuator +sp_before_ellipsis = ignore # ignore/add/remove/force + +# Add or remove space after class ':' +sp_after_class_colon = ignore # ignore/add/remove/force + +# Add or remove space before class ':' +sp_before_class_colon = ignore # ignore/add/remove/force + +# Add or remove space before case ':'. Default=Remove +sp_before_case_colon = remove # ignore/add/remove/force + +# Add or remove space between 'operator' and operator sign +sp_after_operator = ignore # ignore/add/remove/force + +# Add or remove space between the operator symbol and the open paren, as in 'operator ++(' +sp_after_operator_sym = ignore # ignore/add/remove/force + +# Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a' +sp_after_cast = ignore # ignore/add/remove/force + +# Add or remove spaces inside cast parens +sp_inside_paren_cast = ignore # ignore/add/remove/force + +# Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)' +sp_cpp_cast_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'sizeof' and '(' +sp_sizeof_paren = ignore # ignore/add/remove/force + +# Add or remove space after the tag keyword (Pawn) +sp_after_tag = ignore # ignore/add/remove/force + +# Add or remove space inside enum '{' and '}' +sp_inside_braces_enum = ignore # ignore/add/remove/force + +# Add or remove space inside struct/union '{' and '}' +sp_inside_braces_struct = ignore # ignore/add/remove/force + +# Add or remove space inside '{' and '}' +sp_inside_braces = ignore # ignore/add/remove/force + +# Add or remove space inside '{}' +sp_inside_braces_empty = ignore # ignore/add/remove/force + +# Add or remove space between return type and function name +# A minimum of 1 is forced except for pointer return types. +sp_type_func = ignore # ignore/add/remove/force + +# Add or remove space between function name and '(' on function declaration +sp_func_proto_paren = ignore # ignore/add/remove/force + +# Add or remove space between function name and '(' on function definition +sp_func_def_paren = ignore # ignore/add/remove/force + +# Add or remove space inside empty function '()' +sp_inside_fparens = ignore # ignore/add/remove/force + +# Add or remove space inside function '(' and ')' +sp_inside_fparen = ignore # ignore/add/remove/force + +# Add or remove space between ']' and '(' when part of a function call. +sp_square_fparen = ignore # ignore/add/remove/force + +# Add or remove space between ')' and '{' of function +sp_fparen_brace = ignore # ignore/add/remove/force + +# Add or remove space between function name and '(' on function calls +sp_func_call_paren = ignore # ignore/add/remove/force + +# Add or remove space between function name and '()' on function calls without parameters. +# If set to 'ignore' (the default), sp_func_call_paren is used. +sp_func_call_paren_empty = ignore # ignore/add/remove/force + +# Add or remove space between the user function name and '(' on function calls +# You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file. +sp_func_call_user_paren = ignore # ignore/add/remove/force + +# Add or remove space between a constructor/destructor and the open paren +sp_func_class_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'return' and '(' +sp_return_paren = ignore # ignore/add/remove/force + +# Add or remove space between '__attribute__' and '(' +sp_attribute_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'defined' and '(' in '#if defined (FOO)' +sp_defined_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'throw' and '(' in 'throw (something)' +sp_throw_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'catch' and '(' in 'catch (something) { }' +# If set to ignore, sp_before_sparen is used. +sp_catch_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'version' and '(' in 'version (something) { }' (D language) +# If set to ignore, sp_before_sparen is used. +sp_version_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'scope' and '(' in 'scope (something) { }' (D language) +# If set to ignore, sp_before_sparen is used. +sp_scope_paren = ignore # ignore/add/remove/force + +# Add or remove space between macro and value +sp_macro = ignore # ignore/add/remove/force + +# Add or remove space between macro function ')' and value +sp_macro_func = ignore # ignore/add/remove/force + +# Add or remove space between 'else' and '{' if on the same line +sp_else_brace = add # ignore/add/remove/force + +# Add or remove space between '}' and 'else' if on the same line +sp_brace_else = add # ignore/add/remove/force + +# Add or remove space between '}' and the name of a typedef on the same line +sp_brace_typedef = ignore # ignore/add/remove/force + +# Add or remove space between 'catch' and '{' if on the same line +sp_catch_brace = ignore # ignore/add/remove/force + +# Add or remove space between '}' and 'catch' if on the same line +sp_brace_catch = ignore # ignore/add/remove/force + +# Add or remove space between 'finally' and '{' if on the same line +sp_finally_brace = ignore # ignore/add/remove/force + +# Add or remove space between '}' and 'finally' if on the same line +sp_brace_finally = ignore # ignore/add/remove/force + +# Add or remove space between 'try' and '{' if on the same line +sp_try_brace = ignore # ignore/add/remove/force + +# Add or remove space between get/set and '{' if on the same line +sp_getset_brace = ignore # ignore/add/remove/force + +# Add or remove space before the '::' operator +sp_before_dc = ignore # ignore/add/remove/force + +# Add or remove space after the '::' operator +sp_after_dc = ignore # ignore/add/remove/force + +# Add or remove around the D named array initializer ':' operator +sp_d_array_colon = ignore # ignore/add/remove/force + +# Add or remove space after the '!' (not) operator. Default=Remove +sp_not = remove # ignore/add/remove/force + +# Add or remove space after the '~' (invert) operator. Default=Remove +sp_inv = remove # ignore/add/remove/force + +# Add or remove space after the '&' (address-of) operator. Default=Remove +# This does not affect the spacing after a '&' that is part of a type. +sp_addr = remove # ignore/add/remove/force + +# Add or remove space around the '.' or '->' operators. Default=Remove +sp_member = remove # ignore/add/remove/force + +# Add or remove space after the '*' (dereference) operator. Default=Remove +# This does not affect the spacing after a '*' that is part of a type. +sp_deref = remove # ignore/add/remove/force + +# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove +sp_sign = remove # ignore/add/remove/force + +# Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove +sp_incdec = remove # ignore/add/remove/force + +# Add or remove space before a backslash-newline at the end of a line. Default=Add +sp_before_nl_cont = add # ignore/add/remove/force + +# Add or remove space after the scope '+' or '-', as in '-(void) foo;' or '+(int) bar;' +sp_after_oc_scope = ignore # ignore/add/remove/force + +# Add or remove space after the colon in message specs +# '-(int) f:(int) x;' vs '-(int) f: (int) x;' +sp_after_oc_colon = ignore # ignore/add/remove/force + +# Add or remove space before the colon in message specs +# '-(int) f: (int) x;' vs '-(int) f : (int) x;' +sp_before_oc_colon = ignore # ignore/add/remove/force + +# Add or remove space after the colon in message specs +# '[object setValue:1];' vs '[object setValue: 1];' +sp_after_send_oc_colon = ignore # ignore/add/remove/force + +# Add or remove space before the colon in message specs +# '[object setValue:1];' vs '[object setValue :1];' +sp_before_send_oc_colon = ignore # ignore/add/remove/force + +# Add or remove space after the (type) in message specs +# '-(int)f: (int) x;' vs '-(int)f: (int)x;' +sp_after_oc_type = ignore # ignore/add/remove/force + +# Add or remove space after the first (type) in message specs +# '-(int) f:(int)x;' vs '-(int)f:(int)x;' +sp_after_oc_return_type = ignore # ignore/add/remove/force + +# Add or remove space between '@selector' and '(' +# '@selector(msgName)' vs '@selector (msgName)' +# Also applies to @protocol() constructs +sp_after_oc_at_sel = ignore # ignore/add/remove/force + +# Add or remove space between '@selector(x)' and the following word +# '@selector(foo) a:' vs '@selector(foo)a:' +sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force + +# Add or remove space inside '@selector' parens +# '@selector(foo)' vs '@selector( foo )' +# Also applies to @protocol() constructs +sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force + +# Add or remove space before a block pointer caret +# '^int (int arg){...}' vs. ' ^int (int arg){...}' +sp_before_oc_block_caret = ignore # ignore/add/remove/force + +# Add or remove space after a block pointer caret +# '^int (int arg){...}' vs. '^ int (int arg){...}' +sp_after_oc_block_caret = ignore # ignore/add/remove/force + +# Add or remove space around the ':' in 'b ? t : f' +sp_cond_colon = ignore # ignore/add/remove/force + +# Add or remove space around the '?' in 'b ? t : f' +sp_cond_question = ignore # ignore/add/remove/force + +# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here. +sp_case_label = ignore # ignore/add/remove/force + +# Control the space around the D '..' operator. +sp_range = ignore # ignore/add/remove/force + +# Control the space after the opening of a C++ comment '// A' vs '//A' +sp_cmt_cpp_start = ignore # ignore/add/remove/force + +# Controls the spaces between #else or #endif and a trailing comment +sp_endif_cmt = ignore # ignore/add/remove/force + +# Controls the spaces after 'new', 'delete', and 'delete[]' +sp_after_new = ignore # ignore/add/remove/force + +# Controls the spaces before a trailing or embedded comment +sp_before_tr_emb_cmt = ignore # ignore/add/remove/force + +# Number of spaces before a trailing or embedded comment +sp_num_before_tr_emb_cmt = 0 # number + +# +# Code alignment (not left column spaces/tabs) +# + +# Whether to keep non-indenting tabs +align_keep_tabs = false # false/true + +# Whether to use tabs for aligning +align_with_tabs = true # false/true + +# Whether to bump out to the next tab when aligning +align_on_tabstop = false # false/true + +# Whether to left-align numbers +align_number_left = false # false/true + +# Align variable definitions in prototypes and functions +align_func_params = false # false/true + +# Align parameters in single-line functions that have the same name. +# The function names must already be aligned with each other. +align_same_func_call_params = false # false/true + +# The span for aligning variable definitions (0=don't align) +align_var_def_span = 0 # number + +# How to align the star in variable definitions. +# 0=Part of the type 'void * foo;' +# 1=Part of the variable 'void *foo;' +# 2=Dangling 'void *foo;' +align_var_def_star_style = 0 # number + +# How to align the '&' in variable definitions. +# 0=Part of the type +# 1=Part of the variable +# 2=Dangling +align_var_def_amp_style = 0 # number + +# The threshold for aligning variable definitions (0=no limit) +align_var_def_thresh = 0 # number + +# The gap for aligning variable definitions +align_var_def_gap = 0 # number + +# Whether to align the colon in struct bit fields +align_var_def_colon = false # false/true + +# Whether to align any attribute after the variable name +align_var_def_attribute = false # false/true + +# Whether to align inline struct/enum/union variable definitions +align_var_def_inline = false # false/true + +# The span for aligning on '=' in assignments (0=don't align) +align_assign_span = 0 # number + +# The threshold for aligning on '=' in assignments (0=no limit) +align_assign_thresh = 0 # number + +# The span for aligning on '=' in enums (0=don't align) +align_enum_equ_span = 0 # number + +# The threshold for aligning on '=' in enums (0=no limit) +align_enum_equ_thresh = 0 # number + +# The span for aligning struct/union (0=don't align) +align_var_struct_span = 3 # number + +# The threshold for aligning struct/union member definitions (0=no limit) +align_var_struct_thresh = 0 # number + +# The gap for aligning struct/union member definitions +align_var_struct_gap = 8 # number + +# The span for aligning struct initializer values (0=don't align) +align_struct_init_span = 0 # number + +# The minimum space between the type and the synonym of a typedef +align_typedef_gap = 0 # number + +# The span for aligning single-line typedefs (0=don't align) +align_typedef_span = 0 # number + +# How to align typedef'd functions with other typedefs +# 0: Don't mix them at all +# 1: align the open paren with the types +# 2: align the function type name with the other type names +align_typedef_func = 2 # number + +# Controls the positioning of the '*' in typedefs. Just try it. +# 0: Align on typedef type, ignore '*' +# 1: The '*' is part of type name: typedef int *pint; +# 2: The '*' is part of the type, but dangling: typedef int *pint; +align_typedef_star_style = 0 # number + +# Controls the positioning of the '&' in typedefs. Just try it. +# 0: Align on typedef type, ignore '&' +# 1: The '&' is part of type name: typedef int &pint; +# 2: The '&' is part of the type, but dangling: typedef int &pint; +align_typedef_amp_style = 0 # number + +# The span for aligning comments that end lines (0=don't align) +align_right_cmt_span = 0 # number + +# If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment +align_right_cmt_mix = false # false/true + +# If a trailing comment is more than this number of columns away from the text it follows, +# it will qualify for being aligned. This has to be > 0 to do anything. +align_right_cmt_gap = 0 # number + +# Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore) +align_right_cmt_at_col = 0 # number + +# The span for aligning function prototypes (0=don't align) +align_func_proto_span = 0 # number + +# Minimum gap between the return type and the function name. +align_func_proto_gap = 0 # number + +# Align function protos on the 'operator' keyword instead of what follows +align_on_operator = false # false/true + +# Whether to mix aligning prototype and variable declarations. +# If true, align_var_def_XXX options are used instead of align_func_proto_XXX options. +align_mix_var_proto = false # false/true + +# Align single-line functions with function prototypes, uses align_func_proto_span +align_single_line_func = false # false/true + +# Aligning the open brace of single-line functions. +# Requires align_single_line_func=true, uses align_func_proto_span +align_single_line_brace = false # false/true + +# Gap for align_single_line_brace. +align_single_line_brace_gap = 0 # number + +# The span for aligning ObjC msg spec (0=don't align) +align_oc_msg_spec_span = 0 # number + +# Whether to align macros wrapped with a backslash and a newline. +# This will not work right if the macro contains a multi-line comment. +align_nl_cont = false # false/true + +# The minimum space between label and value of a preprocessor define +align_pp_define_gap = 0 # number + +# The span for aligning on '#define' bodies (0=don't align) +align_pp_define_span = 0 # number + +# Align lines that start with '<<' with previous '<<'. Default=true +align_left_shift = true # false/true + +# Span for aligning parameters in an Obj-C message call on the ':' (0=don't align) +align_oc_msg_colon_span = 0 # number + +# Aligning parameters in an Obj-C '+' or '-' declaration on the ':' +align_oc_decl_colon = false # false/true + +# +# Newline adding and removing options +# + +# Whether to collapse empty blocks between '{' and '}' +nl_collapse_empty_body = false # false/true + +# Don't split one-line braced assignments - 'foo_t f = { 1, 2 };' +nl_assign_leave_one_liners = false # false/true + +# Don't split one-line braced statements inside a class xx { } body +nl_class_leave_one_liners = false # false/true + +# Don't split one-line enums: 'enum foo { BAR = 15 };' +nl_enum_leave_one_liners = false # false/true + +# Don't split one-line get or set functions +nl_getset_leave_one_liners = false # false/true + +# Don't split one-line function definitions - 'int foo() { return 0; }' +nl_func_leave_one_liners = false # false/true + +# Don't split one-line if/else statements - 'if(a) b++;' +nl_if_leave_one_liners = false # false/true + +# Add or remove newlines at the start of the file +nl_start_of_file = ignore # ignore/add/remove/force + +# The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force' +nl_start_of_file_min = 0 # number + +# Add or remove newline at the end of the file +nl_end_of_file = ignore # ignore/add/remove/force + +# The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force') +nl_end_of_file_min = 0 # number + +# Add or remove newline between '=' and '{' +nl_assign_brace = ignore # ignore/add/remove/force + +# Add or remove newline between '=' and '[' (D only) +nl_assign_square = ignore # ignore/add/remove/force + +# Add or remove newline after '= [' (D only). Will also affect the newline before the ']' +nl_after_square_assign = ignore # ignore/add/remove/force + +# The number of blank lines after a block of variable definitions at the top of a function body. +# 0=no change (default) +nl_func_var_def_blk = 0 # number + +# Add or remove newline between a function call's ')' and '{', as in: +# list_for_each(item, &list) { } +nl_fcall_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'enum' and '{' +nl_enum_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'struct and '{' +nl_struct_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'union' and '{' +nl_union_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'if' and '{' +nl_if_brace = ignore # ignore/add/remove/force + +# Add or remove newline between '}' and 'else' +nl_brace_else = remove # ignore/add/remove/force + +# Add or remove newline between 'else if' and '{' +# If set to ignore, nl_if_brace is used instead +nl_elseif_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'else' and '{' +nl_else_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'else' and 'if' +nl_else_if = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'finally' +nl_brace_finally = ignore # ignore/add/remove/force + +# Add or remove newline between 'finally' and '{' +nl_finally_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'try' and '{' +nl_try_brace = ignore # ignore/add/remove/force + +# Add or remove newline between get/set and '{' +nl_getset_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'for' and '{' +nl_for_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'catch' and '{' +nl_catch_brace = ignore # ignore/add/remove/force + +# Add or remove newline between '}' and 'catch' +nl_brace_catch = ignore # ignore/add/remove/force + +# Add or remove newline between 'while' and '{' +nl_while_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'using' and '{' +nl_using_brace = ignore # ignore/add/remove/force + +# Add or remove newline between two open or close braces. +# Due to general newline/brace handling, REMOVE may not work. +nl_brace_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'do' and '{' +nl_do_brace = ignore # ignore/add/remove/force + +# Add or remove newline between '}' and 'while' of 'do' statement +nl_brace_while = ignore # ignore/add/remove/force + +# Add or remove newline between 'switch' and '{' +nl_switch_brace = remove # ignore/add/remove/force + +# Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc. +# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch, and nl_catch_brace. +nl_multi_line_cond = true # false/true + +# Force a newline in a define after the macro name for multi-line defines. +nl_multi_line_define = false # false/true + +# Whether to put a newline before 'case' statement +nl_before_case = false # false/true + +# Add or remove newline between ')' and 'throw' +nl_before_throw = ignore # ignore/add/remove/force + +# Whether to put a newline after 'case' statement +nl_after_case = false # false/true + +# Add or remove a newline between a case ':' and '{'. Overrides nl_after_case. +nl_case_colon_brace = ignore # ignore/add/remove/force + +# Newline between namespace and { +nl_namespace_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'template<>' and whatever follows. +nl_template_class = ignore # ignore/add/remove/force + +# Add or remove newline between 'class' and '{' +nl_class_brace = ignore # ignore/add/remove/force + +# Add or remove newline after each ',' in the constructor member initialization +nl_class_init_args = ignore # ignore/add/remove/force + +# Add or remove newline between return type and function name in a function definition +nl_func_type_name = add # ignore/add/remove/force + +# Add or remove newline between return type and function name inside a class {} +# Uses nl_func_type_name or nl_func_proto_type_name if set to ignore. +nl_func_type_name_class = ignore # ignore/add/remove/force + +# Add or remove newline between function scope and name in a definition +# Controls the newline after '::' in 'void A::f() { }' +nl_func_scope_name = ignore # ignore/add/remove/force + +# Add or remove newline between return type and function name in a prototype +nl_func_proto_type_name = ignore # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' +nl_func_paren = ignore # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' in the definition +nl_func_def_paren = ignore # ignore/add/remove/force + +# Add or remove newline after '(' in a function declaration +nl_func_decl_start = ignore # ignore/add/remove/force + +# Add or remove newline after '(' in a function definition +nl_func_def_start = ignore # ignore/add/remove/force + +# Overrides nl_func_decl_start when there is only one parameter. +nl_func_decl_start_single = ignore # ignore/add/remove/force + +# Overrides nl_func_def_start when there is only one parameter. +nl_func_def_start_single = ignore # ignore/add/remove/force + +# Add or remove newline after each ',' in a function declaration +nl_func_decl_args = remove # ignore/add/remove/force + +# Add or remove newline after each ',' in a function definition +nl_func_def_args = remove # ignore/add/remove/force + +# Add or remove newline before the ')' in a function declaration +nl_func_decl_end = ignore # ignore/add/remove/force + +# Add or remove newline before the ')' in a function definition +nl_func_def_end = ignore # ignore/add/remove/force + +# Overrides nl_func_decl_end when there is only one parameter. +nl_func_decl_end_single = ignore # ignore/add/remove/force + +# Overrides nl_func_def_end when there is only one parameter. +nl_func_def_end_single = ignore # ignore/add/remove/force + +# Add or remove newline between '()' in a function declaration. +nl_func_decl_empty = ignore # ignore/add/remove/force + +# Add or remove newline between '()' in a function definition. +nl_func_def_empty = ignore # ignore/add/remove/force + +# Add or remove newline between function signature and '{' +nl_fdef_brace = ignore # ignore/add/remove/force + +# Whether to put a newline after 'return' statement +nl_after_return = false # false/true + +# Add or remove a newline between the return keyword and return expression. +nl_return_expr = ignore # ignore/add/remove/force + +# Whether to put a newline after semicolons, except in 'for' statements +nl_after_semicolon = false # false/true + +# Whether to put a newline after brace open. +# This also adds a newline before the matching brace close. +nl_after_brace_open = false # false/true + +# If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is +# placed between the open brace and a trailing single-line comment. +nl_after_brace_open_cmt = false # false/true + +# Whether to put a newline after a virtual brace open with a non-empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open = false # false/true + +# Whether to put a newline after a virtual brace open with an empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open_empty = false # false/true + +# Whether to put a newline after a brace close. +# Does not apply if followed by a necessary ';'. +nl_after_brace_close = false # false/true + +# Whether to put a newline after a virtual brace close. +# Would add a newline before return in: 'if (foo) a++; return;' +nl_after_vbrace_close = false # false/true + +# Whether to alter newlines in '#define' macros +nl_define_macro = false # false/true + +# Whether to not put blanks after '#ifxx', '#elxx', or before '#endif' +nl_squeeze_ifdef = false # false/true + +# Add or remove blank line before 'if' +nl_before_if = ignore # ignore/add/remove/force + +# Add or remove blank line after 'if' statement +nl_after_if = ignore # ignore/add/remove/force + +# Add or remove blank line before 'for' +nl_before_for = ignore # ignore/add/remove/force + +# Add or remove blank line after 'for' statement +nl_after_for = ignore # ignore/add/remove/force + +# Add or remove blank line before 'while' +nl_before_while = ignore # ignore/add/remove/force + +# Add or remove blank line after 'while' statement +nl_after_while = ignore # ignore/add/remove/force + +# Add or remove blank line before 'switch' +nl_before_switch = ignore # ignore/add/remove/force + +# Add or remove blank line after 'switch' statement +nl_after_switch = ignore # ignore/add/remove/force + +# Add or remove blank line before 'do' +nl_before_do = ignore # ignore/add/remove/force + +# Add or remove blank line after 'do/while' statement +nl_after_do = ignore # ignore/add/remove/force + +# Whether to double-space commented-entries in struct/enum +nl_ds_struct_enum_cmt = false # false/true + +# Whether to double-space before the close brace of a struct/union/enum +# (lower priority than 'eat_blanks_before_close_brace') +nl_ds_struct_enum_close_brace = false # false/true + +# Add or remove a newline around a class colon. +# Related to pos_class_colon, nl_class_init_args, and pos_comma. +nl_class_colon = ignore # ignore/add/remove/force + +# Change simple unbraced if statements into a one-liner +# 'if(b)\n i++;' => 'if(b) i++;' +nl_create_if_one_liner = false # false/true + +# Change simple unbraced for statements into a one-liner +# 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);' +nl_create_for_one_liner = false # false/true + +# Change simple unbraced while statements into a one-liner +# 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' +nl_create_while_one_liner = false # false/true + +# +# Positioning options +# + +# The position of arithmetic operators in wrapped expressions +pos_arith = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of assignment in wrapped expressions. +# Do not affect '=' followed by '{' +pos_assign = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of boolean operators in wrapped expressions +pos_bool = trail # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of comparison operators in wrapped expressions +pos_compare = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of conditional (b ? t : f) operators in wrapped expressions +pos_conditional = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of the comma in wrapped expressions +pos_comma = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of the comma in the constructor initialization list +pos_class_comma = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of colons between constructor and member initialization +pos_class_colon = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force + +# +# Line Splitting options +# + +# Try to limit code width to N number of columns +code_width = 79 # number + +# Whether to fully split long 'for' statements at semi-colons +ls_for_split_full = true # false/true + +# Whether to fully split long function protos/calls at commas +ls_func_split_full = true # false/true + +# +# Blank line options +# + +# The maximum consecutive newlines +nl_max = 0 # number + +# The number of newlines after a function prototype, if followed by another function prototype +nl_after_func_proto = 0 # number + +# The number of newlines after a function prototype, if not followed by another function prototype +nl_after_func_proto_group = 0 # number + +# The number of newlines after '}' of a multi-line function body +nl_after_func_body = 0 # number + +# The number of newlines after '}' of a multi-line function body in a class declaration +nl_after_func_body_class = 0 # number + +# The number of newlines after '}' of a single line function body +nl_after_func_body_one_liner = 0 # number + +# The minimum number of newlines before a multi-line comment. +# Doesn't apply if after a brace open or another multi-line comment. +nl_before_block_comment = 0 # number + +# The minimum number of newlines before a single-line C comment. +# Doesn't apply if after a brace open or other single-line C comments. +nl_before_c_comment = 0 # number + +# The minimum number of newlines before a CPP comment. +# Doesn't apply if after a brace open or other CPP comments. +nl_before_cpp_comment = 0 # number + +# Whether to force a newline after a multi-line comment. +nl_after_multiline_comment = false # false/true + +# The number of newlines after '}' or ';' of a struct/enum/union definition +nl_after_struct = 0 # number + +# The number of newlines after '}' or ';' of a class definition +nl_after_class = 0 # number + +# The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. +# Will not change the newline count if after a brace open. +# 0 = No change. +nl_before_access_spec = 0 # number + +# The number of newlines after a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. +# 0 = No change. +nl_after_access_spec = 0 # number + +# The number of newlines between a function def and the function comment. +# 0 = No change. +nl_comment_func_def = 0 # number + +# The number of newlines after a try-catch-finally block that isn't followed by a brace close. +# 0 = No change. +nl_after_try_catch_finally = 0 # number + +# The number of newlines before and after a property, indexer or event decl. +# 0 = No change. +nl_around_cs_property = 0 # number + +# The number of newlines between the get/set/add/remove handlers in C#. +# 0 = No change. +nl_between_get_set = 0 # number + +# Add or remove newline between C# property and the '{' +nl_property_brace = ignore # ignore/add/remove/force + +# Whether to remove blank lines after '{' +eat_blanks_after_open_brace = true # false/true + +# Whether to remove blank lines before '}' +eat_blanks_before_close_brace = true # false/true + +# +# Code modifying options (non-whitespace) +# + +# Add or remove braces on single-line 'do' statement +mod_full_brace_do = ignore # ignore/add/remove/force + +# Add or remove braces on single-line 'for' statement +mod_full_brace_for = ignore # ignore/add/remove/force + +# Add or remove braces on single-line function definitions. (Pawn) +mod_full_brace_function = ignore # ignore/add/remove/force + +# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'. +mod_full_brace_if = add # ignore/add/remove/force + +# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. +# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. +mod_full_brace_if_chain = false # false/true + +# Don't remove braces around statements that span N newlines +mod_full_brace_nl = 0 # number + +# Add or remove braces on single-line 'while' statement +mod_full_brace_while = add # ignore/add/remove/force + +# Add or remove braces on single-line 'using ()' statement +mod_full_brace_using = ignore # ignore/add/remove/force + +# Add or remove unnecessary paren on 'return' statement +mod_paren_on_return = add # ignore/add/remove/force + +# Whether to change optional semicolons to real semicolons +mod_pawn_semicolon = false # false/true + +# Add parens on 'while' and 'if' statement around bools +mod_full_paren_if_bool = false # false/true + +# Whether to remove superfluous semicolons +mod_remove_extra_semicolon = true # false/true + +# If a function body exceeds the specified number of newlines and doesn't have a comment after +# the close brace, a comment will be added. +mod_add_long_function_closebrace_comment = 0 # number + +# If a switch body exceeds the specified number of newlines and doesn't have a comment after +# the close brace, a comment will be added. +mod_add_long_switch_closebrace_comment = 0 # number + +# If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after +# the #endif, a comment will be added. +mod_add_long_ifdef_endif_comment = 1 # number + +# If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after +# the #else, a comment will be added. +mod_add_long_ifdef_else_comment = 1 # number + +# If TRUE, will sort consecutive single-line 'import' statements [Java, D] +mod_sort_import = false # false/true + +# If TRUE, will sort consecutive single-line 'using' statements [C#] +mod_sort_using = false # false/true + +# If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] +# This is generally a bad idea, as it may break your code. +mod_sort_include = false # false/true + +# If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace. +mod_move_case_break = false # false/true + +# Will add or remove the braces around a fully braced case statement. +# Will only remove the braces if there are no variable declarations in the block. +mod_case_brace = ignore # ignore/add/remove/force + +# If TRUE, it will remove a void 'return;' that appears as the last statement in a function. +mod_remove_empty_return = false # false/true + +# +# Comment modifications +# + +# Try to wrap comments at cmt_width columns +cmt_width = 80 # number + +# Set the comment reflow mode (default: 0) +# 0: no reflowing (apart from the line wrapping due to cmt_width) +# 1: no touching at all +# 2: full reflow +cmt_reflow_mode = 2 # number + +# If false, disable all multi-line comment changes, including cmt_width. keyword substitution, and leading chars. +# Default is true. +cmt_indent_multi = true # false/true + +# Whether to group c-comments that look like they are in a block +cmt_c_group = false # false/true + +# Whether to put an empty '/*' on the first line of the combined c-comment +cmt_c_nl_start = true # false/true + +# Whether to put a newline before the closing '*/' of the combined c-comment +cmt_c_nl_end = true # false/true + +# Whether to group cpp-comments that look like they are in a block +cmt_cpp_group = false # false/true + +# Whether to put an empty '/*' on the first line of the combined cpp-comment +cmt_cpp_nl_start = false # false/true + +# Whether to put a newline before the closing '*/' of the combined cpp-comment +cmt_cpp_nl_end = false # false/true + +# Whether to change cpp-comments into c-comments +cmt_cpp_to_c = true # false/true + +# Whether to put a star on subsequent comment lines +cmt_star_cont = true # false/true + +# The number of spaces to insert at the start of subsequent comment lines +cmt_sp_before_star_cont = 0 # number + +# The number of spaces to insert after the star on subsequent comment lines +cmt_sp_after_star_cont = 0 # number + +# For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of +# the comment are the same length. Default=True +cmt_multi_check_last = true # false/true + +# The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment. +# Will substitute $(filename) with the current file's name. +cmt_insert_file_header = "" # string + +# The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment. +# Will substitute $(filename) with the current file's name. +cmt_insert_file_footer = "" # string + +# The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment. +# Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff. +# Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... } +cmt_insert_func_header = "" # string + +# The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment. +# Will substitute $(class) with the class name. +cmt_insert_class_header = "" # string + +# The filename that contains text to insert before a Obj-C message specification if the method isn't preceded with a C/C++ comment. +# Will substitute $(message) with the function name and $(javaparam) with the javadoc @param and @return stuff. +cmt_insert_oc_msg_header = "" # string + +# If a preprocessor is encountered when stepping backwards from a function name, then +# this option decides whether the comment should be inserted. +# Affects cmt_insert_oc_msg_header, cmt_insert_func_header and cmt_insert_class_header. +cmt_insert_before_preproc = false # false/true + +# +# Preprocessor options +# + +# Control indent of preprocessors inside #if blocks at brace level 0 +pp_indent = ignore # ignore/add/remove/force + +# Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false) +pp_indent_at_level = false # false/true + +# If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1. +pp_indent_count = 1 # number + +# Add or remove space after # based on pp_level of #if blocks +pp_space = ignore # ignore/add/remove/force + +# Sets the number of spaces added with pp_space +pp_space_count = 0 # number + +# The indent for #region and #endregion in C# and '#pragma region' in C/C++ +pp_indent_region = 0 # number + +# Whether to indent the code between #region and #endregion +pp_region_indent_code = false # false/true + +# If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level +pp_indent_if = 0 # number + +# Control whether to indent the code between #if, #else and #endif when not at file-level +pp_if_indent_code = false # false/true + +# Whether to indent '#define' at the brace level (true) or from column 1 (false) +pp_define_at_level = false # false/true + +# You can force a token to be a type with the 'type' option. +# Example: +# type myfoo1 myfoo2 +# +# You can create custom macro-based indentation using macro-open, +# macro-else and macro-close. +# Example: +# macro-open BEGIN_TEMPLATE_MESSAGE_MAP +# macro-open BEGIN_MESSAGE_MAP +# macro-close END_MESSAGE_MAP +# +# You can assign any keyword to any type with the set option. +# set func_call_user _ N_ +# +# The full syntax description of all custom definition config entries +# is shown below: +# +# define custom tokens as: +# - embed whitespace in token using '' escape character, or +# put token in quotes +# - these: ' " and ` are recognized as quote delimiters +# +# type token1 token2 token3 ... +# ^ optionally specify multiple tokens on a single line +# define def_token output_token +# ^ output_token is optional, then NULL is assumed +# macro-open token +# macro-close token +# macro-else token +# set id token1 token2 ... +# ^ optionally specify multiple tokens on a single line +# ^ id is one of the names in token_enum.h sans the CT_ prefix, +# e.g. PP_PRAGMA +# +# all tokens are separated by any mix of ',' commas, '=' equal signs +# and whitespace (space, tab) +# diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..fa0ff27 --- /dev/null +++ b/CHANGES @@ -0,0 +1,19658 @@ + --- 9.16.44 released --- + +6245. [security] Limit the amount of recursion that can be performed + by isccc_cc_fromwire. (CVE-2023-3341) [GL #4152] + +6235. [doc] Clarify BIND 9 time formats. [GL #4266] + +6230. [bug] Prevent an unnecessary query restart if a synthesized + CNAME target points to the CNAME owner. [GL #3835] + + --- 9.16.43 released --- + +6212. [bug] Don't process detach and close netmgr events when + the netmgr has been paused. [GL #4200] + + --- 9.16.42 released --- + +6192. [security] A query that prioritizes stale data over lookup + triggers a fetch to refresh the stale data in cache. + If the fetch is aborted for exceeding the recursion + quota, it was possible for 'named' to enter an infinite + callback loop and crash due to stack overflow. This has + been fixed. (CVE-2023-2911) [GL #4089] + +6190. [security] Improve the overmem cleaning process to prevent the + cache going over the configured limit. (CVE-2023-2828) + [GL #4055] + +6183. [bug] Fix a serve-stale bug where a delegation from cache + could be returned to the client. [GL #3950] + +6173. [bug] Properly process extra "nameserver" lines in + resolv.conf otherwise the next line is not properly + processed. [GL #4066] + +6169. [bug] named could crash when deleting inline-signing zones + with "rndc delzone". [GL #4054] + + --- 9.16.41 released --- + +6157. [bug] When removing delegations in an OPTOUT range + empty-non-terminal NSEC3 records generated by + those delegations were not removed. [GL #4027] + + --- 9.16.40 released --- + +6142. [bug] Reduce the number of dns_dnssec_verify calls made + determining if revoked keys needs to be removed from + the trust anchors. [GL #3981] + +6138. [doc] Fix the DF-flag documentation on the outgoing + UDP packets. [GL #3710] + +6132. [doc] Remove a dead link in the DNSSEC guide. [GL #3967] + +6129. [cleanup] Value stored to 'source' during its initialization is + never read. [GL #3965] + +6124. [bug] When changing from a NSEC3 capable DNSSEC algorithm to + an NSEC3 incapable DNSSEC algorithm using KASP the zone + could sometimes be incompletely signed. [GL #3937] + +5741. [bug] Log files with "timestamp" suffixes could be left in + place after rolling, even if the number of preserved + log files exceeded the configured "versions" limit. + [GL #828] [GL #3959] + + --- 9.16.39 released --- + +6119. [bug] Make sure to revert the reconfigured zones to the + previous version of the view, when the new view + reconfiguration fails during the configuration of + one of the configured zones. [GL #3911] + +6116. [bug] Fix error path cleanup issue in the dns_catz_new_zones() + function. [GL #3900] + +6115. [bug] Unregister db update notify callback before detaching + from the previous db inside the catz update notify + callback. [GL #3777] + +6105. [bug] Detach 'rpzs' and 'catzs' from the previous view in + configure_rpz() and configure_catz(), respectively, + just after attaching it to the new view. [GL #3880] + +6098. [test] Don't test HMAC-MD5 when not supported by libcrypto. + [GL #3871] + +6095. [test] Test various 'islands of trust' configurations when + using managed keys. [GL #3662] + +6094. [bug] Building against (or running with) libuv versions + 1.35.0 and 1.36.0 is now a fatal error. The rules for + mixing and matching compile-time and run-time libuv + versions have been tightened for libuv versions between + 1.35.0 and 1.40.0. [GL #3840] + + --- 9.16.38 released --- + +6083. [bug] Fix DNSRPS-enabled builds as they were inadvertently + broken by change 6042. [GL #3827] + +6081. [bug] Handle primary server address lookup failures in + nsupdate more gracefully. [GL #3830] + +6080. [bug] 'named -V' leaked memory. [GL #3829] + +6079. [bug] Force set the DS state after a 'rdnc dnssec -checkds' + command. [GL #3822] + +6075. [bug] Add missing node lock when setting node->wild in + add_wildcard_magic. [GL #3799] + +6072. [bug] Avoid the OpenSSL lock contention when initializing + Message Digest Contexts by using explicit algorithm + fetching, initializing static contexts for every + supported algorithms, and initializing the new context + by copying the static copy. [GL #3795] + +6069. [bug] Detach from the view in zone_shutdown() to + release the memory held by the dead view + early. [GL #3801] + + --- 9.16.37 released --- + +6067. [security] Fix serve-stale crash when recursive clients soft quota + is reached. (CVE-2022-3924) [GL #3619] + +6066. [security] Handle RRSIG lookups when serve-stale is active. + (CVE-2022-3736) [GL #3622] + +6064. [security] An UPDATE message flood could cause named to exhaust all + available memory. This flaw was addressed by adding a + new "update-quota" statement that controls the number of + simultaneous UPDATE messages that can be processed or + forwarded. The default is 100. A stats counter has been + added to record events when the update quota is + exceeded, and the XML and JSON statistics version + numbers have been updated. (CVE-2022-3094) [GL #3523] + +6062. [func] The DSCP implementation, which has only been + partly operational since 9.16.0, is now marked as + deprecated. Configuring DSCP values in named.conf + will cause a warning will be logged. [GL #3773] + +6060. [bug] Fix a use-after-free bug in dns_zonemgr_releasezone() + by detaching from the zone manager outside of the write + lock. [GL #3768] + +6059. [bug] In some serve stale scenarios, like when following an + expired CNAME record, named could return SERVFAIL if the + previous request wasn't successful. Consider non-stale + data when in serve-stale mode. [GL #3678] + +6058. [bug] Prevent named from crashing when "rndc delzone" + attempts to delete a zone added by a catalog zone. + [GL #3745] + +6050. [bug] Changes to the RPZ response-policy min-update-interval + and add-soa options now take effect as expected when + named is reconfigured. [GL #3740] + +6048. [bug] Fix a log message error in dns_catz_update_from_db(), + where serials with values of 2^31 or larger were logged + incorrectly as negative numbers. [GL #3742] + +6045. [cleanup] The list of supported DNSSEC algorithms changed log + level from "warning" to "notice" to match named's other + startup messages. [GL !7217] + +6044. [bug] There was an "RSASHA236" typo in a log message. + [GL !7206] + +5845. [bug] Refactor the timer to keep track of posted events + as to use isc_task_purgeevent() instead of using + isc_task_purgerange(). The isc_task_purgeevent() + has been refactored to purge a single event instead + of walking through the list of posted events. + [GL #3252] + + --- 9.16.36 released --- + +6043. [bug] The key file IO locks objects would never get + deleted from the hashtable due to off-by-one error. + [GL #3727] + +6042. [bug] ANY responses could sometimes have the wrong TTL. + [GL #3613] + +6040. [bug] Speed up the named shutdown time by explicitly + canceling all recursing ns_client objects for + each ns_clientmgr. [GL #3183] + +6039. [bug] Removing a catalog zone from catalog-zones without + also removing the referenced zone could leave a + dangling pointer. [GL #3683] + +6031. [bug] Move the "final reference detached" log message + from dns_zone unit to the DEBUG(1) log level. + [GL #3707] + +6024. [func] Deprecate 'auto-dnssec'. [GL #3667] + +6021. [bug] Use the current domain name when checking answers from + a dual-stack-server. [GL #3607] + +6020. [bug] Ensure 'named-checkconf -z' respects the check-wildcard + option when loading a zone. [GL #1905] + +6017. [bug] The view's zone table was not locked when it should + have been leading to race conditions when external + extensions that manipulate the zone table where in + use. [GL #3468] + + --- 9.16.35 released --- + +6013. [bug] Fix a crash that could happen when you change + a dnssec-policy zone with NSEC3 to start using + inline-signing. [GL #3591] + +6009. [bug] Don't trust a placeholder KEYDATA from the managed-keys + zone by adding it into secroots. [GL #2895] + +6008. [bug] Fixed a race condition that could cause a crash + in dns_zone_synckeyzone(). [GL #3617] + +6002. [bug] Fix a resolver prefetch bug when the record's TTL value + is equal to the configured prefetch eligibility value, + but the record was erroneously not treated as eligible + for prefetching. [GL #3603] + +6001. [bug] Always call dns_adb_endudpfetch() after calling + dns_adb_beginudpfetch() for UDP queries in resolver.c, + in order to adjust back the quota. [GL #3598] + +6000. [bug] Fix a startup issue on Solaris systems with many + (reportedly > 510) CPUs. Thanks to Stacey Marshall from + Oracle for deep investigation of the problem. [GL #3563] + +5999. [bug] rpz-ip rules could be ineffective in some scenarios + with CD=1 queries. [GL #3247] + +5998. [bug] The RecursClients statistics counter could overflow + in certain resolution scenarios. [GL #3584] + +5996. [bug] Fix a couple of bugs in cfg_print_duration(), which + could result in generating incomplete duration values + when printing the configuration using named-checkconf. + [GL !6880] + + --- 9.16.34 released --- + +5991. [protocol] Add support for parsing and validating "dohpath" to + SVCB. [GL #3544] + +5988. [bug] Some out of memory conditions in opensslrsa_link.c + could lead to memory leaks. [GL #3551] + +5984. [func] 'named -V' now reports the list of supported + DNSSEC/DS/HMAC algorithms and the supported TKEY modes. + [GL #3541] + +5983. [bug] Changing just the TSIG key names for primaries in + catalog zones' member zones was not effective. + [GL #3557] + +5973. [bug] Fixed a possible invalid detach in UPDATE + processing. [GL #3522] + +5963. [bug] Ensure struct named_server is properly initialized. + [GL #6531] + +5921. [test] Convert system tests to use a default DNSKEY algorithm + where the test is not DNSKEY algorithm specific. + [GL #3440] + + --- 9.16.33 released --- + +5962. [security] Fix memory leak in EdDSA verify processing. + (CVE-2022-38178) [GL #3487] + +5961. [security] Fix memory leak in ECDSA verify processing. + (CVE-2022-38177) [GL #3487] + +5960. [security] Fix serve-stale crash that could happen when + stale-answer-client-timeout was set to 0 and there was + a stale CNAME in the cache for an incoming query. + (CVE-2022-3080) [GL #3517] + +5957. [security] Prevent excessive resource use while processing large + delegations. (CVE-2022-2795) [GL #3394] + +5956. [func] Make RRL code treat all QNAMEs that are subject to + wildcard processing within a given zone as the same + name. [GL #3459] + +5955. [port] The libxml2 library has deprecated the usage of + xmlInitThreads() and xmlCleanupThreads() functions. Use + xmlInitParser() and xmlCleanupParser() instead. + [GL #3518] + +5954. [func] Fallback to IDNA2003 processing in dig when IDNA2008 + conversion fails. [GL #3485] + +5953. [bug] Fix a crash on shutdown in delete_trace_entry(). Add + mctx attach/detach pair to make sure that the memory + context used by a memory pool is not destroyed before + the memory pool itself. [GL #3515] + +5952. [bug] Use quotes around address strings in YAML output. + [GL #3511] + +5951. [bug] In some cases, the dnstap query_message field was + erroneously set when logging response messages. + [GL #3501] + +5948. [bug] Fix nsec3.c:dns_nsec3_activex() function, add a missing + dns_db_detachnode() call. [GL #3500] + +5945. [bug] If parsing /etc/bind.key failed, delv could assert + when trying to parse the built in trust anchors as + the parser hadn't been reset. [GL !6468] + +5942. [bug] Fix tkey.c:buildquery() function's error handling by + adding the missing cleanup code. [GL #3492] + +5941. [func] Zones with dnssec-policy now require dynamic DNS or + inline-siging to be configured explicitly. [GL #3381] + +5936. [bug] Don't enable serve-stale for lookups that error because + it is a duplicate query or a query that would be + dropped. [GL #2982] + + --- 9.16.32 released --- + +5934. [func] Improve fetches-per-zone fetch limit logging to log + the final allowed and spilled values of the fetch + counters before the counter object gets destroyed. + [GL #3461] + +5933. [port] Automatically disable RSASHA1 and NSEC3RSASHA1 in + named on Fedorda 33, Oracle Linux 9 and RHEL9 when + they are disabled by the security policy. [GL #3469] + +5932. [bug] Fix rndc dumpdb -expired and always include expired + RRsets, not just for RBTDB_VIRTUAL time window. + [GL #3462] + +5929. [bug] The "max-zone-ttl" option in "dnssec-policy" was + not fully effective; it was used for timing key + rollovers but did not actually place an upper limit + on TTLs when loading a zone. This has been + corrected, and the documentation has been clarified + to indicate that the old "max-zone-ttl" zone option + is now ignored when "dnssec-policy" is in use. + [GL #2918] + +5924. [func] When it's necessary to use AXFR to respond to an + IXFR request, a message explaining the reason + is now logged at level info. [GL #2683] + +5923. [bug] Fix inheritance for dnssec-policy when checking for + inline-signing. [GL #3438] + +5922. [bug] Forwarding of UPDATE message could fail with the + introduction of netmgr. This has been fixed. [GL #3389] + + --- 9.16.31 released --- + +5917. [bug] Update ifconfig.sh script as is miscomputed interface + identifiers when destroying interfaces. [GL #3061] + +5915. [bug] Detect missing closing brace (}) and computational + overflows in $GENERATE directives. [GL #3429] + +5913. [bug] Fix a race between resolver query timeout and + validation in resolver.c:validated(). Remove + resolver.c:maybe_destroy() as it is no loger needed. + [GL #3398] + +5909. [bug] The server-side destination port was missing from dnstap + captures of client traffic. [GL #3309] + +5905. [bug] When the TCP connection would be closed/reset between + the connect/accept and the read, the uv_read_start() + return value would be unexpected and cause an assertion + failure. [GL #3400] + +5903. [bug] When named checks that the OPCODE in a response matches + that of the request, if there is a mismatch named logs + an error. Some of those error messages incorrectly + used RCODE instead of OPCODE to lookup the nemonic. + This has been corrected. [GL !6420] + + --- 9.16.30 released --- + +5899. [func] Don't try to process DNSSEC-related and ZONEMD records + in catz. [GL #3380] + +5890. [bug] When the fetches-per-server quota was adjusted + because of an authoritative server timing out more + or less frequently, it was incorrectly set to 1 + rather than the intended value. This has been + fixed. [GL #3327] + +5888. [bug] Only write key files if the dnssec-policy keymgr has + changed the metadata. [GL #3302] + +5823. [func] Replace hazard pointers based lock-free list with + locked-list based queue that's simpler and has no or + little performance impact. [GL #3180] + + --- 9.16.29 released --- + +5885. [bug] RPZ NSIP and NSDNAME rule processing didn't handle stub + and static-stub zones at or above the query name. This + has now been addressed. [GL #3232] + +5881. [bug] dig +nssearch could hang in rare cases when recv_done() + callback was being called earlier than send_done(). + [GL #3278] + +5880. [func] Add new named command-line option -C to print built-in + defaults. [GL #1326] + +5879. [contrib] dlz: Add FALLTHROUGH and UNREACHABLE macros. [GL #3306] + +5874. [bug] keymgr didn't work with python 3.11. [GL !6157] + +5866. [bug] Work around a jemalloc quirk which could trigger an + out-of-memory condition in named over time. [GL #3287] + +5863. [bug] If there was a pending negative cache DS entry, + validations depending upon it could fail. [GL #3279] + +5858. [bug] Don't remove CDS/CDNSKEY DELETE records on zone sign + when using 'auto-dnssec maintain;'. [GL #2931] + + --- 9.16.28 released --- + +5856. [bug] The "starting maxtime timer" message related to outgoing + zone transfers was incorrectly logged at the ERROR level + instead of DEBUG(1). [GL #3208] + +5852. [func] Add new "reuseport" option to enable/disable load + balancing of sockets. [GL #3249] + +5843. [bug] When an UPDATE targets a zone that is not configured, + the requested zone name is now logged in the "not + authoritative" error message, so that it is easier to + track down problematic update clients. [GL #3209] + +5836. [bug] Quote the dns64 prefix in error messages that complain + about problems with it, to avoid confusion with the + following dns64 ACLs. [GL #3210] + +5834. [cleanup] C99 variable-length arrays are difficult to use safely, + so avoid them except in test code. [GL #3201] + +5828. [bug] Replace single TCP write timer with per-TCP write + timers. [GL #3200] + +5824. [bug] Invalid dnssec-policy definitions were being accepted + where the defined keys did not cover both KSK and ZSK + roles for a given algorithm. This is now checked for + and the dnssec-policy is rejected if both roles are + not present for all algorithms in use. [GL #3142] + + --- 9.16.27 released --- + +5818. [security] A synchronous call to closehandle_cb() caused + isc__nm_process_sock_buffer() to be called recursively, + which in turn left TCP connections hanging in the + CLOSE_WAIT state blocking indefinitely when + out-of-order processing was disabled. (CVE-2022-0396) + [GL #3112] + +5817. [security] The rules for acceptance of records into the cache + have been tightened to prevent the possibility of + poisoning if forwarders send records outside + the configured bailiwick. (CVE-2021-25220) [GL #2950] + +5816. [bug] Make BIND compile with LibreSSL 3.5.0, as it was using + not very accurate pre-processor checks for using shims. + [GL #3172] + +5815. [bug] If an oversized key name of a specific length was used + in the text form of an HTTP or SVBC record, an INSIST + could be triggered when parsing it. [GL #3175] + +5814. [bug] The RecursClients statistics counter could underflow + in certain resolution scenarios. [GL #3147] + +5811. [bug] Reimplement the maximum and idle timeouts for outgoing + zone transfers. [GL #1897] + +5807. [bug] Add a TCP "write" timer, and time out writing + connections after the "tcp-idle-timeout" period + has elapsed. [GL #3132] + +5804. [func] Add a debug log message when starting and ending + the task exclusive mode. [GL #3137] + + --- 9.16.26 released --- + +5801. [bug] Log "quota reached" message when hard quota + is reached when accepting a connection. [GL #3125] + +5800. [func] Add ECS support to the DLZ interface. [GL #3082] + +5797. [bug] A failed view configuration during a named + reconfiguration procedure could cause inconsistencies + in BIND internal structures, causing a crash or other + unexpected errors. [GL #3060] + +5795. [bug] rndc could crash when interrupted by a signal + before receiving a response. [GL #3080] + +5793. [bug] Correctly detect and enable UDP recvmmsg support + in all versions of libuv that support it. [GL #3095] + + --- 9.16.25 released --- + +5789. [bug] Allow replacing expired zone signatures with + signatures created by the KSK. [GL #3049] + +5788. [bug] An assertion could occur if a catalog zone event was + scheduled while the task manager was being shut + down. [GL #3074] + +5787. [doc] Update 'auto-dnssec' documentation, it may only be + activated at zone level. [GL #3023] + +5786. [bug] Defer detaching from zone->raw in zone_shutdown() if + the zone is in the process of being dumped to disk, to + ensure that the unsigned serial number information is + always written in the raw-format header of the signed + version on an inline-signed zone. [GL #3071] + +5785. [bug] named could leak memory when two dnssec-policy clauses + had the same name. named failed to log this error. + [GL #3085] + +5776. [bug] Add a missing isc_condition_destroy() for nmsocket + condition variable and add missing isc_mutex_destroy() + for nmworker lock. [GL #3051] + +5676. [func] Memory use in named was excessive. This has been + addressed by: + - Replacing locked memory pools with normal memory + allocations. + - Reducing the number of retained free items in + unlocked memory pools. + - Disabling the internal allocator by default. + "named -M internal" turns it back on. + [GL #2398] + + --- 9.16.24 released --- + +5773. [func] Change the message when accepting TCP connection has + failed to say "Accepting TCP connection failed" and + change the log level for ISC_R_NOTCONNECTED, ISC_R_QUOTA + and ISC_R_SOFTQUOTA results codes from ERROR to INFO. + [GL #2700] + +5768. [bug] dnssec-dsfromkey failed to omit revoked keys. [GL #853] + +5764. [bug] dns_sdlz_putrr failed to process some valid resource + records. [GL #3021] + +5762. [bug] Fix a "named" crash related to removing and restoring a + `catalog-zone` entry in the configuration file and + running `rndc reconfig`. [GL #1608] + +5758. [bug] mdig now honors the operating system's preferred + ephemeral port range. [GL #2374] + +5757. [test] Replace sed in nsupdate system test with awk to + construct the nsupdate command. The sed expression + was not reliably changing the ttl. [GL #3003] + + --- 9.16.23 released --- + +5752. [bug] Fix an assertion failure caused by missing member zones + during a reload of a catalog zone. [GL #2308] + +5750. [bug] Fix a bug when comparing two RSA keys. There was a typo + which caused the "p" prime factors to not being + compared. [GL #2972] + +5737. [bug] Address Coverity warning in lib/dns/dnssec.c. + [GL #2935] + + --- 9.16.22 released --- + +5736. [security] The "lame-ttl" option is now forcibly set to 0. This + effectively disables the lame server cache, as it could + previously be abused by an attacker to significantly + degrade resolver performance. (CVE-2021-25219) + [GL #2899] + +5724. [bug] Address a potential deadlock when checking zone content + consistency. [GL #2908] + +5723. [bug] Change 5709 broke backward compatibility for the + "check-names master ..." and "check-names slave ..." + options. This has been fixed. [GL #2911] + +5720. [contrib] Old-style DLZ drivers that had to be enabled at + build-time have been marked as deprecated. [GL #2814] + +5719. [func] The "map" zone file format has been marked as + deprecated. [GL #2882] + +5717. [func] The "cache-file" option, which was documented as "for + testing purposes only" and not to be used, has been + removed. [GL #2903] + +5716. [bug] Multiple library names were mistakenly passed to the + krb5-config utility when ./configure was invoked with + the --with-gssapi=[/path/to/]krb5-config option. This + has been fixed by invoking krb5-config separately for + each required library. [GL #2866] + +5715. [func] Add a check for ports specified in "*-source(-v6)" + options clashing with a global listening port. Such a + configuration was already unsupported, but it failed + silently; it is now treated as an error. [GL #2888] + +5714. [bug] Remove the "adjust interface" mechanism which was + responsible for setting up listeners on interfaces when + the "*-source(-v6)" address and port were the same as + the "listen-on(-v6)" address and port. Such a + configuration is no longer supported; under certain + timing conditions, that mechanism could prevent named + from listening on some TCP ports. This has been fixed. + [GL #2852] + +5712. [doc] Add deprecation notice about removing native PKCS#11 + support in the next major BIND 9 release. [GL #2691] + + --- 9.16.21 released --- + +5711. [bug] "map" files exceeding 2GB in size failed to load due to + a size comparison that incorrectly treated the file size + as a signed integer. [GL #2878] + +5710. [port] win32: incorrect parentheses resulted in the wrong + sizeof() tests being used to pick the appropriate + Windows atomic operations for the object's size. + [GL #2891] + +5709. [cleanup] Enum values throughout the code have been updated + to use the terms "primary" and "secondary" instead of + "master" and "slave", respectively. [GL #1944] + +5708. [bug] The thread-local isc_tid_v variable was not properly + initialized when running BIND 9 as a Windows Service, + leading to a crash on startup. [GL #2837] + +5705. [bug] Change #5686 altered the internal memory structure of + zone databases, but neglected to update the MAPAPI value + for zone files in "map" format. This caused named to + attempt to load incompatible map files, triggering an + assertion failure on startup. The MAPAPI value has now + been updated, so named rejects outdated files when + encountering them. [GL #2872] + +5704. [bug] Change #5317 caused the EDNS TCP Keepalive option to be + ignored inadvertently in client requests. It has now + been fixed and this option is handled properly again. + [GL #1927] + +5701. [bug] named-checkconf failed to detect syntactically invalid + values of the "key" and "tls" parameters used to define + members of remote server lists. [GL #2461] + +5700. [bug] When a member zone was removed from a catalog zone, + journal files for the former were not deleted. + [GL #2842] + +5699. [func] Data structures holding DNSSEC signing statistics are + now grown and shrunk as necessary upon key rollover + events. [GL #1721] + +5698. [bug] When a DNSSEC-signed zone which only has a single + signing key available is migrated to use KASP, that key + is now treated as a Combined Signing Key (CSK). + [GL #2857] + +5696. [protocol] Support for HTTPS and SVCB record types has been added. + (This does not include ADDITIONAL section processing for + these record types, only basic support for RR type + parsing and printing.) [GL #1132] + +5694. [bug] Stale data in the cache could cause named to send + non-minimized queries despite QNAME minimization being + enabled. [GL #2665] + +5691. [bug] When a dynamic zone was made available in another view + using the "in-view" statement, running "rndc freeze" + always reported an "already frozen" error even though + the zone was successfully frozen. [GL #2844] + +5690. [func] dnssec-signzone now honors Predecessor and Successor + metadata found in private key files: if a signature for + an RRset generated by the inactive predecessor exists + and does not need to be replaced, no additional + signature is now created for that RRset using the + successor key. This enables dnssec-signzone to gradually + replace RRSIGs during a ZSK rollover. [GL #1551] + + --- 9.16.20 released --- + +5689. [security] An assertion failure occurred when named attempted to + send a UDP packet that exceeded the MTU size, if + Response Rate Limiting (RRL) was enabled. + (CVE-2021-25218) [GL #2856] + +5688. [bug] Zones using KASP and inline-signed zones failed to apply + changes from the unsigned zone to the signed zone under + certain circumstances. This has been fixed. [GL #2735] + +5687. [bug] "rndc reload " could trigger a redundant + reload for an inline-signed zone whose zone file was not + modified since the last "rndc reload". This has been + fixed. [GL #2855] + +5686. [func] The number of internal data structures allocated for + each zone was reduced. [GL #2829] + +5685. [bug] named failed to check the opcode of responses when + performing zone refreshes, stub zone updates, and UPDATE + forwarding. This has been fixed. [GL #2762] + +5682. [bug] Some changes to "zone-statistics" settings were not + properly processed by "rndc reconfig". This has been + fixed. [GL #2820] + +5681. [func] Relax the checks in the dns_zone_cdscheck() function to + allow CDS and CDNSKEY records in the zone that do not + match an existing DNSKEY record, as long as the + algorithm matches. This allows a clean rollover from one + provider to another in a multi-signer DNSSEC + configuration. [GL #2710] + +5679. [func] Thread affinity is no longer set. [GL #2822] + +5678. [bug] The "check DS" code failed to release all resources upon + named shutdown when a refresh was in progress. This has + been fixed. [GL #2811] + +5672. [bug] Authentication of rndc messages could fail if a + "controls" statement was configured with multiple key + algorithms for the same listener. This has been fixed. + [GL #2756] + + --- 9.16.19 released --- + +5671. [bug] A race condition could occur where two threads were + competing for the same set of key file locks, leading to + a deadlock. This has been fixed. [GL #2786] + +5670. [bug] create_keydata() created an invalid placeholder keydata + record upon a refresh failure, which prevented the + database of managed keys from subsequently being read + back. This has been fixed. [GL #2686] + +5669. [func] KASP support was extended with the "check DS" feature. + Zones with "dnssec-policy" and "parental-agents" + configured now check for DS presence and can perform + automatic KSK rollovers. [GL #1126] + +5668. [bug] Rescheduling a setnsec3param() task when a zone failed + to load on startup caused a hang on shutdown. This has + been fixed. [GL #2791] + +5667. [bug] The configuration-checking code failed to account for + the inheritance rules of the "dnssec-policy" option. + This has been fixed. [GL #2780] + +5666. [doc] The safe "edns-udp-size" value was tweaked to match the + probing value from BIND 9.16 for better compatibility. + [GL #2183] + +5665. [bug] If nsupdate sends an SOA request and receives a REFUSED + response, it now fails over to the next available + server. [GL #2758] + +5664. [func] For UDP messages larger than the path MTU, named now + sends an empty response with the TC (TrunCated) bit set. + In addition, setting the DF (Don't Fragment) flag on + outgoing UDP sockets was re-enabled. [GL #2790] + +5662. [bug] Views with recursion disabled are now configured with a + default cache size of 2 MB unless "max-cache-size" is + explicitly set. This prevents cache RBT hash tables from + being needlessly preallocated for such views. [GL #2777] + +5661. [bug] Change 5644 inadvertently introduced a deadlock: when + locking the key file mutex for each zone structure in a + different view, the "in-view" logic was not considered. + This has been fixed. [GL #2783] + +5658. [bug] Increasing "max-cache-size" for a running named instance + (using "rndc reconfig") did not cause the hash tables + used by cache databases to be grown accordingly. This + has been fixed. [GL #2770] + +5655. [bug] Signed, insecure delegation responses prepared by named + either lacked the necessary NSEC records or contained + duplicate NSEC records when both wildcard expansion and + CNAME chaining were required to prepare the response. + This has been fixed. [GL #2759] + +5653. [bug] A bug that caused the NSEC3 salt to be changed on every + restart for zones using KASP has been fixed. [GL #2725] + + --- 9.16.18 released --- + +5660. [bug] The configuration-checking code failed to account for + the inheritance rules of the "key-directory" option. + [GL #2778] + +5659. [bug] When preparing DNS responses, named could replace the + letters 'W' (uppercase) and 'w' (lowercase) with '\000'. + This has been fixed. [GL #2779] + + --- 9.16.17 released --- + +5652. [bug] A copy-and-paste error in change 5584 caused the + IP_DONTFRAG socket option to be enabled instead of + disabled. This has been fixed. [GL #2746] + +5651. [func] Refactor zone dumping to be processed asynchronously via + the uv_work_t thread pool API. [GL #2732] + +5650. [bug] Prevent a crash that could occur if serve-stale was + enabled and a prefetch was triggered during a query + restart. [GL #2733] + +5649. [bug] If a query was answered with stale data on a server with + DNS64 enabled, an assertion could occur if a non-stale + answer arrived afterward. [GL #2731] + +5648. [bug] The calculation of the estimated IXFR transaction size + in dns_journal_iter_init() was invalid. [GL #2685] + +5644. [bug] Fix a race condition in reading and writing key files + for zones using KASP and configured in multiple views. + [GL #1875] + +5643. [cleanup] "make install" no longer creates an empty + ${localstatedir}/run directory. [GL #2709] + +5642. [bug] Zones which are configured in multiple views with + different values set for "dnssec-policy" and with + identical values set for "key-directory" are now + detected and treated as a configuration error. + [GL #2463] + +5641. [bug] Address a potential memory leak in + dst_key_fromnamedfile(). [GL #2689] + +5639. [bug] Check that the first and last SOA record of an AXFR are + consistent. [GL #2528] + +5638. [bug] Improvements related to network manager/task manager + integration: + - isc_managers_create() and isc_managers_destroy() + functions were added to handle setup and teardown of + netmgr, taskmgr, timermgr, and socketmgr, since these + require a precise order of operations now. + - Event queue processing is now quantized to prevent + infinite looping. + - The netmgr can now be paused from within a netmgr + thread. + - Deadlocks due to a conflict between netmgr's + pause/resume and listen/stoplistening operations were + fixed. + [GL #2654] + +5633. [doc] The "inline-signing" option was incorrectly described as + being inherited from the "options"/"view" levels and was + incorrectly accepted at those levels without effect. + This has been fixed. [GL #2536] + +5624. [func] Task manager events are now processed inside network + manager loops. The task manager no longer needs its own + set of worker threads, which improves resolver + performance. [GL #2638] + + --- 9.16.16 released --- + +5637. [func] Change the default value of the "max-ixfr-ratio" option + to "unlimited". [GL #2671] + +5636. [bug] named and named-checkconf did not report an error when + multiple zones with the "dnssec-policy" option set were + using the same zone file. This has been fixed. + [GL #2603] + +5635. [bug] Journal compaction could fail when a journal with + invalid transaction headers was not detected at startup. + This has been fixed. [GL #2670] + +5634. [bug] If "dnssec-policy" was active and a private key file was + temporarily offline during a rekey event, named could + incorrectly introduce replacement keys and break a + signed zone. This has been fixed. [GL #2596] + +5633. [doc] The "inline-signing" option was incorrectly described as + being inherited from the "options"/"view" levels and was + incorrectly accepted at those levels without effect. + This has been fixed. [GL #2536] + +5632. [func] Add a new built-in KASP, "insecure", which is used to + transition a zone from a signed to an unsigned state. + The existing built-in KASP "none" should no longer be + used to unsign a zone. [GL #2645] + +5631. [protocol] Update the implementation of the ZONEMD RR type to match + RFC 8976. [GL #2658] + +5630. [func] Treat DNSSEC responses containing NSEC3 records with + iteration counts greater than 150 as insecure. + [GL #2445] + +5629. [func] Reduce the maximum supported number of NSEC3 iterations + that can be configured for a zone to 150. [GL #2642] + +5627. [bug] RRSIG(SOA) RRsets placed anywhere other than at the zone + apex were triggering infinite resigning loops. This has + been fixed. [GL #2650] + +5626. [bug] When generating zone signing keys, KASP now also checks + for key ID conflicts among newly created keys, rather + than just between new and existing ones. [GL #2628] + +5625. [bug] A deadlock could occur when multiple "rndc addzone", + "rndc delzone", and/or "rndc modzone" commands were + invoked simultaneously for different zones. This has + been fixed. [GL #2626] + +5622. [cleanup] The lib/samples/ directory has been removed, as export + versions of libraries are no longer maintained. + [GL !4835] + +5619. [protocol] Implement draft-vandijk-dnsop-nsec-ttl, updating the + protocol such that NSEC(3) TTL values are set to the + minimum of the SOA MINIMUM value or the SOA TTL. + [GL #2347] + +5618. [bug] Change 5149 introduced some inconsistencies in the way + record TTLs were presented in cache dumps. These + inconsistencies have been eliminated. [GL #389] + [GL #2289] + + --- 9.16.15 released --- + +5621. [bug] Due to a backporting mistake in change 5609, named + binaries built against a Kerberos/GSSAPI library whose + header files did not define the GSS_SPNEGO_MECHANISM + preprocessor macro were not able to start if their + configuration included the "tkey-gssapi-credential" + option. This has been fixed. [GL #2634] + +5620. [bug] If zone journal files written by BIND 9.16.11 or earlier + were present when BIND was upgraded, the zone file for + that zone could have been inadvertently rewritten with + the current zone contents. This caused the original zone + file structure (e.g. comments, $INCLUDE directives) to + be lost, although the zone data itself was preserved. + This has been fixed. [GL #2623] + + --- 9.16.14 released --- + +5617. [security] A specially crafted GSS-TSIG query could cause a buffer + overflow in the ISC implementation of SPNEGO. + (CVE-2021-25216) [GL #2604] + +5616. [security] named crashed when a DNAME record placed in the ANSWER + section during DNAME chasing turned out to be the final + answer to a client query. (CVE-2021-25215) [GL #2540] + +5615. [security] Insufficient IXFR checks could result in named serving a + zone without an SOA record at the apex, leading to a + RUNTIME_CHECK assertion failure when the zone was + subsequently refreshed. This has been fixed by adding an + owner name check for all SOA records which are included + in a zone transfer. (CVE-2021-25214) [GL #2467] + +5614. [bug] Ensure all resources are properly cleaned up when a call + to gss_accept_sec_context() fails. [GL #2620] + +5613. [bug] It was possible to write an invalid transaction header + in the journal file for a managed-keys database after + upgrading. This has been fixed. Invalid headers in + existing journal files are detected and named is able + to recover from them. [GL #2600] + +5611. [func] Set "stale-answer-client-timeout" to "off" by default. + [GL #2608] + +5610. [bug] Prevent a crash which could happen when a lookup + triggered by "stale-answer-client-timeout" was attempted + right after recursion for a client query finished. + [GL #2594] + +5609. [func] The ISC implementation of SPNEGO was removed from BIND 9 + source code. It was no longer necessary as all major + contemporary Kerberos/GSSAPI libraries include support + for SPNEGO. [GL #2607] + +5608. [bug] When sending queries over TCP, dig now properly handles + "+tries=1 +retry=0" by not retrying the connection when + the remote server closes the connection prematurely. + [GL #2490] + +5607. [bug] As "rndc dnssec -checkds" and "rndc dnssec -rollover" + commands may affect the next scheduled key event, + reconfiguration of zone keys is now triggered after + receiving either of these commands to prevent + unnecessary key rollover delays. [GL #2488] + +5606. [bug] CDS/CDNSKEY DELETE records are now removed when a zone + transitions from a secure to an insecure state. + named-checkzone also no longer reports an error when + such records are found in an unsigned zone. [GL #2517] + +5605. [bug] "dig -u" now uses the CLOCK_REALTIME clock source for + more accurate time reporting. [GL #2592] + +5603. [bug] Fix a memory leak that occurred when named failed to + bind a UDP socket to a network interface. [GL #2575] + +5602. [bug] Fix TCPDNS and TLSDNS timers in Network Manager. This + makes the "tcp-initial-timeout" and "tcp-idle-timeout" + options work correctly again. [GL #2583] + +5601. [bug] Zones using KASP could not be thawed after they were + frozen using "rndc freeze". This has been fixed. + [GL #2523] + + --- 9.16.13 released --- + +5597. [bug] When serve-stale was enabled and starting the recursive + resolution process for a query failed, a named instance + could crash if it was configured as both a recursive and + authoritative server. This problem was introduced by + change 5573 and has now been fixed. [GL #2565] + +5595. [cleanup] Public header files for BIND 9 libraries no longer + directly include third-party library headers. This + prevents the need to include paths to third-party header + files in CFLAGS whenever BIND 9 public header files are + used, which could cause build-time issues on hosts with + older versions of BIND 9 installed. [GL #2357] + +5594. [bug] Building with --enable-dnsrps --enable-dnsrps-dl failed. + [GL #2298] + +5593. [bug] Journal files written by older versions of named can now + be read when loading zones, so that journal + incompatibility does not cause problems on upgrade. + Outdated journals are updated to the new format after + loading. [GL #2505] + +5592. [bug] Prevent hazard pointer table overflows on machines with + many cores, by allowing the thread IDs (serving as + indices into hazard pointer tables) of finished threads + to be reused by those created later. [GL #2396] + +5591. [bug] Fix a crash that occurred when + "stale-answer-client-timeout" was triggered without any + (stale) data available in the cache to answer the query. + [GL #2503] + +5590. [bug] NSEC3 records were not immediately created for dynamic + zones using NSEC3 with "dnssec-policy", resulting in + such zones going bogus. Add code to process the + NSEC3PARAM queue at zone load time so that NSEC3 records + for such zones are created immediately. [GL #2498] + +5588. [func] Add a new "purge-keys" option for "dnssec-policy". This + option determines the period of time for which key files + are retained after they become obsolete. [GL #2408] + +5586. [bug] An invalid direction field in a LOC record resulted in + an INSIST failure when a zone file containing such a + record was loaded. [GL #2499] + +5584. [bug] No longer set the IP_DONTFRAG option on UDP sockets, to + prevent dropping outgoing packets exceeding + "max-udp-size". [GL #2466] + +5582. [bug] BIND 9 failed to build when static OpenSSL libraries + were used and the pkg-config files for libssl and/or + libcrypto were unavailable. This has been fixed by + ensuring that the correct linking order for libssl and + libcrypto is always used. [GL #2402] + +5581. [bug] Fix a memory leak that occurred when inline-signed zones + were added to the configuration, followed by a + reconfiguration of named. [GL #2041] + +5580. [test] The system test framework no longer differentiates + between SKIPPED and UNTESTED system test results. Any + system test which is not run is now marked as SKIPPED. + [GL !4517] + +5573. [func] When serve-stale is enabled and stale data is available, + named now returns stale answers upon encountering any + unexpected error in the query resolution process. + However, the "stale-refresh-time" window is still only + started upon a timeout. [GL #2434] + +5564. [cleanup] Network manager's TLSDNS module was refactored to use + libuv and libssl directly instead of a stack of TCP/TLS + sockets. [GL #2335] + + --- 9.16.12 released --- + +5578. [protocol] Make "check-names" accept A records below "_spf", + "_spf_rate", and "_spf_verify" labels in order to cater + for the "exists" SPF mechanism specified in RFC 7208 + section 5.7 and appendix D.1. [GL #2377] + +5577. [bug] Fix the "three is a crowd" key rollover bug in KASP by + correctly implementing Equation (2) of the "Flexible and + Robust Key Rollover" paper. [GL #2375] + +5575. [bug] When migrating to KASP, BIND 9 considered keys with the + "Inactive" and/or "Delete" timing metadata to be + possible active keys. This has been fixed. [GL #2406] + +5572. [bug] Address potential double free in generatexml(). + [GL #2420] + +5571. [bug] named failed to start when its configuration included a + zone with a non-builtin "allow-update" ACL attached. + [GL #2413] + +5570. [bug] Improve performance of the DNSSEC verification code by + reducing the number of repeated calls to + dns_dnssec_keyfromrdata(). [GL #2073] + +5569. [bug] Emit useful error message when "rndc retransfer" is + applied to a zone of inappropriate type. [GL #2342] + +5568. [bug] Fixed a crash in "dnssec-keyfromlabel" when using ECDSA + keys. [GL #2178] + +5567. [bug] Dig now reports unknown dash options while pre-parsing + the options. This prevents "-multi" instead of "+multi" + from reporting memory usage before ending option parsing + with "Invalid option: -lti". [GL #2403] + +5566. [func] Add "stale-answer-client-timeout" option, which is the + amount of time a recursive resolver waits before + attempting to answer the query using stale data from + cache. [GL #2247] + +5565. [func] The SONAMEs for BIND 9 libraries now include the current + BIND 9 version number, in an effort to tightly couple + internal libraries with a specific release. [GL #2387] + +5562. [security] Fix off-by-one bug in ISC SPNEGO implementation. + (CVE-2020-8625) [GL #2354] + +5561. [bug] KASP incorrectly set signature validity to the value of + the DNSKEY signature validity. This is now fixed. + [GL #2383] + +5560. [func] The default value of "max-stale-ttl" has been changed + from 12 hours to 1 day and the default value of + "stale-answer-ttl" has been changed from 1 second to 30 + seconds, following RFC 8767 recommendations. [GL #2248] + +5456. [func] Added "primaries" as a synonym for "masters" in + named.conf, and "primary-only" as a synonym for + "master-only" in the parameters to "notify", to bring + terminology up-to-date with RFC 8499. [GL #1948] + +5362. [func] Limit the size of IXFR responses so that AXFR will + be used instead if it would be smaller. This is + controlled by the "max-ixfr-ratio" option, which + is a percentage representing the ratio of IXFR size + to the size of the entire zone. This value cannot + exceed 100%, which is the default. [GL #1515] + + --- 9.16.11 released --- + +5559. [bug] The --with-maxminddb=PATH form of the build-time option + enabling support for libmaxminddb was not working + correctly. This has been fixed. [GL #2366] + +5557. [bug] Prevent RBTDB instances from being destroyed by multiple + threads at the same time. [GL #2317] + +5556. [bug] Further tweak newline printing in dnssec-signzone and + dnssec-verify. [GL #2359] + +5555. [bug] server->reload_status was not properly initialized. + [GL #2361] + +5554. [bug] dnssec-signzone and dnssec-verify were missing newlines + between log messages. [GL #2359] + +5553. [bug] When reconfiguring named, removing "auto-dnssec" did not + turn off DNSSEC maintenance. [GL #2341] + +5552. [func] When switching to "dnssec-policy none;", named now + permits a safe transition to insecure mode and publishes + the CDS and CDNSKEY DELETE records, as described in RFC + 8078. [GL #1750] + +5551. [bug] named no longer attempts to assign threads to CPUs + outside the CPU affinity set. Thanks to Ole Bjørn + Hessen. [GL #2245] + +5550. [func] dnssec-signzone and named now log a warning when falling + back to the "increment" SOA serial method. [GL #2058] + +5545. [func] OS support for load-balanced sockets is no longer + required to receive incoming queries in multiple netmgr + threads. [GL #2137] + +5543. [bug] Fix UDP performance issues caused by making netmgr + callbacks asynchronous-only. [GL #2320] + +5542. [bug] Refactor netmgr. [GL #1920] [GL #2034] [GL #2061] + [GL #2194] [GL #2221] [GL #2266] [GL #2283] [GL #2318] + [GL #2321] + + --- 9.16.10 released --- + +5544. [func] Restore the default value of "nocookie-udp-size" to 4096 + bytes. [GL #2250] + +5541. [func] Adjust the "max-recursion-queries" default from 75 to + 100. [GL #2305] + +5540. [port] Fix building with native PKCS#11 support for AEP Keyper. + [GL #2315] + +5539. [bug] Tighten handling of missing DNS COOKIE responses over + UDP by falling back to TCP. [GL #2275] + +5538. [func] Add NSEC3 support to KASP. A new option for + "dnssec-policy", "nsec3param", can be used to set the + desired NSEC3 parameters. NSEC3 salt collisions are + automatically prevented during resalting. Salt + generation is now logged with zone context. [GL #1620] + +5534. [bug] The CNAME synthesized from a DNAME was incorrectly + followed when the QTYPE was CNAME or ANY. [GL #2280] + + --- 9.16.9 released --- + +5533. [func] Add the "stale-refresh-time" option, a time window that + starts after a failed lookup, during which a stale RRset + is served directly from cache before a new attempt to + refresh it is made. [GL #2066] + +5530. [bug] dnstap did not capture responses to forwarded UPDATE + requests. [GL #2252] + +5527. [bug] A NULL pointer dereference occurred when creating an NTA + recheck query failed. [GL #2244] + +5525. [bug] Change 5503 inadvertently broke cross-compilation by + replacing a call to AC_LINK_IFELSE() with a call to + AC_RUN_IFELSE() in configure.ac. This has been fixed, + making cross-compilation possible again. [GL #2237] + +5523. [bug] The initial lookup in a zone transitioning to/from a + signed state could fail if the DNSKEY RRset was not + found. [GL #2236] + +5522. [bug] Fixed a race/NULL dereference in TCPDNS send. [GL #2227] + +5520. [bug] Fixed a number of shutdown races, reference counting + errors, and spurious log messages that could occur + in the network manager. [GL #2221] + +5518. [bug] Stub zones now work correctly with primary servers using + "minimal-responses yes". [GL #1736] + +5517. [bug] Do not treat UV_EOF as a TCP4RecvErr or a TCP6RecvErr. + [GL #2208] + + --- 9.16.8 released --- + +5516. [func] The default EDNS buffer size has been changed from 4096 + to 1232 bytes. [GL #2183] + +5515. [func] Add 'rndc dnssec -rollover' command to trigger a manual + rollover for a specific key. [GL #1749] + +5514. [bug] Fix KASP expected key size for Ed25519 and Ed448. + [GL #2171] + +5513. [doc] The ARM section describing the "rrset-order" statement + was rewritten to make it unambiguous and up-to-date with + the source code. [GL #2139] + +5512. [bug] "rrset-order" rules using "order none" were causing + named to crash despite named-checkconf treating them as + valid. [GL #2139] + +5511. [bug] 'dig -u +yaml' failed to display timestamps to the + microsecond. [GL #2190] + +5510. [bug] Implement the attach/detach semantics for dns_message_t + to fix a data race in accessing an already-destroyed + fctx->rmessage. [GL #2124] + +5509. [bug] filter-aaaa: named crashed upon shutdown if it was in + the process of recursing for A RRsets. [GL #1040] + +5508. [func] Added new parameter "-expired" for "rndc dumpdb" that + also prints expired RRsets (awaiting cleanup) to the + dump file. [GL #1870] + +5507. [bug] Named could compute incorrect SIG(0) responses. + [GL #2109] + +5506. [bug] Properly handle failed sysconf() calls, so we don't + report invalid memory size. [GL #2166] + +5505. [bug] Updating contents of a mixed-case RPZ could cause some + rules to be ignored. [GL #2169] + +5503. [bug] Cleaned up reference counting of network manager + handles, now using isc_nmhandle_attach() and _detach() + instead of _ref() and _unref(). [GL #2122] + + --- 9.16.7 released --- + +5501. [func] Log CDS/CDNSKEY publication. [GL #1748] + +5500. [bug] Fix (non-)publication of CDS and CDNSKEY records. + [GL #2103] + +5499. [func] Add '-P ds' and '-D ds' arguments to dnssec-settime. + [GL #1748] + +5497. [bug] 'dig +bufsize=0' failed to disable EDNS. [GL #2054] + +5496. [bug] Address a TSAN report by ensuring each rate limiter + object holds a reference to its task. [GL #2081] + +5495. [bug] With query minimization enabled, named failed to + resolve ip6.arpa. names that had extra labels to the + left of the IPv6 part. [GL #1847] + +5494. [bug] Silence the EPROTO syslog message on older systems. + [GL #1928] + +5493. [bug] Fix off-by-one error when calculating new hash table + size. [GL #2104] + +5492. [bug] Tighten LOC parsing to reject a period (".") and/or "m" + as a value. Fix handling of negative altitudes which are + not whole meters. [GL #2074] + +5491. [bug] rbtversion->glue_table_size could be read without the + appropriate lock being held. [GL #2080] + +5489. [bug] Named erroneously accepted certain invalid resource + records that were incorrectly processed after + subsequently being written to disk and loaded back, as + the wire format differed. Such records include: CERT, + IPSECKEY, NSEC3, NSEC3PARAM, NXT, SIG, TLSA, WKS, and + X25. [GL !3953] + +5488. [bug] NTA code needed to have a weak reference on its + associated view to prevent the latter from being deleted + while NTA tests were being performed. [GL #2067] + +5486. [func] Add 'rndc dnssec -checkds' command, which signals to + named that the DS record for a given zone or key has + been updated in the parent zone. [GL #1613] + + --- 9.16.6 released --- + +5484. [func] Expire zero TTL records quickly rather than using them + for stale answers. [GL #1829] + +5483. [func] A new configuration option "stale-cache-enable" has been + introduced to enable or disable keeping stale answers in + cache. [GL #1712] + +5482. [bug] If the Duplicate Address Detection (DAD) mechanism had + not yet finished after adding a new IPv6 address to the + system, BIND 9 would fail to bind to IPv6 addresses in a + tentative state. [GL #2038] + +5481. [security] "update-policy" rules of type "subdomain" were + incorrectly treated as "zonesub" rules, which allowed + keys used in "subdomain" rules to update names outside + of the specified subdomains. The problem was fixed by + making sure "subdomain" rules are again processed as + described in the ARM. (CVE-2020-8624) [GL #2055] + +5480. [security] When BIND 9 was compiled with native PKCS#11 support, it + was possible to trigger an assertion failure in code + determining the number of bits in the PKCS#11 RSA public + key with a specially crafted packet. (CVE-2020-8623) + [GL #2037] + +5479. [security] named could crash in certain query resolution scenarios + where QNAME minimization and forwarding were both + enabled. (CVE-2020-8621) [GL #1997] + +5478. [security] It was possible to trigger an assertion failure by + sending a specially crafted large TCP DNS message. + (CVE-2020-8620) [GL #1996] + +5477. [bug] The idle timeout for connected TCP sockets, which was + previously set to a high fixed value, is now derived + from the client query processing timeout configured for + a resolver. [GL #2024] + +5476. [security] It was possible to trigger an assertion failure when + verifying the response to a TSIG-signed request. + (CVE-2020-8622) [GL #2028] + +5475. [bug] Wildcard RPZ passthru rules could incorrectly be + overridden by other rules that were loaded from RPZ + zones which appeared later in the "response-policy" + statement. This has been fixed. [GL #1619] + +5474. [bug] dns_rdata_hip_next() failed to return ISC_R_NOMORE + when it should have. [GL !3880] + +5473. [func] The RBT hash table implementation has been changed + to use a faster hash function (HalfSipHash2-4) and + Fibonacci hashing for better distribution. Setting + "max-cache-size" now preallocates a fixed-size hash + table so that rehashing does not cause resolution + brownouts while the hash table is grown. [GL #1775] + +5471. [bug] The introduction of KASP support inadvertently caused + the second field of "sig-validity-interval" to always be + calculated in hours, even in cases when it should have + been calculated in days. This has been fixed. (Thanks to + Tony Finch.) [GL !3735] + +5469. [port] On illumos, a constant called SEC is already defined in + , which conflicts with an identically named + constant in libbind9. This conflict has been resolved. + [GL #1993] + +5468. [bug] Addressed potential double unlock in process_fd(). + [GL #2005] + +5466. [bug] Addressed an error in recursive clients stats reporting. + [GL #1719] + +5465. [func] Added fallback to built-in trust-anchors, managed-keys, + or trusted-keys if the bindkeys-file (bind.keys) cannot + be parsed. [GL #1235] + +5464. [bug] Requesting more than 128 files to be saved when rolling + dnstap log files caused a buffer overflow. This has been + fixed. [GL #1989] + +5462. [bug] Move LMDB locking from LMDB itself to named. [GL #1976] + +5461. [bug] The STALE rdataset header attribute was updated while + the write lock was not being held, leading to incorrect + statistics. The header attributes are now converted to + use atomic operations. [GL #1475] + + --- 9.16.5 released --- + +5458. [bug] Prevent a theoretically possible NULL dereference caused + by a data race between zone_maintenance() and + dns_zone_setview_helper(). [GL #1627] + +5455. [bug] named could crash when cleaning dead nodes in + lib/dns/rbtdb.c that were being reused. [GL #1968] + +5454. [bug] Address a startup crash that occurred when the server + was under load and the root zone had not yet been + loaded. [GL #1862] + +5453. [bug] named crashed on shutdown when a new rndc connection was + received during shutdown. [GL #1747] + +5452. [bug] The "blackhole" ACL was accidentally disabled for client + queries. [GL #1936] + +5451. [func] Add 'rndc dnssec -status' command. [GL #1612] + +5449. [bug] Fix a socket shutdown race in netmgr udp. [GL #1938] + +5448. [bug] Fix a race condition in isc__nm_tcpdns_send(). + [GL #1937] + +5447. [bug] IPv6 addresses ending in "::" could break YAML + parsing. A "0" is now appended to such addresses + in YAML output from dig, mdig, delv, and dnstap-read. + [GL #1952] + +5446. [bug] The validator could fail to accept a properly signed + RRset if an unsupported algorithm appeared earlier in + the DNSKEY RRset than a supported algorithm. It could + also stop if it detected a malformed public key. + [GL #1689] + +5444. [bug] 'rndc dnstap -roll ' did not limit the number of + saved files to . [GL !3728] + +5443. [bug] The "primary" and "secondary" keywords, when used + as parameters for "check-names", were not + processed correctly and were being ignored. [GL #1949] + +5441. [bug] ${LMDB_CFLAGS} was missing from make/includes.in. + [GL #1955] + +5440. [test] Properly handle missing kyua. [GL #1950] + +5439. [bug] The DS RRset returned by dns_keynode_dsset() was used in + a non-thread-safe manner. [GL #1926] + + --- 9.16.4 released --- + +5438. [bug] Fix a race in TCP accepting code. [GL #1930] + +5437. [bug] Fix a data race in lib/dns/resolver.c:log_formerr(). + [GL #1808] + +5436. [security] It was possible to trigger an INSIST when determining + whether a record would fit into a TCP message buffer. + (CVE-2020-8618) [GL #1850] + +5435. [tests] Add RFC 4592 responses examples to the wildcard system + test. [GL #1718] + +5434. [security] It was possible to trigger an INSIST in + lib/dns/rbtdb.c:new_reference() with a particular zone + content and query patterns. (CVE-2020-8619) [GL #1111] + [GL #1718] + +5431. [func] Reject DS records at the zone apex when loading + master files. Log but otherwise ignore attempts to + add DS records at the zone apex via UPDATE. [GL #1798] + +5430. [doc] Update docs - with netmgr, a separate listening socket + is created for each IPv6 interface (just as with IPv4). + [GL #1782] + +5428. [bug] Clean up GSSAPI resources in nsupdate only after taskmgr + has been destroyed. Thanks to Petr Menšík. [GL !3316] + +5426. [bug] Don't abort() when setting SO_INCOMING_CPU on the socket + fails. [GL #1911] + +5425. [func] The default value of "max-stale-ttl" has been changed + from 1 week to 12 hours. [GL #1877] + +5424. [bug] With KASP, when creating a successor key, the "goal" + state of the current active key (predecessor) was not + changed and thus never removed from the zone. [GL #1846] + +5423. [bug] Fix a bug in keymgr_key_has_successor(): it incorrectly + returned true if any other key in the keyring had a + successor. [GL #1845] + +5422. [bug] When using dnssec-policy, print correct key timing + metadata. [GL #1843] + +5421. [bug] Fix a race that could cause named to crash when looking + up the nodename of an RBT node if the tree was modified. + [GL #1857] + +5420. [bug] Add missing isc_{mutex,conditional}_destroy() calls + that caused a memory leak on FreeBSD. [GL #1893] + +5418. [bug] delv failed to parse deprecated trusted-keys-style + trust anchors. [GL #1860] + +5416. [bug] Fix a lock order inversion in lib/isc/unix/socket.c. + [GL #1859] + +5415. [test] Address race in dnssec system test that led to + test failures. [GL #1852] + +5414. [test] Adjust time allowed for journal truncation to occur + in nsupdate system test to avoid test failure. + [GL #1855] + +5413. [test] Address race in autosign system test that led to + test failures. [GL #1852] + +5412. [bug] 'provide-ixfr no;' failed to return up-to-date responses + when the serial was greater than or equal to the + current serial. [GL #1714] + +5411. [cleanup] TCP accept code has been refactored to use a single + accept() and pass the accepted socket to child threads + for processing. [GL !3320] + +5409. [performance] When looking up NSEC3 data in a zone database, skip the + check for empty non-terminal nodes; the NSEC3 tree does + not have any. [GL #1834] + +5408. [protocol] Print Extended DNS Errors if present in OPT record. + [GL #1835] + +5407. [func] Zone timers are now exported via statistics channel. + Thanks to Paul Frieden, Verizon Media. [GL #1232] + +5405. [bug] 'named-checkconf -p' could include spurious text in + server-addresses statements due to an uninitialized DSCP + value. [GL #1812] + + --- 9.16.3 released --- + +5404. [bug] 'named-checkconf -z' could incorrectly indicate + success if errors were found in one view but not in a + subsequent one. [GL #1807] + +5403. [func] Do not set UDP receive/send buffer sizes - use system + defaults. [GL #1713] + +5402. [bug] On FreeBSD, use SO_REUSEPORT_LB instead of SO_REUSEPORT. + Enable use of SO_REUSEADDR on all platforms which + support it. [GL !3365] + +5401. [bug] The number of input queues allocated during dnstap + initialization was too low, which could prevent some + dnstap data from being logged. [GL #1795] + +5400. [func] Add engine support to OpenSSL EdDSA implementation. + [GL #1763] + +5399. [func] Add engine support to OpenSSL ECDSA implementation. + [GL #1534] + +5398. [bug] Named could fail to restart if a zone with a double + quote (") in its name was added with 'rndc addzone'. + [GL #1695] + +5397. [func] Update PKCS#11 EdDSA implementation to PKCS#11 v3.0. + Thanks to Aaron Thompson. [GL !3326] + +5396. [func] When necessary (i.e. in libuv >= 1.37), use the + UV_UDP_RECVMMSG flag to enable recvmmsg() support in + libuv. [GL #1797] + +5395. [security] Further limit the number of queries that can be + triggered from a request. Root and TLD servers + are no longer exempt from max-recursion-queries. + Fetches for missing name server address records + are limited to 4 for any domain. (CVE-2020-8616) + [GL #1388] + +5394. [cleanup] Named formerly attempted to change the effective UID and + GID in named_os_openfile(), which could trigger a + spurious log message if they were already set to the + desired values. This has been fixed. [GL #1042] + [GL #1090] + +5392. [bug] It was possible for named to crash during shutdown + or reconfiguration if an RPZ zone was still being + updated. [GL #1779] + +5390. [security] Replaying a TSIG BADTIME response as a request could + trigger an assertion failure. (CVE-2020-8617) + [GL #1703] + +5389. [bug] Finish PKCS#11 code cleanup, fix a couple of smaller + bugs and use PKCS#11 v3.0 EdDSA macros and constants. + Thanks to Aaron Thompson. [GL !3391] + +5387. [func] Warn about AXFR streams with inconsistent message IDs. + [GL #1674] + +5386. [cleanup] Address Coverity warnings in lib/dns/keymgr.c. + [GL #1737] + +5385. [func] Make ISC rwlock implementation the default again. + [GL #1753] + +5384. [bug] With "dnssec-policy" in effect, "inline-signing" was + implicitly set to "yes". Now "inline-signing" is only + set to "yes" if the zone is not dynamic. [GL #1709] + + --- 9.16.2 released --- + +5383. [func] Add a quota attach function with a callback and clean up + the isc_quota API. [GL !3280] + +5382. [bug] Use clock_gettime() instead of gettimeofday() for + isc_stdtime() function. [GL #1679] + +5381. [bug] Fix logging API data race by adding rwlock and caching + logging levels in stdatomic variables to restore + performance to original levels. [GL #1675] [GL #1717] + +5380. [contrib] Fix building MySQL DLZ modules against MySQL 8 + libraries. [GL #1678] + +5378. [bug] Receiving invalid DNS data was triggering an assertion + failure in nslookup. [GL #1652] + +5376. [bug] Fix ineffective DNS rebinding protection when BIND is + configured as a forwarding DNS server. Thanks to Tobias + Klein. [GL #1574] + +5375. [test] Fix timing issues in the "kasp" system test. [GL #1669] + +5374. [bug] Statistics counters tracking recursive clients and + active connections could underflow. [GL #1087] + +5373. [bug] Collecting statistics for DNSSEC signing operations + (change 5254) caused an array of significant size (over + 100 kB) to be allocated for each configured zone. Each + of these arrays is tracking all possible key IDs; this + could trigger an out-of-memory condition on servers with + a high enough number of zones configured. Fixed by + tracking up to four keys per zone and rotating counters + when keys are replaced. This fixes the immediate problem + of high memory usage, but should be improved in a future + release by growing or shrinking the number of keys to + track upon key rollover events. [GL #1179] + +5372. [bug] Fix migration from existing DNSSEC key files + ("auto-dnssec maintain") to "dnssec-policy". [GL #1706] + +5371. [bug] Improve incremental updates of the RPZ summary + database to reduce delays that could occur when + a policy zone update included a large number of + record deletions. [GL #1447] + +5370. [bug] Deactivation of a netmgr handle associated with a + socket could be skipped in some circumstances. + Fixed by deactivating the netmgr handle before + scheduling the asynchronous close routine. [GL #1700] + +5368. [bug] Named failed to restart if 'rndc addzone' names + contained special characters (e.g. '/'). [GL #1655] + +5367. [bug] Fixed a flaw in the calculation of the zone database + size so that "max-journal-size default" uses the correct + limit. [GL #1661] + + --- 9.16.1 released --- + +5366. [bug] Fix a race condition with the keymgr when the same + zone plus dnssec-policy is configured in multiple + views. [GL #1653] + +5365. [bug] Algorithm rollover was stuck on submitting DS + because keymgr thought it would move to an invalid + state. Fixed by checking the current key against + the desired state, not the existing state. [GL #1626] + +5364. [bug] Algorithm rollover waited too long before introducing + zone signatures. It waited to make sure all signatures + were regenerated, but when introducing a new algorithm, + all signatures are regenerated immediately. Only + add the sign delay if there is a predecessor key. + [GL #1625] + +5363. [bug] When changing a dnssec-policy, existing keys with + properties that no longer match were not being retired. + [GL #1624] + +5361. [bug] named might not accept new connections after + hitting tcp-clients quota. [GL #1643] + +5360. [bug] delv could fail to load trust anchors in DNSKEY + format. [GL #1647] + +5358. [bug] Inline master zones whose master files were touched + but otherwise unchanged and were subsequently reloaded + may have stopped re-signing. [GL !3135] + +5357. [bug] Newly added RRSIG records with expiry times before + the previous earliest expiry times might not be + re-signed in time. This was a side effect of 5315. + [GL !3137] + + --- 9.16.0 released --- + +5356. [func] Update dnssec-policy configuration statements: + - Rename "zone-max-ttl" dnssec-policy option to + "max-zone-ttl" for consistency with the existing + zone option. + - Allow for "lifetime unlimited" as a synonym for + "lifetime PT0S". + - Make "key-directory" optional. + - Warn if specifying a key length does not make + sense; fail if key length is out of range for + the algorithm. + - Allow use of mnemonics when specifying key + algorithm (e.g. "rsasha256", "ecdsa384", etc.). + - Make ISO 8601 durations case-insensitive. + [GL #1598] + +5355. [func] What was set with --with-tuning=large option in + older BIND9 versions is now a default, and + a --with-tuning=small option was added for small + (e.g. OpenWRT) systems. [GL !2989] + +5354. [bug] dnssec-policy created new KSK keys for zones in the + initial stage of signing (with the DS not yet in the + rumoured or omnipresent states). Fix by checking the + key goals rather than the active state when determining + whether new keys are needed. [GL #1593] + +5353. [doc] Document port and dscp parameters in forwarders + configuration option. [GL #914] + +5352. [bug] Correctly handle catalog zone entries containing + characters that aren't legal in filenames. [GL #1592] + +5351. [bug] CDS / CDNSKEY consistency checks failed to handle + removal records. [GL #1554] + +5350. [bug] When a view was configured with class CHAOS, the + server could crash while processing a query for a + non-existent record. [GL #1540] + +5349. [bug] Fix a race in task_pause/unpause. [GL #1571] + +5348. [bug] dnssec-settime -Psync was not being honoured. + [GL !2925] + + --- 9.15.8 released --- + +5347. [bug] Fixed a bug that could cause an intermittent crash + in validator.c when validating a negative cache + entry. [GL #1561] + +5346. [bug] Make hazard pointer array allocations dynamic, fixing + a bug that caused named to crash on machines with more + than 40 cores. [GL #1493] + +5345. [func] Key-style trust anchors and DS-style trust anchors + can now both be used for the same name. [GL #1237] + +5344. [bug] Handle accept() errors properly in netmgr. [GL !2880] + +5343. [func] Add statistics counters to the netmgr. [GL #1311] + +5342. [bug] Disable pktinfo for IPv6 and bind to each interface + explicitly instead, because libuv doesn't support + pktinfo control messages. [GL #1558] + +5341. [func] Simplify passing the bound TCP socket to child + threads by using isc_uv_export/import functions. + [GL !2825] + +5340. [bug] Don't deadlock when binding to a TCP socket fails. + [GL #1499] + +5339. [bug] With some libmaxminddb versions, named could erroneously + match an IP address not belonging to any subnet defined + in a given GeoIP2 database to one of the existing + entries in that database. [GL #1552] + +5338. [bug] Fix line spacing in `rndc secroots`. + Thanks to Tony Finch. [GL !2478] + +5337. [func] 'named -V' now reports maxminddb and protobuf-c + versions. [GL !2686] + + --- 9.15.7 released --- + +5336. [bug] The TCP high-water statistic could report an + incorrect value on startup. [GL #1392] + +5335. [func] Make TCP listening code multithreaded. [GL !2659] + +5334. [doc] Update documentation with dnssec-policy clarifications. + Also change some defaults. [GL !2711] + +5333. [bug] Fix duration printing on Solaris when value is not + an ISO 8601 duration. [GL #1460] + +5332. [func] Renamed "dnssec-keys" configuration statement + to the more descriptive "trust-anchors". [GL !2702] + +5331. [func] Use compiler-provided mechanisms for thread local + storage, and make the requirement for such mechanisms + explicit in configure. [GL #1444] + +5330. [bug] 'configure --without-python' was ineffective if + PYTHON was set in the environment. [GL #1434] + +5329. [bug] Reconfiguring named caused memory to be leaked when any + GeoIP2 database was in use. [GL #1445] + +5328. [bug] rbtdb.c:rdataset_{get,set}ownercase failed to obtain + a node lock. [GL #1417] + +5327. [func] Added a statistics counter to track queries + dropped because the recursive-clients quota was + exceeded. [GL #1399] + +5326. [bug] Add Python dependency on 'distutils.core' to configure. + 'distutils.core' is required for installation. + [GL #1397] + +5325. [bug] Addressed several issues with TCP connections in + the netmgr: restored support for TCP connection + timeouts, restored TCP backlog support, actively + close all open sockets during shutdown. [GL #1312] + +5324. [bug] Change the category of some log messages from general + to the more appropriate catergory of xfer-in. [GL #1394] + +5323. [bug] Fix a bug in DNSSEC trust anchor verification. + [GL !2609] + +5322. [placeholder] + +5321. [bug] Obtain write lock before updating version->records + and version->bytes. [GL #1341] + +5320. [cleanup] Silence TSAN on header->count. [GL #1344] + + --- 9.15.6 released --- + +5319. [func] Trust anchors can now be configured using DS + format to represent a key digest, by using the + new "initial-ds" or "static-ds" keywords in + the "dnssec-keys" statement. + + Note: DNSKEY-format and DS-format trust anchors + cannot both be used for the same domain name. + [GL #622] + +5318. [cleanup] The DNSSEC validation code has been refactored + for clarity and to reduce code duplication. + [GL #622] + +5317. [func] A new asynchronous network communications system + based on libuv is now used for listening for + incoming requests and responding to them. (The + old isc_socket API remains in use for sending + iterative queries and processing responses; this + will be changed too in a later release.) + + This change will make it easier to improve + performance and implement new protocol layers + (e.g., DNS over TLS) in the future. [GL #29] + +5316. [func] A new "dnssec-policy" option has been added to + named.conf to implement a key and signing policy + (KASP) for zones. When this option is in use, + named can generate new keys as needed and + automatically roll both ZSK and KSK keys. (Note + that the syntax for this statement differs from + the dnssec policy used by dnssec-keymgr.) + + See the ARM for configuration details. [GL #1134] + +5315. [bug] Apply the initial RRSIG expiration spread fixed + to all dynamically created records in the zone + including NSEC3. Also fix the signature clusters + when the server has been offline for prolonged + period of times. [GL #1256] + +5314. [func] Added a new statistics variable "tcp-highwater" + that reports the maximum number of simultaneous TCP + clients BIND has handled while running. [GL #1206] + +5313. [bug] The default GeoIP2 database location did not match + the ARM. 'named -V' now reports the default + location. [GL #1301] + +5312. [bug] Do not flush the cache for `rndc validation status`. + Thanks to Tony Finch. [GL !2462] + +5311. [cleanup] Include all views in output of `rndc validation status`. + Thanks to Tony Finch. [GL !2461] + +5310. [bug] TCP failures were affecting EDNS statistics. [GL #1059] + +5309. [placeholder] + +5308. [bug] Don't log DNS_R_UNCHANGED from sync_secure_journal() + at ERROR level in receive_secure_serial(). [GL #1288] + +5307. [bug] Fix hang when named-compilezone output is sent to pipe. + Thanks to Tony Finch. [GL !2481] + +5306. [security] Set a limit on number of simultaneous pipelined TCP + queries. (CVE-2019-6477) [GL #1264] + +5305. [bug] NSEC Aggressive Cache ("synth-from-dnssec") has been + disabled by default because it was found to have + a significant performance impact on the recursive + service. [GL #1265] + +5304. [bug] "dnskey-sig-validity 0;" was not being accepted. + [GL #876] + +5303. [placeholder] + +5302. [bug] Fix checking that "dnstap-output" is defined when + "dnstap" is specified in a view. [GL #1281] + +5301. [bug] Detect partial prefixes / incomplete IPv4 address in + acls. [GL #1143] + +5300. [bug] dig/mdig/delv: Add a colon after EDNS option names, + even when the option is empty, to improve + readability and allow correct parsing of YAML + output. [GL #1226] + + --- 9.15.5 released --- + +5299. [security] A flaw in DNSSEC verification when transferring + mirror zones could allow data to be incorrectly + marked valid. (CVE-2019-6475) [GL #1252] + +5298. [security] Named could assert if a forwarder returned a + referral, rather than resolving the query, when QNAME + minimization was enabled. (CVE-2019-6476) [GL #1051] + +5297. [bug] Check whether a previous QNAME minimization fetch + is still running before starting a new one; return + SERVFAIL and log an error if so. [GL #1191] + +5296. [placeholder] + +5295. [cleanup] Split dns_name_copy() calls into dns_name_copy() and + dns_name_copynf() for those calls that can potentially + fail and those that should not fail respectively. + [GL !2265] + +5294. [func] Fallback to ACE name on output in locale, which does not + support converting it to unicode. [GL #846] + +5293. [bug] On Windows, named crashed upon any attempt to fetch XML + statistics from it. [GL #1245] + +5292. [bug] Queue 'rndc nsec3param' requests while signing inline + zone changes. [GL #1205] + + --- 9.15.4 released --- + +5291. [placeholder] + +5290. [placeholder] + +5289. [bug] Address NULL pointer dereference in rpz.c:rpz_detach. + [GL #1210] + +5288. [bug] dnssec-must-be-secure was not always honored. + [GL #1209] + +5287. [placeholder] + +5286. [contrib] Address potential NULL pointer dereferences in + dlz_mysqldyn_mod.c. [GL #1207] + +5285. [port] win32: implement "-T maxudpXXX". [GL #837] + +5284. [func] Added +unexpected command line option to dig. + By default, dig won't accept a reply from a source + other than the one to which it sent the query. + Invoking dig with +unexpected argument will allow it + to process replies from unexpected sources. + +5283. [bug] When a response-policy zone expires, ensure that + its policies are removed from the RPZ summary + database. [GL #1146] + +5282. [bug] Fixed a bug in searching for possible wildcard matches + for query names in the RPZ summary database. [GL #1146] + +5281. [cleanup] Don't escape commas when reporting named's command + line. [GL #1189] + +5280. [protocol] Add support for displaying EDNS option LLQ. [GL #1201] + +5279. [bug] When loading, reject zones containing CDS or CDNSKEY + RRsets at the zone apex if they would cause DNSSEC + validation failures if published in the parent zone + as the DS RRset. [GL #1187] + +5278. [func] Add YAML output formats for dig, mdig and delv; + use the "+yaml" option to enable. [GL #1145] + + --- 9.15.3 released --- + +5277. [bug] Cache DB statistics could underflow when serve-stale + was in use, because of a bug in counter maintenance + when RRsets become stale. + + Functions for dumping statistics have been updated + to dump active, stale, and ancient statistic + counters. Ancient RRset counters are prefixed + with '~'; stale RRset counters are still prefixed + with '#'. [GL #602] + +5276. [func] DNSSEC Lookaside Validation (DLV) is now obsolete; + all code enabling its use has been removed from the + validator, "delv", and the DNSSEC tools. [GL #7] + +5275. [bug] Mark DS records included in referral messages + with trust level "pending" so that they can be + validated and cached immediately, with no need to + re-query. [GL #964] + +5274. [bug] Address potential use after free race when shutting + down rpz. [GL #1175] + +5273. [bug] Check that bits [64..71] of a dns64 prefix are zero. + [GL #1159] + +5272. [cleanup] Remove isc-config.sh script as the BIND 9 libraries + are now purely internal. [GL #1123] + +5271. [func] The normal (non-debugging) output of dnssec-signzone + and dnssec-verify tools now goes to stdout, instead of + the combination of stderr and stdout. + +5270. [bug] 'dig +expandaaaa +short' did not work. [GL #1152] + +5269. [port] cygwin: can return ETIMEDOUT on connect() with a + non-blocking socket. [GL #1133] + +5268. [placeholder] + +5267. [func] Allow statistics groups display to be toggle-able. + [GL #1030] + +5266. [bug] named-checkconf failed to report dnstap-output + missing from named.conf when dnstap was specified. + [GL #1136] + +5265. [bug] DNS64 and RPZ nodata (CNAME *.) rules interacted badly + [GL #1106] + +5264. [func] New DNS Cookie algorithm - siphash24 - has been added + to BIND 9, and the old HMAC-SHA DNS Cookie algorithms + have been removed. [GL #605] + + --- 9.15.2 released --- + +5263. [cleanup] Use atomics and isc_refcount_t wherever possible. + [GL #1038] + +5262. [func] Removed support for the legacy GeoIP API. [GL #1112] + +5261. [cleanup] Remove SO_BSDCOMPAT socket option usage. + +5260. [bug] dnstap-read was producing malformed output for large + packets. [GL #1093] + +5259. [func] New option '-i' for 'named-checkconf' to ignore + warnings about deprecated options. [GL #1101] + +5258. [func] Added support for the GeoIP2 API from MaxMind. This + will be compiled in by default if the "libmaxminddb" + library is found at compile time, but can be + suppressed using "configure --disable-geoip". + + Certain geoip ACL settings that were available with + legacy GeoIP are not available when using GeoIP2. + [GL #182] + +5257. [bug] Some statistics data was not being displayed. + Add shading to the zone tables. [GL #1030] + +5256. [bug] Ensure that glue records are included in root + priming responses if "minimal-responses" is not + set to "yes". [GL #1092] + +5255. [bug] Errors encountered while reloading inline-signing + zones could be ignored, causing the zone content to + be left in an incompletely updated state rather than + reverted. [GL #1109] + +5254. [func] Collect metrics to report to the statistics-channel + DNSSEC signing operations (dnssec-sign) and refresh + operations (dnssec-refresh) per zone and per keytag. + [GL #513] + +5253. [port] Support platforms that don't define ULLONG_MAX. + [GL #1098] + +5252. [func] Report if the last 'rndc reload/reconfig' failed in + rndc status. [GL !2040] + +5251. [bug] Statistics were broken in x86 Windows builds. + [GL #1081] + +5250. [func] The default size for RSA keys is now 2048 bits, + for both ZSKs and KSKs. [GL #1097] + +5249. [bug] Fix a possible underflow in recursion clients + statistics when hitting recursive clients + soft quota. [GL #1067] + + --- 9.15.1 released --- + +5248. [func] To clarify the configuration of DNSSEC keys, + the "managed-keys" and "trusted-keys" options + have both been deprecated. The new "dnssec-keys" + statement can now be used for all trust anchors, + with the keywords "iniital-key" or "static-key" + to indicate whether the configured trust anchor + should be used for initialization of RFC 5011 key + management, or as a permanent trust anchor. + + The "static-key" keyword will generate a warning if + used for the root zone. + + Configurations using "trusted-keys" or "managed-keys" + will continue to work with no changes, but will + generate warnings in the log. In a future release, + these options will be marked obsolete. [GL #6] + +5247. [cleanup] The 'cleaning-interval' option has been removed. + [GL !1731] + +5246. [func] Log TSIG if appropriate in 'sending notify to' message. + [GL #1058] + +5245. [cleanup] Reduce logging level for IXFR up-to-date poll + responses. [GL #1009] + +5244. [security] Fixed a race condition in dns_dispatch_getnext() + that could cause an assertion failure if a + significant number of incoming packets were + rejected. (CVE-2019-6471) [GL #942] + +5243. [bug] Fix a possible race between dispatcher and socket + code in a high-load cold-cache resolver scenario. + [GL #943] + +5242. [bug] In relaxed qname minimization mode, fall back to + normal resolution when encountering a lame + delegation, and use _.domain/A queries rather + than domain/NS. [GL #1055] + +5241. [bug] Fix Ed448 private and public key ASN.1 prefix blobs. + [GL #225] + +5240. [bug] Remove key id calculation for RSAMD5. [GL #996] + +5239. [func] Change the json-c detection to pkg-config. [GL #855] + +5238. [bug] Fix a possible deadlock in TCP code. [GL #1046] + +5237. [bug] Recurse to find the root server list with 'dig +trace'. + [GL #1028] + +5236. [func] Add SipHash 2-4 implementation in lib/isc/siphash.c + and switch isc_hash_function() to use SipHash 2-4. + [GL #605] + +5235. [cleanup] Refactor lib/isc/app.c to be thread-safe, unused + parts of the API has been removed and the + isc_appctx_t data type has been changed to be + fully opaque. [GL #1023] + +5234. [port] arm: just use the compiler's default support for + yield. [GL #981] + + --- 9.15.0 released --- + +5233. [bug] Negative trust anchors did not work with "forward only;" + to validating resolvers. [GL #997] + +5232. [placeholder] + +5231. [protocol] Add support for displaying CLIENT-TAG and SERVER-TAG. + [GL #960] + +5230. [protocol] The SHA-1 hash algorithm is no longer used when + generating DS and CDS records. [GL #1015] + +5229. [protocol] Enforce known SSHFP fingerprint lengths. [GL #852] + +5228. [func] If trusted-keys and managed-keys were configured + simultaneously for the same name, the key could + not be be rolled automatically. This is now + a fatal configuration error. [GL #868] + +5227. [placeholder] + +5226. [placeholder] + +5225. [func] Allow dig to print out AAAA record fully expanded. + with +[no]expandaaaa. [GL #765] + +5224. [bug] Only test provide-ixfr on TCP streams. [GL #991] + +5223. [bug] Fixed a race in the filter-aaaa plugin accessing + the hash table. [GL #1005] + +5222. [bug] 'delv -t ANY' could leak memory. [GL #983] + +5221. [test] Enable parallel execution of system tests on + Windows. [GL !4101] + +5220. [cleanup] Refactor the isc_stat structure to take advantage + of stdatomic. [GL !1493] + +5219. [bug] Fixed a race in the filter-aaaa plugin that could + trigger a crash when returning an instance object + to the memory pool. [GL #982] + +5218. [bug] Conditionally include . [GL #995] + +5217. [bug] Restore key id calculation for RSAMD5. [GL #996] + +5216. [bug] Fetches-per-zone counter wasn't updated correctly + when doing qname minimization. [GL #992] + +5215. [bug] Change #5124 was incomplete; named could still + return FORMERR instead of SERVFAIL in some cases. + [GL #990] + +5214. [bug] win32: named now removes its lock file upon shutdown. + [GL #979] + +5213. [bug] win32: Eliminated a race which allowed named.exe running + as a service to be killed prematurely during shutdown. + [GL #978] + +5212. [placeholder] + +5211. [bug] Allow out-of-zone additional data to be included + in authoritative responses if recursion is allowed + and "minimal-responses" is disabled. This behavior + was inadvertently removed in change #4605. [GL #817] + +5210. [bug] When dnstap is enabled and recursion is not + available, incoming queries are now logged + as "auth". Previously, this depended on whether + recursion was requested by the client, not on + whether recursion was available. [GL #963] + +5209. [bug] When update-check-ksk is true, add_sigs was not + considering offline keys, leaving record sets signed + with the incorrect type key. [GL #763] + +5208. [test] Run valid rdata wire encodings through totext+fromtext + and tofmttext+fromtext methods to check these methods. + [GL #899] + +5207. [test] Check delv and dig TTL values. [GL #965] + +5206. [bug] Delv could print out bad TTLs. [GL #965] + +5205. [bug] Enforce that a DS hash exists. [GL #899] + +5204. [test] Check that dns_rdata_fromtext() produces a record that + will be accepted by dns_rdata_fromwire(). [GL #852] + +5203. [bug] Enforce whether key rdata exists or not in KEY, + DNSKEY, CDNSKEY and RKEY. [GL #899] + +5202. [bug] was missing ISC_LANG_ENDDECLS. [GL #976] + +5201. [bug] Fix a possible deadlock in RPZ update code. [GL #973] + +5200. [security] tcp-clients settings could be exceeded in some cases, + which could lead to exhaustion of file descriptors. + (CVE-2018-5743) [GL #615] + +5199. [security] In certain configurations, named could crash + if nxdomain-redirect was in use and a redirected + query resulted in an NXDOMAIN from the cache. + (CVE-2019-6467) [GL #880] + +5198. [bug] If a fetch context was being shut down and, at the same + time, we returned from qname minimization, an INSIST + could be hit. [GL #966] + +5197. [bug] dig could die in best effort mode on multiple SIG(0) + records. Similarly on multiple OPT and multiple TSIG + records. [GL #920] + +5196. [bug] make install failed with --with-dlopen=no. [GL #955] + +5195. [bug] "allow-update" and "allow-update-forwarding" were + treated as configuration errors if used at the + options or view level. [GL #913] + +5194. [bug] Enforce non empty ZOMEMD hash. [GL #899] + +5193. [bug] EID and NIMLOC failed to do multi-line output + correctly. [GL #899] + +5192. [placeholder] + +5191. [placeholder] + +5190. [bug] Ignore trust anchors using disabled algorithms. + [GL #806] + +5189. [cleanup] Remove revoked root DNSKEY from bind.keys. [GL #945] + +5188. [func] The "dnssec-enable" option is deprecated and no + longer has any effect; DNSSEC responses are + always enabled. [GL #866] + +5187. [test] Set time zone before running any tests in dnstap_test. + [GL #940] + +5186. [cleanup] More dnssec-keygen manual tidying. [GL !1678] + +5185. [placeholder] + +5184. [bug] Missing unlocks in sdlz.c. [GL #936] + +5183. [bug] Reinitialize ECS data before reusing client + structures. [GL #881] + +5182. [bug] Fix a high-load race/crash in handling of + isc_socket_close() in resolver. [GL #834] + +5181. [func] Add a mechanism for a DLZ module to signal that + the view's allow-transfer ACL should be used to + determine whether transfers are allowed. [GL #803] + +5180. [bug] delv now honors the operating system's preferred + ephemeral port range. [GL #925] + +5179. [cleanup] Replace some vague type declarations with the more + specific dns_secalg_t and dns_dsdigest_t. + Thanks to Tony Finch. [GL !1498] + +5178. [bug] Handle EDQUOT (disk quota) and ENOSPC (disk full) + errors when writing files. [GL #902] + +5177. [func] Add the ability to specify in named.conf whether a + response-policy zone's SOA record should be added + to the additional section (add-soa yes/no). [GL #865] + +5176. [tests] Remove a dependency on libxml in statschannel system + test. [GL #926] + +5175. [bug] Fixed a problem with file input in dnssec-keymgr, + dnssec-coverage and dnssec-checkds when using + python3. [GL #882] + +5174. [doc] Tidy dnssec-keygen manual. [GL !1557] + +5173. [bug] Fixed a race in socket code that could occur when + accept, send, or recv were called from an event + loop but the socket had been closed by another + thread. [RT #874] + +5172. [bug] nsupdate now honors the operating system's preferred + ephemeral port range. [GL #905] + +5171. [func] named plugins are now installed into a separate + directory. Supplying a filename (a string without path + separators) in a "plugin" configuration stanza now + causes named to look for that plugin in that directory. + [GL #878] + +5170. [test] Added --with-dlz-filesystem to feature-test. [GL !1587] + +5169. [bug] The presence of certain types in an otherwise + empty node could cause a crash while processing a + type ANY query. [GL #901] + +5168. [bug] Do not crash on shutdown when RPZ fails to load. Also, + keep previous version of the database if RPZ fails to + load. [GL #813] + +5167. [bug] nxdomain-redirect could sometimes lookup the wrong + redirect name. [GL #892] + +5166. [placeholder] + +5165. [contrib] Removed SDB drivers from contrib; they're obsolete. + [GL #428] + +5164. [bug] Correct errno to result translation in dlz filesystem + modules. [GL #884] + +5163. [cleanup] Out-of-tree builds failed --enable-dnstap. [GL #836] + +5162. [cleanup] Improve dnssec-keymgr manual. Thanks to Tony Finch. + [GL !1518] + +5161. [bug] Do not require the SEP bit to be set for mirror zone + trust anchors. [GL #873] + +5160. [contrib] Added DNAME support to the DLZ LDAP schema. Also + fixed a compilation bug affecting several DLZ + modules. [GL #872] + +5159. [bug] dnssec-coverage was incorrectly ignoring + names specified on the command line without + trailing dots. [GL !1478] + +5158. [protocol] Add support for AMTRELAY and ZONEMD. [GL #867] + +5157. [bug] Nslookup now errors out if there are extra command + line arguments. [GL #207] + +5156. [doc] Extended and refined the section of the ARM describing + mirror zones. [GL #774] + +5155. [func] "named -V" now outputs the default paths to + named.conf, rndc.conf, bind.keys, and other + files used or created by named and other tools, so + that the correct paths to these files can quickly be + determined regardless of the configure settings + used when BIND was built. [GL #859] + +5154. [bug] dig: process_opt could be called twice on the same + message leading to a assertion failure. [GL #860] + +5153. [func] Zone transfer statistics (size, number of records, and + number of messages) are now logged for outgoing + transfers as well as incoming ones. [GL #513] + +5152. [func] Improved logging of DNSSEC key events: + - Zone signing and DNSKEY maintenance events are + now logged to the "dnssec" category + - Messages are now logged when DNSSEC keys are + published, activated, inactivated, deleted, + or revoked. + [GL #714] + +5151. [func] Options that have been been marked as obsolete in + named.conf for a very long time are now fatal + configuration errors. [GL #358] + +5150. [cleanup] Remove the ability to compile BIND with assertions + disabled. [GL #735] + +5149. [func] "rndc dumpdb" now prints a line above a stale RRset + indicating how long the data will be retained in the + cache for emergency use. [GL #101] + +5148. [bug] named did not sign the TKEY response. [GL #821] + +5147. [bug] dnssec-keymgr: Add a five-minute margin to better + handle key events close to 'now'. [GL #848] + +5146. [placeholder] + +5145. [func] Use atomics instead of locked variables for isc_quota + and isc_counter. [GL !1389] + +5144. [bug] dig now returns a non-zero exit code when a TCP + connection is prematurely closed by a peer more than + once for the same lookup. [GL #820] + +5143. [bug] dnssec-keymgr and dnssec-coverage failed to find + key files for zone names ending in ".". [GL #560] + +5142. [cleanup] Removed "configure --disable-rpz-nsip" and + "--disable-rpz-nsdname" options. "nsip-enable" + and "nsdname-enable" both now default to yes, + regardless of compile-time settings. [GL #824] + +5141. [security] Zone transfer controls for writable DLZ zones were + not effective as the allowzonexfr method was not being + called for such zones. (CVE-2019-6465) [GL #790] + +5140. [bug] Don't immediately mark existing keys as inactive and + deleted when running dnssec-keymgr for the first + time. [GL #117] + +5139. [bug] If possible, don't use forwarders when priming. + This ensures we can get root server IP addresses + from priming query response glue, which may not + be present if the forwarding server is returning + minimal responses. [GL #752] + +5138. [bug] Under some circumstances named could hit an assertion + failure when doing qname minimization when using + forwarders. [GL #797] + +5137. [func] named now logs messages whenever a mirror zone becomes + usable or unusable for resolution purposes. [GL #818] + +5136. [cleanup] Check in named-checkconf that allow-update and + allow-update-forwarding are not set at the + view/options level; fix documentation. [GL #512] + +5135. [port] sparc: Use smt_pause() instead of pause. [GL #816] + +5134. [bug] win32: WSAStartup was not called before getservbyname + was called. [GL #590] + +5133. [bug] 'rndc managed-keys' didn't handle class and view + correctly and failed to add new lines between each + view. [GL !1327] + +5132. [bug] Fix race condition in cleanup part of dns_dt_create(). + [GL !1323] + +5131. [cleanup] Address Coverity warnings. [GL #801] + +5130. [cleanup] Remove support for l10n message catalogs. [GL #709] + +5129. [contrib] sdlz_helper.c:build_querylist was not properly + splitting the query string. [GL #798] + +5128. [bug] Refreshkeytime was not being updated for managed + keys zones. [GL #784] + +5127. [bug] rcode.c:maybe_numeric failed to handle NUL in text + regions. [GL #807] + +5126. [bug] Named incorrectly accepted empty base64 and hex encoded + fields when reading master files. [GL #807] + +5125. [bug] Allow for up to 100 records or 64k of data when caching + a negative response. [GL #804] + +5124. [bug] Named could incorrectly return FORMERR rather than + SERVFAIL. [GL #804] + +5123. [bug] dig could hang indefinitely after encountering an error + before creating a TCP socket. [GL #692] + +5122. [bug] In a "forward first;" configuration, a forwarder + timeout did not prevent that forwarder from being + queried again after falling back to full recursive + resolution. [GL #315] + +5121. [contrib] dlz_stub_driver.c fails to return ISC_R_NOTFOUND on none + matching zone names. [GL !1299] + +5120. [placeholder] + +5119. [placeholder] + +5118. [security] Named could crash if it is managing a key with + `managed-keys` and the authoritative zone is rolling + the key to an unsupported algorithm. (CVE-2018-5745) + [GL #780] + +5117. [placeholder] + +5116. [bug] Named/named-checkconf triggered a assertion when + a mirror zone's name is bad. [GL #778] + +5115. [bug] Allow unsupported algorithms in zone when not used for + signing with dnssec-signzone. [GL #783] + +5114. [func] Include a 'reconfig/reload in progress' status line + in rndc status, use it in tests. + +5113. [port] Fixed a Windows build error. + +5112. [bug] Named/named-checkconf could dump core if there was + a missing masters clause and a bad notify clause. + [GL #779] + +5111. [bug] Occluded DNSKEY records could make it into the + delegating NSEC/NSEC3 bitmap. [GL #742] + +5110. [security] Named leaked memory if there were multiple Key Tag + EDNS options present. (CVE-2018-5744) [GL #772] + +5109. [cleanup] Remove support for RSAMD5 algorithm. [GL #628] + + --- 9.13.5 released --- + +5108. [bug] Named could fail to determine bottom of zone when + removing out of date keys leading to invalid NSEC + and NSEC3 records being added to the zone. [GL #771] + +5107. [bug] 'host -U' did not work. [GL #769] + +5106. [experimental] A new "plugin" mechanism has been added to allow + extension of query processing functionality through + the use of dynamically loadable libraries. A + "filter-aaaa.so" plugin has been implemented, + replacing the filter-aaaa feature that was formerly + implemented as a native part of BIND. + + The "filter-aaaa", "filter-aaaa-on-v4" and + "filter-aaaa-on-v6" options can no longer be + configured using native named.conf syntax. However, + loading the filter-aaaa.so plugin and setting its + parameters provides identical functionality. + + Note that the plugin API is a work in progress and + is likely to evolve as further plugins are + implemented. [GL #15] + +5105. [bug] Fix a race between process_fd and socketclose in + unix socket code. [GL #744] + +5104. [cleanup] Log clearer informational message when a catz zone + is overridden by a zone in named.conf. + Thanks to Tony Finch. [GL !1157] + +5103. [bug] Add missing design by contract tests to dns_catz*. + [GL #748] + +5102. [bug] dnssec-coverage failed to use the default TTL when + checking KSK deletion times leading to a exception. + [GL #585] + +5101. [bug] Fix default installation path for Python modules and + remove the dnspython dependency accidentally introduced + by change 4970. [GL #730] + +5100. [func] Pin resolver tasks to specific task queues. [GL !1117] + +5099. [func] Failed mutex and conditional creations are always + fatal. [GL #674] + + --- 9.13.4 released --- + +5098. [func] Failed memory allocations are now fatal. [GL #674] + +5097. [cleanup] Remove embedded ATF unit testing framework + from BIND source distribution. [GL !875] + +5096. [func] Use multiple event loops in socket code, and + make network threads CPU-affinitive. This + significantly improves performance on large + systems. [GL #666] + +5095. [test] Converted all unit tests from ATF to CMocka; + removed the source code for the ATF libraries. + Build with "configure --with-cmocka" to enable + unit testing. [GL #620] + +5094. [func] Add 'dig -r' to disable reading of .digrc. [GL !970] + +5093. [bug] Log lame qname-minimization servers only if they're + really lame. [GL #671] + +5092. [bug] Address memory leak on SIGTERM in nsupdate when using + GSS-TSIG. [GL #558] + +5091. [func] Two new global and per-view options min-cache-ttl + and min-ncache-ttl [GL #613] + +5090. [bug] dig and mdig failed to properly pre-parse dash value + pairs when value was a separate argument and started + with a dash. [GL #584] + +5089. [bug] Restore localhost fallback in dig and host which is + used when no nameserver addresses present in + /etc/resolv.conf are usable due to the requested + address family restrictions. [GL #433] + +5088. [bug] dig/host/nslookup could crash when interrupted close to + a query timeout. [GL #599] + +5087. [test] Check that result tables are complete. [GL #676] + +5086. [func] Log of RPZ now includes the QTYPE and QCLASS. [GL #623] + +5085. [bug] win32: Restore looking up nameservers, search list, + etc. [GL #186] + +5084. [placeholder] + +5083. [func] Add autoconf macro AX_POSIX_SHELL, so we + can use POSIX-compatible shell features + in the scripts. + +5082. [bug] Fixed a race that could cause a crash in + dig/host/nslookup. [GL #650] + +5081. [func] Use per-worker queues in task manager, make task + runners CPU-affine. [GL #659] + +5080. [func] Improvements to "rndc nta" user interface: + - catch and report invalid command line options + - when removing an NTA from all views, do not + abort with an error if the NTA was not found + in one of the views + - include the view name in "rndc nta -dump" + output, for consistency with the add and remove + actions + Thanks to Tony Finch. [GL !816] + +5079. [func] Disable IDN processing in dig and nslookup + when not on a tty. [GL #653] + +5078. [cleanup] Require python components to be explicitly disabled if + python is not available on unix platforms. [GL #601] + +5077. [cleanup] Remove ip6.int support (-i) from dig and mdig. + [GL !969] + +5076. [bug] "require-server-cookie" was not effective if + "rate-limit" was configured. [GL #617] + +5075. [bug] Refresh nameservers from cache when sending final + query in qname minimization. [GL #16] + +5074. [cleanup] Remove vector socket functions - isc_socket_recvv(), + isc_socket_sendtov(), isc_socket_sendtov2(), + isc_socket_sendv() - in order to simplify socket code. + [GL #645] + +5073. [bug] Destroy a task first when destroying rpzs and catzs. + [GL #84] + +5072. [bug] Add unit tests for isc_buffer_copyregion() and fix its + behavior for auto-reallocated buffers. [GL #644] + +5071. [bug] Comparison of NXT records was broken. [GL #631] + +5070. [bug] Record types which support a empty rdata field were + not handling the empty rdata field case. [GL #638] + +5069. [bug] Fix a hang on in RPZ when named is shutdown during RPZ + zone update. [GL !907] + +5068. [bug] Fix a race in RPZ with min-update-interval set to 0. + [GL #643] + +5067. [bug] Don't minimize qname when sending the query + to a forwarder. [GL #361] + +5066. [cleanup] Allow unquoted strings to be used as a zone names + in response-policy statements. [GL #641] + +5065. [bug] Only set IPV6_USE_MIN_MTU on IPv6. [GL #553] + +5064. [test] Initialize TZ environment variable before calling + dns_test_begin in dnstap_test. [GL #624] + +5063. [test] In statschannel test try a few times before failing + when checking if the compressed output is the same as + uncompressed. [GL !909] + +5062. [func] Use non-crypto-secure PRNG to generate nonces for + cookies. [GL !887] + +5061. [protocol] Add support for EID and NIMLOC. [GL #626] + +5060. [bug] GID, UID and UINFO could not be loaded using unknown + record format. [GL #627] + +5059. [bug] Display a per-view list of zones in the web interface. + [GL #427] + +5058. [func] Replace old message digest and hmac APIs with more + generic isc_md and isc_hmac APIs, and convert their + respective tests to cmocka. [GL #305] + +5057. [protocol] Add support for ATMA. [GL #619] + +5056. [placeholder] + +5055. [func] A default list of primary servers for the root zone is + now built into named, allowing the "masters" statement + to be omitted when configuring an IANA root zone + mirror. [GL #564] + +5054. [func] Attempts to use mirror zones with recursion disabled + are now considered a configuration error. [GL #564] + +5053. [func] The only valid zone-level NOTIFY settings for mirror + zones are now "notify no;" and "notify explicit;". + [GL #564] + +5052. [func] Mirror zones are now configured using "type mirror;" + rather than "mirror yes;". [GL #564] + +5051. [doc] Documentation incorrectly stated that the + "server-addresses" static-stub zone option accepts + custom port numbers. [GL #582] + +5050. [bug] The libirs version of getaddrinfo() was unable to parse + scoped IPv6 addresses present in /etc/resolv.conf. + [GL #187] + +5049. [cleanup] QNAME minimization has been deeply refactored. [GL #16] + +5048. [func] Add configure option to enable and enforce FIPS mode + in BIND 9. [GL #506] + +5047. [bug] Messages logged for certain query processing failures + now include a more specific error description if it is + available. [GL #572] + +5046. [bug] named could crash during shutdown if an RPZ + reload was in progress. [RT #46210] + +5045. [func] Remove support for DNSSEC algorithms 3 (DSA) + and 6 (DSA-NSEC3-SHA1). [GL #22] + +5044. [cleanup] If "dnssec-enable" is no, then "dnssec-validation" + now also defaults to no. [GL #388] + +5043. [bug] Fix creating and validating EdDSA signatures. [GL #579] + +5042. [test] Make the chained delegations in reclimit behave + like they would in a regular name server. [GL #578] + +5041. [test] The chain test contains a incomplete delegation. + [GL #568] + +5040. [func] Extended dnstap so that it can log UPDATE requests + and responses as separate message types. Thanks + to Greg Rabil. [GL #570] + +5039. [bug] Named could fail to preserve owner name case of new + RRset. [GL #420] + +5038. [bug] Chaosnet addresses were compared incorrectly. + [GL #562] + +5037. [func] "allow-recursion-on" and "allow-query-cache-on" + each now default to the other if only one of them + is set, in order to be more consistent with the way + "allow-recursion" and "allow-query-cache" work. + Also we now ensure that both query-cache ACLs are + checked when determining cache access. [GL #319] + +5036. [cleanup] Fixed a spacing/formatting error in some RPZ-related + error messages in the log. [GL !805] + +5035. [test] Fixed errors that prevented the DNSRPS subtests + from running in the rpz and rpzrecurse system + tests. [GL #503] + +5034. [bug] A race between threads could prevent zone maintenance + scheduled immediately after zone load from being + performed. [GL #542] + +5033. [bug] When adding NTAs to multiple views using "rndc nta", + the text returned via rndc was incorrectly terminated + after the first line, making it look as if only one + NTA had been added. Also, it was not possible to + differentiate between views with the same name but + different classes; this has been corrected with the + addition of a "-class" option. [GL #105] + +5032. [func] Add krb5-selfsub and ms-selfsub update policy rules. + [GL #511] + +5031. [cleanup] Various defines in platform.h has been either dropped + if always or never triggered on supported platforms + or replaced with config.h equivalents if the defines + didn't have any impact on public headers. Workarounds + for LinuxThreads have been removed because NPTL is + available since Linux kernel 2.6.0. [GL #525] + +5030. [bug] Align CMSG buffers to a 64-bit boundary, fixes crash + on architectures with strict alignment. [GL #521] + + --- 9.13.3 released --- + +5029. [func] Workarounds for servers that misbehave when queried + with EDNS have been removed, because these broken + servers and the workarounds for their noncompliance + cause unnecessary delays, increase code complexity, + and prevent deployment of new DNS features. See + https://dnsflagday.net for further details. [GL #150] + +5028. [bug] Spread the initial RRSIG expiration times over the + entire working sig-validity-interval when signing a + zone in named to even out re-signing and transfer + loads. [GL #418] + +5027. [func] Set SO_SNDBUF size on sockets. [GL #74] + +5026. [bug] rndc reconfig should not touch already loaded zones. + [GL #276] + +5025. [cleanup] Remove isc_keyboard family of functions. [GL #178] + +5024. [func] Replace custom assembly for atomic operations with + atomic support from the compiler. The code will now use + C11 stdatomic, or __atomic, or __sync builtins with GCC + or Clang compilers, and Interlocked functions with MSVC. + [GL #10] + +5023. [cleanup] Remove wrappers that try to fix broken or incomplete + implementations of IPv6, pthreads and other core + functionality required and used by BIND. [GL #192] + +5022. [doc] Update ms-self, ms-subdomain, krb5-self, and + krb5-subdomain documentation. [GL !708] + +5021. [bug] dig returned a non-zero exit code when it received a + reply over TCP after a retry. [GL #487] + +5020. [func] RNG uses thread-local storage instead of locks, if + supported by platform. [GL #496] + +5019. [cleanup] A message is now logged when ixfr-from-differences is + set at zone level for an inline-signed zone. [GL #470] + +5018. [bug] Fix incorrect sizeof arguments in lib/isc/pk11.c. + [GL !588] + +5017. [bug] lib/isc/pk11.c failed to unlink the session before + releasing the lock which is unsafe. [GL !589] + +5016. [bug] Named could assert with overlapping filter-aaaa and + dns64 acls. [GL #445] + +5015. [bug] Reloading all zones caused zone maintenance to cease + for inline-signed zones. [GL #435] + +5014. [bug] Signatures loaded from the journal for the signed + version of an inline-signed zone were not scheduled for + refresh. [GL #482] + +5013. [bug] A referral response with a non-empty ANSWER section was + inadvertently being treated as an error. [GL #390] + +5012. [bug] Fix lock order reversal in pk11_initialize. [GL !590] + +5011. [func] Remove support for unthreaded named. [GL #478] + +5010. [func] New "validate-except" option specifies a list of + domains beneath which DNSSEC validation should not + be performed. [GL #237] + +5009. [bug] Upon an OpenSSL failure, the first error in the OpenSSL + error queue was not logged. [GL #476] + +5008. [bug] "rndc signing -nsec3param ..." requests were silently + ignored for zones which were not yet loaded or + transferred. [GL #468] + +5007. [cleanup] Replace custom ISC boolean and integer data types + with C99 stdint.h and stdbool.h types. [GL #9] + +5006. [cleanup] Code preparing a delegation response was extracted from + query_delegation() and query_zone_delegation() into a + separate function in order to decrease code + duplication. [GL #431] + +5005. [bug] dnssec-verify, and dnssec-signzone at the verification + step, failed on some validly signed zones. [GL #442] + +5004. [bug] 'rndc reconfig' could cause inline zones to stop + re-signing. [GL #439] + +5003. [bug] dns_acl_isinsecure did not handle geoip elements. + [GL #406] + +5002. [bug] mdig: Handle malformed +ednsopt option, support 100 + +ednsopt options per query rather than 100 total and + address memory leaks if +ednsopt was specified. + [GL #410] + +5001. [bug] Fix refcount errors on error paths. [GL !563] + +5000. [bug] named_server_servestale() could leave the server in + exclusive mode if an error occurred. [GL #441] + +4999. [cleanup] Remove custom printf implementation in lib/isc/print.c. + [GL #261] + +4998. [test] Make resolver and cacheclean tests more civilized. + +4997. [security] named could crash during recursive processing + of DNAME records when "deny-answer-aliases" was + in use. (CVE-2018-5740) [GL #387] + +4996. [bug] dig: Handle malformed +ednsopt option. [GL #403] + +4995. [test] Add tests for "tcp-self" update policy. [GL !282] + +4994. [bug] Trust anchor telemetry queries were not being sent + upstream for locally served zones. [GL #392] + +4993. [cleanup] Remove support for silently ignoring 'no-change' deltas + from BIND 8 when processing an IXFR stream. 'no-change' + deltas will now trigger a fallback to AXFR as the + recovery mechanism. [GL #369] + +4992. [bug] The wrong address was being logged for trust anchor + telemetry queries. [GL #379] + +4991. [bug] "rndc reconfig" was incorrectly handling zones whose + "mirror" setting was changed. [GL #381] + +4990. [bug] Prevent a possible NULL reference in pkcs11-keygen. + [GL #401] + +4989. [cleanup] IDN support in dig has been reworked. IDNA2003 + fallbacks were removed in the process. [GL #384] + +4988. [bug] Don't synthesize NXDOMAIN from NSEC for records under + a DNAME. + + --- 9.13.2 released --- + +4987. [cleanup] dns_rdataslab_tordataset() and its related + dns_rdatasetmethods_t callbacks were removed as they + were not being used by anything in BIND. [GL #371] + +4986. [func] When built on Linux, BIND now requires the libcap + library to set process privileges, unless capability + support is explicitly overridden with "configure + --disable-linux-caps". [GL #321] + +4985. [func] Add a new slave zone option, "mirror", to enable + serving a non-authoritative copy of a zone that + is subject to DNSSEC validation before being + used. For now, this option is only meant to + facilitate deployment of an RFC 7706-style local + copy of the root zone. [GL #33] + +4984. [bug] Improve handling of very large incremental + zone transfers to prevent journal corruption. [GL #339] + +4983. [func] Add the ability to not return a DNS COOKIE option + when one is present in the request (answer-cookie no;). + [GL #173] + +4982. [cleanup] Return FORMERR if the question section is empty + and no COOKIE option is present; this restores + older behavior except in the newly specified + COOKIE case. [GL #260] + +4981. [bug] Fix race in cmsg buffer usage in socket code. + [GL #180] + +4980. [bug] Named-checkconf failed to detect bad in-view targets. + [GL #288] + +4979. [placeholder] + +4978. [test] Fix error handling and resolver configuration in the + "rpz" system test. [GL #312] + +4977. [func] When starting up, log the same details that + would be reported by 'named -V'. [GL #247] + +4976. [bug] Log the label with invalid prefix length correctly + when loading RPZ zones. [GL #254] + +4975. [bug] The server cookie computation for sha1 and sha256 did + not match the method described in RFC 7873. [GL #356] + +4974. [bug] Restore default rrset-order to random. [GL #336] + +4973. [func] verifyzone() and the functions it uses were moved to + libdns and refactored to prevent exit() from being + called upon failure. A side effect of that is that + dnssec-signzone and dnssec-verify now check for memory + leaks upon shutdown. [GL #266] + +4972. [func] Declare the 'rdata' argument for dns_rdata_tostruct() + to be const. [GL #341] + +4971. [bug] dnssec-signzone and dnssec-verify did not treat records + below a DNAME as out-of-zone data. [GL #298] + +4970. [func] Add QNAME minimization option to resolver. [GL #16] + +4969. [cleanup] Refactor zone logging functions. [GL #269] + + --- 9.13.1 released --- + +4968. [bug] If glue records are signed, attempt to validate them. + [GL #209] + +4967. [cleanup] Add "answer-cookie" to the parser, marked obsolete. + +4966. [placeholder] + +4965. [func] Add support for marking options as deprecated. + [GL #322] + +4964. [bug] Reduce the probability of double signature when deleting + a DNSKEY by checking if the node is otherwise signed + by the algorithm of the key to be deleted. [GL #240] + +4963. [test] ifconfig.sh now uses "ip" instead of "ifconfig", + if available, to configure the test interfaces on + linux. [GL #302] + +4962. [cleanup] Move 'named -T' processing to its own function. + [GL #316] + +4961. [protocol] Remove support for ECC-GOST (GOST R 34.11-94). + [GL #295] + +4960. [security] When recursion is enabled, but the "allow-recursion" + and "allow-query-cache" ACLs are not specified, + they should be limited to local networks, + but were inadvertently set to match the default + "allow-query", thus allowing remote queries. + (CVE-2018-5738) [GL #309] + +4959. [func] NSID logging (enabled by the "request-nsid" option) + now has its own "nsid" category, instead of using the + "resolver" category. [GL !332] + +4958. [bug] Remove redundant space from NSEC3 record. [GL #281] + +4957. [func] The default setting for "dnssec-validation" is now + "auto", which activates DNSSEC validation using the + IANA root key. (The default can be changed back to + "yes", which activates DNSSEC validation only when keys + are explicitly configured in named.conf, by building + BIND with "configure --disable-auto-validation".) + [GL #30] + +4956. [func] Change isc_random() to be just PRNG using xoshiro128**, + and add isc_nonce_buf() that uses CSPRNG. [GL #289] + +4955. [cleanup] Silence cppcheck warnings in lib/dns/master.c. + [GL #286] + +4954. [func] Messages about serving of stale answers are now + directed to the "serve-stale" logging category. + Also clarified serve-stale documentation. [GL !323] + +4953. [bug] Removed the option to build the red black tree + database without a hash table; the non-hashing + version was buggy and is not needed. [GL #184] + +4952. [func] Authoritative server support in named for the + EDNS CLIENT-SUBNET option (which was experimental + and not practical to deploy) has been removed. + + The ECS option is still supported in dig and mdig + via the +subnet option, and can be parsed and logged + when received by named, but it is no longer used + for ACL processing. The "geoip-use-ecs" option + is now obsolete; a warning will be logged if it is + used in named.conf. "ecs" tags in an ACL definition + are also obsolete and will cause the configuration + to fail to load. [GL #32] + +4951. [protocol] Add "HOME.ARPA" to list of built in empty zones as + per RFC 8375. [GL #273] + + --- 9.13.0 released --- + +4950. [bug] ISC_SOCKEVENTATTR_TRUNC was not be set. [GL #238] + +4949. [placeholder] + +4948. [bug] When request-nsid is turned on, EDNS NSID options + should be logged at level info. Since change 3741 + they have been logged at debug(3) by mistake. + [GL !290] + +4947. [func] Replace all random functions with isc_random(), + isc_random_buf() and isc_random_uniform() API. + [GL #221] + +4946. [bug] Additional glue was not being returned by resolver + for unsigned zones since change 4596. [GL #209] + +4945. [func] BIND can no longer be built without DNSSEC support. + A cryptography provider (i.e., OpenSSL or a hardware + service module with PKCS#11 support) must be + available. [GL #244] + +4944. [cleanup] Silence cppcheck portability warnings in + lib/isc/tests/buffer_test.c. [GL #239] + +4943. [bug] Change 4687 consumed too much memory when running + system tests with --with-tuning=large. Reduced the + hash table size to 512 entries for 'named -m record' + restoring the previous memory footprint. [GL #248] + +4942. [cleanup] Consolidate multiple instances of splitting of + batchline in dig into a single function. [GL #196] + +4941. [cleanup] Silence clang static analyzer warnings. [GL #196] + +4940. [cleanup] Extract the loop in dns__zone_updatesigs() into + separate functions to improve code readability. + [GL #135] + +4939. [test] Add basic unit tests for update_sigs(). [GL #135] + +4938. [placeholder] + +4937. [func] Remove support for OpenSSL < 1.0.0 [GL #191] + +4936. [func] Always use OpenSSL or PKCS#11 random data providers, + and remove the --{enable,disable}-crypto-rand configure + options. [GL #165] + +4935. [func] Add support for LibreSSL >= 2.7.0 (some OpenSSL 1.1.0 + call were added). [GL #191] + +4934. [security] The serve-stale feature could cause an assertion failure + in rbtdb.c even when stale-answer-enable was false. + Simultaneous use of stale cache records and NSEC + aggressive negative caching could trigger a recursion + loop. (CVE-2018-5737) [GL #185] + +4933. [bug] Not creating signing keys for an inline signed zone + prevented changes applied to the raw zone from being + reflected in the secure zone until signing keys were + made available. [GL #159] + +4932. [bug] Bumped signed serial of an inline signed zone was + logged even when an error occurred while updating + signatures. [GL #159] + +4931. [func] Removed the "rbtdb64" database implementation. + [GL #217] + +4930. [bug] Remove a bogus check in nslookup command line + argument processing. [GL #206] + +4929. [func] Add the ability to set RA and TC in queries made by + dig (+[no]raflag, +[no]tcflag). [GL #213] + +4928. [func] The "dnskey-sig-validity" option allows + "sig-validity-interval" to be overridden for signatures + covering DNSKEY RRsets. [GL #145] + +4927. [placeholder] + +4926. [func] Add root key sentinel support. To disable, add + 'root-key-sentinel no;' to named.conf. [GL #37] + +4925. [func] Several configuration options that define intervals + can now take TTL value suffixes (for example, 2h or 1d) + in addition to integer parameters. These include + max-cache-ttl, max-ncache-ttl, max-policy-ttl, + fstrm-set-reopen-interval, interface-interval, and + min-update-interval. [GL #203] + +4924. [cleanup] Clean up the isc_string_* namespace and leave + only strlcpy and strlcat. [GL #178] + +4923. [cleanup] Refactor socket and socket event options into + enum types. [GL !135] + +4922. [bug] dnstap: Log the destination address of client + packets rather than the interface address. + [GL #197] + +4921. [cleanup] Add dns_fixedname_initname() and refactor the caller + code to make usage of the new function, as a part of + refactoring dns_fixedname_*() macros were turned into + functions. [GL #183] + +4920. [cleanup] Clean up libdns removing most of the backwards + compatibility wrappers. + +4919. [cleanup] Clean up the isc_hash_* namespace and leave only + the FNV-1a hash implementation. [GL #178] + +4918. [bug] Fix double free after keygen error in dnssec-keygen + when OpenSSL >= 1.1.0 is used and RSA_generate_key_ex + fails. [GL #109] + +4917. [func] Support 64 RPZ policy zones by default. [GL #123] + +4916. [func] Remove IDNA2003 support and the bundled idnkit-1.0 + library. + +4915. [func] Implement IDNA2008 support in dig by adding support + for libidn2. New dig option +idnin has been added, + which allows to process invalid domain names much + like dig without IDN support. libidn2 version 2.0 + or higher is needed for +idnout enabled by default. + +4914. [security] A bug in zone database reference counting could lead to + a crash when multiple versions of a slave zone were + transferred from a master in close succession. + (CVE-2018-5736) [GL #134] + +4913. [test] Re-implemented older unit tests in bin/tests as ATF, + removed the lib/tests unit testing library. [GL #115] + +4912. [test] Improved the reliability of the 'cds' system test. + [GL #136] + +4911. [test] Improved the reliability of the 'mkeys' system test. + [GL #128] + +4910. [func] Update util/check-changes to work on release branches. + [GL #113] + +4909. [bug] named-checkconf did not detect in-view zone collisions. + [GL #125] + +4908. [test] Eliminated unnecessary waiting in the allow_query + system test. Also changed its name to allow-query. + [GL #81] + +4907. [test] Improved the reliability of the 'notify' system + test. [GL #59] + +4906. [func] Replace getquad() with inet_pton(), completing + change #4900. [GL #56] + +4905. [bug] irs_resconf_load() ignored resolv.conf syntax errors + when "domain" or "search" options were present in that + file. [GL #110] + +4904. [bug] Temporarily revert change #4859. [GL #124] + +4903. [bug] "check-mx fail;" did not prevent MX records containing + IP addresses from being added to a zone by a dynamic + update. [GL #112] + +4902. [test] Improved the reliability of the 'ixfr' system + test. [GL #66] + +4901. [func] "dig +nssearch" now lists the name servers + for a domain that time out, as well as the servers + that respond. [GL #64] + +4900. [func] Remove all uses of inet_aton(). As a result of this + change, IPv4 addresses are now only accepted in + dotted-quad format. [GL #13] + +4899. [test] Convert most of the remaining system tests to be able + to run in parallel, continuing the work from change + #4895. To take advantage of this, use "make -jN check", + where N is the number of processors to use. [GL #91] + +4898. [func] Remove libseccomp based system-call filtering. [GL #93] + +4897. [test] Update to rpz system test so that it doesn't recurse. + [GL #68] + +4896. [test] cacheclean system test was not robust. [GL #82] + +4895. [test] Allow some system tests to run in parallel. + [RT #46602] + +4894. [bug] named could crash while rolling a dnstap output file. + [RT #46942] + +4893. [bug] Address various issues reported by cppcheck. [GL #51] + +4892. [bug] named could leak memory when "rndc reload" was invoked + before all zone loading actions triggered by a previous + "rndc reload" command were completed. [RT #47076] + +4891. [placeholder] + +4890. [func] Remove unused ondestroy callback from libisc. + [isc-projects/bind9!3] + +4889. [func] Warn about the use of old root keys without the new + root key being present. Warn about dlv.isc.org's + key being present. Warn about both managed and + trusted root keys being present. [RT #43670] + +4888. [test] Initialize sockets correctly in sample-update so + that the nsupdate system test will run on Windows. + [RT #47097] + +4887. [test] Enable the rpzrecurse test to run on Windows. + [RT #47093] + +4886. [doc] Document dig -u in manpage. [RT #47150] + +4885. [security] update-policy rules that otherwise ignore the name + field now require that it be set to "." to ensure + that any type list present is properly interpreted. + [RT #47126] + +4884. [bug] named could crash on shutdown due to a race between + shutdown_server() and ns__client_request(). [RT #47120] + +4883. [cleanup] Improved debugging output from dnssec-cds. [RT #47026] + +4882. [bug] Address potential memory leak in + dns_update_signaturesinc. [RT #47084] + +4881. [bug] Only include dst_openssl.h when OpenSSL is required. + [RT #47068] + +4880. [bug] Named wasn't returning the target of a cross-zone + CNAME between two served zones when recursion was + desired and available (RD=1, RA=1). (When this is + not the case, the CNAME target is deliberately + withheld to prevent accidental cache poisoning.) + [RT #47078] + +4879. [bug] dns_rdata_caa:value_len field was too small. + [RT #47086] + +4878. [bug] List 'ply' as a requirement for the 'isc' python + package. [RT #47065] + +4877. [bug] Address integer overflow when exponentially + backing off retry intervals. [RT #47041] + +4876. [bug] Address deadlock with accessing a keytable. [RT #47000] + +4875. [bug] Address compile failures on older systems. [RT #47015] + +4874. [bug] Wrong time display when reporting new keywarntime. + [RT #47042] + +4873. [doc] Grammars for named.conf included in the ARM are now + automatically generated by the configuration parser + itself. As a side effect of the work needed to + separate zone type grammars from each other, this + also makes checking of zone statements in + named-checkconf more correct and consistent. + [RT #36957] + +4872. [bug] Don't permit loading meta RR types such as TKEY + from master files. [RT #47009] + +4871. [bug] Fix configure glitch in detecting stdatomic.h + support on systems with multiple compilers. + [RT #46959] + +4870. [test] Update included ATF library to atf-0.21 preserving + the ATF tool. [RT #46967] + +4869. [bug] Address some cases where NULL with zero length could + be passed to memmove which is undefined behavior and + can lead to bad optimization. [RT #46888] + +4868. [func] dnssec-keygen can no longer generate HMAC keys. + Use tsig-keygen instead. [RT #46404] + +4867. [cleanup] Normalize rndc on/off commands (validation, + querylog, serve-stale) so they all accept the + same synonyms for on/off (yes/no, true/false, + enable/disable). Thanks to Tony Finch. [RT #47022] + +4866. [port] DST library initialization verifies MD5 (when MD5 + was not disabled) and SHA-1 hash and HMAC support. + [RT #46764] + +4865. [cleanup] Simplify handling isc_socket_sendto2() return values. + [RT #46986] + +4864. [bug] named acting as a slave for a catalog zone crashed if + the latter contained a master definition without an IP + address. [RT #45999] + +4863. [bug] Fix various other bugs reported by Valgrind's + memcheck tool. [RT #46978] + +4862. [bug] The rdata flags for RRSIG were not being properly set + when constructing a rdataslab. [RT #46978] + +4861. [bug] The isc_crc64 unit test was not endian independent. + [RT #46973] + +4860. [bug] isc_int8_t should be signed char. [RT #46973] + +4859. [bug] A loop was possible when attempting to validate + unsigned CNAME responses from secure zones; + this caused a delay in returning SERVFAIL and + also increased the chances of encountering + CVE-2017-3145. [RT #46839] + +4858. [security] Addresses could be referenced after being freed + in resolver.c, causing an assertion failure. + (CVE-2017-3145) [RT #46839] + +4857. [bug] Maintain attach/detach semantics for event->db, + event->node, event->rdataset and event->sigrdataset + in query.c. [RT #46891] + +4856. [bug] 'rndc zonestatus' reported the wrong underlying type + for a inline slave zone. [RT #46875] + +4855. [bug] isc_time_formatshorttimestamp produced incorrect + output. [RT #46938] + +4854. [bug] query_synthcnamewildcard should stop generating the + response if query_synthwildcard fails. [RT #46939] + +4853. [bug] Add REQUIRE's and INSIST's to isc_time_formatISO8601L + and isc_time_formatISO8601Lms. [RT #46916] + +4852. [bug] Handle strftime() failing in isc_time_formatISO8601ms. + Add REQUIRE's and INSIST's to isc_time_formattimestamp, + isc_time_formathttptimestamp, isc_time_formatISO8601, + isc_time_formatISO8601ms. [RT #46892] + +4851. [port] Support using kyua as well as atf-run to run the unit + tests. [RT #46853] + +4850. [bug] Named failed to restart with multiple added zones in + lmdb database. [RT #46889] + +4849. [bug] Duplicate zones could appear in the .nzf file if + addzone failed. [RT #46435] + +4848. [func] Zone types "primary" and "secondary" can now be used + as synonyms for "master" and "slave" in named.conf. + [RT #46713] + +4847. [bug] dnssec-dnskey-kskonly was not being honored for + CDS and CDNSKEY. [RT #46755] + +4846. [test] Adjust timing values in runtime system test. Address + named.pid removal races in runtime system test. + [RT #46800] + +4845. [bug] Dig (non iOS) should exit on malformed names. + [RT #46806] + +4844. [test] Address memory leaks in libatf-c. [RT #46798] + +4843. [bug] dnssec-signzone free hashlist on exit. [RT #46791] + +4842. [bug] Conditionally compile opensslecdsa_link.c to avoid + warnings about unused function. [RT #46790] + + --- 9.12.0rc1 released --- + +4841. [bug] Address -fsanitize=undefined warnings. [RT #46786] + +4840. [test] Add tests to cover fallback to using ZSK on inactive + KSK. [RT #46787] + +4839. [bug] zone.c:zone_sign was not properly determining + if there were active KSK and ZSK keys for + a algorithm when update-check-ksk is true + (default) leaving records unsigned with one or + more DNSKEY algorithms. [RT #46774] + +4838. [bug] zone.c:add_sigs was not properly determining + if there were active KSK and ZSK keys for + a algorithm when update-check-ksk is true + (default) leaving records unsigned with one or + more DNSKEY algorithms. [RT #46754] + +4837. [bug] dns_update_signatures{inc} (add_sigs) was not + properly determining if there were active KSK and + ZSK keys for a algorithm when update-check-ksk is + true (default) leaving records unsigned when there + were multiple DNSKEY algorithms for the zone. + [RT #46743] + +4836. [bug] Zones created using "rndc addzone" could + temporarily fail to inherit an "allow-transfer" + ACL that had been configured in the options + statement. [RT #46603] + +4835. [cleanup] Clean up and refactor LMDB-related code. [RT #46718] + +4834. [port] Fix LMDB support on OpenBSD. [RT #46718] + +4833. [bug] isc_event_free should check that the event is not + linked when called. [RT #46725] + +4832. [bug] Events were not being removed from zone->rss_events. + [RT #46725] + +4831. [bug] Convert the RRSIG expirytime to 64 bits for + comparisons in diff.c:resign. [RT #46710] + +4830. [bug] Failure to configure ATF when requested did not cause + an error in top-level configure script. [RT #46655] + +4829. [bug] isc_heap_delete did not zero the index value when + the heap was created with a callback to do that. + [RT #46709] + +4828. [bug] Do not use thread-local storage for storing LMDB reader + locktable slots. [RT #46556] + +4827. [misc] Add a precommit check script util/checklibs.sh + [RT #46215] + +4826. [cleanup] Prevent potential build failures in bin/confgen/ and + bin/named/ when using parallel make. [RT #46648] + +4825. [bug] Prevent a bogus "error during managed-keys processing + (no more)" warning from being logged. [RT #46645] + +4824. [port] Add iOS hooks to dig. [RT #42011] + +4823. [test] Refactor reclimit system test to improve its + reliability and speed. [RT #46632] + +4822. [bug] Use resign_sooner in dns_db_setsigningtime. [RT #46473] + +4821. [bug] When resigning ensure that the SOA's expire time is + always later that the resigning time of other records. + [RT #46473] + +4820. [bug] dns_db_subtractrdataset should transfer the resigning + information to the new header. [RT #46473] + +4819. [bug] Fully backout the transaction when adding a RRset + to the resigning / removal heaps fails. [RT #46473] + +4818. [test] The logfileconfig system test could intermittently + report false negatives on some platforms. [RT #46615] + +4817. [cleanup] Use DNS_NAME_INITABSOLUTE and DNS_NAME_INITNONABSOLUTE. + [RT #45433] + +4816. [bug] Don't use a common array for storing EDNS options + in DiG as it could fill up. [RT #45611] + +4815. [bug] rbt_test.c:insert_and_delete needed to call + dns_rbt_addnode instead of dns_rbt_addname. [RT #46553] + +4814. [cleanup] Use AS_HELP_STRING for consistent help text. [RT #46521] + +4813. [bug] Address potential read after free errors from + query_synthnodata, query_synthwildcard and + query_synthnxdomain. [RT #46547] + +4812. [bug] Minor improvements to stability and consistency of code + handling managed keys. [RT #46468] + +4811. [bug] Revert api changes to use inline + macros. Provide a alternative mechanism to turn + on the use of inline macros when building BIND. + [RT #46520] + +4810. [test] The chain system test failed if the IPv6 interfaces + were not configured. [RT #46508] + + --- 9.12.0b2 released --- + +4809. [port] Check at configure time whether -latomic is needed + for stdatomic.h. [RT #46324] + +4808. [bug] Properly test for zlib.h. [RT #46504] + +4807. [cleanup] isc_rng_randombytes() returns a specified number of + bytes from the PRNG; this is now used instead of + calling isc_rng_random() multiple times. [RT #46230] + +4806. [func] Log messages related to loading of zones are now + directed to the "zoneload" logging category. + [RT #41640] + +4805. [bug] TCP4Active and TCP6Active weren't being updated + correctly. [RT #46454] + +4804. [port] win32: access() does not work on directories as + required by POSIX. Supply a alternative in + isc_file_isdirwritable. [RT #46394] + +4803. [placeholder] + +4802. [test] Refactor mkeys system test to make it quicker and more + reliable. [RT #45293] + +4801. [func] 'dnssec-lookaside auto;' and 'dnssec-lookaside . + trust-anchor dlv.isc.org;' now elicit warnings rather + than being fatal configuration errors. [RT #46410] + +4800. [bug] When processing delzone, write one zone config per + line to the NZF. [RT #46323] + +4799. [cleanup] Improve clarity of keytable unit tests. [RT #46407] + +4798. [func] Keys specified in "managed-keys" statements + are tagged as "initializing" until they have been + updated by a key refresh query. If initialization + fails it will be visible from "rndc secroots". + [RT #46267] + +4797. [func] Removed "isc-hmac-fixup", as the versions of BIND that + had the bug it worked around are long past end of + life. [RT #46411] + +4796. [bug] Increase the maximum configurable TCP keepalive + timeout to 65535. [RT #44710] + +4795. [func] A new statistics counter has been added to track + priming queries. [RT #46313] + +4794. [func] "dnssec-checkds -s" specifies a file from which + to read a DS set rather than querying the parent. + [RT #44667] + +4793. [bug] nsupdate -[46] could overflow the array of server + addresses. [RT #46402] + +4792. [bug] Fix map file header correctness check. [RT #38418] + +4791. [doc] Fixed outdated documentation about export libraries. + [RT #46341] + +4790. [bug] nsupdate could trigger a require when sending a + update to the second address of the server. + [RT #45731] + +4789. [cleanup] Check writability of new-zones-directory. [RT #46308] + +4788. [cleanup] When using "update-policy local", log a warning + when an update matching the session key is received + from a remote host. [RT #46213] + +4787. [cleanup] Turn nsec3param_salt_totext() into a public function, + dns_nsec3param_salttotext(), and add unit tests for it. + [RT #46289] + +4786. [func] The "filter-aaaa-on-v4" and "filter-aaaa-on-v6" + options are no longer conditionally compiled. + [RT #46340] + +4785. [func] The hmac-md5 algorithm is no longer recommended for + use with RNDC keys. The default in rndc-confgen + is now hmac-sha256. [RT #42272] + +4784. [func] The use of dnssec-keygen to generate HMAC keys is + deprecated in favor of tsig-keygen. dnssec-keygen + will print a warning when used for this purpose. + All HMAC algorithms will be removed from + dnssec-keygen in a future release. [RT #42272] + +4783. [test] dnssec: 'check that NOTIFY is sent at the end of + NSEC3 chain generation failed' required more time + on some machines for the IXFR to complete. [RT #46388] + +4782. [test] dnssec: 'checking positive and negative validation + with negative trust anchors' required more time to + complete on some machines. [RT #46386] + +4781. [maint] B.ROOT-SERVERS.NET is now 199.9.14.201. [RT #45889] + +4780. [bug] When answering ANY queries, don't include the NS + RRset in the authority section if it was already + in the answer section. [RT #44543] + +4779. [bug] Expire NTA at the start of the second. Don't update + the expiry value if the record has already expired + after a successful check. [RT #46368] + +4778. [test] Improve synth-from-dnssec testing. [RT #46352] + +4777. [cleanup] Removed a redundant call to configure_view_acl(). + [RT #46369] + +4776. [bug] Improve portability of ht_test. [RT #46333] + +4775. [bug] Address Coverity warnings in ht_test.c and mem_test.c + [RT #46281] + +4774. [bug] was incorrectly included in several + header files. [RT #46311] + +4773. [doc] Fixed generating Doxygen documentation for functions + annotated using certain macros. Miscellaneous + Doxygen-related cleanups. [RT #46276] + + --- 9.12.0b1 released --- + +4772. [test] Expanded unit testing framework for libns, using + hooks to interrupt query flow and inspect state + at specified locations. [RT #46173] + +4771. [bug] When sending RFC 5011 refresh queries, disregard + cached DNSKEY rrsets. [RT #46251] + +4770. [bug] Cache additional data from priming queries as glue. + Previously they were ignored as unsigned + non-answer data from a secure zone, and never + actually got added to the cache, causing hints + to be used frequently for root-server + addresses, which triggered re-priming. [RT #45241] + +4769. [func] The working directory and managed-keys directory has + to be writeable (and seekable). [RT #46077] + +4768. [func] By default, memory is no longer filled with tag values + when it is allocated or freed; this improves + performance but makes debugging of certain memory + issues more difficult. "named -M fill" turns memory + filling back on. (Building "configure + --enable-developer", turns memory fill on by + default again; it can then be disabled with + "named -M nofill".) [RT #45123] + +4767. [func] Add a new function, isc_buffer_printf(), which can be + used to append a formatted string to the used region of + a buffer. [RT #46201] + +4766. [cleanup] Address Coverity warnings. [RT #46150] + +4765. [bug] Address potential INSIST in dnssec-cds. [RT #46150] + +4764. [bug] Address portability issues in cds system test. + [RT #46214] + +4763. [contrib] Improve compatibility when building MySQL DLZ + module by using mysql_config if available. + [RT #45558] + +4762. [func] "update-policy local" is now restricted to updates + from local addresses. (Previously, other addresses + were allowed so long as updates were signed by the + local session key.) [RT #45492] + +4761. [protocol] Add support for DOA. [RT #45612] + +4760. [func] Add glue cache statistics counters. [RT #46028] + +4759. [func] Add logging channel "trust-anchor-telemetry" to + record trust-anchor-telemetry in incoming requests. + Both _ta-XXXX./NULL and EDNS KEY-TAG options + are logged. [RT #46124] + +4758. [doc] Remove documentation of unimplemented "topology". + [RT #46161] + +4757. [func] New "dnssec-cds" command creates a new parent DS + RRset based on CDS or CDNSKEY RRsets found in + a child zone, and generates either a dsset file + or stream of nsupdate commands to update the + parent. Thanks to Tony Finch. [RT #46090] + +4756. [bug] Interrupting dig could lead to an INSIST failure after + certain errors were encountered while querying a host + whose name resolved to more than one address. Change + 4537 increased the odds of triggering this issue by + causing dig to hang indefinitely when certain error + paths were evaluated. dig now also retries TCP queries + (once) if the server gracefully closes the connection + before sending a response. [RT #42832, #45159] + +4755. [cleanup] Silence unnecessary log message when NZF file doesn't + exist. [RT #46186] + +4754. [bug] dns_zone_setview needs a two stage commit to properly + handle errors. [RT #45841] + +4753. [contrib] Software obtainable from known upstream locations + (i.e., zkt, nslint, query-loc) has been removed. + Links to these and other packages can be found at + https://www.isc.org/community/tools [RT #46182] + +4752. [test] Add unit test for isc_net_pton. [RT #46171] + +4751. [func] "dnssec-signzone -S" can now automatically add parent + synchronization records (CDS and CDNSKEY) according + to key metadata set using the -Psync and -Dsync + options to dnssec-keygen and dnssec-settime. + [RT #46149] + +4750. [func] "rndc managed-keys destroy" shuts down RFC 5011 key + maintenance and deletes the managed-keys database. + If followed by "rndc reconfig" or a server restart, + key maintenance is reinitialized from scratch. + This is primarily intended for testing. [RT #32456] + +4749. [func] The ISC DLV service has been shut down, and all + DLV records have been removed from dlv.isc.org. + - Removed references to ISC DLV in documentation + - Removed DLV key from bind.keys + - No longer use ISC DLV by default in delv + - "dnssec-lookaside auto" and configuration of + "dnssec-lookaide" with dlv.isc.org as the trust + anchor are both now fatal errors. + [RT #46155] + +4748. [cleanup] Sprintf to snprintf coversions. [RT #46132] + +4747. [func] Synthesis of responses from DNSSEC-verified records. + Stage 3 - synthesize NODATA responses. [RT #40138] + +4746. [cleanup] Add configured prefixes to configure summary + output. [RT #46153] + +4745. [test] Add color-coded pass/fail messages to system + tests when running on terminals that support them. + [RT #45977] + +4744. [bug] Suppress trust-anchor-telemetry queries if + validation is disabled. [RT #46131] + +4743. [func] Exclude trust-anchor-telemetry queries from + synth-from-dnssec processing. [RT #46123] + +4742. [func] Synthesis of responses from DNSSEC-verified records. + Stage 2 - synthesis of records from wildcard data. + If the dns64 or filter-aaaa* is configured then the + involved lookups are currently excluded. [RT #40138] + +4741. [bug] Make isc_refcount_current() atomically read the + counter value. [RT #46074] + +4740. [cleanup] Avoid triggering format-truncated warnings. [RT #46107] + +4739. [cleanup] Address clang static analysis warnings. [RT #45952] + +4738. [port] win32: strftime mishandles %Z. [RT #46039] + +4737. [cleanup] Address Coverity warnings. [RT #46012] + +4736. [cleanup] (a) Added comments to NSEC3-related functions in + lib/dns/zone.c. (b) Refactored NSEC3 salt formatting + code. (c) Minor tweaks to lock and result handling. + [RT #46053] + +4735. [bug] Add @ISC_OPENSSL_LIBS@ to isc-config. [RT #46078] + +4734. [contrib] Added sample configuration for DNS-over-TLS in + contrib/dnspriv. + +4733. [bug] Change #4706 introduced a bug causing TCP clients + not be reused correctly, leading to unconstrained + memory growth. [RT #46029] + +4732. [func] Change default minimal-responses setting to + no-auth-recursive. [RT #46016] + +4731. [bug] Fix use after free when closing an LMDB. [RT #46000] + +4730. [bug] Fix out of bounds access in DHCID totext() method. + [RT #46001] + +4729. [bug] Don't use memset() to wipe memory, as it may be + removed by compiler optimizations when the + memset() occurs on automatic stack allocation + just before function return. [RT #45947] + +4728. [func] Use C11's stdatomic.h instead of isc_atomic + where available. [RT #40668] + +4727. [bug] Retransferring an inline-signed slave using NSEC3 + around the time its NSEC3 salt was changed could result + in an infinite signing loop. [RT #45080] + +4726. [port] Prevent setsockopt() errors related to TCP_FASTOPEN + from being logged on FreeBSD if the kernel does not + support it. Notify the user when the kernel does + support TCP_FASTOPEN, but it is disabled by sysctl. + Add a new configure option, --disable-tcp-fastopen, to + disable use of TCP_FASTOPEN altogether. [RT #44754] + +4725. [bug] Nsupdate: "recvsoa" was incorrectly reported for + failures in sending the update message. The correct + location to be reported is "update_completed". + [RT #46014] + +4724. [func] By default, BIND now uses the random number + functions provided by the crypto library (i.e., + OpenSSL or a PKCS#11 provider) as a source of + randomness rather than /dev/random. This is + suitable for virtual machine environments + which have limited entropy pools and lack + hardware random number generators. + + This can be overridden by specifying another + entropy source via the "random-device" option + in named.conf, or via the -r command line option; + however, for functions requiring full cryptographic + strength, such as DNSSEC key generation, this + cannot be overridden. In particular, the -r + command line option no longer has any effect on + dnssec-keygen. + + This can be disabled by building with + "configure --disable-crypto-rand". + [RT #31459] [RT #46047] + +4723. [bug] Statistics counter DNSTAPdropped was misidentified + as DNSSECdropped. [RT #46002] + +4722. [cleanup] Clean up uses of strcpy() and strcat() in favor of + strlcpy() and strlcat() for safety. [RT #45981] + +4721. [func] 'dnssec-signzone -x' and 'dnssec-dnskey-kskonly' + options now apply to CDNSKEY and DS records as well + as DNSKEY. Thanks to Tony Finch. [RT #45689] + +4720. [func] Added a statistics counter to track prefetch + queries. [RT #45847] + +4719. [bug] Address PVS static analyzer warnings. [RT #45946] + +4718. [func] Avoid searching for a owner name compression pointer + more than once when writing out a RRset. [RT #45802] + +4717. [bug] Treat replies with QCOUNT=0 as truncated if TC=1, + FORMERR if TC=0, and log the error correctly. + [RT #45836] + +4716. [placeholder] + + --- 9.12.0a1 released --- + +4715. [bug] TreeMemMax was mis-identified as a second HeapMemMax + in the Json cache statistics. [RT #45980] + +4714. [port] openbsd/libressl: add support for building with + --enable-openssl-hash. [RT #45982] + +4713. [func] Added support for the DNS Response Policy Service + (DNSRPS) API, which allows named to use an external + response policy daemon when built with + "configure --enable-dnsrps". Thanks to Farsight + Security. [RT #43376] + +4712. [bug] "dig +domain" and "dig +search" didn't retain the + search domain when retrying with TCP. [RT #45547] + +4711. [test] Some RR types were missing from genzones.sh. + [RT #45782] + +4710. [cleanup] Changed the --enable-openssl-hash default to yes. + [RT #45019] + +4709. [cleanup] Use dns_name_fullhash() to hash names for RRL. + [RT #45435] + +4708. [cleanup] Legacy Windows builds (i.e. for XP and earlier) + are no longer supported. [RT #45186] + +4707. [func] The lightweight resolver daemon and library (lwresd + and liblwres) have been removed. [RT #45186] + +4706. [func] Code implementing name server query processing has + been moved from bin/named to a new library "libns". + Functions remaining in bin/named are now prefixed + with "named_" rather than "ns_". This will make it + easier to write unit tests for name server code, or + link name server functionality into new tools. + [RT #45186] + +4705. [placeholder] + +4704. [cleanup] Silence Visual Studio compiler warnings. [RT #45898] + +4703. [bug] BINDInstall.exe was missing some buffer length checks. + [RT #45898] + +4702. [func] Update function declarations to use + dns_masterstyle_flags_t for style flags. [RT #45924] + +4701. [cleanup] Refactored lib/dns/tsig.c to reduce code + duplication and simplify the disabling of MD5. + [RT #45490] + +4700. [func] Serving of stale answers is now supported. This + allows named to provide stale cached answers when + the authoritative server is under attack. + See max-stale-ttl, stale-answer-enable, + stale-answer-ttl. [RT #44790] + +4699. [func] Multiple cookie-secret clauses can now be specified. + The first one specified is used to generate new + server cookies. [RT #45672] + +4698. [port] Add --with-python-install-dir configure option to allow + specifying a nonstandard installation directory for + Python modules. [RT #45407] + +4697. [bug] Restore workaround for Microsoft Windows TSIG hash + computation bug. [RT #45854] + +4696. [port] Enable filter-aaaa support by default on Windows + builds. [RT #45883] + +4695. [bug] cookie-secrets were not being properly checked by + named-checkconf. [RT #45886] + +4694. [func] dnssec-keygen no longer uses RSASHA1 by default; + the signing algorithm must be specified on + the command line with the "-a" option. Signing + scripts that rely on the existing default behavior + will break; use "dnssec-keygen -a RSASHA1" to + repair them. (The goal of this change is to make + it easier to find scripts using RSASHA1 so they + can be changed in the event of that algorithm + being deprecated in the future.) [RT #44755] + +4693. [func] Synthesis of responses from DNSSEC-verified records. + Stage 1 covers NXDOMAIN synthesis from NSEC records. + This is controlled by synth-from-dnssec and is enabled + by default. [RT #40138] + +4692. [bug] Fix build failures with libressl introduced in 4676. + [RT #45879] + +4691. [func] Add -4/-6 command line options to nsupdate and rndc. + [RT #45632] + +4690. [bug] Command line options -4/-6 were handled inconsistently + between tools. [RT #45632] + +4689. [cleanup] Turn on minimal responses for CDNSKEY and CDS in + addition to DNSKEY and DS. Thanks to Tony Finch. + [RT #45690] + +4688. [protocol] Check and display EDNS KEY TAG options (RFC 8145) in + messages. [RT #44804] + +4687. [func] Refactor tracklines code. [RT #45126] + +4686. [bug] dnssec-settime -p could print a bogus warning about + key deletion scheduled before its inactivation when a + key had an inactivation date set but no deletion date + set. [RT #45807] + +4685. [bug] dnssec-settime incorrectly calculated publication and + activation dates for a successor key. [RT #45806] + +4684. [bug] delv could send bogus DNS queries when an explicit + server address was specified on the command line along + with -4/-6. [RT #45804] + +4683. [bug] Prevent nsupdate from immediately exiting on invalid + user input in interactive mode. [RT #28194] + +4682. [bug] Don't report errors on records below a DNAME. + [RT #44880] + +4681. [bug] Log messages from the validator now include the + associated view unless the view is "_default/IN" + or "_dnsclient/IN". [RT #45770] + +4680. [bug] Fix failing over to another master server address when + nsupdate is used with GSS-API. [RT #45380] + +4679. [cleanup] Suggest using -o when dnssec-verify finds a SOA record + not at top of zone and -o is not used. [RT #45519] + +4678. [bug] geoip-use-ecs has the wrong type when geoip support + is disabled at configure time. [RT #45763] + +4677. [cleanup] Split up the main function in dig to better support + the iOS app version. [RT #45508] + +4676. [cleanup] Allow BIND to be built using OpenSSL 1.0.X with + deprecated functions removed. [RT #45706] + +4675. [cleanup] Don't use C++ keyword class. [RT #45726] + +4674. [func] "dig +sigchase", and related options "+topdown" and + "+trusted-keys", have been removed. Use "delv" for + queries with DNSSEC validation. [RT #42793] + +4673. [port] Silence GCC 7 warnings. [RT #45592] + +4672. [placeholder] + +4671. [bug] Fix a race condition that could cause the + resolver to crash with assertion failure when + chasing DS in specific conditions with a very + short RTT to the upstream nameserver. [RT #45168] + +4670. [cleanup] Ensure that a request MAC is never sent back + in an XFR response unless the signature was + verified. [RT #45494] + +4669. [func] Iterative query logic in resolver.c has been + refactored into smaller functions and commented, + for improved readability, maintainability and + testability. [RT #45362] + +4668. [bug] Use localtime_r and gmtime_r for thread safety. + [RT #45664] + +4667. [cleanup] Refactor RDATA unit tests. [RT #45610] + +4666. [bug] dnssec-keymgr: Domain names beginning with digits (0-9) + could cause a parser error when reading the policy + file. This now works correctly so long as the domain + name is quoted. [RT #45641] + +4665. [protocol] Added support for ED25519 and ED448 DNSSEC signing + algorithms (RFC 8080). (Note: these algorithms + depend on code currently in the development branch + of OpenSSL which has not yet been released.) + [RT #44696] + +4664. [func] Add a "glue-cache" option to enable or disable the + glue cache. The default is "yes". [RT #45125] + +4663. [cleanup] Clarify error message printed by dnssec-dsfromkey. + [RT #21731] + +4662. [performance] Improve cache memory cleanup of zero TTL records + by putting them at the tail of LRU header lists. + [RT #45274] + +4661. [bug] A race condition could occur if a zone was reloaded + while resigning, triggering a crash in + rbtdb.c:closeversion(). [RT #45276] + +4660. [bug] Remove spurious "peer" from Windows socket log + messages. [RT #45617] + +4659. [bug] Remove spurious log message about lmdb-mapsize + not being supported when parsing builtin + configuration file. [RT #45618] + +4658. [bug] Clean up build directory created by "setup.py install" + immediately. [RT #45628] + +4657. [bug] rrchecker system test result could be improperly + determined. [RT #45602] + +4656. [bug] Apply "port" and "dscp" values specified in catalog + zone's "default-masters" option to the generated + configuration of its member zones. [RT #45545] + +4655. [bug] Lack of seccomp could be falsely reported. [RT #45599] + +4654. [cleanup] Don't use C++ keywords delete, new and namespace. + [RT #45538] + +4653. [bug] Reorder includes to move @DST_OPENSSL_INC@ and + @ISC_OPENSSL_INC@ after shipped include directories. + [RT #45581] + +4652. [bug] Nsupdate could attempt to use a zeroed address on + server timeout. [RT #45417] + +4651. [test] Silence coverity warnings in tsig_test.c. [RT #45528] + +4650. [placeholder] + +4649. [bug] The wrong zone was logged when a catalog zone is added. + [RT #45520] + +4648. [bug] "rndc reconfig" on a slave no longer causes all member + zones of configured catalog zones to be removed from + configuration. [RT #45310] + +4647. [bug] Change 4643 broke verification of TSIG signed TCP + message sequences where not all the messages contain + TSIG records. These may be used in AXFR and IXFR + responses. [RT #45509] + +4646. [placeholder] + +4645. [bug] Fix PKCS#11 RSA parsing when MD5 is disabled. + [RT #45300] + +4644. [placeholder] + +4643. [security] An error in TSIG handling could permit unauthorized + zone transfers or zone updates. (CVE-2017-3142) + (CVE-2017-3143) [RT #45383] + +4642. [cleanup] Add more logging of RFC 5011 events affecting the + status of managed keys: newly observed keys, + deletion of revoked keys, etc. [RT #45354] + +4641. [cleanup] Parallel builds (make -j) could fail with --with-atf / + --enable-developer. [RT #45373] + +4640. [bug] If query_findversion failed in query_getdb due to + memory failure the error status was incorrectly + discarded. [RT #45331] + +4639. [bug] Fix a regression in --with-tuning reporting introduced + by change 4488. [RT #45396] + +4638. [bug] Reloading or reconfiguring named could fail on + some platforms when LMDB was in use. [RT #45203] + +4637. [func] "nsec3hash -r" option ("rdata order") takes arguments + in the same order as they appear in NSEC3 or + NSEC3PARAM records, so that NSEC3 parameters can + be cut and pasted from an existing record. Thanks + to Tony Finch for the contribution. [RT #45183] + +4636. [bug] Normalize rpz policy zone names when checking for + existence. [RT #45358] + +4635. [bug] Fix RPZ NSDNAME logging that was logging + failures as NSIP. [RT #45052] + +4634. [contrib] check5011.pl needs to handle optional space before + semi-colon in +multi-line output. [RT #45352] + +4633. [maint] Updated AAAA (2001:500:200::b) for B.ROOT-SERVERS.NET. + +4632. [security] The BIND installer on Windows used an unquoted + service path, which can enable privilege escalation. + (CVE-2017-3141) [RT #45229] + +4631. [security] Some RPZ configurations could go into an infinite + query loop when encountering responses with TTL=0. + (CVE-2017-3140) [RT #45181] + +4630. [bug] "dyndb" is dependent on dlopen existing / being + enabled. [RT #45291] + +4629. [bug] dns_client_startupdate could not be called with a + running client. [RT #45277] + +4628. [bug] Fixed a potential reference leak in query_getdb(). + [RT #45247] + +4627. [placeholder] + +4626. [test] Added more tests for handling of different record + ordering in CNAME and DNAME responses. [QA #430] + +4625. [bug] Running "rndc addzone" and "rndc delzone" at close + to the same time could trigger a deadlock if using + LMDB. [RT #45209] + +4624. [placeholder] + +4623. [bug] Use --with-protobuf-c and --with-libfstrm to find + protoc-c and fstrm_capture. [RT #45187] + +4622. [bug] Remove unnecessary escaping of semicolon in CAA and + URI records. [RT #45216] + +4621. [port] Force alignment of oid arrays to silence loader + warnings. [RT #45131] + +4620. [port] Handle EPFNOSUPPORT being returned when probing + to see if a socket type is supported. [RT #45214] + +4619. [bug] Call isc_mem_put instead of isc_mem_free in + bin/named/server.c:setup_newzones. [RT #45202] + +4618. [bug] Check isc_mem_strdup results in dns_view_setnewzones. + Add logging for lmdb call failures. [RT #45204] + +4617. [test] Update rndc system test to be more delay tolerant. + [RT #45177] + +4616. [bug] When using LMDB, zones deleted using "rndc delzone" + were not correctly removed from the new-zone + database. [RT #45185] + +4615. [bug] AD could be set on truncated answer with no records + present in the answer and authority sections. + [RT #45140] + +4614. [test] Fixed an error in the sockaddr unit test. [RT #45146] + +4613. [func] By default, the maximum size of a zone journal file + is now twice the size of the zone's contents (there + is little benefit to a journal larger than this). + This can be overridden by setting "max-journal-size" + to "unlimited" or to an explicit value up to 2G. + Thanks to Tony Finch. [RT #38324] + +4612. [bug] Silence 'may be use uninitalised' warning and simplify + the code in lwres/getaddinfo:process_answer. + [RT #45158] + +4611. [bug] The default LMDB mapsize was too low and caused + errors after few thousand zones were added using + rndc addzone. A new config option "lmdb-mapsize" + has been introduced to configure the LMDB + mapsize depending on operational needs. + [RT #44954] + +4610. [func] The "new-zones-directory" option specifies the + location of NZF or NZD files for storing + configuration of zones added by "rndc addzone". + Thanks to Petr Menšík. [RT #44853] + +4609. [cleanup] Rearrange makefiles to enable parallel execution + (i.e. "make -j"). [RT #45078] + +4608. [func] DiG now warns about .local queries which are reserved + for Multicast DNS. [RT #44783] + +4607. [bug] The memory context's malloced and maxmalloced counters + were being updated without the appropriate lock being + held. [RT #44869] + +4606. [port] Stop using experimental "Experimental keys on scalar" + feature of perl as it has been removed. [RT #45012] + +4605. [performance] Improve performance for delegation heavy answers + and also general query performance. Removes the + acache feature that didn't significantly improve + performance. Adds a glue cache. Removes + additional-from-cache and additional-from-auth + features. Enables minimal-responses by + default. Improves performance of compression + code, owner case restoration, hash function, + etc. Uses inline buffer implementation by + default. Many other performance changes and fixes. + [RT #44029] + +4604. [bug] Don't use ERR_load_crypto_strings() when building + with OpenSSL 1.1.0. [RT #45117] + +4603. [doc] Automatically generate named.conf(5) man page + from doc/misc/options. Thanks to Tony Finch. + [RT #43525] + +4602. [func] Threads are now set to human-readable + names to assist debugging, when supported by + the OS. [RT #43234] + +4601. [bug] Reject incorrect RSA key lengths during key + generation and and sign/verify context + creation. [RT #45043] + +4600. [bug] Adjust RPZ trigger counts only when the entry + being deleted exists. [RT #43386] + +4599. [bug] Fix inconsistencies in inline signing time + comparison that were introduced with the + introduction of rdatasetheader->resign_lsb. + [RT #42112] + +4598. [func] Update fuzzing code to (1) reply to a DNSKEY + query from named with appropriate DNSKEY used in + fuzzing; (2) patch the QTYPE correctly in + resolver fuzzing; (3) comment things so the rest + of us are able to understand how fuzzing is + implemented in named; (4) Coding style changes, + cleanup, etc. [RT #44787] + +4597. [bug] The validator now ignores SHA-1 DS digest type + when a DS record with SHA-384 digest type is + present and is a supported digest type. + [RT #45017] + +4596. [bug] Validate glue before adding it to the additional + section. This also fixes incorrect TTL capping + when the RRSIG expired earlier than the TTL. + [RT #45062] + +4595. [func] dnssec-keygen will no longer generate RSA keys + less than 1024 bits in length. dnssec-keymgr + was similarly updated. [RT #36895] + +4594. [func] "dnstap-read -x" prints a hex dump of the wire + format of each logged DNS message. [RT #44816] + +4593. [doc] Update README using markdown, remove outdated FAQ + file in favor of the knowledge base. + +4592. [bug] A race condition on shutdown could trigger an + assertion failure in dispatch.c. [RT #43822] + +4591. [port] Addressed some python 3 compatibility issues. + Thanks to Ville Skytta. [RT #44955] [RT #44956] + +4590. [bug] Support for PTHREAD_MUTEX_ADAPTIVE_NP was not being + properly detected. [RT #44871] + +4589. [cleanup] "configure -q" is now silent. [RT #44829] + +4588. [bug] nsupdate could send queries for TKEY to the wrong + server when using GSSAPI. Thanks to Tomas Hozza. + [RT #39893] + +4587. [bug] named-checkzone failed to handle occulted data below + DNAMEs correctly. [RT #44877] + +4586. [func] dig, host and nslookup now use TCP for ANY queries. + [RT #44687] + +4585. [port] win32: Set CompileAS value. [RT #42474] + +4584. [bug] A number of memory usage statistics were not properly + reported when they exceeded 4G. [RT #44750] + +4583. [func] "host -A" returns most records for a name but + omits RRSIG, NSEC and NSEC3. (Thanks to Tony Finch.) + [RT #43032] + +4582. [security] 'rndc ""' could trigger a assertion failure in named. + (CVE-2017-3138) [RT #44924] + +4581. [port] Linux: Add getpid and getrandom to the list of system + calls named uses for seccomp. [RT #44883] + +4580. [bug] 4578 introduced a regression when handling CNAME to + referral below the current domain. [RT #44850] + +4579. [func] Logging channels and dnstap output files can now + be configured with a "suffix" option, set to + either "increment" or "timestamp", indicating + whether to use incrementing numbers or timestamps + as the file suffix when rolling over a log file. + [RT #42838] + +4578. [security] Some chaining (CNAME or DNAME) responses to upstream + queries could trigger assertion failures. + (CVE-2017-3137) [RT #44734] + +4577. [func] Make qtype of resolver fuzzing packet configurable + via command line. [RT #43540] + +4576. [func] The RPZ implementation has been substantially + refactored for improved performance and reliability. + [RT #43449] + +4575. [security] DNS64 with "break-dnssec yes;" can result in an + assertion failure. (CVE-2017-3136) [RT #44653] + +4574. [bug] Dig leaked memory with multiple +subnet options. + [RT #44683] + +4573. [func] Query logic has been substantially refactored (e.g. + query_find function has been split into smaller + functions) for improved readability, maintainability + and testability. [RT #43929] + +4572. [func] The "dnstap-output" option can now take "size" and + "versions" parameters to indicate the maximum size + a dnstap log file can grow before rolling to a new + file, and how many old files to retain. [RT #44502] + +4571. [bug] Out-of-tree builds of backtrace_test failed. + +4570. [cleanup] named did not correctly fall back to the built-in + initializing keys if the bind.keys file was present + but empty. [RT #44531] + +4569. [func] Store both local and remote addresses in dnstap + logging, and modify dnstap-read output format to + print them. [RT #43595] + +4568. [contrib] Added a --with-bind option to the dnsperf configure + script to specify BIND prefix path. + +4567. [port] Call getprotobyname and getservbyname prior to calling + chroot so that shared libraries get loaded. [RT #44537] + +4566. [func] Query logging now includes the ECS option if one + was included in the query. [RT #44476] + +4565. [cleanup] The inline macro versions of isc_buffer_put*() + did not implement automatic buffer reallocation. + [RT #44216] + +4564. [maint] Update the built in managed keys to include the + upcoming root KSK. [RT #44579] + +4563. [bug] Modified zones would occasionally fail to reload. + [RT #39424] + +4562. [func] Add additional memory statistics currently malloced + and maxmalloced per memory context. [RT #43593] + +4561. [port] Silence a warning in strict C99 compilers. [RT #44414] + +4560. [bug] mdig: add -m option to enable memory debugging rather + than having it on all the time. [RT #44509] + +4559. [bug] openssl_link.c didn't compile if ISC_MEM_TRACKLINES + was turned off. [RT #44509] + +4558. [bug] Synthesised CNAME before matching DNAME was still + being cached when it should not have been. [RT #44318] + +4557. [security] Combining dns64 and rpz can result in dereferencing + a NULL pointer (read). (CVE-2017-3135) [RT#44434] + +4556. [bug] Sending an EDNS Padding option using "dig + +ednsopt" could cause a crash in dig. [RT #44462] + +4555. [func] dig +ednsopt: EDNS options can now be specified by + name in addition to numeric value. [RT #44461] + +4554. [bug] Remove double unlock in dns_dispatchmgr_setudp. + [RT #44336] + +4553. [bug] Named could deadlock there were multiple changes to + NSEC/NSEC3 parameters for a zone being processed at + the same time. [RT #42770] + +4552. [bug] Named could trigger a assertion when sending notify + messages. [RT #44019] + +4551. [test] Add system tests for integrity checks of MX and + SRV records. [RT #43953] + +4550. [cleanup] Increased the number of available master file + output style flags from 32 to 64. [RT #44043] + +4549. [func] Added support for the EDNS TCP Keepalive option + (RFC 7828). [RT #42126] + +4548. [func] Added support for the EDNS Padding option (RFC 7830). + [RT #42094] + +4547. [port] Add support for --enable-native-pkcs11 on the AEP + Keyper HSM. [RT #42463] + +4546. [func] Extend the use of const declarations. [RT #43379] + +4545. [func] Expand YAML output from dnstap-read to include + a detailed breakdown of the DNS message contents. + [RT #43642] + +4544. [bug] Add message/payload size to dnstap-read YAML output. + [RT #43622] + +4543. [bug] dns_client_startupdate now delays sending the update + request until isc_app_ctxrun has been called. + [RT #43976] + +4542. [func] Allow rndc to manipulate redirect zones with using + -redirect as the zone name (use "-redirect." to + manipulate a zone named "-redirect"). [RT #43971] + +4541. [bug] rndc addzone should properly reject non master/slave + zones. [RT #43665] + +4540. [bug] Correctly handle ecs entries in dns_acl_isinsecure. + [RT #43601] + +4539. [bug] Referencing a nonexistent zone with RPZ could lead + to a assertion failure when configuring. [RT #43787] + +4538. [bug] Call dns_client_startresolve from client->task. + [RT #43896] + +4537. [bug] Handle timeouts better in dig/host/nslookup. [RT #43576] + +4536. [bug] ISC_SOCKEVENTATTR_USEMINMTU was not being cleared + when reusing the event structure. [RT #43885] + +4535. [bug] Address race condition in setting / testing of + DNS_REQUEST_F_SENDING. [RT #43889] + +4534. [bug] Only set RD, RA and CD in QUERY responses. [RT #43879] + +4533. [bug] dns_client_update should terminate on prerequisite + failures (NXDOMAIN, YXDOMAIN, NXRRSET, YXRRSET) + and also on BADZONE. [RT #43865] + +4532. [contrib] Make gen-data-queryperf.py python 3 compatible. + [RT #43836] + +4531. [security] 'is_zone' was not being properly updated by redirect2 + and subsequently preserved leading to an assertion + failure. (CVE-2016-9778) [RT #43837] + +4530. [bug] Change 4489 broke the handling of CNAME -> DNAME + in responses resulting in SERVFAIL being returned. + [RT #43779] + +4529. [cleanup] Silence noisy log warning when DSCP probe fails + due to firewall rules. [RT #43847] + +4528. [bug] Only set the flag bits for the i/o we are waiting + for on EPOLLERR or EPOLLHUP. [RT #43617] + +4527. [doc] Support DocBook XSL Stylesheets v1.79.1. [RT #43831] + +4526. [doc] Corrected errors and improved formatting of + grammar definitions in the ARM. [RT #43739] + +4525. [doc] Fixed outdated documentation on managed-keys. + [RT #43810] + +4524. [bug] The net zero test was broken causing IPv4 servers + with addresses ending in .0 to be rejected. [RT #43776] + +4523. [doc] Expand config doc for and + . [RT #43768] + +4522. [bug] Handle big gaps in log file version numbers better. + [RT #38688] + +4521. [cleanup] Log it as an error if an entropy source is not + found and there is no fallback available. [RT #43659] + +4520. [cleanup] Alphabetize more of the grammar when printing it + out. Fix unbalanced indenting. [RT #43755] + +4519. [port] win32: handle ERROR_MORE_DATA. [RT #43534] + +4518. [func] The "print-time" option in the logging configuration + can now take arguments "local", "iso8601" or + "iso8601-utc" to indicate the format in which the + date and time should be logged. For backward + compatibility, "yes" is a synonym for "local". + [RT #42585] + +4517. [security] Named could mishandle authority sections that were + missing RRSIGs triggering an assertion failure. + (CVE-2016-9444) [RT # 43632] + +4516. [bug] isc_socketmgr_renderjson was missing from the + windows build. [RT #43602] + +4515. [port] FreeBSD: Find readline headers when they are in + edit/readline/ instead of readline/. [RT #43658] + +4514. [port] NetBSD: strip -WL, from ld command line. [RT #43204] + +4513. [cleanup] Minimum Python versions are now 2.7 and 3.2. + [RT #43566] + +4512. [bug] win32: @GEOIP_INC@ missing from delv.vcxproj.in. + [RT #43556] + +4511. [bug] win32: mdig.exe-BNFT was missing Configure. [RT #43554] + +4510. [security] Named mishandled some responses where covering RRSIG + records are returned without the requested data + resulting in a assertion failure. (CVE-2016-9147) + [RT #43548] + +4509. [test] Make the rrl system test more reliable on slower + machines by using mdig instead of dig. [RT #43280] + +4508. [security] Named incorrectly tried to cache TKEY records which + could trigger a assertion failure when there was + a class mismatch. (CVE-2016-9131) [RT #43522] + +4507. [bug] Named could incorrectly log 'allows updates by IP + address, which is insecure' [RT #43432] + +4506. [func] 'named-checkconf -l' will now list the zones found in + named.conf. [RT #43154] + +4505. [port] Use IP_PMTUDISC_OMIT if available. [RT #35494] + +4504. [security] Allow the maximum number of records in a zone to + be specified. This provides a control for issues + raised in CVE-2016-6170. [RT #42143] + +4503. [cleanup] "make uninstall" now removes files installed by + BIND. (This currently excludes Python files + due to lack of support in setup.py.) [RT #42192] + +4502. [func] Report multiple and experimental options when printing + grammar. [RT #43134] + +4501. [placeholder] + +4500. [bug] Support modifier I64 in isc__print_printf. [RT #43526] + +4499. [port] MacOSX: silence deprecated function warning + by using arc4random_stir() when available + instead of arc4random_addrandom(). [RT #43503] + +4498. [test] Simplify prerequisite checks in system tests. + [RT #43516] + +4497. [port] Add support for OpenSSL 1.1.0. [RT #41284] + +4496. [func] dig: add +idnout to control whether labels are + display in punycode or not. Requires idn support + to be enabled at compile time. [RT #43398] + +4495. [bug] A isc_mutex_init call was not being checked. + [RT #43391] + +4494. [bug] Look for . [RT #43429] + +4493. [bug] bin/tests/system/dyndb/driver/Makefile.in should use + SO_TARGETS. [RT# 43336] + +4492. [bug] irs_resconf_load failed to initialize sortlistnxt + causing bad writes if resolv.conf contained a + sortlist directive. [RT #43459] + +4491. [bug] Improve message emitted when testing whether sendmsg + works with TOS/TCLASS fails. [RT #43483] + +4490. [maint] Added AAAA (2001:500:12::d0d) for G.ROOT-SERVERS.NET. + +4489. [security] It was possible to trigger assertions when processing + a response containing a DNAME answer. (CVE-2016-8864) + [RT #43465] + +4488. [port] Darwin: use -framework for Kerberos. [RT #43418] + +4487. [test] Make system tests work on Windows. [RT #42931] + +4486. [bug] Look in $prefix/lib/pythonX.Y/site-packages for + the python modules we install. [RT #43330] + +4485. [bug] Failure to find readline when requested should be + fatal to configure. [RT #43328] + +4484. [func] Check prefixes in acls to make sure the address and + prefix lengths are consistent. Warn only in + BIND 9.11 and earlier. [RT #43367] + +4483. [bug] Address use before require check and remove extraneous + dns_message_gettsigkey call in dns_tsig_sign. + [RT #43374] + +4482. [cleanup] Change #4455 was incomplete. [RT #43252] + +4481. [func] dig: make +class, +crypto, +multiline, +rrcomments, + +onesoa, +qr, +ttlid, +ttlunits and -u per lookup + rather than global. [RT #42450] + +4480. [placeholder] + +4479. [placeholder] + +4478. [func] Add +continue option to mdig, allow continue on socket + errors. [RT #43281] + +4477. [test] Fix mkeys test timing issues. [RT #41028] + +4476. [test] Fix reclimit test on slower machines. [RT #43283] + +4475. [doc] Update named-checkconf documentation. [RT #43153] + +4474. [bug] win32: call WSAStartup in fromtext_in_wks so that + getprotobyname and getservbyname work. [RT #43197] + +4473. [bug] Only call fsync / _commit on regular files. [RT #43196] + +4472. [bug] Named could fail to find the correct NSEC3 records when + a zone was updated between looking for the answer and + looking for the NSEC3 records proving nonexistence + of the answer. [RT #43247] + + --- 9.11.0 released --- + + --- 9.11.0rc3 released --- + +4471. [cleanup] Render client/query logging format consistent for + ease of log file parsing. (Note that this affects + "querylog" format: there is now an additional field + indicating the client object address.) [RT #43238] + +4470. [bug] Reset message with intent parse before + calling dns_dispatch_getnext. [RT #43229] + +4469. [placeholder] + + --- 9.11.0rc2 released --- + +4468. [bug] Address ECS option handling issues. [RT #43191] + +4467. [security] It was possible to trigger an assertion when + rendering a message. (CVE-2016-2776) [RT #43139] + +4466. [bug] Interface scanning didn't work on a Windows system + without a non local IPv6 addresses. [RT #43130] + +4465. [bug] Don't use "%z" as Windows doesn't support it. + [RT #43131] + +4464. [bug] Fix windows python support. [RT #43173] + +4463. [bug] The dnstap system test failed on some systems. + [RT #43129] + +4462. [bug] Don't describe a returned EDNS COOKIE as "good" + when there isn't a valid server cookie. [RT #43167] + +4461. [bug] win32: not all external data was properly marked + as external data for windows dll. [RT #43161] + + --- 9.11.0rc1 released --- + +4460. [test] Add system test for dnstap using unix domain sockets. + [RT #42926] + +4459. [bug] TCP client objects created to handle pipeline queries + were not cleaned up correctly, causing uncontrolled + memory growth. [RT #43106] + +4458. [cleanup] Update assertions to be more correct, and also remove + use of a reserved word. [RT #43090] + +4457. [maint] Added AAAA (2001:500:a8::e) for E.ROOT-SERVERS.NET. + +4456. [doc] Add DOCTYPE and lang attribute to tags. + [RT #42587] + +4455. [cleanup] Allow dyndb modules to correctly log the filename + and line number when processing configuration text + from named.conf. [RT #43050] + +4454. [bug] 'rndc dnstap -reopen' had a race issue. [RT #43089] + +4453. [bug] Prefetching of DS records failed to update their + RRSIGs. [RT #42865] + +4452. [bug] The default key manager policy file is now + /dnssec-policy.conf (usually + /etc/dnssec-policy.conf). [RT #43064] + +4451. [cleanup] Log more useful information if a PKCS#11 provider + library cannot be loaded. [RT #43076] + +4450. [port] Provide more nuanced HSM support which better matches + the specific PKCS11 providers capabilities. [RT #42458] + +4449. [test] Fix catalog zones test on slower systems. [RT #42997] + +4448. [bug] win32: ::1 was not being found when iterating + interfaces. [RT #42993] + +4447. [tuning] Allow the fstrm_iothr_init() options to be set using + named.conf to control how dnstap manages the data + flow. [RT #42974] + +4446. [bug] The cache_find() and _findrdataset() functions + could find rdatasets that had been marked stale. + [RT #42853] + +4445. [cleanup] isc_errno_toresult() can now be used to call the + formerly private function isc__errno2result(). + [RT #43050] + +4444. [bug] Fixed some issues related to dyndb: A bug caused + braces to be omitted when passing configuration text + from named.conf to a dyndb driver, and there was a + use-after-free in the sample dyndb driver. [RT #43050] + +4443. [func] Set TCP_MAXSEG in addition to IPV6_USE_MIN_MTU on + TCP sockets. [RT #42864] + +4442. [bug] Fix RPZ CIDR tree insertion bug that corrupted + tree data structure with overlapping networks + (longest prefix match was ineffective). + [RT #43035] + +4441. [cleanup] Alphabetize host's help output. [RT #43031] + +4440. [func] Enable TCP fast open support when available on the + server side. [RT #42866] + +4439. [bug] Address race conditions getting ownernames of nodes. + [RT #43005] + +4438. [func] Use LIFO rather than FIFO when processing startup + notify and refresh queries. [RT #42825] + +4437. [func] Minimal-responses now has two additional modes + no-auth and no-auth-recursive which suppress + adding the NS records to the authority section + as well as the associated address records for the + nameservers. [RT #42005] + +4436. [func] Return TLSA records as additional data for MX and SRV + lookups. [RT #42894] + +4435. [tuning] Only set IPV6_USE_MIN_MTU for UDP when the message + will not fit into a single IPv4 encapsulated IPv6 + UDP packet when transmitted over a Ethernet link. + [RT #42871] + +4434. [protocol] Return EDNS EXPIRE option for master zones in addition + to slave zones. [RT #43008] + +4433. [cleanup] Report an error when passing an invalid option or + view name to "rndc dumpdb". [RT #42958] + +4432. [test] Hide rndc output on expected failures in logfileconfig + system test. [RT #27996] + +4431. [bug] named-checkconf now checks the rate-limit clause. + [RT #42970] + +4430. [bug] Lwresd died if a search list was not defined. + Found by 0x710DDDD At Alibaba Security. [RT #42895] + +4429. [bug] Address potential use after free on fclose() error. + [RT #42976] + +4428. [bug] The "test dispatch getnext" unit test could fail + in a threaded build. [RT #42979] + +4427. [bug] The "query" and "response" parameters to the + "dnstap" option had their functions reversed. + + --- 9.11.0b3 released --- + +4426. [bug] Addressed Coverity warnings. [RT #42908] + +4425. [bug] arpaname, dnstap-read and named-rrchecker were not + being installed into ${prefix}/bin. Tidy up + installation issues with CHANGE 4421. [RT #42910] + +4424. [experimental] Named now sends _ta-XXXX./NULL queries + to provide feedback to the trust-anchor administrators + about how key rollovers are progressing as per + draft-ietf-dnsop-edns-key-tag-02. This can be + disabled using 'trust-anchor-telemetry no;'. + [RT #40583] + +4423. [maint] Added missing IPv6 address 2001:500:84::b for + B.ROOT-SERVERS.NET. [RT #42898] + +4422. [port] Silence clang warnings in dig.c and dighost.c. + [RT #42451] + +4421. [func] When built with LMDB (Lightning Memory-mapped + Database), named will now use a database to store + the configuration for zones added by "rndc addzone" + instead of using a flat NZF file. This improves + performance of "rndc delzone" and "rndc modzone" + significantly. Existing NZF files will + automatically by converted to NZD databases. + To view the contents of an NZD or to roll back to + NZF format, use "named-nzd2nzf". To disable + this feature, use "configure --without-lmdb". + [RT #39837] + +4420. [func] nslookup now looks for AAAA as well as A by default. + [RT #40420] + +4419. [bug] Don't cause undefined result if the label of an + entry in catalog zone is changed. [RT #42708] + +4418. [bug] Fix a compiler warning in GSSAPI code. [RT #42879] + +4417. [bug] dnssec-keymgr could fail to create successor keys + if the prepublication interval was set to a value + smaller than the default. [RT #42820] + +4416. [bug] dnssec-keymgr: Domain names in policy files could + fail to match due to trailing dots. [RT #42807] + +4415. [bug] dnssec-keymgr: Expired/deleted keys were not always + excluded. [RT #42884] + +4414. [bug] Corrected a bug in the MIPS implementation of + isc_atomic_xadd(). [RT #41965] + +4413. [bug] GSSAPI negotiation could fail if GSS_S_CONTINUE_NEEDED + was returned. [RT #42733] + + --- 9.11.0b2 released --- + +4412. [cleanup] Make fixes for GCC 6. ISC_OFFSET_MAXIMUM macro was + removed. [RT #42721] + +4411. [func] "rndc dnstap -roll" automatically rolls the + dnstap output file; the previous version is + saved with ".0" suffix, and earlier versions + with ".1" and so on. An optional numeric argument + indicates how many prior files to save. [RT #42830] + +4410. [bug] Address use after free and memory leak with dnstap. + [RT #42746] + +4409. [bug] DNS64 should exclude mapped addresses by default when + an exclude acl is not defined. [RT #42810] + +4408. [func] Continue waiting for expected response when we the + response we get does not match the request. [RT #41026] + +4407. [performance] Use GCC builtin for clz in RPZ lookup code. + [RT #42818] + +4406. [security] getrrsetbyname with a non absolute name could + trigger an infinite recursion bug in lwresd + and named with lwres configured if when combined + with a search list entry the resulting name is + too long. (CVE-2016-2775) [RT #42694] + +4405. [bug] Change 4342 introduced a regression where you could + not remove a delegation in a NSEC3 signed zone using + OPTOUT via nsupdate. [RT #42702] + +4404. [misc] Allow krb5-config to be used when configuring gssapi. + [RT #42580] + +4403. [bug] Rename variables and arguments that shadow: basename, + clone and gai_error. + +4402. [bug] protoc-c is now a hard requirement for --enable-dnstap. + + --- 9.11.0b1 released --- + +4401. [misc] Change LICENSE to MPL 2.0. + +4400. [bug] ttl policy was not being inherited in policy.py. + [RT #42718] + +4399. [bug] policy.py 'ECCGOST', 'ECDSAP256SHA256', and + 'ECDSAP384SHA384' don't have settable keysize. + [RT #42718] + +4398. [bug] Correct spelling of ECDSAP256SHA256 in policy.py. + [RT #42718] + +4397. [bug] Update Windows python support. [RT #42538] + +4396. [func] dnssec-keymgr now takes a '-r randomfile' option. + [RT #42455] + +4395. [bug] Improve out-of-tree installation of python modules. + [RT #42586] + +4394. [func] Add rndc command "dnstap-reopen" to close and + reopen dnstap output files. [RT #41803] + +4393. [bug] Address potential NULL pointer dereferences in + dnstap code. + +4392. [func] Collect statistics for RSSAC02v3 traffic-volume, + traffic-sizes and rcode-volume reporting. [RT #41475] + +4391. [contrib] Fix leaks in contrib DLZ code. [RT #42707] + +4390. [doc] Description of masters with TSIG, allow-query and + allow-transfer options in catalog zones. [RT #42692] + +4389. [test] Rewritten test suite for catalog zones. [RT #42676] + +4388. [func] Support for master entries with TSIG keys in catalog + zones. [RT #42577] + +4387. [bug] Change 4336 was not complete leading to SERVFAIL + being return as NS records expired. [RT #42683] + +4386. [bug] Remove shadowed overmem function/variable. [RT #42706] + +4385. [func] Add support for allow-query and allow-transfer ACLs + to catalog zones. [RT #42578] + +4384. [bug] Change 4256 accidentally disabled logging of the + rndc command. [RT #42654] + +4383. [bug] Correct spelling error in stats channel description of + "EDNS client subnet option received". [RT #42633] + +4382. [bug] rndc {addzone,modzone,delzone,showzone} should all + compare the zone name using a canonical format. + [RT #42630] + +4381. [bug] Missing "zone-directory" option in catalog zone + definition caused BIND to crash. [RT #42579] + + --- 9.11.0a3 released --- + +4380. [experimental] Added a "zone-directory" option to "catalog-zones" + syntax, allowing local masterfiles for slaves + that are provisioned by catalog zones to be stored + in a directory other than the server's working + directory. [RT #42527] + +4379. [bug] An INSIST could be triggered if a zone contains + RRSIG records with expiry fields that loop + using serial number arithmetic. [RT #40571] + +4378. [contrib] #include for strlcat in zone2ldap.c. + [RT #42525] + +4377. [bug] Don't reuse zero TTL responses beyond the current + client set (excludes ANY/SIG/RRSIG queries). + [RT #42142] + +4376. [experimental] Added support for Catalog Zones, a new method for + provisioning secondary servers in which a list of + zones to be served is stored in a DNS zone and can + be propagated to slaves via AXFR/IXFR. [RT #41581] + +4375. [func] Add support for automatic reallocation of isc_buffer + to isc_buffer_put* functions. [RT #42394] + +4374. [bug] Use SAVE/RESTORE macros in query.c to reduce the + probability of reference counting errors as seen + in 4365. [RT #42405] + +4373. [bug] Address undefined behavior in getaddrinfo. [RT #42479] + +4372. [bug] Address undefined behavior in libt_api. [RT #42480] + +4371. [func] New "minimal-any" option reduces the size of UDP + responses for qtype ANY by returning a single + arbitrarily selected RRset instead of all RRsets. + Thanks to Tony Finch. [RT #41615] + +4370. [bug] Address python3 compatibility issues with RNDC module. + [RT #42499] [RT #42506] + + --- 9.11.0a2 released --- + +4369. [bug] Fix 'make' and 'make install' out-of-tree python + support. [RT #42484] + +4368. [bug] Fix a crash when calling "rndc stats" on some + Windows builds because some Visual Studio compilers + generated crashing code for the "%z" printf() + format specifier. [RT #42380] + +4367. [bug] Remove unnecessary assignment of loadtime in + zone_touched. [RT #42440] + +4366. [bug] Address race condition when updating rbtnode bit + fields. [RT #42379] + +4365. [bug] Address zone reference counting errors involving + nxdomain-redirect. [RT #42258] + +4364. [port] freebsd: add -Wl,-E to loader flags [RT #41690] + +4363. [port] win32: Disable explicit triggering UAC when running + BINDInstall. + +4362. [func] Changed rndc reconfig behavior so that newly added + zones are loaded asynchronously and the loading does + not block the server. [RT #41934] + +4361. [cleanup] Where supported, file modification times returned + by isc_file_getmodtime() are now accurate to the + nanosecond. [RT #41968] + +4360. [bug] Silence spurious 'bad key type' message when there is + a existing TSIG key. [RT #42195] + +4359. [bug] Inherited 'also-notify' lists were not being checked + by named-checkconf. [RT #42174] + +4358. [test] Added American Fuzzy Lop harness that allows + feeding fuzzed packets into BIND. + [RT #41723] + +4357. [func] Add the python RNDC module. [RT #42093] + +4356. [func] Add the ability to specify whether to wait for + nameserver addresses to be looked up or not to + RPZ with a new modifying directive 'nsip-wait-recurse'. + [RT #35009] + +4355. [func] "pkcs11-list" now displays the extractability + attribute of private or secret keys stored in + an HSM, as either "true", "false", or "never" + Thanks to Daniel Stirnimann. [RT #36557] + +4354. [bug] Check that the received HMAC length matches the + expected length prior to check the contents on the + control channel. This prevents a OOB read error. + This was reported by Lian Yihan, . + [RT #42215] + +4353. [cleanup] Update PKCS#11 header files. [RT #42175] + +4352. [cleanup] The ISC DNSSEC Lookaside Validation (DLV) service + is scheduled to be disabled in 2017. A warning is + now logged when named is configured to use it, + either explicitly or via "dnssec-lookaside auto;" + [RT #42207] + +4351. [bug] 'dig +noignore' didn't work. [RT #42273] + +4350. [contrib] Declare result in dlz_filesystem_dynamic.c. + +4349. [contrib] kasp2policy: A python script to create a DNSSEC + policy file from an OpenDNSSEC KASP XML file. + +4348. [func] dnssec-keymgr: A new python-based DNSSEC key + management utility, which reads a policy definition + file and can create or update DNSSEC keys as needed + to ensure that a zone's keys match policy, roll over + correctly on schedule, etc. Thanks to Sebastian + Castro for assistance in development. [RT #39211] + +4347. [port] Corrected a build error on x86_64 Solaris. [RT #42150] + +4346. [bug] Fixed a regression introduced in change #4337 which + caused signed domains with revoked KSKs to fail + validation. [RT #42147] + +4345. [contrib] perftcpdns mishandled the return values from + clock_nanosleep. [RT #42131] + +4344. [port] Address openssl version differences. [RT #42059] + +4343. [bug] dns_dnssec_syncupdate mis-declared in . + [RT #42090] + +4342. [bug] 'rndc flushtree' could fail to clean the tree if there + wasn't a node at the specified name. [RT #41846] + + --- 9.11.0a1 released --- + +4341. [bug] Correct the handling of ECS options with + address family 0. [RT #41377] + +4340. [performance] Implement adaptive read-write locks, reducing the + overhead of locks that are only held briefly. + [RT #37329] + +4339. [test] Use "mdig" to test pipelined queries. [RT #41929] + +4338. [bug] Reimplement change 4324 as it wasn't properly doing + all the required book keeping. [RT #41941] + +4337. [bug] The previous change exposed a latent flaw in + key refresh queries for managed-keys when + a cached DNSKEY had TTL 0. [RT #41986] + +4336. [bug] Don't emit records with zero ttl unless the records + were learnt with a zero ttl. [RT #41687] + +4335. [bug] zone->view could be detached too early. [RT #41942] + +4334. [func] 'named -V' now reports zlib version. [RT #41913] + +4333. [maint] L.ROOT-SERVERS.NET is now 199.7.83.42 and + 2001:500:9f::42. + +4332. [placeholder] + +4331. [func] When loading managed signed zones detect if the + RRSIG's inception time is in the future and regenerate + the RRSIG immediately. [RT #41808] + +4330. [protocol] Identify the PAD option as "PAD" when printing out + a message. + +4329. [func] Warn about a common misconfiguration when forwarding + RFC 1918 zones. [RT #41441] + +4328. [performance] Add dns_name_fromwire() benchmark test. [RT #41694] + +4327. [func] Log query and depth counters during fetches when + querytrace (./configure --enable-querytrace) is + enabled (helps in diagnosing). [RT #41787] + +4326. [protocol] Add support for AVC. [RT #41819] + +4325. [func] Add a line to "rndc status" indicating the + hostname and operating system details. [RT #41610] + +4324. [bug] When deleting records from a zone database, interior + nodes could be left empty but not deleted, damaging + search performance afterward. [RT #40997] + +4323. [bug] Improve HTTP header processing on statschannel. + [RT #41674] + +4322. [security] Duplicate EDNS COOKIE options in a response could + trigger an assertion failure. (CVE-2016-2088) + [RT #41809] + +4321. [bug] Zones using mapped files containing out-of-zone data + could return SERVFAIL instead of the expected NODATA + or NXDOMAIN results. [RT #41596] + +4320. [bug] Insufficient memory allocation when handling + "none" ACL could cause an assertion failure in + named when parsing ACL configuration. [RT #41745] + +4319. [security] Fix resolver assertion failure due to improper + DNAME handling when parsing fetch reply messages. + (CVE-2016-1286) [RT #41753] + +4318. [security] Malformed control messages can trigger assertions + in named and rndc. (CVE-2016-1285) [RT #41666] + +4317. [bug] Age all unused servers on fetch timeout. [RT #41597] + +4316. [func] Add option to tools to print RRs in unknown + presentation format [RT #41595]. + +4315. [bug] Check that configured view class isn't a meta class. + [RT #41572]. + +4314. [contrib] Added 'dnsperf-2.1.0.0-1', a set of performance + testing tools provided by Nominum, Inc. + +4313. [bug] Handle ns_client_replace failures in test mode. + [RT #41190] + +4312. [bug] dig's unknown DNS and EDNS flags (MBZ value) logging + was not consistent. [RT #41600] + +4311. [bug] Prevent "rndc delzone" from being used on + response-policy zones. [RT #41593] + +4310. [performance] Use __builtin_expect() where available to annotate + conditions with known behavior. [RT #41411] + +4309. [cleanup] Remove the spurious "none" filename from log messages + when processing built-in configuration. [RT #41594] + +4308. [func] Added operating system details to "named -V" + output. [RT #41452] + +4307. [bug] "dig +subnet" and "mdig +subnet" could send + incorrectly-formatted Client Subnet options + if the prefix length was not divisible by 8. + Also fixed a memory leak in "mdig". [RT #45178] + +4306. [maint] Added a PKCS#11 openssl patch supporting + version 1.0.2f [RT #38312] + +4305. [bug] dnssec-signzone was not removing unnecessary rrsigs + from the zone's apex. [RT #41483] + +4304. [port] xfer system test failed as 'tail -n +value' is not + portable. [RT #41315] + +4303. [bug] "dig +subnet" was unable to send a prefix length of + zero, as it was incorrectly changed to 32 for v4 + prefixes or 128 for v6 prefixes. In addition to + fixing this, "dig +subnet=0" has been added as a + short form for 0.0.0.0/0. The same changes have + also been made in "mdig". [RT #41553] + +4302. [port] win32: fixed a build error in VS 2015. [RT #41426] + +4301. [bug] dnssec-settime -p [DP]sync was not working. [RT #41534] + +4300. [bug] A flag could be set in the wrong field when setting + up non-recursive queries; this could cause the + SERVFAIL cache to cache responses it shouldn't. + New querytrace logging has been added which + identified this error. [RT #41155] + +4299. [bug] Check that exactly totallen bytes are read when + reading a RRset from raw files in both single read + and incremental modes. [RT #41402] + +4298. [bug] dns_rpz_add errors in loadzone were not being + propagated up the call stack. [RT #41425] + +4297. [test] Ensure delegations in RPZ zones fail robustly. + [RT #41518] + +4296. [bug] TCP packet sizes were calculated incorrectly in the + stats channel; they could be counted in the wrong + histogram bucket. [RT #40587] + +4295. [bug] An unchecked result in dns_message_pseudosectiontotext() + could allow incorrect text formatting of EDNS EXPIRE + options. [RT #41437] + +4294. [bug] Fixed a regression in which "rndc stop -p" failed + to print the PID. [RT #41513] + +4293. [bug] Address memory leak on priming query creation failure. + [RT #41512] + +4292. [placeholder] + +4291. [cleanup] Added a required include to dns/forward.h. [RT #41474] + +4290. [func] The timers returned by the statistics channel + (indicating current time, server boot time, and + most recent reconfiguration time) are now reported + with millisecond accuracy. [RT #40082] + +4289. [bug] The server could crash due to memory being used + after it was freed if a zone transfer timed out. + [RT #41297] + +4288. [bug] Fixed a regression in resolver.c:possibly_mark() + which caused known-bogus servers to be queried + anyway. [RT #41321] + +4287. [bug] Silence an overly noisy log message when message + parsing fails. [RT #41374] + +4286. [security] render_ecs errors were mishandled when printing out + a OPT record resulting in a assertion failure. + (CVE-2015-8705) [RT #41397] + +4285. [security] Specific APL data could trigger a INSIST. + (CVE-2015-8704) [RT #41396] + +4284. [bug] Some GeoIP options were incorrectly documented + using abbreviated forms which were not accepted by + named. The code has been updated to allow both + long and abbreviated forms. [RT #41381] + +4283. [bug] OPENSSL_config is no longer re-callable. [RT #41348] + +4282. [func] 'dig +[no]mapped' determine whether the use of mapped + IPv4 addresses over IPv6 is permitted or not. The + default is +mapped. [RT #41307] + +4281. [bug] Teach dns_message_totext about BADCOOKIE. [RT #41257] + +4280. [performance] Use optimal message sizes to improve compression + in AXFRs. This reduces network traffic. [RT #40996] + +4279. [test] Don't use fixed ports when unit testing. [RT #41194] + +4278. [bug] 'delv +short +[no]split[=##]' didn't work as expected. + [RT #41238] + +4277. [performance] Improve performance of the RBT, the central zone + datastructure: The aux hashtable was improved, + hash function was updated to perform more + uniform mapping, uppernode was added to + dns_rbtnode, and other cleanups and performance + improvements were made. [RT #41165] + +4276. [protocol] Add support for SMIMEA. [RT #40513] + +4275. [performance] Lazily initialize dns_compress->table only when + compression is enabled. [RT #41189] + +4274. [performance] Speed up typemap processing from text. [RT #41196] + +4273. [bug] Only call dns_test_begin() and dns_test_end() once each + in nsec3_test as it fails with GOST if called multiple + times. + +4272. [bug] dig: the +norrcomments option didn't work with +multi. + [RT #41234] + +4271. [test] Unit tests could deadlock in isc__taskmgr_pause(). + [RT #41235] + +4270. [security] Update allowed OpenSSL versions as named is + potentially vulnerable to CVE-2015-3193. + +4269. [bug] Zones using "map" format master files currently + don't work as policy zones. This limitation has + now been documented; attempting to use such zones + in "response-policy" statements is now a + configuration error. [RT #38321] + +4268. [func] "rndc status" now reports the path to the + configuration file. [RT #36470] + +4267. [test] Check sdlz error handling. [RT #41142] + +4266. [placeholder] + +4265. [bug] Address unchecked isc_mem_get calls. [RT #41187] + +4264. [bug] Check const of strchr/strrchr assignments match + argument's const status. [RT #41150] + +4263. [contrib] Address compiler warnings in mysqldyn module. + [RT #41130] + +4262. [bug] Fixed a bug in epoll socket code that caused + sockets to not be registered for ready + notification in some cases, causing named to not + read from or write to them, resulting in what + appear to the user as blocked connections. + [RT #41067] + +4261. [maint] H.ROOT-SERVERS.NET is 198.97.190.53 and 2001:500:1::53. + [RT #40556] + +4260. [security] Insufficient testing when parsing a message allowed + records with an incorrect class to be be accepted, + triggering a REQUIRE failure when those records + were subsequently cached. (CVE-2015-8000) [RT #40987] + +4259. [func] Add an option for non-destructive control channel + access using a "read-only" clause. In such + cases, a restricted set of rndc commands are + allowed for querying information from named. + [RT #40498] + +4258. [bug] Limit rndc query message sizes to 32 KiB. This should + not break any legitimate rndc commands, but will + prevent a rogue rndc query from allocating too + much memory. [RT #41073] + +4257. [cleanup] Python scripts reported incorrect version. [RT #41080] + +4256. [bug] Allow rndc command arguments to be quoted so as + to allow spaces. [RT #36665] + +4255. [performance] Add 'message-compression' option to disable DNS + compression in responses. [RT #40726] + +4254. [bug] Address missing lock when getting zone's serial. + [RT #41072] + +4253. [security] Address fetch context reference count handling error + on socket error. (CVE-2015-8461) [RT#40945] + +4252. [func] Add support for automating the generation CDS and + CDNSKEY rrsets to named and dnssec-signzone. + [RT #40424] + +4251. [bug] NTAs were deleted when the server was reconfigured + or reloaded. [RT #41058] + +4250. [func] Log the TSIG key in use during inbound zone + transfers. [RT #41075] + +4249. [func] Improve error reporting of TSIG / SIG(0) records in + the wrong location. [RT #41030] + +4248. [performance] Add an isc_atomic_storeq() function, use it in + stats counters to improve performance. + [RT #39972] [RT #39979] + +4247. [port] Require both HAVE_JSON and JSON_C_VERSION to be + defined to report json library version. [RT #41045] + +4246. [test] Ensure the statschannel system test runs when BIND + is not built with libjson. [RT #40944] + +4245. [placeholder] + +4244. [bug] The parser was not reporting that use-ixfr is obsolete. + [RT #41010] + +4243. [func] Improved stats reporting from Timothe Litt. [RT #38941] + +4242. [bug] Replace the client if not already replaced when + prefetching. [RT #41001] + +4241. [doc] Improved the TSIG, TKEY, and SIG(0) sections in + the ARM. [RT #40955] + +4240. [port] Fix LibreSSL compatibility. [RT #40977] + +4239. [func] Changed default servfail-ttl value to 1 second from 10. + Also, the maximum value is now 30 instead of 300. + [RT #37556] + +4238. [bug] Don't send to servers on net zero (0.0.0.0/8). + [RT #40947] + +4237. [doc] Upgraded documentation toolchain to use DocBook 5 + and dblatex. [RT #40766] + +4236. [performance] On machines with 2 or more processors (CPU), the + default value for the number of UDP listeners + has been changed to the number of detected + processors minus one. [RT #40761] + +4235. [func] Added support in named for "dnstap", a fast method of + capturing and logging DNS traffic, and a new command + "dnstap-read" to read a dnstap log file. Use + "configure --enable-dnstap" to enable this + feature (note that this requires libprotobuf-c + and libfstrm). See the ARM for configuration details. + + Thanks to Robert Edmonds of Farsight Security. + [RT #40211] + +4234. [func] Add deflate compression in statistics channel HTTP + server. [RT #40861] + +4233. [test] Add tests for CDS and CDNSKEY with delegation-only. + [RT #40597] + +4232. [contrib] Address unchecked memory allocation calls in + query-loc and zone2ldap. [RT #40789] + +4231. [contrib] Address unchecked calloc call in dlz_mysqldyn_mod.c. + [RT #40840] + +4230. [contrib] dlz_wildcard_dynamic.c:dlz_create could return a + uninitialized result. [RT #40839] + +4229. [bug] A variable could be used uninitialized in + dns_update_signaturesinc. [RT #40784] + +4228. [bug] Address race condition in dns_client_destroyrestrans. + [RT #40605] + +4227. [bug] Silence static analysis warnings. [RT #40828] + +4226. [bug] Address a theoretical shutdown race in + zone.c:notify_send_queue(). [RT #38958] + +4225. [port] freebsd/openbsd: Use '${CC} -shared' for building + shared libraries. [RT #39557] + +4224. [func] Added support for "dyndb", a new interface for loading + zone data from an external database, developed by + Red Hat for the FreeIPA project. + + DynDB drivers fully implement the BIND database + API, and are capable of significantly better + performance and functionality than DLZ drivers, + while taking advantage of advanced database + features not available in BIND such as multi-master + replication. + + Thanks to Adam Tkac and Petr Spacek of Red Hat. + [RT #35271] + +4223. [func] Add support for setting max-cache-size to percentage + of available physical memory, set default to 90%. + [RT #38442] + +4222. [func] Bias IPv6 servers when selecting the next server to + query. [RT #40836] + +4221. [bug] Resource leak on DNS_R_NXDOMAIN in fctx_create. + [RT #40583] + +4220. [doc] Improve documentation for zone-statistics. + [RT #36955] + +4219. [bug] Set event->result to ISC_R_WOULDBLOCK on EWOULDBLOCK, + EGAIN when these soft error are not retried for + isc_socket_send*(). + +4218. [bug] Potential null pointer dereference on out of memory + if mmap is not supported. [RT #40777] + +4217. [protocol] Add support for CSYNC. [RT #40532] + +4216. [cleanup] Silence static analysis warnings. [RT #40649] + +4215. [bug] nsupdate: skip to next request on GSSTKEY create + failure. [RT #40685] + +4214. [protocol] Add support for TALINK. [RT #40544] + +4213. [bug] Don't reuse a cache across multiple classes. + [RT #40205] + +4212. [func] Re-query if we get a bad client cookie returned over + UDP. [RT #40748] + +4211. [bug] Ensure that lwresd gets at least one task to work + with if enabled. [RT #40652] + +4210. [cleanup] Silence use after free false positive. [RT #40743] + +4209. [bug] Address resource leaks in dlz modules. [RT #40654] + +4208. [bug] Address null pointer dereferences on out of memory. + [RT #40764] + +4207. [bug] Handle class mismatches with raw zone files. + [RT #40746] + +4206. [bug] contrib: fixed a possible NULL dereference in + DLZ wildcard module. [RT #40745] + +4205. [bug] 'named-checkconf -p' could include unwanted spaces + when printing tuples with unset optional fields. + [RT #40731] + +4204. [bug] 'dig +trace' failed to lookup the correct type if + the initial root NS query was retried. [RT #40296] + +4203. [test] The rrchecker system test now tests conversion + to and from unknown-type format. [RT #40584] + +4202. [bug] isccc_cc_fromwire() could return an incorrect + result. [RT #40614] + +4201. [func] The default preferred-glue is now the address record + type of the transport the query was received + over. [RT #40468] + +4200. [cleanup] win32: update BINDinstall to be BIND release + independent. [RT #38915] + +4199. [protocol] Add support for NINFO, RKEY, SINK, TA. + [RT #40545] [RT #40547] [RT #40561] [RT #40563] + +4198. [placeholder] + +4197. [bug] 'named-checkconf -z' didn't handle 'in-view' clauses. + [RT #40603] + +4196. [doc] Improve how "enum + other" types are documented. + [RT #40608] + +4195. [bug] 'max-zone-ttl unlimited;' was broken. [RT #40608] + +4194. [bug] named-checkconf -p failed to properly print a port + range. [RT #40634] + +4193. [bug] Handle broken servers that return BADVERS incorrectly. + [RT #40427] + +4192. [bug] The default rrset-order of random was not always being + applied. [RT #40456] + +4191. [protocol] Accept DNS-SD non LDH PTR records in reverse zones + as per RFC 6763. [RT #37889] + +4190. [protocol] Accept Active Directory gc._msdcs. name as + valid with check-names. still needs to be + LDH. [RT #40399] + +4189. [cleanup] Don't exit on overly long tokens in named.conf. + [RT #40418] + +4188. [bug] Support HTTP/1.0 client properly on the statistics + channel. [RT #40261] + +4187. [func] When any RR type implementation doesn't + implement totext() for the RDATA's wire + representation and returns ISC_R_NOTIMPLEMENTED, + such RDATA is now printed in unknown + presentation format (RFC 3597). RR types affected + include LOC(29) and APL(42). [RT #40317]. + +4186. [bug] Fixed an RPZ bug where a QNAME would be matched + against a policy RR with wildcard owner name + (trigger) where the QNAME was the wildcard owner + name's parent. For example, the bug caused a query + with QNAME "example.com" to match a policy RR with + "*.example.com" as trigger. [RT #40357] + +4185. [bug] Fixed an RPZ bug where a policy RR with wildcard + owner name (trigger) would prevent another policy RR + with its parent owner name from being + loaded. For example, the bug caused a policy RR + with trigger "example.com" to not have any + effect when a previous policy RR with trigger + "*.example.com" existed in that RPZ zone. + [RT #40357] + +4184. [bug] Fixed a possible memory leak in name compression + when rendering long messages. (Also, improved + wire_test for testing such messages.) [RT #40375] + +4183. [cleanup] Use timing-safe memory comparisons in cryptographic + code. Also, the timing-safe comparison functions have + been renamed to avoid possible confusion with + memcmp(). Thanks to Loganaden Velvindron of + AFRINIC. [RT #40148] + +4182. [cleanup] Use mnemonics for RR class and type comparisons. + [RT #40297] + +4181. [bug] Queued notify messages could be dequeued from the + wrong rate limiter queue. [RT #40350] + +4180. [bug] Error responses in pipelined queries could + cause a crash in client.c. [RT #40289] + +4179. [bug] Fix double frees in getaddrinfo() in libirs. + [RT #40209] + +4178. [bug] Fix assertion failure in parsing UNSPEC(103) RR from + text. [RT #40274] + +4177. [bug] Fix assertion failure in parsing NSAP records from + text. [RT #40285] + +4176. [bug] Address race issues with lwresd. [RT #40284] + +4175. [bug] TKEY with GSS-API keys needed bigger buffers. + [RT #40333] + +4174. [bug] "dnssec-coverage -r" didn't handle time unit + suffixes correctly. [RT #38444] + +4173. [bug] dig +sigchase was not properly matching the trusted + key. [RT #40188] + +4172. [bug] Named / named-checkconf didn't handle a view of CLASS0. + [RT #40265] + +4171. [bug] Fixed incorrect class checks in TSIG RR + implementation. [RT #40287] + +4170. [security] An incorrect boundary check in the OPENPGPKEY + rdatatype could trigger an assertion failure. + (CVE-2015-5986) [RT #40286] + +4169. [test] Added a 'wire_test -d' option to read input as + raw binary data, for use as a fuzzing harness. + [RT #40312] + +4168. [security] A buffer accounting error could trigger an + assertion failure when parsing certain malformed + DNSSEC keys. (CVE-2015-5722) [RT #40212] + +4167. [func] Update rndc's usage output to include recently added + commands. Thanks to Tony Finch for submitting a + patch. [RT #40010] + +4166. [func] Print informative output from rndc showzone when + allow-new-zones is not enabled for a view. Thanks to + Tony Finch for submitting a patch. [RT #40009] + +4165. [security] A failure to reset a value to NULL in tkey.c could + result in an assertion failure. (CVE-2015-5477) + [RT #40046] + +4164. [bug] Don't rename slave files and journals on out of memory. + [RT #40033] + +4163. [bug] Address compiler warnings. [RT #40024] + +4162. [bug] httpdmgr->flags was not being initialized. [RT #40017] + +4161. [test] Add JSON test for traffic size stats; also test + for consistency between "rndc stats" and the XML + and JSON statistics channel contents. [RT #38700] + +4160. [placeholder] + +4159. [cleanup] Alphabetize dig's help output. [RT #39966] + +4158. [placeholder] + +4157. [placeholder] + +4156. [func] Added statistics counters to track the sizes + of incoming queries and outgoing responses in + histogram buckets, as specified in RSSAC002. + [RT #39049] + +4155. [func] Allow RPZ rewrite logging to be configured on a + per-zone basis using a newly introduced log clause in + the response-policy option. [RT #39754] + +4154. [bug] A OPT record should be included with the FORMERR + response when there is a malformed EDNS option. + [RT #39647] + +4153. [bug] Dig should zero non significant +subnet bits. Check + that non significant ECS bits are zero on receipt. + [RT #39647] + +4152. [func] Implement DNS COOKIE option. This replaces the + experimental SIT option of BIND 9.10. The following + named.conf directives are available: send-cookie, + cookie-secret, cookie-algorithm, nocookie-udp-size + and require-server-cookie. The following dig options + are available: +[no]cookie[=value] and +[no]badcookie. + [RT #39928] + +4151. [bug] 'rndc flush' could cause a deadlock. [RT #39835] + +4150. [bug] win32: listen-on-v6 { any; }; was not working. Apply + minimal fix. [RT #39667] + +4149. [bug] Fixed a race condition in the getaddrinfo() + implementation in libirs, which caused the delv + utility to crash with an assertion failure when using + the '@server' syntax with a hostname argument. + [RT #39899] + +4148. [bug] Fix a bug when printing zone names with '/' character + in XML and JSON statistics output. [RT #39873] + +4147. [bug] Filter-aaaa / filter-aaaa-on-v4 / filter-aaaa-on-v6 + was returning referrals rather than nodata responses + when the AAAA records were filtered. [RT #39843] + +4146. [bug] Address reference leak that could prevent a clean + shutdown. [RT #37125] + +4145. [bug] Not all unassociated adb entries where being printed. + [RT #37125] + +4144. [func] Add statistics counters for nxdomain redirections. + [RT #39790] + +4143. [placeholder] + +4142. [bug] rndc addzone with view specified saved NZF config + that could not be read back by named. This has now + been fixed. [RT #39845] + +4141. [bug] A formatting bug caused rndc zonestatus to print + negative numbers for large serial values. This has + now been fixed. [RT #39854] + +4140. [cleanup] Remove redundant nzf_remove() call during delzone. + [RT #39844] + +4139. [doc] Fix rpz-client-ip documentation. [RT #39783] + +4138. [security] An uninitialized value in validator.c could result + in an assertion failure. (CVE-2015-4620) [RT #39795] + +4137. [bug] Make rndc reconfig report configuration errors the + same way rndc reload does. [RT #39635] + +4136. [bug] Stale statistics counters with the leading + '#' prefix (such as #NXDOMAIN) were not being + updated correctly. This has been fixed. [RT #39141] + +4135. [cleanup] Log expired NTA at startup. [RT #39680] + +4134. [cleanup] Include client-ip rules when logging the number + of RPZ rules of each type. [RT #39670] + +4133. [port] Update how various json libraries are handled. + [RT #39646] + +4132. [cleanup] dig: added +rd as a synonym for +recurse, + added +class as an unabbreviated alternative + to +cl. [RT #39686] + +4131. [bug] Addressed further problems with reloading RPZ + zones. [RT #39649] + +4130. [bug] The compatibility shim for *printf() misprinted some + large numbers. [RT #39586] + +4129. [port] Address API changes in OpenSSL 1.1.0. [RT #39532] + +4128. [bug] Address issues raised by Coverity 7.6. [RT #39537] + +4127. [protocol] CDS and CDNSKEY need to be signed by the key signing + key as per RFC 7344, Section 4.1. [RT #37215] + +4126. [bug] Addressed a regression introduced in change #4121. + [RT #39611] + +4125. [test] Added tests for dig, renamed delv test to digdelv. + [RT #39490] + +4124. [func] Log errors or warnings encountered when parsing the + internal default configuration. Clarify the logging + of errors and warnings encountered in rndc + addzone or modzone parameters. [RT #39440] + +4123. [port] Added %z (size_t) format options to the portable + internal printf/sprintf implementation. [RT #39586] + +4122. [bug] The server could match a shorter prefix than what was + available in CLIENT-IP policy triggers, and so, an + unexpected action could be taken. This has been + corrected. [RT #39481] + +4121. [bug] On servers with one or more policy zones + configured as slaves, if a policy zone updated + during regular operation (rather than at + startup) using a full zone reload, such as via + AXFR, a bug could allow the RPZ summary data to + fall out of sync, potentially leading to an + assertion failure in rpz.c when further + incremental updates were made to the zone, such + as via IXFR. [RT #39567] + +4120. [bug] A bug in RPZ could cause the server to crash if + policy zones were updated while recursion was + pending for RPZ processing of an active query. + [RT #39415] + +4119. [test] Allow dig to set the message opcode. [RT #39550] + +4118. [bug] Teach isc-config.sh about irs. [RT #39213] + +4117. [protocol] Add EMPTY.AS112.ARPA as per RFC 7534. + +4116. [bug] Fix a bug in RPZ that could cause some policy + zones that did not specifically require + recursion to be treated as if they did; + consequently, setting qname-wait-recurse no; was + sometimes ineffective. [RT #39229] + +4115. [func] "rndc -r" now prints the result code (e.g., + ISC_R_SUCCESS, ISC_R_TIMEOUT, etc) after + running the requested command. [RT #38913] + +4114. [bug] Fix a regression in radix tree implementation + introduced by ECS code. This bug was never + released, but it was reported by a user testing + master. [RT #38983] + +4113. [test] Check for Net::DNS is some system test + prerequisites. [RT #39369] + +4112. [bug] Named failed to load when "root-delegation-only" + was used without a list of domains to exclude. + [RT #39380] + +4111. [doc] Alphabetize rndc man page. [RT #39360] + +4110. [bug] Address memory leaks / null pointer dereferences + on out of memory. [RT #39310] + +4109. [port] linux: support reading the local port range from + net.ipv4.ip_local_port_range. [RT # 39379] + +4108. [func] An additional NXDOMAIN redirect method (option + "nxdomain-redirect") has been added, allowing + redirection to a specified DNS namespace instead + of a single redirect zone. [RT #37989] + +4107. [bug] Address potential deadlock when updating zone content. + [RT #39269] + +4106. [port] Improve readline support. [RT #38938] + +4105. [port] Misc fixes for Microsoft Visual Studio + 2015 CTP6 in 64 bit mode. [RT #39308] + +4104. [bug] Address uninitialized elements. [RT #39252] + +4103. [port] Misc fixes for Microsoft Visual Studio + 2015 CTP6. [RT #39267] + +4102. [bug] Fix a use after free bug introduced in change + #4094. [RT #39281] + +4101. [bug] dig: the +split and +rrcomments options didn't + work with +short. [RT #39291] + +4100. [bug] Inherited owernames on the line immediately following + a $INCLUDE were not working. [RT #39268] + +4099. [port] clang: make unknown commandline options hard errors + when determining what options are supported. + [RT #39273] + +4098. [bug] Address use-after-free issue when using a + predecessor key with dnssec-settime. [RT #39272] + +4097. [func] Add additional logging about xfrin transfer status. + [RT #39170] + +4096. [bug] Fix a use after free of query->sendevent. + [RT #39132] + +4095. [bug] zone->options2 was not being properly initialized. + [RT #39228] + +4094. [bug] A race during shutdown or reconfiguration could + cause an assertion in mem.c. [RT #38979] + +4093. [func] Dig now learns the SIT value from truncated + responses when it retries over TCP. [RT #39047] + +4092. [bug] 'in-view' didn't work for zones beneath a empty zone. + [RT #39173] + +4091. [cleanup] Some cleanups in isc mem code. [RT #38896] + +4090. [bug] Fix a crash while parsing malformed CAA RRs in + presentation format, i.e., from text such as + from master files. Thanks to John Van de + Meulebrouck Brendgard for discovering and + reporting this problem. [RT #39003] + +4089. [bug] Send notifies immediately for slave zones during + startup. [RT #38843] + +4088. [port] Fixed errors when building with libressl. [RT #38899] + +4087. [bug] Fix a crash due to use-after-free due to sequencing + of tasks actions. [RT #38495] + +4086. [bug] Fix out-of-srcdir build with native pkcs11. [RT #38831] + +4085. [bug] ISC_PLATFORM_HAVEXADDQ could be inconsistently set. + [RT #38828] + +4084. [bug] Fix a possible race in updating stats counters. + [RT #38826] + +4083. [cleanup] Print the number of CPUs and UDP listeners + consistently in the log and in "rndc status" + output; indicate whether threads are supported + in "named -V" output. [RT #38811] + +4082. [bug] Incrementally sign large inline zone deltas. + [RT #37927] + +4081. [cleanup] Use dns_rdatalist_init consistently. [RT #38759] + +4080. [func] Completed change #4022, adding a "lock-file" option + to named.conf to override the default lock file, + in addition to the "named -X " command + line option. Setting the lock file to "none" + using either method disables the check completely. + [RT #37908] + +4079. [func] Preserve the case of the owner name of records to + the RRset level. [RT #37442] + +4078. [bug] Handle the case where CMSG_SPACE(sizeof(int)) != + CMSG_SPACE(sizeof(char)). [RT #38621] + +4077. [test] Add static-stub regression test for DS NXDOMAIN + return making the static stub disappear. [RT #38564] + +4076. [bug] Named could crash on shutdown with outstanding + reload / reconfig events. [RT #38622] + +4075. [placeholder] + +4074. [cleanup] Cleaned up more warnings from gcc -Wshadow. [RT #38708] + +4073. [cleanup] Add libjson-c version number reporting to + "named -V"; normalize version number formatting. + [RT #38056] + +4072. [func] Add a --enable-querytrace configure switch for + very verbose query trace logging. (This option + has a negative performance impact and should be + used only for debugging.) [RT #37520] + +4071. [cleanup] Initialize pthread mutex attrs just once, instead of + doing it per mutex creation. [RT #38547] + +4070. [bug] Fix a segfault in nslookup in a query such as + "nslookup isc.org AMS.SNS-PB.ISC.ORG -all". + [RT #38548] + +4069. [doc] Reorganize options in the nsupdate man page. + [RT #38515] + +4068. [bug] Omit unknown serial number from JSON zone statistics. + [RT #38604] + +4067. [cleanup] Reduce noise from RRL when query logging is + disabled. [RT #38648] + +4066. [doc] Reorganize options in the dig man page. [RT #38516] + +4065. [test] Additional RFC 5011 tests. [RT #38569] + +4064. [contrib] dnssec-keyset.sh: Generates a specified number + of DNSSEC keys with timing set to implement a + pre-publication key rollover strategy. Thanks + to Jeffry A. Spain. [RT #38459] + +4063. [bug] Asynchronous zone loads were not handled + correctly when the zone load was already in + progress; this could trigger a crash in zt.c. + [RT #37573] + +4062. [bug] Fix an out-of-bounds read in RPZ code. If the + read succeeded, it doesn't result in a bug + during operation. If the read failed, named + could segfault. [RT #38559] + +4061. [bug] Handle timeout in legacy system test. [RT #38573] + +4060. [bug] dns_rdata_freestruct could be called on a + uninitialized structure when handling a error. + [RT #38568] + +4059. [bug] Addressed valgrind warnings. [RT #38549] + +4058. [bug] UDP dispatches could use the wrong pseudorandom + number generator context. [RT #38578] + +4057. [bug] 'dnssec-dsfromkey -T 0' failed to add ttl field. + [RT #38565] + +4056. [bug] Expanded automatic testing of trust anchor + management and fixed several small bugs including + a memory leak and a possible loss of key state + information. [RT #38458] + +4055. [func] "rndc managed-keys" can be used to check status + of trust anchors or to force keys to be refreshed, + Also, the managed keys data file has easier-to-read + comments. [RT #38458] + +4054. [func] Added a new tool 'mdig', a lightweight clone of + dig able to send multiple pipelined queries. + [RT #38261] + +4053. [security] Revoking a managed trust anchor and supplying + an untrusted replacement could cause named + to crash with an assertion failure. + (CVE-2015-1349) [RT #38344] + +4052. [bug] Fix a leak of query fetchlock. [RT #38454] + +4051. [bug] Fix a leak of pthread_mutexattr_t. [RT #38454] + +4050. [bug] RPZ could send spurious SERVFAILs in response + to duplicate queries. [RT #38510] + +4049. [bug] CDS and CDNSKEY had the wrong attributes. [RT #38491] + +4048. [bug] adb hash table was not being grown. [RT #38470] + +4047. [cleanup] "named -V" now reports the current running versions + of OpenSSL and the libxml2 libraries, in addition to + the versions that were in use at build time. + +4046. [bug] Accounting of "total use" in memory context + statistics was not correct. [RT #38370] + +4045. [bug] Skip to next master on dns_request_createvia4 failure. + [RT #25185] + +4044. [bug] Change 3955 was not complete, resulting in an assertion + failure if the timing was just right. [RT #38352] + +4043. [func] "rndc modzone" can be used to modify the + configuration of an existing zone, using similar + syntax to "rndc addzone". [RT #37895] + +4042. [bug] zone.c:iszonesecure was being called too late. + [RT #38371] + +4041. [func] TCP sockets can now be shared while connecting. + (This will be used to enable client-side support + of pipelined queries.) [RT #38231] + +4040. [func] Added server-side support for pipelined TCP + queries. Clients may continue sending queries via + TCP while previous queries are being processed + in parallel. (The new "keep-response-order" + option allows clients to be specified for which + the old behavior will still be used.) [RT #37821] + +4039. [cleanup] Cleaned up warnings from gcc -Wshadow. [RT #37381] + +4038. [bug] Add 'rpz' flag to node and use it to determine whether + to call dns_rpz_delete. This should prevent unbalanced + add / delete calls. [RT #36888] + +4037. [bug] also-notify was ignoring the tsig key when checking + for duplicates resulting in some expected notify + messages not being sent. [RT #38369] + +4036. [bug] Make call to open a temporary file name safe during + NZF creation. [RT #38331] + +4035. [bug] Close temporary and NZF FILE pointers before moving + the former into the latter's place, as required on + Windows. [RT #38332] + +4034. [func] When added, negative trust anchors (NTA) are now + saved to files (viewname.nta), in order to + persist across restarts of the named server. + [RT #37087] + +4033. [bug] Missing out of memory check in request.c:req_send. + [RT #38311] + +4032. [bug] Built-in "empty" zones did not correctly inherit the + "allow-transfer" ACL from the options or view. + [RT #38310] + +4031. [bug] named-checkconf -z failed to report a missing file + with a hint zone. [RT #38294] + +4030. [func] "rndc delzone" is now applicable to zones that were + configured in named.conf, as well as zones that + were added via "rndc addzone". (Note, however, that + if named.conf is not also modified, the deleted zone + will return when named is reloaded.) [RT #37887] + +4029. [func] "rndc showzone" displays the current configuration + of a specified zone. [RT #37887] + +4028. [bug] $GENERATE with a zero step was not being caught as a + error. A $GENERATE with a / but no step was not being + caught as a error. [RT #38262] + +4027. [port] Net::DNS 0.81 compatibility. [RT #38165] + +4026. [bug] Fix RFC 3658 reference in dig +sigchase. [RT #38173] + +4025. [port] bsdi: failed to build. [RT #38047] + +4024. [bug] dns_rdata_opt_first, dns_rdata_opt_next, + dns_rdata_opt_current, dns_rdata_txt_first, + dns_rdata_txt_next and dns_rdata_txt_current were + documented but not implemented. These have now been + implemented. + + dns_rdata_spf_first, dns_rdata_spf_next and + dns_rdata_spf_current were documented but not + implemented. The prototypes for these + functions have been removed. [RT #38068] + +4023. [bug] win32: socket handling with explicit ports and + invoking named with -4 was broken for some + configurations. [RT #38068] + +4022. [func] Stop multiple spawns of named by limiting number of + processes to 1. This is done by using a lockfile and + checking whether we can listen on any configured + TCP interfaces. [RT #37908] + +4021. [bug] Adjust max-recursion-queries to accommodate + the need for more queries when the cache is + empty. [RT #38104] + +4020. [bug] Change 3736 broke nsupdate's SOA MNAME discovery + resulting in updates being sent to the wrong server. + [RT #37925] + +4019. [func] If named is not configured to validate the answer + then allow fallback to plain DNS on timeout even + when we know the server supports EDNS. [RT #37978] + +4018. [placeholder] + +4017. [test] Add system test to check lookups to legacy servers + with broken DNS behavior. [RT #37965] + +4016. [bug] Fix a dig segfault due to bad linked list usage. + [RT #37591] + +4015. [bug] Nameservers that are skipped due to them being + CNAMEs were not being logged. They are now logged + to category 'cname' as per BIND 8. [RT #37935] + +4014. [bug] When including a master file origin_changed was + not being properly set leading to a potentially + spurious 'inherited owner' warning. [RT #37919] + +4013. [func] Add a new tcp-only option to server (config) / + peer (struct) to use TCP transport to send + queries (in place of UDP transport with a + TCP fallback on truncated (TC set) response). + [RT #37800] + +4012. [cleanup] Check returned status of OpenSSL digest and HMAC + functions when they return one. Note this applies + only to FIPS capable OpenSSL libraries put in + FIPS mode and MD5. [RT #37944] + +4011. [bug] master's list port and dscp inheritance was not + properly implemented. [RT #37792] + +4010. [cleanup] Clear the prefetchable state when initiating a + prefetch. [RT #37399] + +4009. [func] delv: added a +tcp option. [RT #37855] + +4008. [contrib] Updated zkt to latest version (1.1.3). [RT #37886] + +4007. [doc] Remove acl forward reference restriction. [RT #37772] + +4006. [security] A flaw in delegation handling could be exploited + to put named into an infinite loop. This has + been addressed by placing limits on the number + of levels of recursion named will allow (default 7), + and the number of iterative queries that it will + send (default 50) before terminating a recursive + query (CVE-2014-8500). + + The recursion depth limit is configured via the + "max-recursion-depth" option, and the query limit + via the "max-recursion-queries" option. [RT #37580] + +4005. [func] The buffer used for returning text from rndc + commands is now dynamically resizable, allowing + arbitrarily large amounts of text to be sent back + to the client. (Prior to this change, it was + possible for the output of "rndc tsig-list" to be + truncated.) [RT #37731] + +4004. [bug] When delegations had AAAA glue but not A, a + reference could be leaked causing an assertion + failure on shutdown. [RT #37796] + +4003. [security] When geoip-directory was reconfigured during + named run-time, the previously loaded GeoIP + data could remain, potentially causing wrong + ACLs to be used or wrong results to be served + based on geolocation (CVE-2014-8680). [RT #37720] + +4002. [security] Lookups in GeoIP databases that were not + loaded could cause an assertion failure + (CVE-2014-8680). [RT #37679] + +4001. [security] The caching of GeoIP lookups did not always + handle address families correctly, potentially + resulting in an assertion failure (CVE-2014-8680). + [RT #37672] + +4000. [bug] NXDOMAIN redirection incorrectly handled NXRRSET + from the redirect zone. [RT #37722] + +3999. [func] "mkeys" and "nzf" files are now named after + their corresponding views, unless the view name + contains characters that would be incompatible + with use in a filename (i.e., slash, backslash, + or capital letters). If a view name does contain + these characters, the files will still be named + using a cryptographic hash of the view name. + Regardless of this, if a file using the old name + format is found to exist, it will continue to be + used. [RT #37704] + +3998. [bug] isc_radix_search was returning matches that were + too precise. [RT #37680] + +3997. [protocol] Add OPENGPGKEY record. [RT# 37671] + +3996. [bug] Address use after free on out of memory error in + keyring_add. [RT #37639] + +3995. [bug] receive_secure_serial holds the zone lock for too + long. [RT #37626] + +3994. [func] Dig now supports setting the last unassigned DNS + header flag bit (dig +zflag). [RT #37421] + +3993. [func] Dig now supports EDNS negotiation by default. + (dig +[no]ednsnegotiation). + + Note: This is disabled by default in BIND 9.10 + and enabled by default in BIND 9.11. [RT #37604] + +3992. [func] DiG can now send queries without questions + (dig +header-only). [RT #37599] + +3991. [func] Add the ability to buffer logging output by specifying + "buffered yes;" when defining a channel. [RT #26561] + +3990. [test] Add tests for unknown DNSSEC algorithm handling. + [RT #37541] + +3989. [cleanup] Remove redundant dns_db_resigned calls. [RT #35748] + +3988. [func] Allow the zone serial of a dynamically updatable + zone to be updated via "rndc signing -serial". + [RT #37404] + +3987. [port] Handle future Visual Studio 14 incompatible changes. + [RT #37380] + +3986. [doc] Add the BIND version number to page footers + in the ARM. [RT #37398] + +3985. [doc] Describe how +ndots and +search interact in dig. + [RT #37529] + +3984. [func] Accept 256 byte long PINs in native PKCS#11 + crypto. [RT #37410] + +3983. [bug] Change #3940 was incomplete: negative trust anchors + could be set to last up to a week, but the + "nta-lifetime" and "nta-recheck" options were + still limited to one day. [RT #37522] + +3982. [doc] Include release notes in product documentation. + [RT #37272] + +3981. [bug] Cache DS/NXDOMAIN independently of other query types. + [RT #37467] + +3980. [bug] Improve --with-tuning=large by self tuning of SO_RCVBUF + size. [RT #37187] + +3979. [bug] Negative trust anchor fetches were not properly + managed. [RT #37488] + +3978. [test] Added a unit test for Diffie-Hellman key + computation, completing change #3974. [RT #37477] + +3977. [cleanup] "rndc secroots" reported a "not found" error when + there were no negative trust anchors set. [RT #37506] + +3976. [bug] When refreshing managed-key trust anchors, clear + any cached trust so that they will always be + revalidated with the current set of secure + roots. [RT #37506] + +3975. [bug] Don't populate or use the bad cache for queries that + don't request or use recursion. [RT #37466] + +3974. [bug] Handle DH_compute_key() failure correctly in + openssldh_link.c. [RT #37477] + +3973. [test] Added hooks for Google Performance Tools CPU profiler, + including real-time/wall-clock profiling. Use + "configure --with-gperftools-profiler" to enable. + [RT #37339] + +3972. [bug] Fix host's usage statement. [RT #37397] + +3971. [bug] Reduce the cascading failures due to a bad $TTL line + in named-checkconf / named-checkzone. [RT #37138] + +3970. [contrib] Fixed a use after free bug in the SDB LDAP driver. + [RT #37237] + +3969. [test] Added 'delv' system test. [RT #36901] + +3968. [bug] Silence spurious log messages when using 'named -[46]'. + [RT #37308] + +3967. [test] Add test for inlined signed zone in multiple views + with different DNSKEY sets. [RT #35759] + +3966. [bug] Missing dns_db_closeversion call in receive_secure_db. + [RT #35746] + +3965. [func] Log outgoing packets and improve packet logging to + support logging the remote address. [RT #36624] + +3964. [func] nsupdate now performs check-names processing. + [RT #36266] + +3963. [test] Added NXRRSET test cases to the "dlzexternal" + system test. [RT #37344] + +3962. [bug] 'dig +topdown +trace +sigchase' address unhandled error + conditions. [RT #34663] + +3961. [bug] Forwarding of SIG(0) signed UPDATE messages failed with + BADSIG. [RT #37216] + +3960. [bug] 'dig +sigchase' could loop forever. [RT #37220] + +3959. [bug] Updates could be lost if they arrived immediately + after a rndc thaw. [RT #37233] + +3958. [bug] Detect when writeable files have multiple references + in named.conf. [RT #37172] + +3957. [bug] "dnssec-keygen -S" failed for ECCGOST, ECDSAP256SHA256 + and ECDSAP384SHA384. [RT #37183] + +3956. [func] Notify messages are now rate limited by notify-rate and + startup-notify-rate instead of serial-query-rate. + [RT #24454] + +3955. [bug] Notify messages due to changes are no longer queued + behind startup notify messages. [RT #24454] + +3954. [bug] Unchecked mutex init in dlz_dlopen_driver.c [RT #37112] + +3953. [bug] Don't escape semi-colon in TXT fields. [RT #37159] + +3952. [bug] dns_name_fullcompare failed to set *nlabelsp when the + two name pointers were the same. [RT #37176] + +3951. [func] Add the ability to set yet-to-be-defined EDNS flags + to dig (+ednsflags=#). [RT #37142] + +3950. [port] Changed the bin/python Makefile to work around a + bmake bug in FreeBSD 10 and NetBSD 6. [RT #36993] + +3949. [experimental] Experimental support for draft-andrews-edns1 by sending + EDNS(1) queries (define DRAFT_ANDREWS_EDNS1 when + building). Add support for limiting the EDNS version + advertised to servers: server { edns-version 0; }; + Log the EDNS version received in the query log. + [RT #35864] + +3948. [port] solaris: RCVBUFSIZE was too large on Solaris with + --with-tuning=large. [RT #37059] + +3947. [cleanup] Set the executable bit on libraries when using + libtool. [RT #36786] + +3946. [cleanup] Improved "configure" search for a python interpreter. + [RT #36992] + +3945. [bug] Invalid wildcard expansions could be incorrectly + accepted by the validator. [RT #37093] + +3944. [test] Added a regression test for "server-id". [RT #37057] + +3943. [func] SERVFAIL responses can now be cached for a + limited time (configured by "servfail-ttl", + default 10 seconds, limit 30). This can reduce + the frequency of retries when an authoritative + server is known to be failing, e.g., due to + ongoing DNSSEC validation problems. [RT #21347] + +3942. [bug] Wildcard responses from a optout range should be + marked as insecure. [RT #37072] + +3941. [doc] Include the BIND version number in the ARM. [RT #37067] + +3940. [func] "rndc nta" now allows negative trust anchors to be + set for up to one week. [RT #37069] + +3939. [func] Improve UPDATE forwarding performance by allowing TCP + connections to be shared. [RT #37039] + +3938. [func] Added quotas to be used in recursive resolvers + that are under high query load for names in zones + whose authoritative servers are nonresponsive or + are experiencing a denial of service attack. + + - "fetches-per-server" limits the number of + simultaneous queries that can be sent to any + single authoritative server. The configured + value is a starting point; it is automatically + adjusted downward if the server is partially or + completely non-responsive. The algorithm used to + adjust the quota can be configured via the + "fetch-quota-params" option. + - "fetches-per-zone" limits the number of + simultaneous queries that can be sent for names + within a single domain. (Note: Unlike + "fetches-per-server", this value is not + self-tuning.) + - New stats counters have been added to count + queries spilled due to these quotas. + + See the ARM for details of these options. [RT #37125] + +3937. [func] Added some debug logging to better indicate the + conditions causing SERVFAILs when resolving. + [RT #35538] + +3936. [func] Added authoritative support for the EDNS Client + Subnet (ECS) option. + + ACLs can now include "ecs" elements which specify + an address or network prefix; if an ECS option is + included in a DNS query, then the address encoded + in the option will be matched against "ecs" ACL + elements. + + Also, if an ECS address is included in a query, + then it will be used instead of the client source + address when matching "geoip" ACL elements. This + behavior can be overridden with "geoip-use-ecs no;". + (Note: to enable "geoip" ACLs, use "configure + --with-geoip". This requires libGeoIP version + 1.5.0 or higher.) + + When "ecs" or "geoip" ACL elements are used to + select a view for a query, the response will include + an ECS option to indicate which client network the + answer is valid for. + + (Thanks to Vincent Bernat.) [RT #36781] + +3935. [bug] "geoip asnum" ACL elements would not match unless + the full organization name was specified. They + can now match against the AS number alone (e.g., + AS1234). [RT #36945] + +3934. [bug] Catch bad 'sit-secret' in named-checkconf. Improve + sit-secret documentation. [RT #36980] + +3933. [bug] Corrected the implementation of dns_rdata_casecompare() + for the HIP rdata type. [RT #36911] + +3932. [test] Improved named-checkconf tests. [RT #36911] + +3931. [cleanup] Cleanup how dlz grammar is defined. [RT #36879] + +3930. [bug] "rndc nta -r" could cause a server hang if the + NTA was not found. [RT #36909] + +3929. [bug] 'host -a' needed to clear idnoptions. [RT #36963] + +3928. [test] Improve rndc system test. [RT #36898] + +3927. [bug] dig: report PKCS#11 error codes correctly when + compiled with --enable-native-pkcs11. [RT #36956] + +3926. [doc] Added doc for geoip-directory. [RT #36877] + +3925. [bug] DS lookup of RFC 1918 empty zones failed. [RT #36917] + +3924. [bug] Improve 'rndc addzone' error reporting. [RT #35187] + +3923. [bug] Sanity check the xml2-config output. [RT #22246] + +3922. [bug] When resigning, dnssec-signzone was removing + all signatures from delegation nodes. It now + retains DS and (if applicable) NSEC signatures. + [RT #36946] + +3921. [bug] AD was inappropriately set on RPZ responses. [RT #36833] + +3920. [doc] Added doc for masterfile-style. [RT #36823] + +3919. [bug] dig: continue to next line if a address lookup fails + in batch mode. [RT #36755] + +3918. [doc] Update check-spf documentation. [RT #36910] + +3917. [bug] dig, nslookup and host now continue on names that are + too long after applying a search list elements. + [RT #36892] + +3916. [contrib] zone2sqlite checked wrong result code. Address + compiler warnings. [RT #36931] + +3915. [bug] Address a assertion if a route event arrived while + shutting down. [RT #36887] + +3914. [bug] Allow the URI target and CAA value fields to + be zero length. [RT #36737] + +3913. [bug] Address race issue in dispatch. [RT #36731] + +3912. [bug] Address some unrecoverable lookup failures. [RT #36330] + +3911. [func] Implement EDNS EXPIRE option client side, allowing + a slave server to set the expiration timer correctly + when transferring zone data from another slave + server. [RT #35925] + +3910. [bug] Fix races to free event during shutdown. [RT #36720] + +3909. [bug] When computing the number of elements required for a + acl count_acl_elements could have a short count leading + to a assertion failure. Also zero out new acl elements + in dns_acl_merge. [RT #36675] + +3908. [bug] rndc now differentiates between a zone in multiple + views and a zone that doesn't exist at all. [RT #36691] + +3907. [cleanup] Alphabetize rndc help. [RT #36683] + +3906. [protocol] Update URI record format to comply with + draft-faltstrom-uri-08. [RT #36642] + +3905. [bug] Address deadlock between view.c and adb.c. [RT #36341] + +3904. [func] Add the RPZ SOA to the additional section. [RT36507] + +3903. [bug] Improve the accuracy of DiG's reported round trip + time. [RT 36611] + +3902. [bug] liblwres wasn't handling link-local addresses in + nameserver clauses in resolv.conf. [RT #36039] + +3901. [protocol] Added support for CAA record type (RFC 6844). + [RT #36625] + +3900. [bug] Fix a crash in PostgreSQL DLZ driver. [RT #36637] + +3899. [bug] "request-ixfr" is only applicable to slave and redirect + zones. [RT #36608] + +3898. [bug] Too small a buffer in tohexstr() calls in test code. + [RT #36598] + +3897. [bug] RPZ summary information was not properly being updated + after a AXFR resulting in changes sometimes being + ignored. [RT #35885] + +3896. [bug] Address performance issues with DSCP code on some + platforms. [RT #36534] + +3895. [func] Add the ability to set the DSCP code point to dig. + [RT #36546] + +3894. [bug] Buffers in isc_print_vsnprintf were not properly + initialized leading to potential overflows when + printing out quad values. [RT #36505] + +3893. [bug] Peer DSCP values could be returned without being set. + [RT #36538] + +3892. [bug] Setting '-t aaaa' in .digrc had unintended side + effects. [RT #36452] + +3891. [bug] Use ${INSTALL_SCRIPT} rather than ${INSTALL_PROGRAM} + to install python programs. + +3890. [bug] RRSIG sets that were not loaded in a single transaction + at start up where not being correctly added to + re-signing heaps. [RT #36302] + +3889. [port] hurd: configure fixes as per: + https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=746540 + +3888. [func] 'rndc status' now reports the number of automatic + zones. [RT #36015] + +3887. [cleanup] Make all static symbols in rbtdb64 end in "64" so + they are easier to use in a debugger. [RT #36373] + +3886. [bug] rbtdb_write_header should use a once to initialize + FILE_VERSION. [RT #36374] + +3885. [port] Use 'open()' rather than 'file()' to open files in + python. + +3884. [protocol] Add CDS and CDNSKEY record types. [RT #36333] + +3883. [placeholder] + +3882. [func] By default, negative trust anchors will be tested + periodically to see whether data below them can be + validated, and if so, they will be allowed to + expire early. The "rndc nta -force" option + overrides this behavior. The default NTA lifetime + and the recheck frequency can be configured by the + "nta-lifetime" and "nta-recheck" options. [RT #36146] + +3881. [bug] Address memory leak with UPDATE error handling. + [RT #36303] + +3880. [test] Update ans.pl to work with new TSIG support in + Net::DNS; add additional Net::DNS version prerequisite + checks. [RT #36327] + +3879. [func] Add version printing option to various BIND utilities. + [RT #10686] + +3878. [bug] Using the incorrect filename for a DLZ module + caused a segmentation fault on startup. [RT #36286] + +3877. [bug] Inserting and deleting parent and child nodes + in response policy zones could trigger an assertion + failure. [RT #36272] + +3876. [bug] Improve efficiency of DLZ redirect zones by + suppressing unnecessary database lookups. [RT #35835] + +3875. [cleanup] Clarify log message when unable to read private + key files. [RT #24702] + +3874. [test] Check that only "check-names master" is needed for + updates to be accepted. + +3873. [protocol] Only warn for SPF without TXT spf record. [RT #36210] + +3872. [bug] Address issues found by static analysis. [RT #36209] + +3871. [bug] Don't publish an activated key automatically before + its publish time. [RT #35063] + +3870. [func] Updated the random number generator used in + the resolver to use the updated ChaCha based one + (similar to OpenBSD's changes). Also moved the + RNG to libisc and added unit tests for it. + [RT #35942] + +3869. [doc] Document that in-view zones cannot be used for + response policy zones. [RT #35941] + +3868. [bug] isc_mem_setwater incorrectly cleared hi_called + potentially leaving over memory cleaner running. + [RT #35270] + +3867. [func] "rndc nta" can now be used to set a temporary + negative trust anchor, which disables DNSSEC + validation below a specified name for a specified + period of time (not exceeding 24 hours). This + can be used when validation for a domain is known + to be failing due to a configuration error on + the part of the domain owner rather than a + spoofing attack. [RT #29358] + +3866. [bug] Named could die on disk full in generate_session_key. + [RT #36119] + +3865. [test] Improved testability of the red-black tree + implementation and added unit tests. [RT #35904] + +3864. [bug] RPZ didn't work well when being used as forwarder. + [RT #36060] + +3863. [bug] The "E" flag was missing from the query log as a + unintended side effect of code rearrangement to + support EDNS EXPIRE. [RT #36117] + +3862. [cleanup] Return immediately if we are not going to log the + message in ns_client_dumpmessage. + +3861. [security] Missing isc_buffer_availablelength check results + in a REQUIRE assertion when printing out a packet + (CVE-2014-3859). [RT #36078] + +3860. [bug] ioctl(DP_POLL) array size needs to be determined + at run time as it is limited to {OPEN_MAX}. + [RT #35878] + +3859. [placeholder] + +3858. [bug] Disable GCC 4.9 "delete null pointer check". + [RT #35968] + +3857. [bug] Make it harder for a incorrect NOEDNS classification + to be made. [RT #36020] + +3856. [bug] Configuring libjson without also configuring libxml + resulted in a REQUIRE assertion when retrieving + statistics using json. [RT #36009] + +3855. [bug] Limit smoothed round trip time aging to no more than + once a second. [RT #32909] + +3854. [cleanup] Report unrecognized options, if any, in the final + configure summary. [RT #36014] + +3853. [cleanup] Refactor dns_rdataslab_fromrdataset to separate out + the handling of a rdataset with no records. [RT #35968] + +3852. [func] Increase the default number of clients available + for servicing lightweight resolver queries, and + make them configurable via the "lwres-tasks" and + "lwres-clients" options. (Thanks to Tomas Hozza.) + [RT #35857] + +3851. [func] Allow libseccomp based system-call filtering + on Linux; use "configure --enable-seccomp" to + turn it on. Thanks to Loganaden Velvindron + of AFRINIC for the contribution. [RT #35347] + +3850. [bug] Disabling forwarding could trigger a REQUIRE assertion. + [RT #35979] + +3849. [doc] Alphabetized dig's +options. [RT #35992] + +3848. [bug] Adjust 'statistics-channels specified but not effective' + error message to account for JSON support. [RT #36008] + +3847. [bug] 'configure --with-dlz-postgres' failed to fail when + there is not support available. + +3846. [bug] "dig +notcp ixfr=" should result in a UDP + ixfr query. [RT #35980] + +3845. [placeholder] + +3844. [bug] Use the x64 version of the Microsoft Visual C++ + Redistributable when built for 64 bit Windows. + [RT #35973] + +3843. [protocol] Check EDNS EXPIRE option in dns_rdata_fromwire. + [RT #35969] + +3842. [bug] Adjust RRL log-only logging category. [RT #35945] + +3841. [cleanup] Refactor zone.c:add_opt to use dns_message_buildopt. + [RT #35924] + +3840. [port] Check for arc4random_addrandom() before using it; + it's been removed from OpenBSD 5.5. [RT #35907] + +3839. [test] Use only posix-compatible shell in system tests. + [RT #35625] + +3838. [protocol] EDNS EXPIRE as been assigned a code point of 9. + +3837. [security] A NULL pointer is passed to query_prefetch resulting + a REQUIRE assertion failure when a fetch is actually + initiated (CVE-2014-3214). [RT #35899] + +3836. [bug] Address C++ keyword usage in header file. + +3835. [bug] Geoip ACL elements didn't work correctly when + referenced via named or nested ACLs. [RT #35879] + +3834. [bug] The re-signing heaps were not being updated soon enough + leading to multiple re-generations of the same RRSIG + when a zone transfer was in progress. [RT #35273] + +3833. [bug] Cross compiling was broken due to calling genrandom at + build time. [RT #35869] + +3832. [func] "named -L " causes named to send log + messages to the specified file by default instead + of to the system log. (Thanks to Tony Finch.) + [RT #35845] + +3831. [cleanup] Reduce logging noise when EDNS state changes occur. + [RT #35843] + +3830. [func] When query logging is enabled, log query errors at + the same level ('info') as the queries themselves. + [RT #35844] + +3829. [func] "dig +ttlunits" causes dig to print TTL values + with time-unit suffixes: w, d, h, m, s for + weeks, days, hours, minutes, and seconds. (Thanks + to Tony Finch.) [RT #35823] + +3828. [func] "dnssec-signzone -N date" updates serial number + to the current date in YYYYMMDDNN format. + [RT #35800] + +3827. [placeholder] + +3826. [bug] Corrected bad INSIST logic in isc_radix_remove(). + [RT #35870] + +3825. [bug] Address sign extension bug in isc_regex_validate. + [RT #35758] + +3824. [bug] A collision between two flag values could cause + problems with cache cleaning when SIT was enabled. + [RT #35858] + +3823. [func] Log the rpz cname target when rewriting. [RT #35667] + +3822. [bug] Log the correct type of static-stub zones when + removing them. [RT #35842] + +3821. [contrib] Added a new "mysqldyn" DLZ module with dynamic + update and transaction support. Thanks to Marty + Lee for the contribution. [RT #35656] + +3820. [func] The DLZ API doesn't pass the database version to + the lookup() function; this can cause DLZ modules + that allow dynamic updates to mishandle prerequisite + checks. This has been corrected by adding a + 'dbversion' field to the dns_clientinfo_t + structure. [RT #35656] + +3819. [bug] NSEC3 hashes need to be able to be entered and + displayed without padding. This is not a issue for + currently defined algorithms but may be for future + hash algorithms. [RT #27925] + +3818. [bug] Stop lying to the optimizer that 'void *arg' is a + constant in isc_event_allocate. + +3817. [func] The "delve" command is now spelled "delv" to avoid + a namespace collision with the Xapian project. + [RT #35801] + +3816. [func] "dig +qr" now reports query size. (Thanks to + Tony Finch.) [RT #35822] + +3815. [doc] Clarify "nsupdate -y" usage in man page. [RT #35808] + +3814. [func] The "masterfile-style" zone option controls the + formatting of dumped zone files. Options are + "relative" (multiline format) and "full" (one + record per line). The default is "relative". + [RT #20798] + +3813. [func] "host" now recognizes the "timeout", "attempts" and + "debug" options when set in /etc/resolv.conf. + (Thanks to Adam Tkac at RedHat.) [RT #21885] + +3812. [func] Dig now supports sending arbitrary EDNS options from + the command line (+ednsopt=code[:value]). [RT #35584] + +3811. [func] "serial-update-method date;" sets serial number + on dynamic update to today's date in YYYYMMDDNN + format. (Thanks to Bradley Forschinger.) [RT #24903] + +3810. [bug] Work around broken nameservers that fail to ignore + unknown EDNS options. [RT #35766] + +3809. [doc] Fix SIT and NSID documentation. + +3808. [doc] Clean up "prefetch" documentation. [RT #35751] + +3807. [bug] Fix sign extension bug in dns_name_fromtext when + lowercase is set. [RT #35743] + +3806. [test] Improved system test portability. [RT #35625] + +3805. [contrib] Added contrib/perftcpdns, a performance testing tool + for DNS over TCP. [RT #35710] + + --- 9.10.0rc1 released --- + +3804. [bug] Corrected a race condition in dispatch.c in which + portentry could be reset leading to an assertion + failure in socket_search(). (Change #3708 + addressed the same issue but was incomplete.) + [RT #35128] + +3803. [bug] "named-checkconf -z" incorrectly rejected zones + using alternate data sources for not having a "file" + option. [RT #35685] + +3802. [bug] Various header files were not being installed. + +3801. [port] Fix probing for gssapi support on FreeBSD. [RT #35615] + +3800. [bug] A pending event on the route socket could cause an + assertion failure when shutting down named. [RT #35674] + +3799. [bug] Improve named's command line error reporting. + [RT #35603] + +3798. [bug] 'rndc zonestatus' was reporting the wrong re-signing + time. [RT #35659] + +3797. [port] netbsd: geoip support probing was broken. [RT #35642] + +3796. [bug] Register dns and pkcs#11 error codes. [RT #35629] + +3795. [bug] Make named-checkconf detect raw masterfiles for + hint zones and reject them. [RT #35268] + +3794. [maint] Added AAAA for C.ROOT-SERVERS.NET. + +3793. [bug] zone.c:save_nsec3param() could assert when out of + memory. [RT #35621] + +3792. [func] Provide links to the alternate statistics views when + displaying in a browser. [RT #35605] + +3791. [placeholder] + +3790. [bug] Handle broken nameservers that send BADVERS in + response to unknown EDNS options. Maintain + statistics on BADVERS responses. + +3789. [bug] Null pointer dereference on rbt creation failure. + +3788. [bug] dns_peer_getrequestsit was returning request_nsid by + mistake. + + --- 9.10.0b2 released --- + +3787. [bug] The code that checks whether "auto-dnssec" is + allowed was ignoring "allow-update" ACLs set at + the options or view level. [RT #29536] + +3786. [func] Provide more detailed error codes when using + native PKCS#11. "pkcs11-tokens" now fails robustly + rather than asserting when run against an HSM with + an incomplete PKCS#11 API implementation. [RT #35479] + +3785. [bug] Debugging code dumphex didn't accept arbitrarily long + input (only compiled with -DDEBUG). [RT #35544] + +3784. [bug] Using "rrset-order fixed" when it had not been + enabled at compile time caused inconsistent + results. It now works as documented, defaulting + to cyclic mode. [RT #28104] + +3783. [func] "tsig-keygen" is now available as an alternate + command name for "ddns-confgen". It generates + a TSIG key in named.conf format without comments. + [RT #35503] + +3782. [func] Specifying "auto" as the salt when using + "rndc signing -nsec3param" causes named to + generate a 64-bit salt at random. [RT #35322] + +3781. [tuning] Use adaptive mutex locks when available; this + has been found to improve performance under load + on many systems. "configure --with-locktype=standard" + restores conventional mutex locks. [RT #32576] + +3780. [bug] $GENERATE handled negative numbers incorrectly. + [RT #25528] + +3779. [cleanup] Clarify the error message when using an option + that was not enabled at compile time. [RT #35504] + +3778. [bug] Log a warning when the wrong address family is + used in "listen-on" or "listen-on-v6". [RT #17848] + +3777. [bug] EDNS EXPIRE code could dump core when processing + DLZ queries. [RT #35493] + +3776. [func] "rndc -q" suppresses output from successful + rndc commands. Errors are printed on stderr. + [RT #21393] + +3775. [bug] dlz_dlopen driver could return the wrong error + code on API version mismatch, leading to a segfault. + [RT #35495] + +3774. [func] When using "request-nsid", log the NSID value in + printable form as well as hex. [RT #20864] + +3773. [func] "host", "nslookup" and "nsupdate" now have + options to print the version number and exit. + [RT #26057] + +3772. [contrib] Added sqlite3 dynamically-loadable DLZ module. + (Based in part on a contribution from Tim Tessier.) + [RT #20822] + +3771. [cleanup] Adjusted log level for "using built-in key" + messages. [RT #24383] + +3770. [bug] "dig +trace" could fail with an assertion when it + needed to fall back to TCP due to a truncated + response. [RT #24660] + +3769. [doc] Improved documentation of "rndc signing -list". + [RT #30652] + +3768. [bug] "dnssec-checkds" was missing the SHA-384 digest + algorithm. [RT #34000] + +3767. [func] Log explicitly when using rndc.key to configure + command channel. [RT #35316] + +3766. [cleanup] Fixed problems with building outside the source + tree when using native PKCS#11. [RT #35459] + +3765. [bug] Fixed a bug in "rndc secroots" that could crash + named when dumping an empty keynode. [RT #35469] + +3764. [bug] The dnssec-keygen/settime -S and -i options + (to set up a successor key and set the prepublication + interval) were missing from dnssec-keyfromlabel. + [RT #35394] + +3763. [bug] delve: Cache DNSSEC records to avoid the need to + re-fetch them when restarting validation. [RT #35476] + +3762. [bug] Address build problems with --pkcs11-native + + --with-openssl with ECDSA support. [RT #35467] + +3761. [bug] Address dangling reference bug in dns_keytable_add. + [RT #35471] + +3760. [bug] Improve SIT with native PKCS#11 and on Windows. + [RT #35433] + +3759. [port] Enable delve on Windows. [RT #35441] + +3758. [port] Enable export library APIs on Windows. [RT #35382] + +3757. [port] Enable Python tools (dnssec-coverage, + dnssec-checkds) to run on Windows. [RT #34355] + +3756. [bug] GSSAPI Kerberos realm checking was broken in + check_config leading to spurious messages being + logged. [RT #35443] + + --- 9.10.0b1 released --- + +3755. [func] Add stats counters for known EDNS options + others. + [RT #35447] + +3754. [cleanup] win32: Installer now places files in the + Program Files area rather than system services. + [RT #35361] + +3753. [bug] allow-notify was ignoring keys. [RT #35425] + +3752. [bug] Address potential REQUIRE failure if + DNS_STYLEFLAG_COMMENTDATA is set when printing out + a rdataset. + +3751. [tuning] The default setting for the -U option (setting + the number of UDP listeners per interface) has + been adjusted to improve performance. [RT #35417] + +3750. [experimental] Partially implement EDNS EXPIRE option as described + in draft-andrews-dnsext-expire-00. Retrieval of + the remaining time until expiry for slave zones + is supported. + + EXPIRE uses an experimental option code (65002), + which is subject to change. [RT #35416] + +3749. [func] "dig +subnet" sends an EDNS client subnet option + containing the specified address/prefix when + querying. (Thanks to Wilmer van der Gaast.) + [RT #35415] + +3748. [test] Use delve to test dns_client interfaces. [RT #35383] + +3747. [bug] A race condition could lead to a core dump when + destroying a resolver fetch object. [RT #35385] + +3746. [func] New "max-zone-ttl" option enforces maximum + TTLs for zones. If loading a zone containing a + higher TTL, the load fails. DDNS updates with + higher TTLs are accepted but the TTL is truncated. + (Note: Currently supported for master zones only; + inline-signing slaves will be added.) [RT #38405] + +3745. [func] "configure --with-tuning=large" adjusts various + compiled-in constants and default settings to + values suited to large servers with abundant + memory. [RT #29538] + +3744. [experimental] SIT: send and process Source Identity Tokens + (similar to DNS Cookies by Donald Eastlake 3rd), + which are designed to help clients detect off-path + spoofed responses and for servers to identify + legitimate clients. + + SIT uses an experimental EDNS option code (65001), + which will be changed to an IANA-assigned value + if the experiment is deemed a success. + + SIT can be enabled via "configure --enable-sit" (or + --enable-developer). It is enabled by default in + Windows. + + Servers can be configured to send smaller responses + to clients that have not identified themselves via + SIT. RRL processing has also been updated; + legitimate clients are not subject to rate + limiting. [RT #35389] + +3743. [bug] delegation-only flag wasn't working in forward zone + declarations despite being documented. This is + needed to support turning off forwarding and turning + on delegation only at the same name. [RT #35392] + +3742. [port] linux: libcap support: declare curval at start of + block. [RT #35387] + +3741. [func] "delve" (domain entity lookup and validation engine): + A new tool with dig-like semantics for performing DNS + lookups, with internal DNSSEC validation, using the + same resolver and validator logic as named. This + allows easy validation of DNSSEC data in environments + with untrustworthy resolvers, and assists with + troubleshooting of DNSSEC problems. [RT #32406] + +3740. [contrib] Minor fixes to configure --with-dlz-bdb, + --with-dlz-postgres and --with-dlz-odbc. [RT #35340] + +3739. [func] Added per-zone stats counters to track TCP and + UDP queries. [RT #35375] + +3738. [bug] --enable-openssl-hash failed to build. [RT #35343] + +3737. [bug] 'rndc retransfer' could trigger a assertion failure + with inline zones. [RT #35353] + +3736. [bug] nsupdate: When specifying a server by name, + fall back to alternate addresses if the first + address for that name is not reachable. [RT #25784] + +3735. [cleanup] Merged the libiscpk11 library into libisc + to simplify dependencies. [RT #35205] + +3734. [bug] Improve building with libtool. [RT #35314] + +3733. [func] Improve interface scanning support. Interface + information will be automatically updated if the + OS supports routing sockets (MacOS, *BSD, Linux). + Use "automatic-interface-scan no;" to disable. + + Add "rndc scan" to trigger a scan. [RT #23027] + +3732. [contrib] Fixed a type mismatch causing the ODBC DLZ + driver to dump core on 64-bit systems. [RT #35324] + +3731. [func] Added a "no-case-compress" ACL, which causes + named to use case-insensitive compression + (disabling change #3645) for specified + clients. (This is useful when dealing + with broken client implementations that + use case-sensitive name comparisons, + rejecting responses that fail to match the + capitalization of the query that was sent.) + [RT #35300] + +3730. [cleanup] Added "never" as a synonym for "none" when + configuring key event dates in the dnssec tools. + [RT #35277] + +3729. [bug] dnssec-keygen could set the publication date + incorrectly when only the activation date was + specified on the command line. [RT #35278] + +3728. [doc] Expanded native-PKCS#11 documentation, + specifically pkcs11: URI labels. [RT #35287] + +3727. [func] The isc_bitstring API is no longer used and + has been removed from libisc. [RT #35284] + +3726. [cleanup] Clarified the error message when attempting + to configure more than 32 response-policy zones. + [RT #35283] + +3725. [contrib] Updated zkt and nslint to newest versions, + cleaned up and rearranged the contrib + directory, and added a README. + + --- 9.10.0a2 released --- + +3724. [bug] win32: Fixed a bug that prevented dig and + host from exiting properly after completing + a UDP query. [RT #35288] + +3723. [cleanup] Imported keys are now handled the same way + regardless of DNSSEC algorithm. [RT #35215] + +3722. [bug] Using geoip ACLs in a blackhole statement + could cause a segfault. [RT #35272] + +3721. [doc] Improved documentation of the EDNS processing + enhancements introduced in change #3593. [RT #35275] + +3720. [bug] Address compiler warnings. [RT #35261] + +3719. [bug] Address memory leak in in peer.c. [RT #35255] + +3718. [bug] A missing ISC_LINK_INIT in log.c. [RT #35260] + +3717. [port] hpux: Treat EOPNOTSUPP as a expected error code when + probing to see if it is possible to set dscp values + on a per packet basis. [RT #35252] + +3716. [bug] The dns_request code was setting dcsp values when not + requested. [RT #35252] + +3715. [bug] The region and city databases could fail to + initialize when using some versions of libGeoIP, + causing assertion failures when named was + configured to use them. [RT #35427] + +3714. [test] System tests that need to test for cryptography + support before running can now use a common + "testcrypto.sh" script to do so. [RT #35213] + +3713. [bug] Save memory by not storing "also-notify" addresses + in zone objects that are configured not to send + notify requests. [RT #35195] + +3712. [placeholder] + +3711. [placeholder] + +3710. [bug] Address double dns_zone_detach when switching to + using automatic empty zones from regular zones. + [RT #35177] + +3709. [port] Use built-in versions of strptime() and timegm() + on all platforms to avoid portability issues. + [RT #35183] + +3708. [bug] Address a portentry locking issue in dispatch.c. + [RT #35128] + +3707. [bug] irs_resconf_load now returns ISC_R_FILENOTFOUND + on a missing resolv.conf file and initializes the + structure as if it had been configured with: + + nameserver ::1 + nameserver 127.0.0.1 + + Note: Callers will need to be updated to treat + ISC_R_FILENOTFOUND as a qualified success or else + they will leak memory. The following code fragment + will work with both old and new versions without + changing the behaviour of the existing code. + + resconf = NULL; + result = irs_resconf_load(mctx, "/etc/resolv.conf", + &resconf); + if (result != ISC_SUCCESS) { + if (resconf != NULL) + irs_resconf_destroy(&resconf); + .... + } + + [RT #35194] + +3706. [contrib] queryperf: Fixed a possible integer overflow when + printing results. [RT #35182] + +3705. [func] "configure --enable-native-pkcs11" enables BIND + to use the PKCS#11 API for all cryptographic + functions, so that it can drive a hardware service + module directly without the need to use a modified + OpenSSL as intermediary (so long as the HSM's vendor + provides a complete-enough implementation of the + PKCS#11 interface). This has been tested successfully + with the Thales nShield HSM and with SoftHSMv2 from + the OpenDNSSEC project. [RT #29031] + +3704. [protocol] Accept integer timestamps in RRSIG records. [RT #35185] + +3703. [func] To improve recursive resolver performance, cache + records which are still being requested by clients + can now be automatically refreshed from the + authoritative server before they expire, reducing + or eliminating the time window in which no answer + is available in the cache. See the "prefetch" option + for more details. [RT #35041] + +3702. [func] 'dnssec-coverage -l' option specifies a length + of time to check for coverage; events further into + the future are ignored. 'dnssec-coverage -z' + checks only ZSK events, and 'dnssec-coverage -k' + checks only KSK events. (Thanks to Peter Palfrader.) + [RT #35168] + +3701. [func] named-checkconf can now obscure shared secrets + when printing by specifying '-x'. [RT #34465] + +3700. [func] Allow access to subgroups of XML statistics via + special URLs http://:/xml/v3/server, + /zones, /net, /tasks, /mem, and /status. [RT #35115] + +3699. [bug] Improvements to statistics channel XSL stylesheet: + the stylesheet can now be cached by the browser; + section headers are omitted from the stats display + when there is no data in those sections to be + displayed; counters are now right-justified for + easier readability. [RT #35117] + +3698. [cleanup] Replaced all uses of memcpy() with memmove(). + [RT #35120] + +3697. [bug] Handle "." as a search list element when IDN support + is enabled. [RT #35133] + +3696. [bug] dig failed to handle AXFR style IXFR responses which + span multiple messages. [RT #35137] + +3695. [bug] Address a possible race in dispatch.c. [RT #35107] + +3694. [bug] Warn when a key-directory is configured for a zone, + but does not exist or is not a directory. [RT #35108] + +3693. [security] memcpy was incorrectly called with overlapping + ranges resulting in malformed names being generated + on some platforms. This could cause INSIST failures + when serving NSEC3 signed zones (CVE-2014-0591). + [RT #35120] + +3692. [bug] Two calls to dns_db_getoriginnode were fatal if there + was no data at the node. [RT #35080] + +3691. [contrib] Address null pointer dereference in LDAP and + MySQL DLZ modules. + +3690. [bug] Iterative responses could be missed when the source + port for an upstream query was the same as the + listener port (53). [RT #34925] + +3689. [bug] Fixed a bug causing an insecure delegation from one + static-stub zone to another to fail with a broken + trust chain. [RT #35081] + +3688. [bug] loadnode could return a freed node on out of memory. + [RT #35106] + +3687. [bug] Address null pointer dereference in zone_xfrdone. + [RT #35042] + +3686. [func] "dnssec-signzone -Q" drops signatures from keys + that are still published but no longer active. + [RT #34990] + +3685. [bug] "rndc refresh" didn't work correctly with slave + zones using inline-signing. [RT #35105] + +3684. [bug] The list of included files would grow on reload. + [RT 35090] + +3683. [cleanup] Add a more detailed "not found" message to rndc + commands which specify a zone name. [RT #35059] + +3682. [bug] Correct the behavior of rndc retransfer to allow + inline-signing slave zones to retain NSEC3 parameters + instead of reverting to NSEC. [RT #34745] + +3681. [port] Update the Windows build system to support feature + selection and WIN64 builds. This is a work in + progress. [RT #34160] + +3680. [bug] Ensure buffer space is available in "rndc zonestatus". + [RT #35084] + +3679. [bug] dig could fail to clean up TCP sockets still + waiting on connect(). [RT #35074] + +3678. [port] Update config.guess and config.sub. [RT #35060] + +3677. [bug] 'nsupdate' leaked memory if 'realm' was used multiple + times. [RT #35073] + +3676. [bug] "named-checkconf -z" now checks zones of type + hint and redirect as well as master. [RT #35046] + +3675. [misc] Provide a place for third parties to add version + information for their extensions in the version + file by setting the EXTENSIONS variable. + + --- 9.10.0a1 released --- + +3674. [bug] RPZ zeroed ttls if the query type was '*'. [RT #35026] + +3673. [func] New "in-view" zone option allows direct sharing + of zones between views. [RT #32968] + +3672. [func] Local address can now be specified when using + dns_client API. [RT #34811] + +3671. [bug] Don't allow dnssec-importkey overwrite a existing + non-imported private key. + +3670. [bug] Address read after free in server side of + lwres_getrrsetbyname. [RT #29075] + +3669. [port] freebsd: --with-gssapi needs -lhx509. [RT #35001] + +3668. [bug] Fix cast in lex.c which could see 0xff treated as eof. + [RT #34993] + +3667. [test] dig: add support to keep the TCP socket open between + successive queries (+[no]keepopen). [RT #34918] + +3666. [func] Add a tool, named-rrchecker, for checking the syntax + of individual resource records. This tool is intended + to be called by provisioning systems so that the front + end does not need to be upgraded to support new DNS + record types. [RT #34778] + +3665. [bug] Failure to release lock on error in receive_secure_db. + [RT #34944] + +3664. [bug] Updated OpenSSL PKCS#11 patches to fix active list + locking and other bugs. [RT #34855] + +3663. [bug] Address bugs in dns_rdata_fromstruct and + dns_rdata_tostruct for WKS and ISDN types. [RT #34910] + +3662. [bug] 'host' could die if a UDP query timed out. [RT #34870] + +3661. [bug] Address lock order reversal deadlock with inline zones. + [RT #34856] + +3660. [cleanup] Changed the name of "isc-config.sh" to "bind9-config". + [RT #23825] + +3659. [port] solaris: don't add explicit dependencies/rules for + python programs as make won't use the implicit rules. + [RT #34835] + +3658. [port] linux: Address platform specific compilation issue + when libcap-devel is installed. [RT #34838] + +3657. [port] Some readline clones don't accept NULL pointers when + calling add_history. [RT #34842] + +3656. [security] Treat an all zero netmask as invalid when generating + the localnets acl. (The prior behavior could + allow unexpected matches when using some versions + of Winsock: CVE-2013-6320.) [RT #34687] + +3655. [cleanup] Simplify TCP message processing when requesting a + zone transfer. [RT #34825] + +3654. [bug] Address race condition with manual notify requests. + [RT #34806] + +3653. [func] Create delegations for all "children" of empty zones + except "forward first". [RT #34826] + +3652. [bug] Address bug with rpz-drop policy. [RT #34816] + +3651. [tuning] Adjust when a master server is deemed unreachable. + [RT #27075] + +3650. [tuning] Use separate rate limiting queues for refresh and + notify requests. [RT #30589] + +3649. [cleanup] Include a comment in .nzf files, giving the name of + the associated view. [RT #34765] + +3648. [test] Updated the ATF test framework to version 0.17. + [RT #25627] + +3647. [bug] Address a race condition when shutting down a zone. + [RT #34750] + +3646. [bug] Journal filename string could be set incorrectly, + causing garbage in log messages. [RT #34738] + +3645. [protocol] Use case sensitive compression when responding to + queries. [RT #34737] + +3644. [protocol] Check that EDNS subnet client options are well formed. + [RT #34718] + +3643. [doc] Clarify RRL "slip" documentation. + +3642. [func] Allow externally generated DNSKEY to be imported + into the DNSKEY management framework. A new tool + dnssec-importkey is used to do this. [RT #34698] + +3641. [bug] Handle changes to sig-validity-interval settings + better. [RT #34625] + +3640. [bug] ndots was not being checked when searching. Only + continue searching on NXDOMAIN responses. Add the + ability to specify ndots to nslookup. [RT #34711] + +3639. [bug] Treat type 65533 (KEYDATA) as opaque except when used + in a key zone. [RT #34238] + +3638. [cleanup] Add the ability to handle ENOPROTOOPT in case it is + encountered. [RT #34668] + +3637. [bug] 'allow-query-on' was checking the source address + rather than the destination address. [RT #34590] + +3636. [bug] Automatic empty zones now behave better with + forward only "zones" beneath them. [RT #34583] + +3635. [bug] Signatures were not being removed from a zone with + only KSK keys for a algorithm. [RT #34439] + +3634. [func] Report build-id in rndc status. Report build-id + when building from a git repository. [RT #20422] + +3633. [cleanup] Refactor OPT processing in named to make it easier + to support new EDNS options. [RT #34414] + +3632. [bug] Signature from newly inactive keys were not being + removed. [RT #32178] + +3631. [bug] Remove spurious warning about missing signatures when + qtype is SIG. [RT #34600] + +3630. [bug] Ensure correct ID computation for MD5 keys. [RT #33033] + +3629. [func] Allow the printing of cryptographic fields in DNSSEC + records by dig to be suppressed (dig +nocrypto). + [RT #34534] + +3628. [func] Report DNSKEY key id's when dumping the cache. + [RT #34533] + +3627. [bug] RPZ changes were not effective on slaves. [RT #34450] + +3626. [func] dig: NSID output now easier to read. [RT #21160] + +3625. [bug] Don't send notify messages to machines outside of the + test setup. + +3624. [bug] Look for 'json_object_new_int64' when looking for a + the json library. [RT #34449] + +3623. [placeholder] + +3622. [tuning] Eliminate an unnecessary lock when incrementing + cache statistics. [RT #34339] + +3621. [security] Incorrect bounds checking on private type 'keydata' + can lead to a remotely triggerable REQUIRE failure + (CVE-2013-4854). [RT #34238] + +3620. [func] Added "rpz-client-ip" policy triggers, enabling + RPZ responses to be configured on the basis of + the client IP address; this can be used, for + example, to blacklist misbehaving recursive + or stub resolvers. [RT #33605] + +3619. [bug] Fixed a bug in RPZ with "recursive-only no;" + [RT #33776] + +3618. [func] "rndc reload" now checks modification times of + include files as well as master files to determine + whether to skip reloading a zone. [RT #33936] + +3617. [bug] Named was failing to answer queries during + "rndc reload" [RT #34098] + +3616. [bug] Change #3613 was incomplete. [RT #34177] + +3615. [cleanup] "configure" now finishes by printing a summary + of optional BIND features and whether they are + active or inactive. ("configure --enable-full-report" + increases the verbosity of the summary.) [RT #31777] + +3614. [port] Check for . [RT #34162] + +3613. [bug] named could crash when deleting inline-signing + zones with "rndc delzone". [RT #34066] + +3612. [port] Check whether to use -ljson or -ljson-c. [RT #34115] + +3611. [bug] Improved resistance to a theoretical authentication + attack based on differential timing. [RT #33939] + +3610. [cleanup] win32: Some executables had been omitted from the + installer. [RT #34116] + +3609. [bug] Corrected a possible deadlock in applications using + the export version of the isc_app API. [RT #33967] + +3608. [port] win32: added todos.pl script to ensure all text files + the win32 build depends on are converted to DOS + newline format. [RT #22067] + +3607. [bug] dnssec-keygen had broken 'Invalid keyfile' error + message. [RT #34045] + +3606. [func] "rndc flushtree" now flushes matching + records in the address database and bad cache + as well as the DNS cache. (Previously only the + DNS cache was flushed.) [RT #33970] + +3605. [port] win32: Addressed several compatibility issues + with newer versions of Visual Studio. [RT #33916] + +3604. [bug] Fixed a compile-time error when building with + JSON but not XML. [RT #33959] + +3603. [bug] Install . [RT #33956] + +3602. [contrib] Added DLZ Perl module, allowing Perl scripts to + integrate with named and serve DNS data. + (Contributed by John Eaglesham of Yahoo.) + +3601. [bug] Added to PKCS#11 openssl patches a value len + attribute in DH derive key. [RT #33928] + +3600. [cleanup] dig: Fixed a typo in the warning output when receiving + an oversized response. [RT #33910] + +3599. [tuning] Check for pointer equivalence in name comparisons. + [RT #18125] + +3598. [cleanup] Improved portability of map file code. [RT #33820] + +3597. [bug] Ensure automatic-resigning heaps are reconstructed + when loading zones in map format. [RT #33381] + +3596. [port] Updated win32 build documentation, added + dnssec-verify. [RT #22067] + +3595. [port] win32: Fix build problems introduced by change #3550. + [RT #33807] + +3594. [maint] Update config.guess and config.sub. [RT #33816] + +3593. [func] Update EDNS processing to better track remote server + capabilities. [RT #30655] + +3592. [doc] Moved documentation of rndc command options to the + rndc man page. [RT #33506] + +3591. [func] Use CRC-64 to detect map file corruption at load + time. [RT #33746] + +3590. [bug] When using RRL on recursive servers, defer + rate-limiting until after recursion is complete; + also, use correct rcode for slipped NXDOMAIN + responses. [RT #33604] + +3589. [func] Report serial numbers in when starting zone transfers. + Report accepted NOTIFY requests including serial. + [RT #33037] + +3588. [bug] dig: addressed a memory leak in the sigchase code + that could cause a shutdown crash. [RT #33733] + +3587. [func] 'named -g' now checks the logging configuration but + does not use it. [RT #33473] + +3586. [bug] Handle errors in xmlDocDumpFormatMemoryEnc. [RT #33706] + +3585. [func] "rndc delzone -clean" option removes zone files + when deleting a zone. [RT #33570] + +3584. [security] Caching data from an incompletely signed zone could + trigger an assertion failure in resolver.c + (CVE-2013-3919). [RT #33690] + +3583. [bug] Address memory leak in GSS-API processing [RT #33574] + +3582. [bug] Silence false positive warning regarding missing file + directive for inline slave zones. [RT #33662] + +3581. [bug] Changed the tcp-listen-queue default to 10. [RT #33029] + +3580. [bug] Addressed a possible race in acache.c [RT #33602] + +3579. [maint] Updates to PKCS#11 openssl patches, supporting + versions 0.9.8y, 1.0.0k, 1.0.1e [RT #33463] + +3578. [bug] 'rndc -c file' now fails if 'file' does not exist. + [RT #33571] + +3577. [bug] Handle zero TTL values better. [RT #33411] + +3576. [bug] Address a shutdown race when validating. [RT #33573] + +3575. [func] Changed the logging category for RRL events from + 'queries' to 'query-errors'. [RT #33540] + +3574. [doc] The 'hostname' keyword was missing from server-id + description in the named.conf man page. [RT #33476] + +3573. [bug] "rndc addzone" and "rndc delzone" incorrectly handled + zone names containing punctuation marks and other + nonstandard characters. [RT #33419] + +3572. [func] Threads are now enabled by default on most + operating systems. [RT #25483] + +3571. [bug] Address race condition in dns_client_startresolve(). + [RT #33234] + +3570. [bug] Check internal pointers are valid when loading map + files. [RT #33403] + +3569. [contrib] Ported mysql DLZ driver to dynamically-loadable + module, and added multithread support. [RT #33394] + +3568. [cleanup] Add a product description line to the version file, + to be reported by named -v/-V. [RT #33366] + +3567. [bug] Silence clang static analyzer warnings. [RT #33365] + +3566. [func] Log when forwarding updates to master. [RT #33240] + +3565. [placeholder] + +3564. [bug] Improved handling of corrupted map files. [RT #33380] + +3563. [contrib] zone2sqlite failed with some table names. [RT #33375] + +3562. [func] Update map file header format to include a SHA-1 hash + of the database content, so that corrupted map files + can be rejected at load time. [RT #32459] + +3561. [bug] dig: issue a warning if an EDNS query returns FORMERR + or NOTIMP. Adjust usage message. [RT #33363] + +3560. [bug] isc-config.sh did not honor includedir and libdir + when set via configure. [RT #33345] + +3559. [func] Check that both forms of Sender Policy Framework + records exist or do not exist. [RT #33355] + +3558. [bug] IXFR of a DLZ stored zone was broken. [RT #33331] + +3557. [bug] Reloading redirect zones was broken. [RT #33292] + +3556. [maint] Added AAAA for D.ROOT-SERVERS.NET. + +3555. [bug] Address theoretical race conditions in acache.c + (change #3553 was incomplete). [RT #33252] + +3554. [bug] RRL failed to correctly rate-limit upward + referrals and failed to count dropped error + responses in the statistics. [RT #33225] + +3553. [bug] Address suspected double free in acache. [RT #33252] + +3552. [bug] Wrong getopt option string for 'nsupdate -r'. + [RT #33280] + +3551. [bug] resolver.querydscp[46] were uninitialized. [RT #32686] + +3550. [func] Unified the internal and export versions of the + BIND libraries, allowing external clients to use + the same libraries as BIND. [RT #33131] + +3549. [doc] Documentation for "request-nsid" was missing. + [RT #33153] + +3548. [bug] The NSID request code in resolver.c was broken + resulting in invalid EDNS options being sent. + [RT #33153] + +3547. [bug] Some malformed unknown rdata records were not properly + detected and rejected. [RT #33129] + +3546. [func] Add EUI48 and EUI64 types. [RT #33082] + +3545. [bug] RRL slip behavior was incorrect when set to 1. + [RT #33111] + +3544. [contrib] check5011.pl: Script to report the status of + managed keys as recorded in managed-keys.bind. + Contributed by Tony Finch + +3543. [bug] Update socket structure before attaching to socket + manager after accept. [RT #33084] + +3542. [placeholder] + +3541. [bug] Parts of libdns were not properly initialized when + built in libexport mode. [RT #33028] + +3540. [test] libt_api: t_info and t_assert were not thread safe. + +3539. [port] win32: timestamp format didn't match other platforms. + +3538. [test] Running "make test" now requires loopback interfaces + to be set up. [RT #32452] + +3537. [tuning] Slave zones, when updated, now send NOTIFY messages + to peers before being dumped to disk rather than + after. [RT #27242] + +3536. [func] Add support for setting Differentiated Services Code + Point (DSCP) values in named. Most configuration + options which take a "port" option (e.g., + listen-on, forwarders, also-notify, masters, + notify-source, etc) can now also take a "dscp" + option specifying a code point for use with + outgoing traffic, if supported by the underlying + OS. [RT #27596] + +3535. [bug] Minor win32 cleanups. [RT #32962] + +3534. [bug] Extra text after an embedded NULL was ignored when + parsing zone files. [RT #32699] + +3533. [contrib] query-loc-0.4.0: memory leaks. [RT #32960] + +3532. [contrib] zkt: fixed buffer overrun, resource leaks. [RT #32960] + +3531. [bug] win32: A uninitialized value could be returned on out + of memory. [RT #32960] + +3530. [contrib] Better RTT tracking in queryperf. [RT #30128] + +3529. [func] Named now listens on both IPv4 and IPv6 interfaces + by default. Named previously only listened on IPv4 + interfaces by default unless named was running in + IPv6 only mode. [RT #32945] + +3528. [func] New "dnssec-coverage" command scans the timing + metadata for a set of DNSSEC keys and reports if a + lapse in signing coverage has been scheduled + inadvertently. (Note: This tool depends on python; + it will not be built or installed on systems that + do not have a python interpreter.) [RT #28098] + +3527. [compat] Add a URI to allow applications to explicitly + request a particular XML schema from the statistics + channel, returning 404 if not supported. [RT #32481] + +3526. [cleanup] Set up dependencies for unit tests correctly during + build. [RT #32803] + +3525. [func] Support for additional signing algorithms in rndc: + hmac-sha1, -sha224, -sha256, -sha384, and -sha512. + The -A option to rndc-confgen can be used to + select the algorithm for the generated key. + (The default is still hmac-md5; this may + change in a future release.) [RT #20363] + +3524. [func] Added an alternate statistics channel in JSON format, + when the server is built with the json-c library: + http://[address]:[port]/json. [RT #32630] + +3523. [contrib] Ported filesystem and ldap DLZ drivers to + dynamically-loadable modules, and added the + "wildcard" module based on a contribution from + Vadim Goncharov . [RT #23569] + +3522. [bug] DLZ lookups could fail to return SERVFAIL when + they ought to. [RT #32685] + +3521. [bug] Address memory leak in opensslecdsa_link.c. [RT #32249] + +3520. [bug] 'mctx' was not being referenced counted in some places + where it should have been. [RT #32794] + +3519. [func] Full replay protection via four-way handshake is + now mandatory for rndc clients. Very old versions + of rndc will no longer work. [RT #32798] + +3518. [bug] Increase the size of dns_rrl_key.s.rtype by one bit + so that all dns_rrl_rtype_t enum values fit regardless + of whether it is treated as signed or unsigned by + the compiler. [RT #32792] + +3517. [bug] Reorder destruction to avoid shutdown race. [RT #32777] + +3516. [placeholder] + +3515. [port] '%T' is not portable in strftime(). [RT #32763] + +3514. [bug] The ranges for valid key sizes in ddns-confgen and + rndc-confgen were too constrained. Keys up to 512 + bits are now allowed for most algorithms, and up + to 1024 bits for hmac-sha384 and hmac-sha512. + [RT #32753] + +3513. [func] "dig -u" prints times in microseconds rather than + milliseconds. [RT #32704] + +3512. [func] "rndc validation check" reports the current status + of DNSSEC validation. [RT #21397] + +3511. [doc] Improve documentation of redirect zones. [RT #32756] + +3510. [func] "rndc status" and XML statistics channel now report + server start and reconfiguration times. [RT #21048] + +3509. [cleanup] Added a product line to version file to allow for + easy naming of different products (BIND + vs BIND ESV, for example). [RT #32755] + +3508. [contrib] queryperf was incorrectly rejecting the -T option. + [RT #32338] + +3507. [bug] Statistics channel XSL had a glitch when attempting + to chart query data before any queries had been + received. [RT #32620] + +3506. [func] When setting "max-cache-size" and "max-acache-size", + the keyword "unlimited" is no longer defined as equal + to 4 gigabytes (except on 32-bit platforms); it + means literally unlimited. [RT #32358] + +3505. [bug] When setting "max-cache-size" and "max-acache-size", + larger values than 4 gigabytes could not be set + explicitly, though larger sizes were available + when setting cache size to 0. This has been + corrected; the full range is now available. + [RT #32358] + +3504. [func] Add support for ACLs based on geographic location, + using MaxMind GeoIP databases. Based on code + contributed by Ken Brownfield . + [RT #30681] + +3503. [doc] Clarify size_spec syntax. [RT #32449] + +3502. [func] zone-statistics: "no" is now a synonym for "none", + instead of "terse". [RT #29165] + +3501. [func] zone-statistics now takes three options: full, + terse, and none. "yes" and "no" are retained as + synonyms for full and terse, respectively. [RT #29165] + +3500. [security] Support NAPTR regular expression validation on + all platforms without using libregex, which + can be vulnerable to memory exhaustion attack + (CVE-2013-2266). [RT #32688] + +3499. [doc] Corrected ARM documentation of built-in zones. + [RT #32694] + +3498. [bug] zone statistics for zones which matched a potential + empty zone could have their zone-statistics setting + overridden. + +3497. [func] When deleting a slave/stub zone using 'rndc delzone' + report the files that were being used so they can + be cleaned up if desired. [RT #27899] + +3496. [placeholder] + +3495. [func] Support multiple response-policy zones (up to 32), + while improving RPZ performance. "response-policy" + syntax now includes a "min-ns-dots" clause, with + default 1, to exclude top-level domains from + NSIP and NSDNAME checking. --enable-rpz-nsip and + --enable-rpz-nsdname are now the default. [RT #32251] + +3494. [func] DNS RRL: Blunt the impact of DNS reflection and + amplification attacks by rate-limiting substantially- + identical responses. [RT #28130] + +3493. [contrib] Added BDBHPT dynamically-loadable DLZ module, + contributed by Mark Goldfinch. [RT #32549] + +3492. [bug] Fixed a regression in zone loading performance + due to lock contention. [RT #30399] + +3491. [bug] Slave zones using inline-signing must specify a + file name. [RT #31946] + +3490. [bug] When logging RDATA during update, truncate if it's + too long. [RT #32365] + +3489. [bug] --enable-developer now turns on ISC_LIST_CHECKINIT. + dns_dlzcreate() failed to properly initialize + dlzdb.link. When cloning a rdataset do not copy + the link contents. [RT #32651] + +3488. [bug] Use after free error with DH generated keys. [RT #32649] + +3487. [bug] Change 3444 was not complete. There was a additional + place where the NOQNAME proof needed to be saved. + [RT #32629] + +3486. [bug] named could crash when using TKEY-negotiated keys + that had been deleted and then recreated. [RT #32506] + +3485. [cleanup] Only compile openssl_gostlink.c if we support GOST. + +3484. [bug] Some statistics were incorrectly rendered in XML. + [RT #32587] + +3483. [placeholder] + +3482. [func] dig +nssearch now prints name servers that don't + have address records (missing AAAA or A, or the name + doesn't exist). [RT #29348] + +3481. [cleanup] Removed use of const const in atf. + +3480. [bug] Silence logging noise when setting up zone + statistics. [RT #32525] + +3479. [bug] Address potential memory leaks in gssapi support + code. [RT #32405] + +3478. [port] Fix a build failure in strict C99 environments + [RT #32475] + +3477. [func] Expand logging when adding records via DDNS update + [RT #32365] + +3476. [bug] "rndc zonestatus" could report a spurious "not + found" error on inline-signing zones. [RT #29226] + +3475. [cleanup] Changed name of 'map' zone file format (previously + 'fast'). [RT #32458] + +3474. [bug] nsupdate could assert when the local and remote + address families didn't match. [RT #22897] + +3473. [bug] dnssec-signzone/verify could incorrectly report + an error condition due to an empty node above an + opt-out delegation lacking an NSEC3. [RT #32072] + +3472. [bug] The active-connections counter in the socket + statistics could underflow. [RT #31747] + +3471. [bug] The number of UDP dispatches now defaults to + the number of CPUs even if -n has been set to + a higher value. [RT #30964] + +3470. [bug] Slave zones could fail to dump when successfully + refreshing after an initial failure. [RT #31276] + +3469. [bug] Handle DLZ lookup failures more gracefully. Improve + backward compatibility between versions of DLZ dlopen + API. [RT #32275] + +3468. [security] RPZ rules to generate A records (but not AAAA records) + could trigger an assertion failure when used in + conjunction with DNS64 (CVE-2012-5689). [RT #32141] + +3467. [bug] Added checks in dnssec-keygen and dnssec-settime + to check for delete date < inactive date. [RT #31719] + +3466. [contrib] Corrected the DNS_CLIENTINFOMETHODS_VERSION check + in DLZ example driver. [RT #32275] + +3465. [bug] Handle isolated reserved ports. [RT #31778] + +3464. [maint] Updates to PKCS#11 openssl patches, supporting + versions 0.9.8x, 1.0.0j, 1.0.1c [RT #29749] + +3463. [doc] Clarify managed-keys syntax in ARM. [RT #32232] + +3462. [doc] Clarify server selection behavior of dig when using + -4 or -6 options. [RT #32181] + +3461. [bug] Negative responses could incorrectly have AD=1 + set. [RT #32237] + +3460. [bug] Only link against readline where needed. [RT #29810] + +3459. [func] Added -J option to named-checkzone/named-compilezone + to specify the path to the journal file. [RT #30958] + +3458. [bug] Return FORMERR when presented with a overly long + domain named in a request. [RT #29682] + +3457. [protocol] Add ILNP records (NID, LP, L32, L64). [RT #31836] + +3456. [port] g++47: ATF failed to compile. [RT #32012] + +3455. [contrib] queryperf: fix getopt option list. [RT #32338] + +3454. [port] sparc64: improve atomic support. [RT #25182] + +3453. [bug] 'rndc addzone' of a zone with 'inline-signing yes;' + failed. [RT #31960] + +3452. [bug] Accept duplicate singleton records. [RT #32329] + +3451. [port] Increase per thread stack size from 64K to 1M. + [RT #32230] + +3450. [bug] Stop logfileconfig system test spam system logs. + [RT #32315] + +3449. [bug] gen.c: use the pre-processor to construct format + strings so that compiler can perform sanity checks; + check the snprintf results. [RT #17576] + +3448. [bug] The allow-query-on ACL was not processed correctly. + [RT #29486] + +3447. [port] Add support for libxml2-2.9.x [RT #32231] + +3446. [port] win32: Add source ID (see change #3400) to build. + [RT #31683] + +3445. [bug] Warn about zone files with blank owner names + immediately after $ORIGIN directives. [RT #31848] + +3444. [bug] The NOQNAME proof was not being returned from cached + insecure responses. [RT #21409] + +3443. [bug] ddns-confgen: Some TSIG algorithms were incorrectly + rejected when generating keys. [RT #31927] + +3442. [port] Net::DNS 0.69 introduced a non backwards compatible + change. [RT #32216] + +3441. [maint] D.ROOT-SERVERS.NET is now 199.7.91.13. + +3440. [bug] Reorder get_key_struct to not trigger a assertion when + cleaning up due to out of memory error. [RT #32131] + +3439. [placeholder] + +3438. [bug] Don't accept unknown data escape in quotes. [RT #32031] + +3437. [bug] isc_buffer_init -> isc_buffer_constinit to initialize + buffers with constant data. [RT #32064] + +3436. [bug] Check malloc/calloc return values. [RT #32088] + +3435. [bug] Cross compilation support in configure was broken. + [RT #32078] + +3434. [bug] Pass client info to the DLZ findzone() entry + point in addition to lookup(). This makes it + possible for a database to answer differently + whether it's authoritative for a name depending + on the address of the client. [RT #31775] + +3433. [bug] dlz_findzone() did not correctly handle + ISC_R_NOMORE. [RT #31172] + +3432. [func] Multiple DLZ databases can now be configured. + DLZ databases are searched in the order configured, + unless set to "search no", in which case a + zone can be configured to be retrieved from a + particular DLZ database by using a "dlz " + option in the zone statement. DLZ databases can + support type "master" and "redirect" zones. + [RT #27597] + +3431. [bug] ddns-confgen: Some valid key algorithms were + not accepted. [RT #31927] + +3430. [bug] win32: isc_time_formatISO8601 was missing the + 'T' between the date and time. [RT #32044] + +3429. [bug] dns_zone_getserial2 could a return success without + returning a valid serial. [RT #32007] + +3428. [cleanup] dig: Add timezone to date output. [RT #2269] + +3427. [bug] dig +trace incorrectly displayed name server + addresses instead of names. [RT #31641] + +3426. [bug] dnssec-checkds: Clearer output when records are not + found. [RT #31968] + +3425. [bug] "acacheentry" reference counting was broken resulting + in use after free. [RT #31908] + +3424. [func] dnssec-dsfromkey now emits the hash without spaces. + [RT #31951] + +3423. [bug] "rndc signing -nsec3param" didn't accept the full + range of possible values. Address portability issues. + [RT #31938] + +3422. [bug] Added a clear error message for when the SOA does not + match the referral. [RT #31281] + +3421. [bug] Named loops when re-signing if all keys are offline. + [RT #31916] + +3420. [bug] Address VPATH compilation issues. [RT #31879] + +3419. [bug] Memory leak on validation cancel. [RT #31869] + +3418. [func] New XML schema (version 3.0) for the statistics channel + adds query type statistics at the zone level, and + flattens the XML tree and uses compressed format to + optimize parsing. Includes new XSL that permits + charting via the Google Charts API on browsers that + support javascript in XSL. The old XML schema has been + deprecated. [RT #30023] + +3417. [placeholder] + +3416. [bug] Named could die on shutdown if running with 128 UDP + dispatches per interface. [RT #31743] + +3415. [bug] named could die with a REQUIRE failure if a validation + was canceled. [RT #31804] + +3414. [bug] Address locking issues found by Coverity. [RT #31626] + +3413. [func] Record the number of DNS64 AAAA RRsets that have been + synthesized. [RT #27636] + +3412. [bug] Copy timeval structure from control message data. + [RT #31548] + +3411. [tuning] Use IPV6_USE_MIN_MTU or equivalent with TCP in addition + to UDP. [RT #31690] + +3410. [bug] Addressed Coverity warnings. [RT #31626] + +3409. [contrib] contrib/dane/mkdane.sh: Tool to generate TLSA RR's + from X.509 certificates, for use with DANE + (DNS-based Authentication of Named Entities). + [RT #30513] + +3408. [bug] Some DNSSEC-related options (update-check-ksk, + dnssec-loadkeys-interval, dnssec-dnskey-kskonly) + are now legal in slave zones as long as + inline-signing is in use. [RT #31078] + +3407. [placeholder] + +3406. [bug] mem.c: Fix compilation errors when building with + ISC_MEM_TRACKLINES or ISC_MEMPOOL_NAMES disabled. + Also, ISC_MEM_DEBUG is no longer optional. [RT #31559] + +3405. [bug] Handle time going backwards in acache. [RT #31253] + +3404. [bug] dnssec-signzone: When re-signing a zone, remove + RRSIG and NSEC records from nodes that used to be + in-zone but are now below a zone cut. [RT #31556] + +3403. [bug] Silence noisy OpenSSL logging. [RT #31497] + +3402. [test] The IPv6 interface numbers used for system + tests were incorrect on some platforms. [RT #25085] + +3401. [bug] Addressed Coverity warnings. [RT #31484] + +3400. [cleanup] "named -V" can now report a source ID string, defined + in the "srcid" file in the build tree and normally set + to the most recent git hash. [RT #31494] + +3399. [port] netbsd: rename 'bool' parameter to avoid namespace + clash. [RT #31515] + +3398. [bug] SOA parameters were not being updated with inline + signed zones if the zone was modified while the + server was offline. [RT #29272] + +3397. [bug] dig crashed when using +nssearch with +tcp. [RT #25298] + +3396. [bug] OPT records were incorrectly removed from signed, + truncated responses. [RT #31439] + +3395. [protocol] Add RFC 6598 reverse zones to built in empty zones + list, 64.100.IN-ADDR.ARPA ... 127.100.IN-ADDR.ARPA. + [RT #31336] + +3394. [bug] Adjust 'successfully validated after lower casing + signer' log level and category. [RT #31414] + +3393. [bug] 'host -C' could core dump if REFUSED was received. + [RT #31381] + +3392. [func] Keep statistics on REFUSED responses. [RT #31412] + +3391. [bug] A DNSKEY lookup that encountered a CNAME failed. + [RT #31262] + +3390. [bug] Silence clang compiler warnings. [RT #30417] + +3389. [bug] Always return NOERROR (not 0) in TSIG. [RT #31275] + +3388. [bug] Fixed several Coverity warnings. + Note: This change includes a fix for a bug that + was subsequently determined to be an exploitable + security vulnerability, CVE-2012-5688: named could + die on specific queries with dns64 enabled. + [RT #30996] + +3387. [func] DS digest can be disabled at runtime with + disable-ds-digests. [RT #21581] + +3386. [bug] Address locking violation when generating new NSEC / + NSEC3 chains. [RT #31224] + +3385. [bug] named-checkconf didn't detect missing master lists + in also-notify clauses. [RT #30810] + +3384. [bug] Improved logging of crypto errors. [RT #30963] + +3383. [security] A certain combination of records in the RBT could + cause named to hang while populating the additional + section of a response. [RT #31090] + +3382. [bug] SOA query from slave used use-v6-udp-ports range, + if set, regardless of the address family in use. + [RT #24173] + +3381. [contrib] Update queryperf to support more RR types. + [RT #30762] + +3380. [bug] named could die if a nonexistent master list was + referenced in a also-notify. [RT #31004] + +3379. [bug] isc_interval_zero and isc_time_epoch should be + "const (type)* const". [RT #31069] + +3378. [bug] Handle missing 'managed-keys-directory' better. + [RT #30625] + +3377. [bug] Removed spurious newline from NSEC3 multiline + output. [RT #31044] + +3376. [bug] Lack of EDNS support was being recorded without a + successful response. [RT #30811] + +3375. [bug] 'rndc dumpdb' failed on empty caches. [RT #30808] + +3374. [bug] isc_parse_uint32 failed to return a range error on + systems with 64 bit longs. [RT #30232] + +3373. [bug] win32: open raw files in binary mode. [RT #30944] + +3372. [bug] Silence spurious "deleted from unreachable cache" + messages. [RT #30501] + +3371. [bug] AD=1 should behave like DO=1 when deciding whether to + add NS RRsets to the additional section or not. + [RT #30479] + +3370. [bug] Address use after free while shutting down. [RT #30241] + +3369. [bug] nsupdate terminated unexpectedly in interactive mode + if built with readline support. [RT #29550] + +3368. [bug] , and + were not C++ safe. + +3367. [bug] dns_dnsseckey_create() result was not being checked. + [RT #30685] + +3366. [bug] Fixed Read-After-Write dependency violation for IA64 + atomic operations. [RT #25181] + +3365. [bug] Removed spurious newlines from log messages in + zone.c [RT #30675] + +3364. [security] Named could die on specially crafted record. + [RT #30416] + +3363. [bug] Need to allow "forward" and "fowarders" options + in static-stub zones; this had been overlooked. + [RT #30482] + +3362. [bug] Setting some option values to 0 in named.conf + could trigger an assertion failure on startup. + [RT #27730] + +3361. [bug] "rndc signing -nsec3param" didn't work correctly + when salt was set to '-' (no salt). [RT #30099] + +3360. [bug] 'host -w' could die. [RT #18723] + +3359. [bug] An improperly-formed TSIG secret could cause a + memory leak. [RT #30607] + +3358. [placeholder] + +3357. [port] Add support for libxml2-2.8.x [RT #30440] + +3356. [bug] Cap the TTL of signed RRsets when RRSIGs are + approaching their expiry, so they don't remain + in caches after expiry. [RT #26429] + +3355. [port] Use more portable awk in verify system test. + +3354. [func] Improve OpenSSL error logging. [RT #29932] + +3353. [bug] Use a single task for task exclusive operations. + [RT #29872] + +3352. [bug] Ensure that learned server attributes timeout of the + adb cache. [RT #29856] + +3351. [bug] isc_mem_put and isc_mem_putanddetach didn't report + caller if either ISC_MEM_DEBUGSIZE or ISC_MEM_DEBUGCTX + memory debugging flags are set. [RT #30243] + +3350. [bug] Memory read overrun in isc___mem_reallocate if + ISC_MEM_DEBUGCTX memory debugging flag is set. + [RT #30240] + +3349. [bug] Change #3345 was incomplete. [RT #30233] + +3348. [bug] Prevent RRSIG data from being cached if a negative + record matching the covering type exists at a higher + trust level. Such data already can't be retrieved from + the cache since change 3218 -- this prevents it + being inserted into the cache as well. [RT #26809] + +3347. [bug] dnssec-settime: Issue a warning when writing a new + private key file would cause a change in the + permissions of the existing file. [RT #27724] + +3346. [security] Bad-cache data could be used before it was + initialized, causing an assert. [RT #30025] + +3345. [bug] Addressed race condition when removing the last item + or inserting the first item in an ISC_QUEUE. + [RT #29539] + +3344. [func] New "dnssec-checkds" command checks a zone to + determine which DS records should be published + in the parent zone, or which DLV records should be + published in a DLV zone, and queries the DNS to + ensure that it exists. (Note: This tool depends + on python; it will not be built or installed on + systems that do not have a python interpreter.) + [RT #28099] + +3343. [placeholder] + +3342. [bug] Change #3314 broke saving of stub zones to disk + resulting in excessive cpu usage in some cases. + [RT #29952] + +3341. [func] New "dnssec-verify" command checks a signed zone + to ensure correctness of signatures and of NSEC/NSEC3 + chains. [RT #23673] + +3340. [func] Added new 'map' zone file format, which is an image + of a zone database that can be loaded directly into + memory via mmap(), allowing much faster zone loading. + (Note: Because of pointer sizes and other + considerations, this file format is platform-dependent; + 'map' zone files cannot always be transferred from one + server to another.) [RT #25419] + +3339. [func] Allow the maximum supported rsa exponent size to be + specified: "max-rsa-exponent-size ;" [RT #29228] + +3338. [bug] Address race condition in units tests: asyncload_zone + and asyncload_zt. [RT #26100] + +3337. [bug] Change #3294 broke support for the multiple keys + in controls. [RT #29694] + +3336. [func] Maintain statistics for RRsets tagged as "stale". + [RT #29514] + +3335. [func] nslookup: return a nonzero exit code when unable + to get an answer. [RT #29492] + +3334. [bug] Hold a zone table reference while performing a + asynchronous load of a zone. [RT #28326] + +3333. [bug] Setting resolver-query-timeout too low can cause + named to not recover if it loses connectivity. + [RT #29623] + +3332. [bug] Re-use cached DS rrsets if possible. [RT #29446] + +3331. [security] dns_rdataslab_fromrdataset could produce bad + rdataslabs. [RT #29644] + +3330. [func] Fix missing signatures on NOERROR results despite + RPZ rewriting. Also + - add optional "recursive-only yes|no" to the + response-policy statement + - add optional "max-policy-ttl" to the response-policy + statement to limit the false data that + "recursive-only no" can introduce into + resolvers' caches + - add a RPZ performance test to bin/tests/system/rpz + when queryperf is available. + - the encoding of PASSTHRU action to "rpz-passthru". + (The old encoding is still accepted.) + [RT #26172] + + +3329. [bug] Handle RRSIG signer-name case consistently: We + generate RRSIG records with the signer-name in + lower case. We accept them with any case, but if + they fail to validate, we try again in lower case. + [RT #27451] + +3328. [bug] Fixed inconsistent data checking in dst_parse.c. + [RT #29401] + +3327. [func] Added 'filter-aaaa-on-v6' option; this is similar + to 'filter-aaaa-on-v4' but applies to IPv6 + connections. (Use "configure --enable-filter-aaaa" + to enable this option.) [RT #27308] + +3326. [func] Added task list statistics: task model, worker + threads, quantum, tasks running, tasks ready. + [RT #27678] + +3325. [func] Report cache statistics: memory use, number of + nodes, number of hash buckets, hit and miss counts. + [RT #27056] + +3324. [test] Add better tests for ADB stats [RT #27057] + +3323. [func] Report the number of buckets the resolver is using. + [RT #27020] + +3322. [func] Monitor the number of active TCP and UDP dispatches. + [RT #27055] + +3321. [func] Monitor the number of recursive fetches and the + number of open sockets, and report these values in + the statistics channel. [RT #27054] + +3320. [func] Added support for monitoring of recursing client + count. [RT #27009] + +3319. [func] Added support for monitoring of ADB entry count and + hash size. [RT #27057] + +3318. [tuning] Reduce the amount of work performed while holding a + bucket lock when finished with a fetch context. + [RT #29239] + +3317. [func] Add ECDSA support (RFC 6605). [RT #21918] + +3316. [tuning] Improved locking performance when recursing. + [RT #28836] + +3315. [tuning] Use multiple dispatch objects for sending upstream + queries; this can improve performance on busy + multiprocessor systems by reducing lock contention. + [RT #28605] + +3314. [bug] The masters list could be updated while stub_callback + or refresh_callback were using it. [RT #26732] + +3313. [protocol] Add TLSA record type. [RT #28989] + +3312. [bug] named-checkconf didn't detect a bad dns64 clients acl. + [RT #27631] + +3311. [bug] Abort the zone dump if zone->db is NULL in + zone.c:zone_gotwritehandle. [RT #29028] + +3310. [test] Increase table size for mutex profiling. [RT #28809] + +3309. [bug] resolver.c:fctx_finddone() was not thread safe. + [RT #27995] + +3308. [placeholder] + +3307. [bug] Add missing ISC_LANG_BEGINDECLS and ISC_LANG_ENDDECLS. + [RT #28956] + +3306. [bug] Improve DNS64 reverse zone performance. [RT #28563] + +3305. [func] Add wire format lookup method to sdb. [RT #28563] + +3304. [bug] Use hmctx, not mctx when freeing rbtdb->heaps. + [RT #28571] + +3303. [bug] named could die when reloading. [RT #28606] + +3302. [bug] dns_dnssec_findmatchingkeys could fail to find + keys if the zone name contained character that + required special mappings. [RT #28600] + +3301. [contrib] Update queryperf to build on darwin. Add -R flag + for non-recursive queries. [RT #28565] + +3300. [bug] Named could die if gssapi was enabled in named.conf + but was not compiled in. [RT #28338] + +3299. [bug] Make SDB handle errors from database drivers better. + [RT #28534] + +3298. [bug] Named could dereference a NULL pointer in + zmgr_start_xfrin_ifquota if the zone was being removed. + [RT #28419] + +3297. [bug] Named could die on a malformed master file. [RT #28467] + +3296. [bug] Named could die with a INSIST failure in + client.c:exit_check. [RT #28346] + +3295. [bug] Adjust isc_time_secondsastimet range check to be more + portable. [RT # 26542] + +3294. [bug] isccc/cc.c:table_fromwire failed to free alist on + error. [RT #28265] + +3293. [func] nsupdate: list supported type. [RT #28261] + +3292. [func] Log messages in the axfr stream at debug 10. + [RT #28040] + +3291. [port] Fixed a build error on systems without ENOTSUP. + [RT #28200] + +3290. [bug] was not being installed. [RT #28169] + +3289. [bug] 'rndc retransfer' failed for inline zones. [RT #28036] + +3288. [bug] dlz_destroy() function wasn't correctly registered + by the DLZ dlopen driver. [RT #28056] + +3287. [port] Update ans.pl to work with Net::DNS 0.68. [RT #28028] + +3286. [bug] Managed key maintenance timer could fail to start + after 'rndc reconfig'. [RT #26786] + +3285. [bug] val-frdataset was incorrectly disassociated in + proveunsecure after calling startfinddlvsep. + [RT #27928] + +3284. [bug] Address race conditions with the handling of + rbtnode.deadlink. [RT #27738] + +3283. [bug] Raw zones with with more than 512 records in a RRset + failed to load. [RT #27863] + +3282. [bug] Restrict the TTL of NS RRset to no more than that + of the old NS RRset when replacing it. + [RT #27792] [RT #27884] + +3281. [bug] SOA refresh queries could be treated as cancelled + despite succeeding over the loopback interface. + [RT #27782] + +3280. [bug] Potential double free of a rdataset on out of memory + with DNS64. [RT #27762] + +3279. [bug] Hold a internal reference to the zone while performing + a asynchronous load. Address potential memory leak + if the asynchronous is cancelled. [RT #27750] + +3278. [bug] Make sure automatic key maintenance is started + when "auto-dnssec maintain" is turned on during + "rndc reconfig". [RT #26805] + +3277. [bug] win32: isc_socket_dup is not implemented. [RT #27696] + +3276. [bug] win32: ns_os_openfile failed to return NULL on + safe_open failure. [RT #27696] + +3275. [bug] Corrected rndc -h output; the 'rndc sync -clean' + option had been misspelled as '-clear'. (To avoid + future confusion, both options now work.) [RT #27173] + +3274. [placeholder] + +3273. [bug] AAAA responses could be returned in the additional + section even when filter-aaaa-on-v4 was in use. + [RT #27292] + +3272. [func] New "rndc zonestatus" command prints information + about the specified zone. [RT #21671] + +3271. [port] darwin: mksymtbl is not always stable, loop several + times before giving up. mksymtbl was using non + portable perl to covert 64 bit hex strings. [RT #27653] + + --- 9.9.0rc2 released --- + +3270. [bug] "rndc reload" didn't reuse existing zones correctly + when inline-signing was in use. [RT #27650] + +3269. [port] darwin 11 and later now built threaded by default. + +3268. [bug] Convert RRSIG expiry times to 64 timestamps to work + out the earliest expiry time. [RT #23311] + +3267. [bug] Memory allocation failures could be mis-reported as + unexpected error. New ISC_R_UNSET result code. + [RT #27336] + +3266. [bug] The maximum number of NSEC3 iterations for a + DNSKEY RRset was not being properly computed. + [RT #26543] + +3265. [bug] Corrected a problem with lock ordering in the + inline-signing code. [RT #27557] + +3264. [bug] Automatic regeneration of signatures in an + inline-signing zone could stall when the server + was restarted. [RT #27344] + +3263. [bug] "rndc sync" did not affect the unsigned side of an + inline-signing zone. [RT #27337] + +3262. [bug] Signed responses were handled incorrectly by RPZ. + [RT #27316] + +3261. [func] RRset ordering now defaults to random. [RT #27174] + +3260. [bug] "rrset-order cyclic" could appear not to rotate + for some query patterns. [RT #27170/27185] + + --- 9.9.0rc1 released --- + +3259. [bug] named-compilezone: Suppress "dump zone to " + message when writing to stdout. [RT #27109] + +3258. [test] Add "forcing full sign with unreadable keys" test. + [RT #27153] + +3257. [bug] Do not generate a error message when calling fsync() + in a pipe or socket. [RT #27109] + +3256. [bug] Disable empty zones for lwresd -C. [RT #27139] + +3255. [func] No longer require that a empty zones be explicitly + enabled or that a empty zone is disabled for + RFC 1918 empty zones to be configured. [RT #27139] + +3254. [bug] Set isc_socket_ipv6only() on the IPv6 control channels. + [RT #22249] + +3253. [bug] Return DNS_R_SYNTAX when the input to a text field is + too long. [RT #26956] + +3252. [bug] When master zones using inline-signing were + updated while the server was offline, the source + zone could fall out of sync with the signed + copy. They can now resynchronize. [RT #26676] + +3251. [bug] Enforce a upper bound (65535 bytes) on the amount of + memory dns_sdlz_putrr() can allocate per record to + prevent run away memory consumption on ISC_R_NOSPACE. + [RT #26956] + +3250. [func] 'configure --enable-developer'; turn on various + configure options, normally off by default, that + we want developers to build and test with. [RT #27103] + +3249. [bug] Update log message when saving slave zones files for + analysis after load failures. [RT #27087] + +3248. [bug] Configure options --enable-fixed-rrset and + --enable-exportlib were incompatible with each + other. [RT #27087] + +3247. [bug] 'raw' format zones failed to preserve load order + breaking 'fixed' sort order. [RT #27087] + +3246. [bug] Named failed to start with a empty also-notify list. + [RT #27087] + +3245. [bug] Don't report a error unchanged serials unless there + were other changes when thawing a zone with + ixfr-fromdifferences. [RT #26845] + +3244. [func] Added readline support to nslookup and nsupdate. + Also simplified nsupdate syntax to make "update" + and "prereq" optional. [RT #24659] + +3243. [port] freebsd,netbsd,bsdi: the thread defaults were not + being properly set. + +3242. [func] Extended the header of raw-format master files to + include the serial number of the zone from which + they were generated, if different (as in the case + of inline-signing zones). This is to be used in + inline-signing zones, to track changes between the + unsigned and signed versions of the zone, which may + have different serial numbers. + + (Note: raw zonefiles generated by this version of + BIND are no longer compatible with prior versions. + To generate a backward-compatible raw zonefile + using dnssec-signzone or named-compilezone, specify + output format "raw=0" instead of simply "raw".) + [RT #26587] + +3241. [bug] Address race conditions in the resolver code. + [RT #26889] + +3240. [bug] DNSKEY state change events could be missed. [RT #26874] + +3239. [bug] dns_dnssec_findmatchingkeys needs to use a consistent + timestamp. [RT #26883] + +3238. [bug] keyrdata was not being reinitialized in + lib/dns/rbtdb.c:iszonesecure. [RT #26913] + +3237. [bug] dig -6 didn't work with +trace. [RT #26906] + +3236. [bug] Backed out changes #3182 and #3202, related to + EDNS(0) fallback behavior. [RT #26416] + +3235. [func] dns_db_diffx, a extended dns_db_diff which returns + the generated diff and optionally writes it to a + journal. [RT #26386] + +3234. [bug] 'make depend' produced invalid makefiles. [RT #26830] + +3233. [bug] 'rndc freeze/thaw' didn't work for inline zones. + [RT #26632] + +3232. [bug] Zero zone->curmaster before return in + dns_zone_setmasterswithkeys(). [RT #26732] + +3231. [bug] named could fail to send a incompressible zone. + [RT #26796] + +3230. [bug] 'dig axfr' failed to properly handle a multi-message + axfr with a serial of 0. [RT #26796] + +3229. [bug] Fix local variable to struct var assignment + found by CLANG warning. + +3228. [tuning] Dynamically grow symbol table to improve zone + loading performance. [RT #26523] + +3227. [bug] Interim fix to make WKS's use of getprotobyname() + and getservbyname() self thread safe. [RT #26232] + +3226. [bug] Address minor resource leakages. [RT #26624] + +3225. [bug] Silence spurious "setsockopt(517, IPV6_V6ONLY) failed" + messages. [RT #26507] + +3224. [bug] 'rndc signing' argument parsing was broken. [RT #26684] + +3223. [bug] 'task_test privilege_drop' generated false positives. + [RT #26766] + +3222. [cleanup] Replace dns_journal_{get,set}_bitws with + dns_journal_{get,set}_sourceserial. [RT #26634] + +3221. [bug] Fixed a potential core dump on shutdown due to + referencing fetch context after it's been freed. + [RT #26720] + + --- 9.9.0b2 released --- + +3220. [bug] Change #3186 was incomplete; dns_db_rpz_findips() + could fail to set the database version correctly, + causing an assertion failure. [RT #26180] + +3219. [bug] Disable NOEDNS caching following a timeout. + +3218. [security] Cache lookup could return RRSIG data associated with + nonexistent records, leading to an assertion + failure. [RT #26590] + +3217. [cleanup] Fix build problem with --disable-static. [RT #26476] + +3216. [bug] resolver.c:validated() was not thread-safe. [RT #26478] + +3215. [bug] 'rndc recursing' could cause a core dump. [RT #26495] + +3214. [func] Add 'named -U' option to set the number of UDP + listener threads per interface. [RT #26485] + +3213. [doc] Clarify ixfr-from-differences behavior. [RT #25188] + +3212. [bug] rbtdb.c: failed to remove a node from the deadnodes + list prior to adding a reference to it leading a + possible assertion failure. [RT #23219] + +3211. [func] dnssec-signzone: "-f -" prints to stdout; "-O full" + option prints in single-line-per-record format. + [RT #20287] + +3210. [bug] Canceling the oldest query due to recursive-client + overload could trigger an assertion failure. [RT #26463] + +3209. [func] Add "dnssec-lookaside 'no'". [RT #24858] + +3208. [bug] 'dig -y' handle unknown tsig algorithm better. + [RT #25522] + +3207. [contrib] Fixed build error in Berkeley DB DLZ module. [RT #26444] + +3206. [cleanup] Add ISC information to log at start time. [RT #25484] + +3205. [func] Upgrade dig's defaults to better reflect modern + nameserver behavior. Enable "dig +adflag" and + "dig +edns=0" by default. Enable "+dnssec" when + running "dig +trace". [RT #23497] + +3204. [bug] When a master server that has been marked as + unreachable sends a NOTIFY, mark it reachable + again. [RT #25960] + +3203. [bug] Increase log level to 'info' for validation failures + from expired or not-yet-valid RRSIGs. [RT #21796] + +3202. [bug] NOEDNS caching on timeout was too aggressive. + [RT #26416] + +3201. [func] 'rndc querylog' can now be given an on/off parameter + instead of only being used as a toggle. [RT #18351] + +3200. [doc] Some rndc functions were undocumented or were + missing from 'rndc -h' output. [RT #25555] + +3199. [func] When logging client information, include the name + being queried. [RT #25944] + +3198. [doc] Clarified that dnssec-settime can alter keyfile + permissions. [RT #24866] + +3197. [bug] Don't try to log the filename and line number when + the config parser can't open a file. [RT #22263] + +3196. [bug] nsupdate: return nonzero exit code when target zone + doesn't exist. [RT #25783] + +3195. [cleanup] Silence "file not found" warnings when loading + managed-keys zone. [RT #26340] + +3194. [doc] Updated RFC references in the 'empty-zones-enable' + documentation. [RT #25203] + +3193. [cleanup] Changed MAXZONEKEYS to DNS_MAXZONEKEYS, moved to + dnssec.h. [RT #26415] + +3192. [bug] A query structure could be used after being freed. + [RT #22208] + +3191. [bug] Print NULL records using "unknown" format. [RT #26392] + +3190. [bug] Underflow in error handling in isc_mutexblock_init. + [RT #26397] + +3189. [test] Added a summary report after system tests. [RT #25517] + +3188. [bug] zone.c:zone_refreshkeys() could fail to detach + references correctly when errors occurred, causing + a hang on shutdown. [RT #26372] + +3187. [port] win32: support for Visual Studio 2008. [RT #26356] + + --- 9.9.0b1 released --- + +3186. [bug] Version/db mismatch in rpz code. [RT #26180] + +3185. [func] New 'rndc signing' option for auto-dnssec zones: + - 'rndc signing -list' displays the current + state of signing operations + - 'rndc signing -clear' clears the signing state + records for keys that have fully signed the zone + - 'rndc signing -nsec3param' sets the NSEC3 + parameters for the zone + The 'rndc keydone' syntax is removed. [RT #23729] + +3184. [bug] named had excessive cpu usage when a redirect zone was + configured. [RT #26013] + +3183. [bug] Added RTLD_GLOBAL flag to dlopen call. [RT #26301] + +3182. [bug] Auth servers behind firewalls which block packets + greater than 512 bytes may cause other servers to + perform poorly. Now, adb retains edns information + and caches noedns servers. [RT #23392/24964] + +3181. [func] Inline-signing is now supported for master zones. + [RT #26224] + +3180. [func] Local copies of slave zones are now saved in raw + format by default, to improve startup performance. + 'masterfile-format text;' can be used to override + the default, if desired. [RT #25867] + +3179. [port] kfreebsd: build issues. [RT #26273] + +3178. [bug] A race condition introduced by change #3163 could + cause an assertion failure on shutdown. [RT #26271] + +3177. [func] 'rndc keydone', remove the indicator record that + named has finished signing the zone with the + corresponding key. [RT #26206] + +3176. [doc] Corrected example code and added a README to the + sample external DLZ module in contrib/dlz/example. + [RT #26215] + +3175. [bug] Fix how DNSSEC positive wildcard responses from a + NSEC3 signed zone are validated. Stop sending a + unnecessary NSEC3 record when generating such + responses. [RT #26200] + +3174. [bug] Always compute to revoked key tag from scratch. + [RT #26186] + +3173. [port] Correctly validate root DS responses. [RT #25726] + +3172. [port] darwin 10.* and freebsd [89] are now built threaded by + default. + +3171. [bug] Exclusively lock the task when adding a zone using + 'rndc addzone'. [RT #25600] + + --- 9.9.0a3 released --- + +3170. [func] RPZ update: + - fix precedence among competing rules + - improve ARM text including documenting rule precedence + - try to rewrite CNAME chains until first hit + - new "rpz" logging channel + - RDATA for CNAME rules can include wildcards + - replace "NO-OP" named.conf policy override with + "PASSTHRU" and add "DISABLED" override ("NO-OP" + is still recognized) + [RT #25172] + +3169. [func] Catch db/version mis-matches when calling dns_db_*(). + [RT #26017] + +3168. [bug] Nxdomain redirection could trigger an assert with + a ANY query. [RT #26017] + +3167. [bug] Negative answers from forwarders were not being + correctly tagged making them appear to not be cached. + [RT #25380] + +3166. [bug] Upgrading a zone to support inline-signing failed. + [RT #26014] + +3165. [bug] dnssec-signzone could generate new signatures when + resigning, even when valid signatures were already + present. [RT #26025] + +3164. [func] Enable DLZ modules to retrieve client information, + so that responses can be changed depending on the + source address of the query. [RT #25768] + +3163. [bug] Use finer-grained locking in client.c to address + concurrency problems with large numbers of threads. + [RT #26044] + +3162. [test] start.pl: modified to allow for "named.args" in + ns*/ subdirectory to override stock arguments to + named. Largely from RT #26044, but no separate ticket. + +3161. [bug] zone.c:del_sigs failed to always reset rdata leading + assertion failures. [RT #25880] + +3160. [bug] When printing out a NSEC3 record in multiline form + the newline was not being printed causing type codes + to be run together. [RT #25873] + +3159. [bug] On some platforms, named could assert on startup + when running in a chrooted environment without + /proc. [RT #25863] + +3158. [bug] Recursive servers would prefer a particular UDP + socket instead of using all available sockets. + [RT #26038] + +3157. [tuning] Reduce the time spent in "rndc reconfig" by parsing + the config file before pausing the server. [RT #21373] + +3156. [placeholder] + + --- 9.9.0a2 released --- + +3155. [bug] Fixed a build failure when using contrib DLZ + drivers (e.g., mysql, postgresql, etc). [RT #25710] + +3154. [bug] Attempting to print an empty rdataset could trigger + an assert. [RT #25452] + +3153. [func] Extend request-ixfr to zone level and remove the + side effect of forcing an AXFR. [RT #25156] + +3152. [cleanup] Some versions of gcc and clang failed due to + incorrect use of __builtin_expect. [RT #25183] + +3151. [bug] Queries for type RRSIG or SIG could be handled + incorrectly. [RT #21050] + +3150. [func] Improved startup and reconfiguration time by + enabling zones to load in multiple threads. [RT #25333] + +3149. [placeholder] + +3148. [bug] Processing of normal queries could be stalled when + forwarding a UPDATE message. [RT #24711] + +3147. [func] Initial inline signing support. [RT #23657] + + --- 9.9.0a1 released --- + +3146. [test] Fixed gcc4.6.0 errors in ATF. [RT #25598] + +3145. [test] Capture output of ATF unit tests in "./atf.out" if + there were any errors while running them. [RT #25527] + +3144. [bug] dns_dbiterator_seek() could trigger an assert when + used with a nonexistent database node. [RT #25358] + +3143. [bug] Silence clang compiler warnings. [RT #25174] + +3142. [bug] NAPTR is class agnostic. [RT #25429] + +3141. [bug] Silence spurious "zone serial (0) unchanged" messages + associated with empty zones. [RT #25079] + +3140. [func] New command "rndc flushtree " clears the + specified name from the server cache along with + all names under it. [RT #19970] + +3139. [test] Added tests from RFC 6234, RFC 2202, and RFC 1321 + for the hashing algorithms (md5, sha1 - sha512, and + their hmac counterparts). [RT #25067] + +3138. [bug] Address memory leaks and out-of-order operations when + shutting named down. [RT #25210] + +3137. [func] Improve hardware scalability by allowing multiple + worker threads to process incoming UDP packets. + This can significantly increase query throughput + on some systems. [RT #22992] + +3136. [func] Add RFC 1918 reverse zones to the list of built-in + empty zones switched on by the 'empty-zones-enable' + option. [RT #24990] + +3135. [port] FreeBSD: workaround broken IPV6_USE_MIN_MTU processing. + See http://www.freebsd.org/cgi/query-pr.cgi?pr=158307 + [RT #24950] + +3134. [bug] Improve the accuracy of dnssec-signzone's signing + statistics. [RT #16030] + +3133. [bug] Change #3114 was incomplete. [RT #24577] + +3132. [placeholder] + +3131. [tuning] Improve scalability by allocating one zone task + per 100 zones at startup time, rather than using a + fixed-size task table. [RT #24406] + +3130. [func] Support alternate methods for managing a dynamic + zone's serial number. Two methods are currently + defined using serial-update-method, "increment" + (default) and "unixtime". [RT #23849] + +3129. [bug] Named could crash on 'rndc reconfig' when + allow-new-zones was set to yes and named ACLs + were used. [RT #22739] + +3128. [func] Inserting an NSEC3PARAM via dynamic update in an + auto-dnssec zone that has not been signed yet + will cause it to be signed with the specified NSEC3 + parameters when keys are activated. The + NSEC3PARAM record will not appear in the zone until + it is signed, but the parameters will be stored. + [RT #23684] + +3127. [bug] 'rndc thaw' will now remove a zone's journal file + if the zone serial number has been changed and + ixfr-from-differences is not in use. [RT #24687] + +3126. [security] Using DNAME record to generate replacements caused + RPZ to exit with a assertion failure. [RT #24766] + +3125. [security] Using wildcard CNAME records as a replacement with + RPZ caused named to exit with a assertion failure. + [RT #24715] + +3124. [bug] Use an rdataset attribute flag to indicate + negative-cache records rather than using rrtype 0; + this will prevent problems when that rrtype is + used in actual DNS packets. [RT #24777] + +3123. [security] Change #2912 exposed a latent flaw in + dns_rdataset_totext() that could cause named to + crash with an assertion failure. [RT #24777] + +3122. [cleanup] dnssec-settime: corrected usage message. [RT #24664] + +3121. [security] An authoritative name server sending a negative + response containing a very large RRset could + trigger an off-by-one error in the ncache code + and crash named. [RT #24650] + +3120. [bug] Named could fail to validate zones listed in a DLV + that validated insecure without using DLV and had + DS records in the parent zone. [RT #24631] + +3119. [bug] When rolling to a new DNSSEC key, a private-type + record could be created and never marked complete. + [RT #23253] + +3118. [bug] nsupdate could dump core on shutdown when using + SIG(0) keys. [RT #24604] + +3117. [cleanup] Remove doc and parser references to the + never-implemented 'auto-dnssec create' option. + [RT #24533] + +3116. [func] New 'dnssec-update-mode' option controls updates + of DNSSEC records in signed dynamic zones. Set to + 'no-resign' to disable automatic RRSIG regeneration + while retaining the ability to sign new or changed + data. [RT #24533] + +3115. [bug] Named could fail to return requested data when + following a CNAME that points into the same zone. + [RT #24455] + +3114. [bug] Retain expired RRSIGs in dynamic zones if key is + inactive and there is no replacement key. [RT #23136] + +3113. [doc] Document the relationship between serial-query-rate + and NOTIFY messages. + +3112. [doc] Add missing descriptions of the update policy name + types "ms-self", "ms-subdomain", "krb5-self" and + "krb5-subdomain", which allow machines to update + their own records, to the BIND 9 ARM. + +3111. [bug] Improved consistency checks for dnssec-enable and + dnssec-validation, added test cases to the + checkconf system test. [RT #24398] + +3110. [bug] dnssec-signzone: Wrong error message could appear + when attempting to sign with no KSK. [RT #24369] + +3109. [func] The also-notify option now uses the same syntax + as a zone's masters clause. This means it is + now possible to specify a TSIG key to use when + sending notifies to a given server, or to include + an explicit named masters list in an also-notify + statement. [RT #23508] + +3108. [cleanup] dnssec-signzone: Clarified some error and + warning messages; removed #ifdef ALLOW_KSKLESS_ZONES + code (use -P instead). [RT #20852] + +3107. [bug] dnssec-signzone: Report the correct number of ZSKs + when using -x. [RT #20852] + +3106. [func] When logging client requests, include the name of + the TSIG key if any. [RT #23619] + +3105. [bug] GOST support can be suppressed by "configure + --without-gost" [RT #24367] + +3104. [bug] Better support for cross-compiling. [RT #24367] + +3103. [bug] Configuring 'dnssec-validation auto' in a view + instead of in the options statement could trigger + an assertion failure in named-checkconf. [RT #24382] + +3102. [func] New 'dnssec-loadkeys-interval' option configures + how often, in minutes, to check the key repository + for updates when using automatic key maintenance. + Default is every 60 minutes (formerly hard-coded + to 12 hours). [RT #23744] + +3101. [bug] Zones using automatic key maintenance could fail + to check the key repository for updates. [RT #23744] + +3100. [security] Certain response policy zone configurations could + trigger an INSIST when receiving a query of type + RRSIG. [RT #24280] + +3099. [test] "dlz" system test now runs but gives R:SKIPPED if + not compiled with --with-dlz-filesystem. [RT #24146] + +3098. [bug] DLZ zones were answering without setting the AA bit. + [RT #24146] + +3097. [test] Add a tool to test handling of malformed packets. + [RT #24096] + +3096. [bug] Set KRB5_KTNAME before calling log_cred() in + dst_gssapi_acceptctx(). [RT #24004] + +3095. [bug] Handle isolated reserved ports in the port range. + [RT #23957] + +3094. [doc] Expand dns64 documentation. + +3093. [bug] Fix gssapi/kerberos dependencies [RT #23836] + +3092. [bug] Signatures for records at the zone apex could go + stale due to an incorrect timer setting. [RT #23769] + +3091. [bug] Fixed a bug in which zone keys that were published + and then subsequently activated could fail to trigger + automatic signing. [RT #22911] + +3090. [func] Make --with-gssapi default [RT #23738] + +3089. [func] dnssec-dsfromkey now supports reading keys from + standard input "dnssec-dsfromkey -f -". [RT #20662] + +3088. [bug] Remove bin/tests/system/logfileconfig/ns1/named.conf + and add setup.sh in order to resolve changing + named.conf issue. [RT #23687] + +3087. [bug] DDNS updates using SIG(0) with update-policy match + type "external" could cause a crash. [RT #23735] + +3086. [bug] Running dnssec-settime -f on an old-style key will + now force an update to the new key format even if no + other change has been specified, using "-P now -A now" + as default values. [RT #22474] + +3085. [func] New '-R' option in dnssec-signzone forces removal + of signatures which have not yet expired but + were generated by a key that no longer exists. + [RT #22471] + +3084. [func] A new command "rndc sync" dumps pending changes in + a dynamic zone to disk; "rndc sync -clean" also + removes the journal file after syncing. Also, + "rndc freeze" no longer removes journal files. + [RT #22473] + +3083. [bug] NOTIFY messages were not being sent when generating + a NSEC3 chain incrementally. [RT #23702] + +3082. [port] strtok_r is threads only. [RT #23747] + +3081. [bug] Failure of DNAME substitution did not return + YXDOMAIN. [RT #23591] + +3080. [cleanup] Replaced compile time constant by STDTIME_ON_32BITS. + [RT #23587] + +3079. [bug] Handle isc_event_allocate failures in t_tasks. + [RT #23572] + +3078. [func] Added a new include file with function typedefs + for the DLZ "dlopen" driver. [RT #23629] + +3077. [bug] zone.c:zone_refreshkeys() incorrectly called + dns_zone_attach(), use zone->irefs instead. [RT #23303] + +3076. [func] New '-L' option in dnssec-keygen, dnsset-settime, and + dnssec-keyfromlabel sets the default TTL of the + key. When possible, automatic signing will use that + TTL when the key is published. [RT #23304] + +3075. [bug] dns_dnssec_findzonekeys{2} used a inconsistent + timestamp when determining which keys are active. + [RT #23642] + +3074. [bug] Make the adb cache read through for zone data and + glue learn for zone named is authoritative for. + [RT #22842] + +3073. [bug] managed-keys changes were not properly being recorded. + [RT #20256] + +3072. [bug] dns_dns64_aaaaok() potential NULL pointer dereference. + [RT #20256] + +3071. [bug] has_nsec could be used uninitialized in + update.c:next_active. [RT #20256] + +3070. [bug] dnssec-signzone potential NULL pointer dereference. + [RT #20256] + +3069. [cleanup] Silence warnings messages from clang static analysis. + [RT #20256] + +3068. [bug] Named failed to build with a OpenSSL without engine + support. [RT #23473] + +3067. [bug] ixfr-from-differences {master|slave}; failed to + select the master/slave zones. [RT #23580] + +3066. [func] The DLZ "dlopen" driver is now built by default, + no longer requiring a configure option. To + disable it, use "configure --without-dlopen". + Driver also supported on win32. [RT #23467] + +3065. [bug] RRSIG could have time stamps too far in the future. + [RT #23356] + +3064. [bug] powerpc: add sync instructions to the end of atomic + operations. [RT #23469] + +3063. [contrib] More verbose error reporting from DLZ LDAP. [RT #23402] + +3062. [func] Made several changes to enhance human readability + of DNSSEC data in dig output and in generated + zone files: + - DNSKEY record comments are more verbose, no + longer used in multiline mode only + - multiline RRSIG records reformatted + - multiline output mode for NSEC3PARAM records + - "dig +norrcomments" suppresses DNSKEY comments + - "dig +split=X" breaks hex/base64 records into + fields of width X; "dig +nosplit" disables this. + [RT #22820] + +3061. [func] New option "dnssec-signzone -D", only write out + generated DNSSEC records. [RT #22896] + +3060. [func] New option "dnssec-signzone -X " allows + specification of a separate expiration date + for DNSKEY RRSIGs and other RRSIGs. [RT #22141] + +3059. [test] Added a regression test for change #3023. + +3058. [bug] Cause named to terminate at startup or rndc reconfig/ + reload to fail, if a log file specified in the conf + file isn't a plain file. [RT #22771] + +3057. [bug] "rndc secroots" would abort after the first error + and so could miss some views. [RT #23488] + +3056. [func] Added support for URI resource record. [RT #23386] + +3055. [placeholder] + +3054. [bug] Added elliptic curve support check in + GOST OpenSSL engine detection. [RT #23485] + +3053. [bug] Under a sustained high query load with a finite + max-cache-size, it was possible for cache memory + to be exhausted and not recovered. [RT #23371] + +3052. [test] Fixed last autosign test report. [RT #23256] + +3051. [bug] NS records obscure DNAME records at the bottom of the + zone if both are present. [RT #23035] + +3050. [bug] The autosign system test was timing dependent. + Wait for the initial autosigning to complete + before running the rest of the test. [RT #23035] + +3049. [bug] Save and restore the gid when creating creating + named.pid at startup. [RT #23290] + +3048. [bug] Fully separate view key management. [RT #23419] + +3047. [bug] DNSKEY NODATA responses not cached fixed in + validator.c. Tests added to dnssec system test. + [RT #22908] + +3046. [bug] Use RRSIG original TTL to compute validated RRset + and RRSIG TTL. [RT #23332] + +3045. [removed] Replaced by change #3050. + +3044. [bug] Hold the socket manager lock while freeing the socket. + [RT #23333] + +3043. [test] Merged in the NetBSD ATF test framework (currently + version 0.12) for development of future unit tests. + Use configure --with-atf to build ATF internally + or configure --with-atf=prefix to use an external + copy. [RT #23209] + +3042. [bug] dig +trace could fail attempting to use IPv6 + addresses on systems with only IPv4 connectivity. + [RT #23297] + +3041. [bug] dnssec-signzone failed to generate new signatures on + ttl changes. [RT #23330] + +3040. [bug] Named failed to validate insecure zones where a node + with a CNAME existed between the trust anchor and the + top of the zone. [RT #23338] + +3039. [func] Redirect on NXDOMAIN support. [RT #23146] + +3038. [bug] Install . [RT #23342] + +3037. [doc] Update COPYRIGHT to contain all the individual + copyright notices that cover various parts. + +3036. [bug] Check built-in zone arguments to see if the zone + is re-usable or not. [RT #21914] + +3035. [cleanup] Simplify by using strlcpy. [RT #22521] + +3034. [cleanup] nslookup: use strlcpy instead of safecopy. [RT #22521] + +3033. [cleanup] Add two INSIST(bucket != DNS_ADB_INVALIDBUCKET). + [RT #22521] + +3032. [bug] rdatalist.c: add missing REQUIREs. [RT #22521] + +3031. [bug] dns_rdataclass_format() handle a zero sized buffer. + [RT #22521] + +3030. [bug] dns_rdatatype_format() handle a zero sized buffer. + [RT #22521] + +3029. [bug] isc_netaddr_format() handle a zero sized buffer. + [RT #22521] + +3028. [bug] isc_sockaddr_format() handle a zero sized buffer. + [RT #22521] + +3027. [bug] Add documented REQUIREs to cfg_obj_asnetprefix() to + catch NULL pointer dereferences before they happen. + [RT #22521] + +3026. [bug] lib/isc/httpd.c: check that we have enough space + after calling grow_headerspace() and if not + re-call grow_headerspace() until we do. [RT #22521] + +3025. [bug] Fixed a possible deadlock due to zone resigning. + [RT #22964] + +3024. [func] RTT Banding removed due to minor security increase + but major impact on resolver latency. [RT #23310] + +3023. [bug] Named could be left in an inconsistent state when + receiving multiple AXFR response messages that were + not all TSIG-signed. [RT #23254] + +3022. [bug] Fixed rpz SERVFAILs after failed zone transfers + [RT #23246] + +3021. [bug] Change #3010 was incomplete. [RT #22296] + +3020. [bug] auto-dnssec failed to correctly update the zone when + changing the DNSKEY RRset. [RT #23232] + +3019. [test] Test: check apex NSEC3 records after adding DNSKEY + record via UPDATE. [RT #23229] + +3018. [bug] Named failed to check for the "none;" acl when deciding + if a zone may need to be re-signed. [RT #23120] + +3017. [doc] dnssec-keyfromlabel -I was not properly documented. + [RT #22887] + +3016. [bug] rndc usage missing '-b'. [RT #22937] + +3015. [port] win32: fix IN6_IS_ADDR_LINKLOCAL and + IN6_IS_ADDR_SITELOCAL macros. [RT #22724] + +3014. [placeholder] + +3013. [bug] The DNS64 ttl was not always being set as expected. + [RT #23034] + +3012. [bug] Remove DNSKEY TTL change pairs before generating + signing records for any remaining DNSKEY changes. + [RT #22590] + +3011. [func] Change the default query timeout from 30 seconds + to 10. Allow setting this in named.conf using the new + 'resolver-query-timeout' option, which specifies a max + time in seconds. 0 means 'default' and anything longer + than 30 will be silently set to 30. [RT #22852] + +3010. [bug] Fixed a bug where "rndc reconfig" stopped the timer + for refreshing managed-keys. [RT #22296] + +3009. [bug] clients-per-query code didn't work as expected with + particular query patterns. [RT #22972] + + --- 9.8.0b1 released --- + +3008. [func] Response policy zones (RPZ) support. [RT #21726] + +3007. [bug] Named failed to preserve the case of domain names in + rdata which is not compressible when writing master + files. [RT #22863] + +3006. [func] Allow dynamically generated TSIG keys to be preserved + across restarts of named. Initially this is for + TSIG keys generated using GSSAPI. [RT #22639] + +3005. [port] Solaris: Work around the lack of + gsskrb5_register_acceptor_identity() by setting + the KRB5_KTNAME environment variable to the + contents of tkey-gssapi-keytab. Also fixed + test errors on MacOSX. [RT #22853] + +3004. [func] DNS64 reverse support. [RT #22769] + +3003. [experimental] Added update-policy match type "external", + enabling named to defer the decision of whether to + allow a dynamic update to an external daemon. + (Contributed by Andrew Tridgell.) [RT #22758] + +3002. [bug] isc_mutex_init_errcheck() failed to destroy attr. + [RT #22766] + +3001. [func] Added a default trust anchor for the root zone, which + can be switched on by setting "dnssec-validation auto;" + in the named.conf options. [RT #21727] + +3000. [bug] More TKEY/GSS fixes: + - nsupdate can now get the default realm from + the user's Kerberos principal + - corrected gsstest compilation flags + - improved documentation + - fixed some NULL dereferences + [RT #22795] + +2999. [func] Add GOST support (RFC 5933). [RT #20639] + +2998. [func] Add isc_task_beginexclusive and isc_task_endexclusive + to the task api. [RT #22776] + +2997. [func] named -V now reports the OpenSSL and libxml2 versions + it was compiled against. [RT #22687] + +2996. [security] Temporarily disable SO_ACCEPTFILTER support. + [RT #22589] + +2995. [bug] The Kerberos realm was not being correctly extracted + from the signer's identity. [RT #22770] + +2994. [port] NetBSD: use pthreads by default on NetBSD >= 5.0, and + do not use threads on earlier versions. Also kill + the unproven-pthreads, mit-pthreads, and ptl2 support. + +2993. [func] Dynamically grow adb hash tables. [RT #21186] + +2992. [contrib] contrib/check-secure-delegation.pl: A simple tool + for looking at a secure delegation. [RT #22059] + +2991. [contrib] contrib/zone-edit.sh: A simple zone editing tool for + dynamic zones. [RT #22365] + +2990. [bug] 'dnssec-settime -S' no longer tests prepublication + interval validity when the interval is set to 0. + [RT #22761] + +2989. [func] Added support for writable DLZ zones. (Contributed + by Andrew Tridgell of the Samba project.) [RT #22629] + +2988. [experimental] Added a "dlopen" DLZ driver, allowing the creation + of external DLZ drivers that can be loaded as + shared objects at runtime rather than linked with + named. Currently this is switched on via a + compile-time option, "configure --with-dlz-dlopen". + Note: the syntax for configuring DLZ zones + is likely to be refined in future releases. + (Contributed by Andrew Tridgell of the Samba + project.) [RT #22629] + +2987. [func] Improve ease of configuring TKEY/GSS updates by + adding a "tkey-gssapi-keytab" option. If set, + updates will be allowed with any key matching + a principal in the specified keytab file. + "tkey-gssapi-credential" is no longer required + and is expected to be deprecated. (Contributed + by Andrew Tridgell of the Samba project.) + [RT #22629] + +2986. [func] Add new zone type "static-stub". It's like a stub + zone, but the nameserver names and/or their IP + addresses are statically configured. [RT #21474] + +2985. [bug] Add a regression test for change #2896. [RT #21324] + +2984. [bug] Don't run MX checks when the target of the MX record + is ".". [RT #22645] + +2983. [bug] Include "loadkeys" in rndc help output. [RT #22493] + + --- 9.8.0a1 released --- + +2982. [bug] Reference count dst keys. dst_key_attach() can be used + increment the reference count. + + Note: dns_tsigkey_createfromkey() callers should now + always call dst_key_free() rather than setting it + to NULL on success. [RT #22672] + +2981. [func] Partial DNS64 support (AAAA synthesis). [RT #21991] + +2980. [bug] named didn't properly handle UPDATES that changed the + TTL of the NSEC3PARAM RRset. [RT #22363] + +2979. [bug] named could deadlock during shutdown if two + "rndc stop" commands were issued at the same + time. [RT #22108] + +2978. [port] hpux: look for [RT #21919] + +2977. [bug] 'nsupdate -l' report if the session key is missing. + [RT #21670] + +2976. [bug] named could die on exit after negotiating a GSS-TSIG + key. [RT #22573] + +2975. [bug] rbtdb.c:cleanup_dead_nodes_callback() acquired the + wrong lock which could lead to server deadlock. + [RT #22614] + +2974. [bug] Some valid UPDATE requests could fail due to a + consistency check examining the existing version + of the zone rather than the new version resulting + from the UPDATE. [RT #22413] + +2973. [bug] bind.keys.h was being removed by the "make clean" + at the end of configure resulting in build failures + where there is very old version of perl installed. + Move it to "make maintainer-clean". [RT #22230] + +2972. [bug] win32: address windows socket errors. [RT #21906] + +2971. [bug] Fixed a bug that caused journal files not to be + compacted on Windows systems as a result of + non-POSIX-compliant rename() semantics. [RT #22434] + +2970. [security] Adding a NO DATA negative cache entry failed to clear + any matching RRSIG records. A subsequent lookup of + of NO DATA cache entry could trigger a INSIST when the + unexpected RRSIG was also returned with the NO DATA + cache entry. + + CVE-2010-3613, VU#706148. [RT #22288] + +2969. [security] Fix acl type processing so that allow-query works + in options and view statements. Also add a new + set of tests to verify proper functioning. + + CVE-2010-3615, VU#510208. [RT #22418] + +2968. [security] Named could fail to prove a data set was insecure + before marking it as insecure. One set of conditions + that can trigger this occurs naturally when rolling + DNSKEY algorithms. + + CVE-2010-3614, VU#837744. [RT #22309] + +2967. [bug] 'host -D' now turns on debugging messages earlier. + [RT #22361] + +2966. [bug] isc_print_vsnprintf() failed to check if there was + space available in the buffer when adding a left + justified character with a non zero width, + (e.g. "%-1c"). [RT #22270] + +2965. [func] Test HMAC functions using test data from RFC 2104 and + RFC 4634. [RT #21702] + +2964. [placeholder] + +2963. [security] The allow-query acl was being applied instead of the + allow-query-cache acl to cache lookups. [RT #22114] + +2962. [port] win32: add more dependencies to BINDBuild.dsw. + [RT #22062] + +2961. [bug] Be still more selective about the non-authoritative + answers we apply change 2748 to. [RT #22074] + +2960. [func] Check that named accepts non-authoritative answers. + [RT #21594] + +2959. [func] Check that named starts with a missing masterfile. + [RT #22076] + +2958. [bug] named failed to start with a missing master file. + [RT #22076] + +2957. [bug] entropy_get() and entropy_getpseudo() failed to match + the API for RAND_bytes() and RAND_pseudo_bytes() + respectively. [RT #21962] + +2956. [port] Enable atomic operations on the PowerPC64. [RT #21899] + +2955. [func] Provide more detail in the recursing log. [RT #22043] + +2954. [bug] contrib: dlz_mysql_driver.c bad error handling on + build_sqldbinstance failure. [RT #21623] + +2953. [bug] Silence spurious "expected covering NSEC3, got an + exact match" message when returning a wildcard + no data response. [RT #21744] + +2952. [port] win32: named-checkzone and named-checkconf failed + to initialize winsock. [RT #21932] + +2951. [bug] named failed to generate a correct signed response + in a optout, delegation only zone with no secure + delegations. [RT #22007] + +2950. [bug] named failed to perform a SOA up to date check when + falling back to TCP on UDP timeouts when + ixfr-from-differences was set. [RT #21595] + +2949. [bug] dns_view_setnewzones() contained a memory leak if + it was called multiple times. [RT #21942] + +2948. [port] MacOS: provide a mechanism to configure the test + interfaces at reboot. See bin/tests/system/README + for details. + +2947. [placeholder] + +2946. [doc] Document the default values for the minimum and maximum + zone refresh and retry values in the ARM. [RT #21886] + +2945. [doc] Update empty-zones list in ARM. [RT #21772] + +2944. [maint] Remove ORCHID prefix from built in empty zones. + [RT #21772] + +2943. [func] Add support to load new keys into managed zones + without signing immediately with "rndc loadkeys". + Add support to link keys with "dnssec-keygen -S" + and "dnssec-settime -S". [RT #21351] + +2942. [contrib] zone2sqlite failed to setup the entropy sources. + [RT #21610] + +2941. [bug] sdb and sdlz (dlz's zone database) failed to support + DNAME at the zone apex. [RT #21610] + +2940. [port] Remove connection aborted error message on + Windows. [RT #21549] + +2939. [func] Check that named successfully skips NSEC3 records + that fail to match the NSEC3PARAM record currently + in use. [RT #21868] + +2938. [bug] When generating signed responses, from a signed zone + that uses NSEC3, named would use a uninitialized + pointer if it needed to skip a NSEC3 record because + it didn't match the selected NSEC3PARAM record for + zone. [RT #21868] + +2937. [bug] Worked around an apparent race condition in over + memory conditions. Without this fix a DNS cache DB or + ADB could incorrectly stay in an over memory state, + effectively refusing further caching, which + subsequently made a BIND 9 caching server unworkable. + This fix prevents this problem from happening by + polling the state of the memory context, rather than + making a copy of the state, which appeared to cause + a race. This is a "workaround" in that it doesn't + solve the possible race per se, but several experiments + proved this change solves the symptom. Also, the + polling overhead hasn't been reported to be an issue. + This bug should only affect a caching server that + specifies a finite max-cache-size. It's also quite + likely that the bug happens only when enabling threads, + but it's not confirmed yet. [RT #21818] + +2936. [func] Improved configuration syntax and multiple-view + support for addzone/delzone feature (see change + #2930). Removed "new-zone-file" option, replaced + with "allow-new-zones (yes|no)". The new-zone-file + for each view is now created automatically, with + a filename generated from a hash of the view name. + It is no longer necessary to "include" the + new-zone-file in named.conf; this happens + automatically. Zones that were not added via + "rndc addzone" can no longer be removed with + "rndc delzone". [RT #19447] + +2935. [bug] nsupdate: improve 'file not found' error message. + [RT #21871] + +2934. [bug] Use ANSI C compliant shift range in lib/isc/entropy.c. + [RT #21871] + +2933. [bug] 'dig +nsid' used stack memory after it went out of + scope. This could potentially result in a unknown, + potentially malformed, EDNS option being sent instead + of the desired NSID option. [RT #21781] + +2932. [cleanup] Corrected a numbering error in the "dnssec" test. + [RT #21597] + +2931. [bug] Temporarily and partially disable change 2864 + because it would cause infinite attempts of RRSIG + queries. This is an urgent care fix; we'll + revisit the issue and complete the fix later. + [RT #21710] + +2930. [experimental] New "rndc addzone" and "rndc delzone" commands + allow dynamic addition and deletion of zones. + To enable this feature, specify a "new-zone-file" + option at the view or options level in named.conf. + Zone configuration information for the new zones + will be written into that file. To make the new + zones persist after a restart, "include" the file + into named.conf in the appropriate view. (Note: + This feature is not yet documented, and its syntax + is expected to change.) [RT #19447] + +2929. [bug] Improved handling of GSS security contexts: + - added LRU expiration for generated TSIGs + - added the ability to use a non-default realm + - added new "realm" keyword in nsupdate + - limited lifetime of generated keys to 1 hour + or the lifetime of the context (whichever is + smaller) + [RT #19737] + +2928. [bug] Be more selective about the non-authoritative + answer we apply change 2748 to. [RT #21594] + +2927. [placeholder] + +2926. [placeholder] + +2925. [bug] Named failed to accept uncachable negative responses + from insecure zones. [RT #21555] + +2924. [func] 'rndc secroots' dump a combined summary of the + current managed keys combined with trusted keys. + [RT #20904] + +2923. [bug] 'dig +trace' could drop core after "connection + timeout". [RT #21514] + +2922. [contrib] Update zkt to version 1.0. + +2921. [bug] The resolver could attempt to destroy a fetch context + too soon. [RT #19878] + +2920. [func] Allow 'filter-aaaa-on-v4' to be applied selectively + to IPv4 clients. New acl 'filter-aaaa' (default any). + +2919. [func] Add autosign-ksk and autosign-zsk virtual time tests. + [RT #20840] + +2918. [maint] Add AAAA address for I.ROOT-SERVERS.NET. + +2917. [func] Virtual time test framework. [RT #20801] + +2916. [func] Add framework to use IPv6 in tests. + fd92:7065:b8e:ffff::1 ... fd92:7065:b8e:ffff::7 + +2915. [cleanup] Be smarter about which objects we attempt to compile + based on configure options. [RT #21444] + +2914. [bug] Make the "autosign" system test more portable. + [RT #20997] + +2913. [func] Add pkcs#11 system tests. [RT #20784] + +2912. [func] Windows clients don't like UPDATE responses that clear + the zone section. [RT #20986] + +2911. [bug] dnssec-signzone didn't handle out of zone records well. + [RT #21367] + +2910. [func] Sanity check Kerberos credentials. [RT #20986] + +2909. [bug] named-checkconf -p could die if "update-policy local;" + was specified in named.conf. [RT #21416] + +2908. [bug] It was possible for re-signing to stop after removing + a DNSKEY. [RT #21384] + +2907. [bug] The export version of libdns had undefined references. + [RT #21444] + +2906. [bug] Address RFC 5011 implementation issues. [RT #20903] + +2905. [port] aix: set use_atomic=yes with native compiler. + [RT #21402] + +2904. [bug] When using DLV, sub-zones of the zones in the DLV, + could be incorrectly marked as insecure instead of + secure leading to negative proofs failing. This was + a unintended outcome from change 2890. [RT #21392] + +2903. [bug] managed-keys-directory missing from namedconf.c. + [RT #21370] + +2902. [func] Add regression test for change 2897. [RT #21040] + +2901. [port] Use AC_C_FLEXIBLE_ARRAY_MEMBER. [RT #21316] + +2900. [bug] The placeholder negative caching element was not + properly constructed triggering a INSIST in + dns_ncache_towire(). [RT #21346] + +2899. [port] win32: Support linking against OpenSSL 1.0.0. + +2898. [bug] nslookup leaked memory when -domain=value was + specified. [RT #21301] + +2897. [bug] NSEC3 chains could be left behind when transitioning + to insecure. [RT #21040] + +2896. [bug] "rndc sign" failed to properly update the zone + when adding a DNSKEY for publication only. [RT #21045] + +2895. [func] genrandom: add support for the generation of multiple + files. [RT #20917] + +2894. [contrib] DLZ LDAP support now use '$' not '%'. [RT #21294] + +2893. [bug] Improve managed keys support. New named.conf option + managed-keys-directory. [RT #20924] + +2892. [bug] Handle REVOKED keys better. [RT #20961] + +2891. [maint] Update empty-zones list to match + draft-ietf-dnsop-default-local-zones-13. [RT #21099] + +2890. [bug] Handle the introduction of new trusted-keys and + DS, DLV RRsets better. [RT #21097] + +2889. [bug] Elements of the grammar where not properly reported. + [RT #21046] + +2888. [bug] Only the first EDNS option was displayed. [RT #21273] + +2887. [bug] Report the keytag times in UTC in the .key file, + local time is presented as a comment within the + comment. [RT #21223] + +2886. [bug] ctime() is not thread safe. [RT #21223] + +2885. [bug] Improve -fno-strict-aliasing support probing in + configure. [RT #21080] + +2884. [bug] Insufficient validation in dns_name_getlabelsequence(). + [RT #21283] + +2883. [bug] 'dig +short' failed to handle really large datasets. + [RT #21113] + +2882. [bug] Remove memory context from list of active contexts + before clearing 'magic'. [RT #21274] + +2881. [bug] Reduce the amount of time the rbtdb write lock + is held when closing a version. [RT #21198] + +2880. [cleanup] Make the output of dnssec-keygen and dnssec-revoke + consistent. [RT #21078] + +2879. [contrib] DLZ bdbhpt driver fails to close correct cursor. + [RT #21106] + +2878. [func] Incrementally write the master file after performing + a AXFR. [RT #21010] + +2877. [bug] The validator failed to skip obviously mismatching + RRSIGs. [RT #21138] + +2876. [bug] Named could return SERVFAIL for negative responses + from unsigned zones. [RT #21131] + +2875. [bug] dns_time64_fromtext() could accept non digits. + [RT #21033] + +2874. [bug] Cache lack of EDNS support only after the server + successfully responds to the query using plain DNS. + [RT #20930] + +2873. [bug] Canceling a dynamic update via the dns/client module + could trigger an assertion failure. [RT #21133] + +2872. [bug] Modify dns/client.c:dns_client_createx() to only + require one of IPv4 or IPv6 rather than both. + [RT #21122] + +2871. [bug] Type mismatch in mem_api.c between the definition and + the header file, causing build failure with + --enable-exportlib. [RT #21138] + +2870. [maint] Add AAAA address for L.ROOT-SERVERS.NET. + +2869. [bug] Fix arguments to dns_keytable_findnextkeynode() call. + [RT #20877] + +2868. [cleanup] Run "make clean" at the end of configure to ensure + any changes made by configure are integrated. + Use --with-make-clean=no to disable. [RT #20994] + +2867. [bug] Don't set GSS_C_SEQUENCE_FLAG as Windows DNS servers + don't like it. [RT #20986] + +2866. [bug] Windows does not like the TSIG name being compressed. + [RT #20986] + +2865. [bug] memset to zero event.data. [RT #20986] + +2864. [bug] Direct SIG/RRSIG queries were not handled correctly. + [RT #21050] + +2863. [port] linux: disable IPv6 PMTUD and use network minimum MTU. + [RT #21056] + +2862. [bug] nsupdate didn't default to the parent zone when + updating DS records. [RT #20896] + +2861. [doc] dnssec-settime man pages didn't correctly document the + inactivation time. [RT #21039] + +2860. [bug] named-checkconf's usage was out of date. [RT #21039] + +2859. [bug] When canceling validation it was possible to leak + memory. [RT #20800] + +2858. [bug] RTT estimates were not being adjusted on ICMP errors. + [RT #20772] + +2857. [bug] named-checkconf did not fail on a bad trusted key. + [RT #20705] + +2856. [bug] The size of a memory allocation was not always properly + recorded. [RT #20927] + +2855. [func] nsupdate will now preserve the entered case of domain + names in update requests it sends. [RT #20928] + +2854. [func] dig: allow the final soa record in a axfr response to + be suppressed, dig +onesoa. [RT #20929] + +2853. [bug] add_sigs() could run out of scratch space. [RT #21015] + +2852. [bug] Handle broken DNSSEC trust chains better. [RT #15619] + +2851. [doc] nslookup.1, removed from the docbook + source as it produced bad nroff. [RT #21007] + +2850. [bug] If isc_heap_insert() failed due to memory shortage + the heap would have corrupted entries. [RT #20951] + +2849. [bug] Don't treat errors from the xml2 library as fatal. + [RT #20945] + +2848. [doc] Moved README.dnssec, README.libdns, README.pkcs11 and + README.rfc5011 into the ARM. [RT #20899] + +2847. [cleanup] Corrected usage message in dnssec-settime. [RT #20921] + +2846. [bug] EOF on unix domain sockets was not being handled + correctly. [RT #20731] + +2845. [bug] RFC 5011 client could crash on shutdown. [RT #20903] + +2844. [doc] notify-delay default in ARM was wrong. It should have + been five (5) seconds. + +2843. [func] Prevent dnssec-keygen and dnssec-keyfromlabel from + creating key files if there is a chance that the new + key ID will collide with an existing one after + either of the keys has been revoked. (To override + this in the case of dnssec-keyfromlabel, use the -y + option. dnssec-keygen will simply create a + different, non-colliding key, so an override is + not necessary.) [RT #20838] + +2842. [func] Added "smartsign" and improved "autosign" and + "dnssec" regression tests. [RT #20865] + +2841. [bug] Change 2836 was not complete. [RT #20883] + +2840. [bug] Temporary fixed pkcs11-destroy usage check. + [RT #20760] + +2839. [bug] A KSK revoked by named could not be deleted. + [RT #20881] + +2838. [placeholder] + +2837. [port] Prevent Linux spurious warnings about fwrite(). + [RT #20812] + +2836. [bug] Keys that were scheduled to become active could + be delayed. [RT #20874] + +2835. [bug] Key inactivity dates were inadvertently stored in + the private key file with the outdated tag + "Unpublish" rather than "Inactive". This has been + fixed; however, any existing keys that had Inactive + dates set will now need to have them reset, using + 'dnssec-settime -I'. [RT #20868] + +2834. [bug] HMAC-SHA* keys that were longer than the algorithm + digest length were used incorrectly, leading to + interoperability problems with other DNS + implementations. This has been corrected. + (Note: If an oversize key is in use, and + compatibility is needed with an older release of + BIND, the new tool "isc-hmac-fixup" can convert + the key secret to a form that will work with all + versions.) [RT #20751] + +2833. [cleanup] Fix usage messages in dnssec-keygen and dnssec-settime. + [RT #20851] + +2832. [bug] Modify "struct stat" in lib/export/samples/nsprobe.c + to avoid redefinition in some OSs [RT 20831] + +2831. [security] Do not attempt to validate or cache + out-of-bailiwick data returned with a secure + answer; it must be re-fetched from its original + source and validated in that context. [RT #20819] + +2830. [bug] Changing the OPTOUT setting could take multiple + passes. [RT #20813] + +2829. [bug] Fixed potential node inconsistency in rbtdb.c. + [RT #20808] + +2828. [security] Cached CNAME or DNAME RR could be returned to clients + without DNSSEC validation. [RT #20737] + +2827. [security] Bogus NXDOMAIN could be cached as if valid. [RT #20712] + +2826. [bug] NSEC3->NSEC transitions could fail due to a lock not + being released. [RT #20740] + +2825. [bug] Changing the setting of OPTOUT in a NSEC3 chain that + was in the process of being created was not properly + recorded in the zone. [RT #20786] + +2824. [bug] "rndc sign" was not being run by the correct task. + [RT #20759] + +2823. [bug] rbtdb.c:getsigningtime() was missing locks. [RT #20781] + +2822. [bug] rbtdb.c:loadnode() could return the wrong result. + [RT #20802] + +2821. [doc] Add note that named-checkconf doesn't automatically + read rndc.key and bind.keys [RT #20758] + +2820. [func] Handle read access failure of OpenSSL configuration + file more user friendly (PKCS#11 engine patch). + [RT #20668] + +2819. [cleanup] Removed unnecessary DNS_POINTER_MAXHOPS define. + [RT #20771] + +2818. [cleanup] rndc could return an incorrect error code + when a zone was not found. [RT #20767] + +2817. [cleanup] Removed unnecessary isc_task_endexclusive() calls. + [RT #20768] + +2816. [bug] previous_closest_nsec() could fail to return + data for NSEC3 nodes [RT #29730] + +2815. [bug] Exclusively lock the task when freezing a zone. + [RT #19838] + +2814. [func] Provide a definitive error message when a master + zone is not loaded. [RT #20757] + +2813. [bug] Better handling of unreadable DNSSEC key files. + [RT #20710] + +2812. [bug] Make sure updates can't result in a zone with + NSEC-only keys and NSEC3 records. [RT #20748] + +2811. [cleanup] Add "rndc sign" to list of commands in rndc usage + output. [RT #20733] + +2810. [doc] Clarified the process of transitioning an NSEC3 zone + to insecure. [RT #20746] + +2809. [cleanup] Restored accidentally-deleted text in usage output + in dnssec-settime and dnssec-revoke [RT #20739] + +2808. [bug] Remove the attempt to install atomic.h from lib/isc. + atomic.h is correctly installed by the architecture + specific subdirectories. [RT #20722] + +2807. [bug] Fixed a possible ASSERT when reconfiguring zone + keys. [RT #20720] + + --- 9.7.0rc1 released --- + +2806. [bug] "rdnc sign" could delay re-signing the DNSKEY + when it had changed. [RT #20703] + +2805. [bug] Fixed namespace problems encountered when building + external programs using non-exported BIND9 libraries + (i.e., built without --enable-exportlib). [RT #20679] + +2804. [bug] Send notifies when a zone is signed with "rndc sign" + or as a result of a scheduled key change. [RT #20700] + +2803. [port] win32: Install named-journalprint, nsec3hash, arpaname + and genrandom under windows. [RT #20670] + +2802. [cleanup] Rename journalprint to named-journalprint. [RT #20670] + +2801. [func] Detect and report records that are different according + to DNSSEC but are semantically equal according to plain + DNS. Apply plain DNS comparisons rather than DNSSEC + comparisons when processing UPDATE requests. + dnssec-signzone now removes such semantically duplicate + records prior to signing the RRset. + + named-checkzone -r {ignore|warn|fail} (default warn) + named-compilezone -r {ignore|warn|fail} (default warn) + + named.conf: check-dup-records {ignore|warn|fail}; + +2800. [func] Reject zones which have NS records which refer to + CNAMEs, DNAMEs or don't have address record (class IN + only). Reject UPDATEs which would cause the zone + to fail the above checks if committed. [RT #20678] + +2799. [cleanup] Changed the "secure-to-insecure" option to + "dnssec-secure-to-insecure", and "dnskey-ksk-only" + to "dnssec-dnskey-kskonly", for clarity. [RT #20586] + +2798. [bug] Addressed bugs in managed-keys initialization + and rollover. [RT #20683] + +2797. [bug] Don't decrement the dispatch manager's maxbuffers. + [RT #20613] + +2796. [bug] Missing dns_rdataset_disassociate() call in + dns_nsec3_delnsec3sx(). [RT #20681] + +2795. [cleanup] Add text to differentiate "update with no effect" + log messages. [RT #18889] + +2794. [bug] Install . [RT #20677] + +2793. [func] Add "autosign" and "metadata" tests to the + automatic tests. [RT #19946] + +2792. [func] "filter-aaaa-on-v4" can now be set in view + options (if compiled in). [RT #20635] + +2791. [bug] The installation of isc-config.sh was broken. + [RT #20667] + +2790. [bug] Handle DS queries to stub zones. [RT #20440] + +2789. [bug] Fixed an INSIST in dispatch.c [RT #20576] + +2788. [bug] dnssec-signzone could sign with keys that were + not requested [RT #20625] + +2787. [bug] Spurious log message when zone keys were + dynamically reconfigured. [RT #20659] + +2786. [bug] Additional could be promoted to answer. [RT #20663] + + --- 9.7.0b3 released --- + +2785. [bug] Revoked keys could fail to self-sign [RT #20652] + +2784. [bug] TC was not always being set when required glue was + dropped. [RT #20655] + +2783. [func] Return minimal responses to EDNS/UDP queries with a UDP + buffer size of 512 or less. [RT #20654] + +2782. [port] win32: use getaddrinfo() for hostname lookups. + [RT #20650] + +2781. [bug] Inactive keys could be used for signing. [RT #20649] + +2780. [bug] dnssec-keygen -A none didn't properly unset the + activation date in all cases. [RT #20648] + +2779. [bug] Dynamic key revocation could fail. [RT #20644] + +2778. [bug] dnssec-signzone could fail when a key was revoked + without deleting the unrevoked version. [RT #20638] + +2777. [contrib] DLZ MYSQL auto reconnect support discovery was wrong. + +2776. [bug] Change #2762 was not correct. [RT #20647] + +2775. [bug] Accept RSASHA256 and RSASHA512 as NSEC3 compatible + in dnssec-keyfromlabel. [RT #20643] + +2774. [bug] Existing cache DB wasn't being reused after + reconfiguration. [RT #20629] + +2773. [bug] In autosigned zones, the SOA could be signed + with the KSK. [RT #20628] + +2772. [security] When validating, track whether pending data was from + the additional section or not and only return it if + validates as secure. [RT #20438] + +2771. [bug] dnssec-signzone: DNSKEY records could be + corrupted when importing from key files [RT #20624] + +2770. [cleanup] Add log messages to resolver.c to indicate events + causing FORMERR responses. [RT #20526] + +2769. [cleanup] Change #2742 was incomplete. [RT #19589] + +2768. [bug] dnssec-signzone: -S no longer implies -g [RT #20568] + +2767. [bug] named could crash on startup if a zone was + configured with auto-dnssec and there was no + key-directory. [RT #20615] + +2766. [bug] isc_socket_fdwatchpoke() should only update the + socketmgr state if the socket is not pending on a + read or write. [RT #20603] + +2765. [bug] Skip masters for which the TSIG key cannot be found. + [RT #20595] + +2764. [bug] "rndc-confgen -a" could trigger a REQUIRE. [RT #20610] + +2763. [bug] "rndc sign" didn't create an NSEC chain. [RT #20591] + +2762. [bug] DLV validation failed with a local slave DLV zone. + [RT #20577] + +2761. [cleanup] Enable internal symbol table for backtrace only for + systems that are known to work. Currently, BSD + variants, Linux and Solaris are supported. [RT #20202] + +2760. [cleanup] Corrected named-compilezone usage summary. [RT #20533] + +2759. [doc] Add information about .jbk/.jnw files to + the ARM. [RT #20303] + +2758. [bug] win32: Added a workaround for a windows 2008 bug + that could cause the UDP client handler to shut + down. [RT #19176] + +2757. [bug] dig: assertion failure could occur in connect + timeout. [RT #20599] + +2756. [bug] Fixed corrupt logfile message in update.c. [RT #20597] + +2755. [placeholder] + +2754. [bug] Secure-to-insecure transitions failed when zone + was signed with NSEC3. [RT #20587] + +2753. [bug] Removed an unnecessary warning that could appear when + building an NSEC chain. [RT #20589] + +2752. [bug] Locking violation. [RT #20587] + +2751. [bug] Fixed a memory leak in dnssec-keyfromlabel. [RT #20588] + +2750. [bug] dig: assertion failure could occur when a server + didn't have an address. [RT #20579] + +2749. [bug] ixfr-from-differences generated a non-minimal ixfr + for NSEC3 signed zones. [RT #20452] + +2748. [func] Identify bad answers from GTLD servers and treat them + as referrals. [RT #18884] + +2747. [bug] Journal roll forwards failed to set the re-signing + time of RRSIGs correctly. [RT #20541] + +2746. [port] hpux: address signed/unsigned expansion mismatch of + dns_rbtnode_t.nsec. [RT #20542] + +2745. [bug] configure script didn't probe the return type of + gai_strerror(3) correctly. [RT #20573] + +2744. [func] Log if a query was over TCP. [RT #19961] + +2743. [bug] RRSIG could be incorrectly set in the NSEC3 record + for a insecure delegation. + + --- 9.7.0b2 released --- + +2742. [cleanup] Clarify some DNSSEC-related log messages in + validator.c. [RT #19589] + +2741. [func] Allow the dnssec-keygen progress messages to be + suppressed (dnssec-keygen -q). Automatically + suppress the progress messages when stdin is not + a tty. [RT #20474] + +2740. [placeholder] + +2739. [cleanup] Clean up API for initializing and clearing trust + anchors for a view. [RT #20211] + +2738. [func] Add RSASHA256 and RSASHA512 tests to the dnssec system + test. [RT #20453] + +2737. [func] UPDATE requests can leak existence information. + [RT #17261] + +2736. [func] Improve the performance of NSEC signed zones with + more than a normal amount of glue below a delegation. + [RT #20191] + +2735. [bug] dnssec-signzone could fail to read keys + that were specified on the command line with + full paths, but weren't in the current + directory. [RT #20421] + +2734. [port] cygwin: arpaname did not compile. [RT #20473] + +2733. [cleanup] Clean up coding style in pkcs11-* tools. [RT #20355] + +2732. [func] Add optional filter-aaaa-on-v4 option, available + if built with './configure --enable-filter-aaaa'. + Filters out AAAA answers to clients connecting + via IPv4. (This is NOT recommended for general + use.) [RT #20339] + +2731. [func] Additional work on change 2709. The key parser + will now ignore unrecognized fields when the + minor version number of the private key format + has been increased. It will reject any key with + the major version number increased. [RT #20310] + +2730. [func] Have dnssec-keygen display a progress indication + a la 'openssl genrsa' on standard error. Note + when the first '.' is followed by a long stop + one has the choice between slow generation vs. + poor random quality, i.e., '-r /dev/urandom'. + [RT #20284] + +2729. [func] When constructing a CNAME from a DNAME use the DNAME + TTL. [RT #20451] + +2728. [bug] dnssec-keygen, dnssec-keyfromlabel and + dnssec-signzone now warn immediately if asked to + write into a nonexistent directory. [RT #20278] + +2727. [func] The 'key-directory' option can now specify a relative + path. [RT #20154] + +2726. [func] Added support for SHA-2 DNSSEC algorithms, + RSASHA256 and RSASHA512. [RT #20023] + +2725. [doc] Added information about the file "managed-keys.bind" + to the ARM. [RT #20235] + +2724. [bug] Updates to a existing node in secure zone using NSEC + were failing. [RT #20448] + +2723. [bug] isc_base32_totext(), isc_base32hex_totext(), and + isc_base64_totext(), didn't always mark regions of + memory as fully consumed after conversion. [RT #20445] + +2722. [bug] Ensure that the memory associated with the name of + a node in a rbt tree is not altered during the life + of the node. [RT #20431] + +2721. [port] Have dst__entropy_status() prime the random number + generator. [RT #20369] + +2720. [bug] RFC 5011 trust anchor updates could trigger an + assert if the DNSKEY record was unsigned. [RT #20406] + +2719. [func] Skip trusted/managed keys for unsupported algorithms. + [RT #20392] + +2718. [bug] The space calculations in opensslrsa_todns() were + incorrect. [RT #20394] + +2717. [bug] named failed to update the NSEC/NSEC3 record when + the last private type record was removed as a result + of completing the signing the zone with a key. + [RT #20399] + +2716. [bug] nslookup debug mode didn't return the ttl. [RT #20414] + + --- 9.7.0b1 released --- + +2715. [bug] Require OpenSSL support to be explicitly disabled. + [RT #20288] + +2714. [port] aix/powerpc: 'asm("ics");' needs non standard assembler + flags. + +2713. [bug] powerpc: atomic operations missing asm("ics") / + __isync() calls. + +2712. [func] New 'auto-dnssec' zone option allows zone signing + to be fully automated in zones configured for + dynamic DNS. 'auto-dnssec allow;' permits a zone + to be signed by creating keys for it in the + key-directory and using 'rndc sign '. + 'auto-dnssec maintain;' allows that too, plus it + also keeps the zone's DNSSEC keys up to date + according to their timing metadata. [RT #19943] + +2711. [port] win32: Add the bin/pkcs11 tools into the full + build. [RT #20372] + +2710. [func] New 'dnssec-signzone -x' flag and 'dnskey-ksk-only' + zone option cause a zone to be signed with only KSKs + signing the DNSKEY RRset, not ZSKs. This reduces + the size of a DNSKEY answer. [RT #20340] + +2709. [func] Added some data fields, currently unused, to the + private key file format, to allow implementation + of explicit key rollover in a future release + without impairing backward or forward compatibility. + [RT #20310] + +2708. [func] Insecure to secure and NSEC3 parameter changes via + update are now fully supported and no longer require + defines to enable. We now no longer overload the + NSEC3PARAM flag field, nor the NSEC OPT bit at the + apex. Secure to insecure changes are controlled by + by the named.conf option 'secure-to-insecure'. + + Warning: If you had previously enabled support by + adding defines at compile time to BIND 9.6 you should + ensure that all changes that are in progress have + completed prior to upgrading to BIND 9.7. BIND 9.7 + is not backwards compatible. + +2707. [func] dnssec-keyfromlabel no longer require engine name + to be specified in the label if there is a default + engine or the -E option has been used. Also, it + now uses default algorithms as dnssec-keygen does + (i.e., RSASHA1, or NSEC3RSASHA1 if -3 is used). + [RT #20371] + +2706. [bug] Loading a zone with a very large NSEC3 salt could + trigger an assert. [RT #20368] + +2705. [placeholder] + +2704. [bug] Serial of dynamic and stub zones could be inconsistent + with their SOA serial. [RT #19387] + +2703. [func] Introduce an OpenSSL "engine" argument with -E + for all binaries which can take benefit of + crypto hardware. [RT #20230] + +2702. [func] Update PKCS#11 tools (bin/pkcs11) [RT #20225 & all] + +2701. [doc] Correction to ARM: hmac-md5 is no longer the only + supported TSIG key algorithm. [RT #18046] + +2700. [doc] The match-mapped-addresses option is discouraged. + [RT #12252] + +2699. [bug] Missing lock in rbtdb.c. [RT #20037] + +2698. [placeholder] + +2697. [port] win32: ensure that S_IFMT, S_IFDIR, S_IFCHR and + S_IFREG are defined after including . + [RT #20309] + +2696. [bug] named failed to successfully process some valid + acl constructs. [RT #20308] + +2695. [func] DHCP/DDNS - update fdwatch code for use by + DHCP. Modify the api to isc_sockfdwatch_t (the + callback function for isc_socket_fdwatchcreate) + to include information about the direction (read + or write) and add isc_socket_fdwatchpoke. + [RT #20253] + +2694. [bug] Reduce default NSEC3 iterations from 100 to 10. + [RT #19970] + +2693. [port] Add some noreturn attributes. [RT #20257] + +2692. [port] win32: 32/64 bit cleanups. [RT #20335] + +2691. [func] dnssec-signzone: retain the existing NSEC or NSEC3 + chain when re-signing a previously-signed zone. + Use -u to modify NSEC3 parameters or switch + between NSEC and NSEC3. [RT #20304] + +2690. [bug] win32: fix isc_thread_key_getspecific() prototype. + [RT #20315] + +2689. [bug] Correctly handle snprintf result. [RT #20306] + +2688. [bug] Use INTERFACE_F_POINTTOPOINT, not IFF_POINTOPOINT, + to decide to fetch the destination address. [RT #20305] + +2687. [bug] Fixed dnssec-signzone -S handling of revoked keys. + Also, added warnings when revoking a ZSK, as this is + not defined by protocol (but is legal). [RT #19943] + +2686. [bug] dnssec-signzone should clean the old NSEC chain when + signing with NSEC3 and vice versa. [RT #20301] + +2685. [contrib] Update contrib/zkt to version 0.99c. [RT #20054] + +2684. [cleanup] dig: formalize +ad and +cd as synonyms for + +adflag and +cdflag. [RT #19305] + +2683. [bug] dnssec-signzone should clean out old NSEC3 chains when + the NSEC3 parameters used to sign the zone change. + [RT #20246] + +2682. [bug] "configure --enable-symtable=all" failed to + build. [RT #20282] + +2681. [bug] IPSECKEY RR of gateway type 3 was not correctly + decoded. [RT #20269] + +2680. [func] Move contrib/pkcs11-keygen to bin/pkcs11. [RT #20067] + +2679. [func] dig -k can now accept TSIG keys in named.conf + format. [RT #20031] + +2678. [func] Treat DS queries as if "minimal-response yes;" + was set. [RT #20258] + +2677. [func] Changes to key metadata behavior: + - Keys without "publish" or "active" dates set will + no longer be used for smart signing. However, + those dates will be set to "now" by default when + a key is created; to generate a key but not use + it yet, use dnssec-keygen -G. + - New "inactive" date (dnssec-keygen/settime -I) + sets the time when a key is no longer used for + signing but is still published. + - The "unpublished" date (-U) is deprecated in + favor of "deleted" (-D). + [RT #20247] + +2676. [bug] --with-export-installdir should have been + --with-export-includedir. [RT #20252] + +2675. [bug] dnssec-signzone could crash if the key directory + did not exist. [RT #20232] + + --- 9.7.0a3 released --- + +2674. [bug] "dnssec-lookaside auto;" crashed if named was built + without openssl. [RT #20231] + +2673. [bug] The managed-keys.bind zone file could fail to + load due to a spurious result from sync_keyzone() + [RT #20045] + +2672. [bug] Don't enable searching in 'host' when doing reverse + lookups. [RT #20218] + +2671. [bug] Add support for PKCS#11 providers not returning + the public exponent in RSA private keys + (OpenCryptoki for instance) in + dnssec-keyfromlabel. [RT #19294] + +2670. [bug] Unexpected connect failures failed to log enough + information to be useful. [RT #20205] + +2669. [func] Update PKCS#11 support to support Keyper HSM. + Update PKCS#11 patch to be against openssl-0.9.8i. + +2668. [func] Several improvements to dnssec-* tools, including: + - dnssec-keygen and dnssec-settime can now set key + metadata fields 0 (to unset a value, use "none") + - dnssec-revoke sets the revocation date in + addition to the revoke bit + - dnssec-settime can now print individual metadata + fields instead of always printing all of them, + and can print them in unix epoch time format for + use by scripts + [RT #19942] + +2667. [func] Add support for logging stack backtrace on assertion + failure (not available for all platforms). [RT #19780] + +2666. [func] Added an 'options' argument to dns_name_fromstring() + (API change from 9.7.0a2). [RT #20196] + +2665. [func] Clarify syntax for managed-keys {} statement, add + ARM documentation about RFC 5011 support. [RT #19874] + +2664. [bug] create_keydata() and minimal_update() in zone.c + didn't properly check return values for some + functions. [RT #19956] + +2663. [func] win32: allow named to run as a service using + "NT AUTHORITY\LocalService" as the account. [RT #19977] + +2662. [bug] lwres_getipnodebyname() and lwres_getipnodebyaddr() + returned a misleading error code when lwresd was + down. [RT #20028] + +2661. [bug] Check whether socket fd exceeds FD_SETSIZE when + creating lwres context. [RT #20029] + +2660. [func] Add a new set of DNS libraries for non-BIND9 + applications. See README.libdns. [RT #19369] + +2659. [doc] Clarify dnssec-keygen doc: key name must match zone + name for DNSSEC keys. [RT #19938] + +2658. [bug] dnssec-settime and dnssec-revoke didn't process + key file paths correctly. [RT #20078] + +2657. [cleanup] Lower "journal file does not exist, creating it" + log level to debug 1. [RT #20058] + +2656. [func] win32: add a "tools only" check box to the installer + which causes it to only install dig, host, nslookup, + nsupdate and relevant DLLs. [RT #19998] + +2655. [doc] Document that key-directory does not affect + bind.keys, rndc.key or session.key. [RT #20155] + +2654. [bug] Improve error reporting on duplicated names for + deny-answer-xxx. [RT #20164] + +2653. [bug] Treat ENGINE_load_private_key() failures as key + not found rather than out of memory. [RT #18033] + +2652. [func] Provide more detail about what record is being + deleted. [RT #20061] + +2651. [bug] Dates could print incorrectly in K*.key files on + 64-bit systems. [RT #20076] + +2650. [bug] Assertion failure in dnssec-signzone when trying + to read keyset-* files. [RT #20075] + +2649. [bug] Set the domain for forward only zones. [RT #19944] + +2648. [port] win32: isc_time_seconds() was broken. [RT #19900] + +2647. [bug] Remove unnecessary SOA updates when a new KSK is + added. [RT #19913] + +2646. [bug] Incorrect cleanup on error in socket.c. [RT #19987] + +2645. [port] "gcc -m32" didn't work on amd64 and x86_64 platforms + which default to 64 bits. [RT #19927] + + --- 9.7.0a2 released --- + +2644. [bug] Change #2628 caused a regression on some systems; + named was unable to write the PID file and would + fail on startup. [RT #20001] + +2643. [bug] Stub zones interacted badly with NSEC3 support. + [RT #19777] + +2642. [bug] nsupdate could dump core on solaris when reading + improperly formatted key files. [RT #20015] + +2641. [bug] Fixed an error in parsing update-policy syntax, + added a regression test to check it. [RT #20007] + +2640. [security] A specially crafted update packet will cause named + to exit. [RT #20000] + +2639. [bug] Silence compiler warnings in gssapi code. [RT #19954] + +2638. [bug] Install arpaname. [RT #19957] + +2637. [func] Rationalize dnssec-signzone's signwithkey() calling. + [RT #19959] + +2636. [func] Simplify zone signing and key maintenance with the + dnssec-* tools. Major changes: + - all dnssec-* tools now take a -K option to + specify a directory in which key files will be + stored + - DNSSEC can now store metadata indicating when + they are scheduled to be published, activated, + revoked or removed; these values can be set by + dnssec-keygen or overwritten by the new + dnssec-settime command + - dnssec-signzone -S (for "smart") option reads key + metadata and uses it to determine automatically + which keys to publish to the zone, use for + signing, revoke, or remove from the zone + [RT #19816] + +2635. [bug] isc_inet_ntop() incorrectly handled 0.0/16 addresses. + [RT #19716] + +2634. [port] win32: Add support for libxml2, enable + statschannel. [RT #19773] + +2633. [bug] Handle 15 bit rand() functions. [RT #19783] + +2632. [func] util/kit.sh: warn if documentation appears to be out of + date. [RT #19922] + +2631. [bug] Handle "//", "/./" and "/../" in mkdirpath(). + [RT #19926 ] + +2630. [func] Improved syntax for DDNS autoconfiguration: use + "update-policy local;" to switch on local DDNS in a + zone. (The "ddns-autoconf" option has been removed.) + [RT #19875] + +2629. [port] Check for seteuid()/setegid(), use setresuid()/ + setresgid() if not present. [RT #19932] + +2628. [port] linux: Allow /var/run/named/named.pid to be opened + at startup with reduced capabilities in operation. + [RT #19884] + +2627. [bug] Named aborted if the same key was included in + trusted-keys more than once. [RT #19918] + +2626. [bug] Multiple trusted-keys could trigger an assertion + failure. [RT #19914] + +2625. [bug] Missing UNLOCK in rbtdb.c. [RT #19865] + +2624. [func] 'named-checkconf -p' will print out the parsed + configuration. [RT #18871] + +2623. [bug] Named started searches for DS non-optimally. [RT #19915] + +2622. [bug] Printing of named.conf grammar was broken. [RT #19919] + +2621. [doc] Made copyright boilerplate consistent. [RT #19833] + +2620. [bug] Delay thawing the zone until the reload of it has + completed successfully. [RT #19750] + +2619. [func] Add support for RFC 5011, automatic trust anchor + maintenance. The new "managed-keys" statement can + be used in place of "trusted-keys" for zones which + support this protocol. (Note: this syntax is + expected to change prior to 9.7.0 final.) [RT #19248] + +2618. [bug] The sdb and sdlz db_interator_seek() methods could + loop infinitely. [RT #19847] + +2617. [bug] ifconfig.sh failed to emit an error message when + run from the wrong location. [RT #19375] + +2616. [bug] 'host' used the nameservers from resolv.conf even + when a explicit nameserver was specified. [RT #19852] + +2615. [bug] "__attribute__((unused))" was in the wrong place + for ia64 gcc builds. [RT #19854] + +2614. [port] win32: 'named -v' should automatically be executed + in the foreground. [RT #19844] + +2613. [placeholder] + + --- 9.7.0a1 released --- + +2612. [func] Add default values for the arguments to + dnssec-keygen. Without arguments, it will now + generate a 1024-bit RSASHA1 zone-signing key, + or with the -f KSK option, a 2048-bit RSASHA1 + key-signing key. [RT #19300] + +2611. [func] Add -l option to dnssec-dsfromkey to generate + DLV records instead of DS records. [RT #19300] + +2610. [port] sunos: Change #2363 was not complete. [RT #19796] + +2609. [func] Simplify the configuration of dynamic zones: + - add ddns-confgen command to generate + configuration text for named.conf + - add zone option "ddns-autoconf yes;", which + causes named to generate a TSIG session key + and allow updates to the zone using that key + - add '-l' (localhost) option to nsupdate, which + causes nsupdate to connect to a locally-running + named process using the session key generated + by named + [RT #19284] + +2608. [func] Perform post signing verification checks in + dnssec-signzone. These can be disabled with -P. + + The post sign verification test ensures that for each + algorithm in use there is at least one non revoked + self signed KSK key. That all revoked KSK keys are + self signed. That all records in the zone are signed + by the algorithm. [RT #19653] + +2607. [bug] named could incorrectly delete NSEC3 records for + empty nodes when processing a update request. + [RT #19749] + +2606. [bug] "delegation-only" was not being accepted in + delegation-only type zones. [RT #19717] + +2605. [bug] Accept DS responses from delegation only zones. + [RT # 19296] + +2604. [func] Add support for DNS rebinding attack prevention through + new options, deny-answer-addresses and + deny-answer-aliases. Based on contributed code from + JD Nurmi, Google. [RT #18192] + +2603. [port] win32: handle .exe extension of named-checkzone and + named-comilezone argv[0] names under windows. + [RT #19767] + +2602. [port] win32: fix debugging command line build of libisccfg. + [RT #19767] + +2601. [doc] Mention file creation mode mask in the + named manual page. + +2600. [doc] ARM: miscellaneous reformatting for different + page widths. [RT #19574] + +2599. [bug] Address rapid memory growth when validation fails. + [RT #19654] + +2598. [func] Reserve the -F flag. [RT #19657] + +2597. [bug] Handle a validation failure with a insecure delegation + from a NSEC3 signed master/slave zone. [RT #19464] + +2596. [bug] Stale tree nodes of cache/dynamic rbtdb could stay + long, leading to inefficient memory usage or rejecting + newer cache entries in the worst case. [RT #19563] + +2595. [bug] Fix unknown extended rcodes in dig. [RT #19625] + +2594. [func] Have rndc warn if using its default configuration + file when the key file also exists. [RT #19424] + +2593. [bug] Improve a corner source of SERVFAILs [RT #19632] + +2592. [bug] Treat "any" as a type in nsupdate. [RT #19455] + +2591. [bug] named could die when processing a update in + removed_orphaned_ds(). [RT #19507] + +2590. [func] Report zone/class of "update with no effect". + [RT #19542] + +2589. [bug] dns_db_unregister() failed to clear '*dbimp'. + [RT #19626] + +2588. [bug] SO_REUSEADDR could be set unconditionally after failure + of bind(2) call. This should be rare and mostly + harmless, but may cause interference with other + processes that happen to use the same port. [RT #19642] + +2587. [func] Improve logging by reporting serial numbers for + when zone serial has gone backwards or unchanged. + [RT #19506] + +2586. [bug] Missing cleanup of SIG rdataset in searching a DLZ DB + or SDB. [RT #19577] + +2585. [bug] Uninitialized socket name could be referenced via a + statistics channel, triggering an assertion failure in + XML rendering. [RT #19427] + +2584. [bug] alpha: gcc optimization could break atomic operations. + [RT #19227] + +2583. [port] netbsd: provide a control to not add the compile + date to the version string, -DNO_VERSION_DATE. + +2582. [bug] Don't emit warning log message when we attempt to + remove non-existent journal. [RT #19516] + +2581. [contrib] dlz/mysql set MYSQL_OPT_RECONNECT option on connection. + Requires MySQL 5.0.19 or later. [RT #19084] + +2580. [bug] UpdateRej statistics counter could be incremented twice + for one rejection. [RT #19476] + +2579. [bug] DNSSEC lookaside validation failed to handle unknown + algorithms. [RT #19479] + +2578. [bug] Changed default sig-signing-type to 65534, because + 65535 turns out to be reserved. [RT #19477] + +2577. [doc] Clarified some statistics counters. [RT #19454] + +2576. [bug] NSEC record were not being correctly signed when + a zone transitions from insecure to secure. + Handle such incorrectly signed zones. [RT #19114] + +2575. [func] New functions dns_name_fromstring() and + dns_name_tostring(), to simplify conversion + of a string to a dns_name structure and vice + versa. [RT #19451] + +2574. [doc] Document nsupdate -g and -o. [RT #19351] + +2573. [bug] Replacing a non-CNAME record with a CNAME record in a + single transaction in a signed zone failed. [RT #19397] + +2572. [func] Simplify DLV configuration, with a new option + "dnssec-lookaside auto;" This is the equivalent + of "dnssec-lookaside . trust-anchor dlv.isc.org;" + plus setting a trusted-key for dlv.isc.org. + + Note: The trusted key is hard-coded into named, + but is also stored in (and can be overridden + by) $sysconfdir/bind.keys. As the ISC DLV key + rolls over it can be kept up to date by replacing + the bind.keys file with a key downloaded from + https://www.isc.org/solutions/dlv. [RT #18685] + +2571. [func] Add a new tool "arpaname" which translates IP addresses + to the corresponding IN-ADDR.ARPA or IP6.ARPA name. + [RT #18976] + +2570. [func] Log the destination address the query was sent to. + [RT #19209] + +2569. [func] Move journalprint, nsec3hash, and genrandom + commands from bin/tests into bin/tools; + "make install" will put them in $sbindir. [RT #19301] + +2568. [bug] Report when the write to indicate a otherwise + successful start fails. [RT #19360] + +2567. [bug] dst__privstruct_writefile() could miss write errors. + write_public_key() could miss write errors. + dnssec-dsfromkey could miss write errors. + [RT #19360] + +2566. [cleanup] Clarify logged message when an insecure DNSSEC + response arrives from a zone thought to be secure: + "insecurity proof failed" instead of "not + insecure". [RT #19400] + +2565. [func] Add support for HIP record. Includes new functions + dns_rdata_hip_first(), dns_rdata_hip_next() + and dns_rdata_hip_current(). [RT #19384] + +2564. [bug] Only take EDNS fallback steps when processing timeouts. + [RT #19405] + +2563. [bug] Dig could leak a socket causing it to wait forever + to exit. [RT #19359] + +2562. [doc] ARM: miscellaneous improvements, reorganization, + and some new content. + +2561. [doc] Add isc-config.sh(1) man page. [RT #16378] + +2560. [bug] Add #include to iptable.c. [RT #18258] + +2559. [bug] dnssec-dsfromkey could compute bad DS records when + reading from a K* files. [RT #19357] + +2558. [func] Set the ownership of missing directories created + for pid-file if -u has been specified on the command + line. [RT #19328] + +2557. [cleanup] PCI compliance: + * new libisc log module file + * isc_dir_chroot() now also changes the working + directory to "/". + * additional INSISTs + * additional logging when files can't be removed. + +2556. [port] Solaris: mkdir(2) on tmpfs filesystems does not do the + error checks in the correct order resulting in the + wrong error code sometimes being returned. [RT #19249] + +2555. [func] dig: when emitting a hex dump also display the + corresponding characters. [RT #19258] + +2554. [bug] Validation of uppercase queries from NSEC3 zones could + fail. [RT #19297] + +2553. [bug] Reference leak on DNSSEC validation errors. [RT #19291] + +2552. [bug] zero-no-soa-ttl-cache was not being honored. + [RT #19340] + +2551. [bug] Potential Reference leak on return. [RT #19341] + +2550. [bug] Check --with-openssl= finds . + [RT #19343] + +2549. [port] linux: define NR_OPEN if not currently defined. + [RT #19344] + +2548. [bug] Install iterated_hash.h. [RT #19335] + +2547. [bug] openssl_link.c:mem_realloc() could reference an + out-of-range area of the source buffer. New public + function isc_mem_reallocate() was introduced to address + this bug. [RT #19313] + +2546. [func] Add --enable-openssl-hash configure flag to use + OpenSSL (in place of internal routine) for hash + functions (MD5, SHA[12] and HMAC). [RT #18815] + +2545. [doc] ARM: Legal hostname checking (check-names) is + for SRV RDATA too. [RT #19304] + +2544. [cleanup] Removed unused structure members in adb.c. [RT #19225] + +2543. [contrib] Update contrib/zkt to version 0.98. [RT #19113] + +2542. [doc] Update the description of dig +adflag. [RT #19290] + +2541. [bug] Conditionally update dispatch manager statistics. + [RT #19247] + +2540. [func] Add a nibble mode to $GENERATE. [RT #18872] + +2539. [security] Update the interaction between recursion, allow-query, + allow-query-cache and allow-recursion. [RT #19198] + +2538. [bug] cache/ADB memory could grow over max-cache-size, + especially with threads and smaller max-cache-size + values. [RT #19240] + +2537. [func] Added more statistics counters including those on socket + I/O events and query RTT histograms. [RT #18802] + +2536. [cleanup] Silence some warnings when -Werror=format-security is + specified. [RT #19083] + +2535. [bug] dig +showsearch and +trace interacted badly. [RT #19091] + +2534. [func] Check NAPTR records regular expressions and + replacement strings to ensure they are syntactically + valid and consistent. [RT #18168] + +2533. [doc] ARM: document @ (at-sign). [RT #17144] + +2532. [bug] dig: check the question section of the response to + see if it matches the asked question. [RT #18495] + +2531. [bug] Change #2207 was incomplete. [RT #19098] + +2530. [bug] named failed to reject insecure to secure transitions + via UPDATE. [RT #19101] + +2529. [cleanup] Upgrade libtool to silence complaints from recent + version of autoconf. [RT #18657] + +2528. [cleanup] Silence spurious configure warning about + --datarootdir [RT #19096] + +2527. [placeholder] + +2526. [func] New named option "attach-cache" that allows multiple + views to share a single cache to save memory and + improve lookup efficiency. Based on contributed code + from Barclay Osborn, Google. [RT #18905] + +2525. [func] New logging category "query-errors" to provide detailed + internal information about query failures, especially + about server failures. [RT #19027] + +2524. [port] sunos: dnssec-signzone needs strtoul(). [RT #19129] + +2523. [bug] Random type rdata freed by dns_nsec_typepresent(). + [RT #19112] + +2522. [security] Handle -1 from DSA_do_verify() and EVP_VerifyFinal(). + +2521. [bug] Improve epoll cross compilation support. [RT #19047] + +2520. [bug] Update xml statistics version number to 2.0 as change + #2388 made the schema incompatible to the previous + version. [RT #19080] + +2519. [bug] dig/host with -4 or -6 didn't work if more than two + nameserver addresses of the excluded address family + preceded in resolv.conf. [RT #19081] + +2518. [func] Add support for the new CERT types from RFC 4398. + [RT #19077] + +2517. [bug] dig +trace with -4 or -6 failed when it chose a + nameserver address of the excluded address type. + [RT #18843] + +2516. [bug] glue sort for responses was performed even when not + needed. [RT #19039] + +2515. [port] win32: build dnssec-dsfromkey and dnssec-keyfromlabel. + [RT #19063] + +2514. [bug] dig/host failed with -4 or -6 when resolv.conf contains + a nameserver of the excluded address family. + [RT #18848] + +2513. [bug] Fix windows cli build. [RT #19062] + +2512. [func] Print a summary of the cached records which make up + the negative response. [RT #18885] + +2511. [cleanup] dns_rdata_tofmttext() add const to linebreak. + [RT #18885] + +2510. [bug] "dig +sigchase" could trigger REQUIRE failures. + [RT #19033] + +2509. [bug] Specifying a fixed query source port was broken. + [RT #19051] + +2508. [placeholder] + +2507. [func] Log the recursion quota values when killing the + oldest query or refusing to recurse due to quota. + [RT #19022] + +2506. [port] solaris: Check at configure time if + hack_shutup_pthreadonceinit is needed. [RT #19037] + +2505. [port] Treat amd64 similarly to x86_64 when determining + atomic operation support. [RT #19031] + +2504. [bug] Address race condition in the socket code. [RT #18899] + +2503. [port] linux: improve compatibility with Linux Standard + Base. [RT #18793] + +2502. [cleanup] isc_radix: Improve compliance with coding style, + document function in . [RT #18534] + +2501. [func] $GENERATE now supports all rdata types. Multi-field + rdata types need to be quoted. See the ARM for + details. [RT #18368] + +2500. [contrib] contrib/sdb/pgsql/zonetodb.c called non-existent + function. [RT #18582] + +2499. [port] solaris: lib/lwres/getaddrinfo.c namespace clash. + [RT #18837] + + --- 9.6.0rc1 released --- + +2498. [bug] Removed a bogus function argument used with + ISC_SOCKET_USE_POLLWATCH: it could cause compiler + warning or crash named with the debug 1 level + of logging. [RT #18917] + +2497. [bug] Don't add RRSIG bit to NSEC3 bit map for insecure + delegation. + +2496. [bug] Add sanity length checks to NSID option. [RT #18813] + +2495. [bug] Tighten RRSIG checks. [RT #18795] + +2494. [bug] isc/radix.h, dns/sdlz.h and dns/dlz.h were not being + installed. [RT #18826] + +2493. [bug] The linux capabilities code was not correctly cleaning + up after itself. [RT #18767] + +2492. [func] Rndc status now reports the number of cpus discovered + and the number of worker threads when running + multi-threaded. [RT #18273] + +2491. [func] Attempt to re-use a local port if we are already using + the port. [RT #18548] + +2490. [port] aix: work around a kernel bug where IPV6_RECVPKTINFO + is cleared when IPV6_V6ONLY is set. [RT #18785] + +2489. [port] solaris: Workaround Solaris's kernel bug about + /dev/poll: + http://bugs.opensolaris.org/view_bug.do?bug_id=6724237 + Define ISC_SOCKET_USE_POLLWATCH at build time to enable + this workaround. [RT #18870] + +2488. [func] Added a tool, dnssec-dsfromkey, to generate DS records + from keyset and .key files. [RT #18694] + +2487. [bug] Give TCP connections longer to complete. [RT #18675] + +2486. [func] The default locations for named.pid and lwresd.pid + are now /var/run/named/named.pid and + /var/run/lwresd/lwresd.pid respectively. + + This allows the owner of the containing directory + to be set, for "named -u" support, and allows there + to be a permanent symbolic link in the path, for + "named -t" support. [RT #18306] + +2485. [bug] Change update's the handling of obscured RRSIG + records. Not all orphaned DS records were being + removed. [RT #18828] + +2484. [bug] It was possible to trigger a REQUIRE failure when + adding NSEC3 proofs to the response in + query_addwildcardproof(). [RT #18828] + +2483. [port] win32: chroot() is not supported. [RT #18805] + +2482. [port] libxml2: support versions 2.7.* in addition + to 2.6.*. [RT #18806] + + --- 9.6.0b1 released --- + +2481. [bug] rbtdb.c:matchparams() failed to handle NSEC3 chain + collisions. [RT #18812] + +2480. [bug] named could fail to emit all the required NSEC3 + records. [RT #18812] + +2479. [bug] xfrout:covers was not properly initialized. [RT #18801] + +2478. [bug] 'addresses' could be used uninitialized in + configure_forward(). [RT #18800] + +2477. [bug] dig: the global option to print the command line is + +cmd not print_cmd. Update the output to reflect + this. [RT #17008] + +2476. [doc] ARM: improve documentation for max-journal-size and + ixfr-from-differences. [RT #15909] [RT #18541] + +2475. [bug] LRU cache cleanup under overmem condition could purge + particular entries more aggressively. [RT #17628] + +2474. [bug] ACL structures could be allocated with insufficient + space, causing an array overrun. [RT #18765] + +2473. [port] linux: raise the limit on open files to the possible + maximum value before spawning threads; 'files' + specified in named.conf doesn't seem to work with + threads as expected. [RT #18784] + +2472. [port] linux: check the number of available cpu's before + calling chroot as it depends on "/proc". [RT #16923] + +2471. [bug] named-checkzone was not reporting missing mandatory + glue when sibling checks were disabled. [RT #18768] + +2470. [bug] Elements of the isc_radix_node_t could be incorrectly + overwritten. [RT #18719] + +2469. [port] solaris: Work around Solaris's select() limitations. + [RT #18769] + +2468. [bug] Resolver could try unreachable servers multiple times. + [RT #18739] + +2467. [bug] Failure of fcntl(F_DUPFD) wasn't logged. [RT #18740] + +2466. [doc] ARM: explain max-cache-ttl 0 SERVFAIL issue. + [RT #18302] + +2465. [bug] Adb's handling of lame addresses was different + for IPv4 and IPv6. [RT #18738] + +2464. [port] linux: check that a capability is present before + trying to set it. [RT #18135] + +2463. [port] linux: POSIX doesn't include the IPv6 Advanced Socket + API and glibc hides parts of the IPv6 Advanced Socket + API as a result. This is stupid as it breaks how the + two halves (Basic and Advanced) of the IPv6 Socket API + were designed to be used but we have to live with it. + Define _GNU_SOURCE to pull in the IPv6 Advanced Socket + API. [RT #18388] + +2462. [doc] Document -m (enable memory usage debugging) + option for dig. [RT #18757] + +2461. [port] sunos: Change #2363 was not complete. [RT #17513] + + --- 9.6.0a1 released --- + +2460. [bug] Don't call dns_db_getnsec3parameters() on the cache. + [RT #18697] + +2459. [contrib] Import dnssec-zkt to contrib/zkt. [RT #18448] + +2458. [doc] ARM: update and correction for max-cache-size. + [RT #18294] + +2457. [tuning] max-cache-size is reverted to 0, the previous + default. It should be safe because expired cache + entries are also purged. [RT #18684] + +2456. [bug] In ACLs, ::/0 and 0.0.0.0/0 would both match any + address, regardless of family. They now correctly + distinguish IPv4 from IPv6. [RT #18559] + +2455. [bug] Stop metadata being transferred via axfr/ixfr. + [RT #18639] + +2454. [func] nsupdate: you can now set a default ttl. [RT #18317] + +2453. [bug] Remove NULL pointer dereference in dns_journal_print(). + [RT #18316] + +2452. [func] Improve bin/test/journalprint. [RT #18316] + +2451. [port] solaris: handle runtime linking better. [RT #18356] + +2450. [doc] Fix lwresd docbook problem for manual page. + [RT #18672] + +2449. [placeholder] + +2448. [func] Add NSEC3 support. [RT #15452] + +2447. [cleanup] libbind has been split out as a separate product. + +2446. [func] Add a new log message about build options on startup. + A new command-line option '-V' for named is also + provided to show this information. [RT #18645] + +2445. [doc] ARM out-of-date on empty reverse zones (list includes + RFC1918 address, but these are not yet compiled in). + [RT #18578] + +2444. [port] Linux, FreeBSD, AIX: Turn off path mtu discovery + (clear DF) for UDP responses and requests. + +2443. [bug] win32: UDP connect() would not generate an event, + and so connected UDP sockets would never clean up. + Fix this by doing an immediate WSAConnect() rather + than an io completion port type for UDP. + +2442. [bug] A lock could be destroyed twice. [RT #18626] + +2441. [bug] isc_radix_insert() could copy radix tree nodes + incompletely. [RT #18573] + +2440. [bug] named-checkconf used an incorrect test to determine + if an ACL was set to none. + +2439. [bug] Potential NULL dereference in dns_acl_isanyornone(). + [RT #18559] + +2438. [bug] Timeouts could be logged incorrectly under win32. + +2437. [bug] Sockets could be closed too early, leading to + inconsistent states in the socket module. [RT #18298] + +2436. [security] win32: UDP client handler can be shutdown. [RT #18576] + +2435. [bug] Fixed an ACL memory leak affecting win32. + +2434. [bug] Fixed a minor error-reporting bug in + lib/isc/win32/socket.c. + +2433. [tuning] Set initial timeout to 800ms. + +2432. [bug] More Windows socket handling improvements. Stop + using I/O events and use IO Completion Ports + throughout. Rewrite the receive path logic to make + it easier to support multiple simultaneous + requesters in the future. Add stricter consistency + checking as a compile-time option (define + ISC_SOCKET_CONSISTENCY_CHECKS; defaults to off). + +2431. [bug] Acl processing could leak memory. [RT #18323] + +2430. [bug] win32: isc_interval_set() could round down to + zero if the input was less than NS_INTERVAL + nanoseconds. Round up instead. [RT #18549] + +2429. [doc] nsupdate should be in section 1 of the man pages. + [RT #18283] + +2428. [bug] dns_iptable_merge() mishandled merges of negative + tables. [RT #18409] + +2427. [func] Treat DNSKEY queries as if "minimal-response yes;" + was set. [RT #18528] + +2426. [bug] libbind: inet_net_pton() can sometimes return the + wrong value if excessively large net masks are + supplied. [RT #18512] + +2425. [bug] named didn't detect unavailable query source addresses + at load time. [RT #18536] + +2424. [port] configure now probes for a working epoll + implementation. Allow the use of kqueue, + epoll and /dev/poll to be selected at compile + time. [RT #18277] + +2423. [security] Randomize server selection on queries, so as to + make forgery a little more difficult. Instead of + always preferring the server with the lowest RTT, + pick a server with RTT within the same 128 + millisecond band. [RT #18441] + +2422. [bug] Handle the special return value of a empty node as + if it was a NXRRSET in the validator. [RT #18447] + +2421. [func] Add new command line option '-S' for named to specify + the max number of sockets. [RT #18493] + Use caution: this option may not work for some + operating systems without rebuilding named. + +2420. [bug] Windows socket handling cleanup. Let the io + completion event send out canceled read/write + done events, which keeps us from writing to memory + we no longer have ownership of. Add debugging + socket_log() function. Rework TCP socket handling + to not leak sockets. + +2419. [cleanup] Document that isc_socket_create() and isc_socket_open() + should not be used for isc_sockettype_fdwatch sockets. + [RT #18521] + +2418. [bug] AXFR request on a DLZ could trigger a REQUIRE failure + [RT #18430] + +2417. [bug] Connecting UDP sockets for outgoing queries could + unexpectedly fail with an 'address already in use' + error. [RT #18411] + +2416. [func] Log file descriptors that cause exceeding the + internal maximum. [RT #18460] + +2415. [bug] 'rndc dumpdb' could trigger various assertion failures + in rbtdb.c. [RT #18455] + +2414. [bug] A masterdump context held the database lock too long, + causing various troubles such as dead lock and + recursive lock acquisition. [RT #18311, #18456] + +2413. [bug] Fixed an unreachable code path in socket.c. [RT #18442] + +2412. [bug] win32: address a resource leak. [RT #18374] + +2411. [bug] Allow using a larger number of sockets than FD_SETSIZE + for select(). To enable this, set ISC_SOCKET_MAXSOCKETS + at compilation time. [RT #18433] + + Note: with changes #2469 and #2421 above, there is no + need to tweak ISC_SOCKET_MAXSOCKETS at compilation time + any more. + +2410. [bug] Correctly delete m_versionInfo. [RT #18432] + +2409. [bug] Only log that we disabled EDNS processing if we were + subsequently successful. [RT #18029] + +2408. [bug] A duplicate TCP dispatch event could be sent, which + could then trigger an assertion failure in + resquery_response(). [RT #18275] + +2407. [port] hpux: test for sys/dyntune.h. [RT #18421] + +2406. [placeholder] + +2405. [cleanup] The default value for dnssec-validation was changed to + "yes" in 9.5.0-P1 and all subsequent releases; this + was inadvertently omitted from CHANGES at the time. + +2404. [port] hpux: files unlimited support. + +2403. [bug] TSIG context leak. [RT #18341] + +2402. [port] Support Solaris 2.11 and over. [RT #18362] + +2401. [bug] Expect to get E[MN]FILE errno internal_accept() + (from accept() or fcntl() system calls). [RT #18358] + +2400. [bug] Log if kqueue()/epoll_create()/open(/dev/poll) fails. + [RT #18297] + +2399. [placeholder] + +2398. [bug] Improve file descriptor management. New, + temporary, named.conf option reserved-sockets, + default 512. [RT #18344] + +2397. [bug] gssapi_functions had too many elements. [RT #18355] + +2396. [bug] Don't set SO_REUSEADDR for randomized ports. + [RT #18336] + +2395. [port] Avoid warning and no effect from "files unlimited" + on Linux when running as root. [RT #18335] + +2394. [bug] Default configuration options set the limit for + open files to 'unlimited' as described in the + documentation. [RT #18331] + +2393. [bug] nested acls containing keys could trigger an + assertion in acl.c. [RT #18166] + +2392. [bug] remove 'grep -q' from acl test script, some platforms + don't support it. [RT #18253] + +2391. [port] hpux: cover additional recvmsg() error codes. + [RT #18301] + +2390. [bug] dispatch.c could make a false warning on 'odd socket'. + [RT #18301]. + +2389. [bug] Move the "working directory writable" check to after + the ns_os_changeuser() call. [RT #18326] + +2388. [bug] Avoid using tables for layout purposes in + statistics XSL [RT #18159]. + +2387. [bug] Silence compiler warnings in lib/isc/radix.c. + [RT #18147] [RT #18258] + +2386. [func] Add warning about too small 'open files' limit. + [RT #18269] + +2385. [bug] A condition variable in socket.c could leak in + rare error handling [RT #17968]. + +2384. [security] Fully randomize UDP query ports to improve + forgery resilience. [RT #17949, #18098] + +2383. [bug] named could double queries when they resulted in + SERVFAIL due to overkilling EDNS0 failure detection. + [RT #18182] + +2382. [doc] Add descriptions of DHCID, IPSECKEY, SPF and SSHFP + to ARM. + +2381. [port] dlz/mysql: support multiple install layouts for + mysql. /include/{,mysql/}mysql.h and + /lib/{,mysql/}. [RT #18152] + +2380. [bug] dns_view_find() was not returning NXDOMAIN/NXRRSET + proofs which, in turn, caused validation failures + for insecure zones immediately below a secure zone + the server was authoritative for. [RT #18112] + +2379. [contrib] queryperf/gen-data-queryperf.py: removed redundant + TLDs and supported RRs with TTLs [RT #17972] + +2378. [bug] gssapi_functions{} had a redundant member in BIND 9.5. + [RT #18169] + +2377. [bug] Address race condition in dnssec-signzone. [RT #18142] + +2376. [bug] Change #2144 was not complete. + +2375. [placeholder] + +2374. [bug] "blackhole" ACLs could cause named to segfault due + to some uninitialized memory. [RT #18095] + +2373. [bug] Default values of zone ACLs were re-parsed each time a + new zone was configured, causing an overconsumption + of memory. [RT #18092] + +2372. [bug] Fixed incorrect TAG_HMACSHA256_BITS value [RT #18047] + +2371. [doc] Add +nsid option to dig man page. [RT #18039] + +2370. [bug] "rndc freeze" could trigger an assertion in named + when called on a nonexistent zone. [RT #18050] + +2369. [bug] libbind: Array bounds overrun on read in bitncmp(). + [RT #18054] + +2368. [port] Linux: use libcap for capability management if + possible. [RT #18026] + +2367. [bug] Improve counting of dns_resstatscounter_retry + [RT #18030] + +2366. [bug] Adb shutdown race. [RT #18021] + +2365. [bug] Fix a bug that caused dns_acl_isany() to return + spurious results. [RT #18000] + +2364. [bug] named could trigger a assertion when serving a + malformed signed zone. [RT #17828] + +2363. [port] sunos: pre-set "lt_cv_sys_max_cmd_len=4096;". + [RT #17513] + +2362. [cleanup] Make "rrset-order fixed" a compile-time option. + settable by "./configure --enable-fixed-rrset". + Disabled by default. [RT #17977] + +2361. [bug] "recursion" statistics counter could be counted + multiple times for a single query. [RT #17990] + +2360. [bug] Fix a condition where we release a database version + (which may acquire a lock) while holding the lock. + +2359. [bug] Fix NSID bug. [RT #17942] + +2358. [doc] Update host's default query description. [RT #17934] + +2357. [port] Don't use OpenSSL's engine support in versions before + OpenSSL 0.9.7f. [RT #17922] + +2356. [bug] Built in mutex profiler was not scalable enough. + [RT #17436] + +2355. [func] Extend the number statistics counters available. + [RT #17590] + +2354. [bug] Failed to initialize some rdatasetheader_t elements. + [RT #17927] + +2353. [func] Add support for Name Server ID (RFC 5001). + 'dig +nsid' requests NSID from server. + 'request-nsid yes;' causes recursive server to send + NSID requests to upstream servers. Server responds + to NSID requests with the string configured by + 'server-id' option. [RT #17091] + +2352. [bug] Various GSS_API fixups. [RT #17729] + +2351. [bug] convertxsl.pl generated very long lines. [RT #17906] + +2350. [port] win32: IPv6 support. [RT #17797] + +2349. [func] Provide incremental re-signing support for secure + dynamic zones. [RT #1091] + +2348. [func] Use the EVP interface to OpenSSL. Add PKCS#11 support. + Documentation is in the new README.pkcs11 file. + New tool, dnssec-keyfromlabel, which takes the + label of a key pair in a HSM and constructs a DNS + key pair for use by named and dnssec-signzone. + [RT #16844] + +2347. [bug] Delete now traverses the RB tree in the canonical + order. [RT #17451] + +2346. [func] Memory statistics now cover all active memory contexts + in increased detail. [RT #17580] + +2345. [bug] named-checkconf failed to detect when forwarders + were set at both the options/view level and in + a root zone. [RT #17671] + +2344. [bug] Improve "logging{ file ...; };" documentation. + [RT #17888] + +2343. [bug] (Seemingly) duplicate IPv6 entries could be + created in ADB. [RT #17837] + +2342. [func] Use getifaddrs() if available under Linux. [RT #17224] + +2341. [bug] libbind: add missing -I../include for off source + tree builds. [RT #17606] + +2340. [port] openbsd: interface configuration. [RT #17700] + +2339. [port] tru64: support for libbind. [RT #17589] + +2338. [bug] check_ds() could be called with a non DS rdataset. + [RT #17598] + +2337. [bug] BUILD_LDFLAGS was not being correctly set. [RT #17614] + +2336. [func] If "named -6" is specified then listen on all IPv6 + interfaces if there are not listen-on-v6 clauses in + named.conf. [RT #17581] + +2335. [port] sunos: libbind and *printf() support for long long. + [RT #17513] + +2334. [bug] Bad REQUIRES in fromstruct_in_naptr(), off by one + bug in fromstruct_txt(). [RT #17609] + +2333. [bug] Fix off by one error in isc_time_nowplusinterval(). + [RT #17608] + +2332. [contrib] query-loc-0.4.0. [RT #17602] + +2331. [bug] Failure to regenerate any signatures was not being + reported nor being past back to the UPDATE client. + [RT #17570] + +2330. [bug] Remove potential race condition when handling + over memory events. [RT #17572] + + WARNING: API CHANGE: over memory callback + function now needs to call isc_mem_waterack(). + See for details. + +2329. [bug] Clearer help text for dig's '-x' and '-i' options. + +2328. [maint] Add AAAA addresses for A.ROOT-SERVERS.NET, + F.ROOT-SERVERS.NET, H.ROOT-SERVERS.NET, + J.ROOT-SERVERS.NET, K.ROOT-SERVERS.NET and + M.ROOT-SERVERS.NET. + +2327. [bug] It was possible to dereference a NULL pointer in + rbtdb.c. Implement dead node processing in zones as + we do for caches. [RT #17312] + +2326. [bug] It was possible to trigger a INSIST in the acache + processing. + +2325. [port] Linux: use capset() function if available. [RT #17557] + +2324. [bug] Fix IPv6 matching against "any;". [RT #17533] + +2323. [port] tru64: namespace clash. [RT #17547] + +2322. [port] MacOS: work around the limitation of setrlimit() + for RLIMIT_NOFILE. [RT #17526] + +2321. [placeholder] + +2320. [func] Make statistics counters thread-safe for platforms + that support certain atomic operations. [RT #17466] + +2319. [bug] Silence Coverity warnings in + lib/dns/rdata/in_1/apl_42.c. [RT #17469] + +2318. [port] sunos fixes for libbind. [RT #17514] + +2317. [bug] "make distclean" removed bind9.xsl.h. [RT #17518] + +2316. [port] Missing #include in lib/dns/gssapictx.c. + [RT #17513] + +2315. [bug] Used incorrect address family for mapped IPv4 + addresses in acl.c. [RT #17519] + +2314. [bug] Uninitialized memory use on error path in + bin/named/lwdnoop.c. [RT #17476] + +2313. [cleanup] Silence Coverity warnings. Handle private stacks. + [RT #17447] [RT #17478] + +2312. [cleanup] Silence Coverity warning in lib/isc/unix/socket.c. + [RT #17458] + +2311. [bug] IPv6 addresses could match IPv4 ACL entries and + vice versa. [RT #17462] + +2310. [bug] dig, host, nslookup: flush stdout before emitting + debug/fatal messages. [RT #17501] + +2309. [cleanup] Fix Coverity warnings in lib/dns/acl.c and iptable.c. + [RT #17455] + +2308. [cleanup] Silence Coverity warning in bin/named/controlconf.c. + [RT #17495] + +2307. [bug] Remove infinite loop from lib/dns/sdb.c. [RT #17496] + +2306. [bug] Remove potential race from lib/dns/resolver.c. + [RT #17470] + +2305. [security] inet_network() buffer overflow. CVE-2008-0122. + +2304. [bug] Check returns from all dns_rdata_tostruct() calls. + [RT #17460] + +2303. [bug] Remove unnecessary code from bin/named/lwdgnba.c. + [RT #17471] + +2302. [bug] Fix memset() calls in lib/tests/t_api.c. [RT #17472] + +2301. [bug] Remove resource leak and fix error messages in + bin/tests/system/lwresd/lwtest.c. [RT #17474] + +2300. [bug] Fixed failure to close open file in + bin/tests/names/t_names.c. [RT #17473] + +2299. [bug] Remove unnecessary NULL check in + bin/nsupdate/nsupdate.c. [RT #17475] + +2298. [bug] isc_mutex_lock() failure not caught in + bin/tests/timers/t_timers.c. [RT #17468] + +2297. [bug] isc_entropy_createfilesource() failure not caught in + bin/tests/dst/t_dst.c. [RT #17467] + +2296. [port] Allow docbook stylesheet location to be specified to + configure. [RT #17457] + +2295. [bug] Silence static overrun error in bin/named/lwaddr.c. + [RT #17459] + +2294. [func] Allow the experimental statistics channels to have + multiple connections and ACL. + Note: the stats-server and stats-server-v6 options + available in the previous beta releases are replaced + with the generic statistics-channels statement. + +2293. [func] Add ACL regression test. [RT #17375] + +2292. [bug] Log if the working directory is not writable. + [RT #17312] + +2291. [bug] PR_SET_DUMPABLE may be set too late. Also report + failure to set PR_SET_DUMPABLE. [RT #17312] + +2290. [bug] Let AD in the query signal that the client wants AD + set in the response. [RT #17301] + +2289. [func] named-checkzone now reports the out-of-zone CNAME + found. [RT #17309] + +2288. [port] win32: mark service as running when we have finished + loading. [RT #17441] + +2287. [bug] Use 'volatile' if the compiler supports it. [RT #17413] + +2286. [func] Allow a TCP connection to be used as a weak + authentication method for reverse zones. + New update-policy methods tcp-self and 6to4-self. + [RT #17378] + +2285. [func] Test framework for client memory context management. + [RT #17377] + +2284. [bug] Memory leak in UPDATE prerequisite processing. + [RT #17377] + +2283. [bug] TSIG keys were not attaching to the memory + context. TSIG keys should use the rings + memory context rather than the clients memory + context. [RT #17377] + +2282. [bug] Acl code fixups. [RT #17346] [RT #17374] + +2281. [bug] Attempts to use undefined acls were not being logged. + [RT #17307] + +2280. [func] Allow the experimental http server to be reached + over IPv6 as well as IPv4. [RT #17332] + +2279. [bug] Use setsockopt(SO_NOSIGPIPE), when available, + to protect applications from receiving spurious + SIGPIPE signals when using the resolver. + +2278. [bug] win32: handle the case where Windows returns no + search list or DNS suffix. [RT #17354] + +2277. [bug] Empty zone names were not correctly being caught at + in the post parse checks. [RT #17357] + +2276. [bug] Install . [RT #17359] + +2275. [func] Add support to dig to perform IXFR queries over UDP. + [RT #17235] + +2274. [func] Log zone transfer statistics. [RT #17336] + +2273. [bug] Adjust log level to WARNING when saving inconsistent + stub/slave master and journal files. [RT #17279] + +2272. [bug] Handle illegal dnssec-lookaside trust-anchor names. + [RT #17262] + +2271. [bug] Fix a memory leak in http server code [RT #17100] + +2270. [bug] dns_db_closeversion() version->writer could be reset + before it is tested. [RT #17290] + +2269. [contrib] dbus memory leaks and missing va_end calls. [RT #17232] + +2268. [bug] 0.IN-ADDR.ARPA was missing from the empty zones + list. + + --- 9.5.0b1 released --- + +2267. [bug] Radix tree node_num value could be set incorrectly, + causing positive ACL matches to look like negative + ones. [RT #17311] + +2266. [bug] client.c:get_clientmctx() returned the same mctx + once the pool of mctx's was filled. [RT #17218] + +2265. [bug] Test that the memory context's basic_table is non NULL + before freeing. [RT #17265] + +2264. [bug] Server prefix length was being ignored. [RT #17308] + +2263. [bug] "named-checkconf -z" failed to set default value + for "check-integrity". [RT #17306] + +2262. [bug] Error status from all but the last view could be + lost. [RT #17292] + +2261. [bug] Fix memory leak with "any" and "none" ACLs [RT #17272] + +2260. [bug] Reported wrong clients-per-query when increasing the + value. [RT #17236] + +2259. [placeholder] + + --- 9.5.0a7 released --- + +2258. [bug] Fallback from IXFR/TSIG to SOA/AXFR/TSIG broken. + [RT #17241] + +2257. [bug] win32: Use the full path to vcredist_x86.exe when + calling it. [RT #17222] + +2256. [bug] win32: Correctly register the installation location of + bindevt.dll. [RT #17159] + +2255. [maint] L.ROOT-SERVERS.NET is now 199.7.83.42. + +2254. [bug] timer.c:dispatch() failed to lock timer->lock + when reading timer->idle allowing it to see + intermediate values as timer->idle was reset by + isc_timer_touch(). [RT #17243] + +2253. [func] "max-cache-size" defaults to 32M. + "max-acache-size" defaults to 16M. + +2252. [bug] Fixed errors in sortlist code [RT #17216] + +2251. [placeholder] + +2250. [func] New flag 'memstatistics' to state whether the + memory statistics file should be written or not. + Additionally named's -m option will cause the + statistics file to be written. [RT #17113] + +2249. [bug] Only set Authentic Data bit if client requested + DNSSEC, per RFC 3655 [RT #17175] + +2248. [cleanup] Fix several errors reported by Coverity. [RT #17160] + +2247. [doc] Sort doc/misc/options. [RT #17067] + +2246. [bug] Make the startup of test servers (ans.pl) more + robust. [RT #17147] + +2245. [bug] Validating lack of DS records at trust anchors wasn't + working. [RT #17151] + +2244. [func] Allow the check of nameserver names against the + SOA MNAME field to be disabled by specifying + 'notify-to-soa yes;'. [RT #17073] + +2243. [func] Configuration files without a newline at the end now + parse without error. [RT #17120] + +2242. [bug] nsupdate: GSS-TSIG support using the Heimdal Kerberos + library could require a source of random data. + [RT #17127] + +2241. [func] nsupdate: add a interactive 'help' command. [RT #17099] + +2240. [bug] Cleanup nsupdates GSS-TSIG support. Convert + a number of INSIST()s into plain fatal() errors + which report the triggering result code. + The 'key' command wasn't disabling GSS-TSIG. + [RT #17099] + +2239. [func] Ship a pre built bin/named/bind9.xsl.h. [RT #17114] + +2238. [bug] It was possible to trigger a REQUIRE when a + validation was canceled. [RT #17106] + +2237. [bug] libbind: res_init() was not thread aware. [RT #17123] + +2236. [bug] dnssec-signzone failed to preserve the case of + of wildcard owner names. [RT #17085] + +2235. [bug] was not being installed. [RT #17135] + +2234. [port] Correct some compiler warnings on SCO OSr5 [RT #17134] + +2233. [func] Add support for O(1) ACL processing, based on + radix tree code originally written by Kevin + Brintnall. [RT #16288] + +2232. [bug] dns_adb_findaddrinfo() could fail and return + ISC_R_SUCCESS. [RT #17137] + +2231. [bug] Building dlzbdb (contrib/dlz/bin/dlzbdb) was broken. + [RT #17088] + +2230. [bug] We could INSIST reading a corrupted journal. + [RT #17132] + +2229. [bug] Null pointer dereference on query pool creation + failure. [RT #17133] + +2228. [contrib] contrib: Change 2188 was incomplete. + +2227. [cleanup] Tidied up the FAQ. [RT #17121] + +2226. [placeholder] + +2225. [bug] More support for systems with no IPv4 addresses. + [RT #17111] + +2224. [bug] Defer journal compaction if a xfrin is in progress. + [RT #17119] + +2223. [bug] Make a new journal when compacting. [RT #17119] + +2222. [func] named-checkconf now checks server key references. + [RT #17097] + +2221. [bug] Set the event result code to reflect the actual + record turned to caller when a cache update is + rejected due to a more credible answer existing. + [RT #17017] + +2220. [bug] win32: Address a race condition in final shutdown of + the Windows socket code. [RT #17028] + +2219. [bug] Apply zone consistency checks to additions, not + removals, when updating. [RT #17049] + +2218. [bug] Remove unnecessary REQUIRE from dns_validator_create(). + [RT #16976] + +2217. [func] Adjust update log levels. [RT #17092] + +2216. [cleanup] Fix a number of errors reported by Coverity. + [RT #17094] + +2215. [bug] Bad REQUIRE check isc_hmacsha1_verify(). [RT #17094] + +2214. [bug] Deregister OpenSSL lock callback when cleaning + up. Reorder OpenSSL cleanup so that RAND_cleanup() + is called before the locks are destroyed. [RT #17098] + +2213. [bug] SIG0 diagnostic failure messages were looking at the + wrong status code. [RT #17101] + +2212. [func] 'host -m' now causes memory statistics and active + memory to be printed at exit. [RT 17028] + +2211. [func] Update "dynamic update temporarily disabled" message. + [RT #17065] + +2210. [bug] Deleting class specific records via UPDATE could + fail. [RT #17074] + +2209. [port] osx: linking against user supplied static OpenSSL + libraries failed as the system ones were still being + found. [RT #17078] + +2208. [port] win32: make sure both build methods produce the + same output. [RT #17058] + +2207. [port] Some implementations of getaddrinfo() fail to set + ai_canonname correctly. [RT #17061] + + --- 9.5.0a6 released --- + +2206. [security] "allow-query-cache" and "allow-recursion" now + cross inherit from each other. + + If allow-query-cache is not set in named.conf then + allow-recursion is used if set, otherwise allow-query + is used if set, otherwise the default (localnets; + localhost;) is used. + + If allow-recursion is not set in named.conf then + allow-query-cache is used if set, otherwise allow-query + is used if set, otherwise the default (localnets; + localhost;) is used. + + [RT #16987] + +2205. [bug] libbind: change #2119 broke thread support. [RT #16982] + +2204. [bug] "rndc flushname name unknown-view" caused named + to crash. [RT #16984] + +2203. [security] Query id generation was cryptographically weak. + [RT # 16915] + +2202. [security] The default acls for allow-query-cache and + allow-recursion were not being applied. [RT #16960] + +2201. [bug] The build failed in a separate object directory. + [RT #16943] + +2200. [bug] The search for cached NSEC records was stopping to + early leading to excessive DLV queries. [RT #16930] + +2199. [bug] win32: don't call WSAStartup() while loading dlls. + [RT #16911] + +2198. [bug] win32: RegCloseKey() could be called when + RegOpenKeyEx() failed. [RT #16911] + +2197. [bug] Add INSIST to catch negative responses which are + not setting the event result code appropriately. + [RT #16909] + +2196. [port] win32: yield processor while waiting for once to + to complete. [RT #16958] + +2195. [func] dnssec-keygen now defaults to nametype "ZONE" + when generating DNSKEYs. [RT #16954] + +2194. [bug] Close journal before calling 'done' in xfrin.c. + + --- 9.5.0a5 released --- + +2193. [port] win32: BINDInstall.exe is now linked statically. + [RT #16906] + +2192. [port] win32: use vcredist_x86.exe to install Visual + Studio's redistributable dlls if building with + Visual Stdio 2005 or later. + +2191. [func] named-checkzone now allows dumping to stdout (-). + named-checkconf now has -h for help. + named-checkzone now has -h for help. + rndc now has -h for help. + Better handling of '-?' for usage summaries. + [RT #16707] + +2190. [func] Make fallback to plain DNS from EDNS due to timeouts + more visible. New logging category "edns-disabled". + [RT #16871] + +2189. [bug] Handle socket() returning EINTR. [RT #15949] + +2188. [contrib] queryperf: autoconf changes to make the search for + libresolv or libbind more robust. [RT #16299] + +2187. [bug] query_addds(), query_addwildcardproof() and + query_addnxrrsetnsec() should take a version + argument. [RT #16368] + +2186. [port] cygwin: libbind: check for struct sockaddr_storage + independently of IPv6. [RT #16482] + +2185. [port] sunos: libbind: check for ssize_t, memmove() and + memchr(). [RT #16463] + +2184. [bug] bind9.xsl.h didn't build out of the source tree. + [RT #16830] + +2183. [bug] dnssec-signzone didn't handle offline private keys + well. [RT #16832] + +2182. [bug] dns_dispatch_createtcp() and dispatch_createudp() + could return ISC_R_SUCCESS when they ran out of + memory. [RT #16365] + +2181. [port] sunos: libbind: add paths.h from BIND 8. [RT #16462] + +2180. [cleanup] Remove bit test from 'compress_test' as they + are no longer needed. [RT #16497] + +2179. [func] 'rndc command zone' will now find 'zone' if it is + unique to all the views. [RT #16821] + +2178. [bug] 'rndc reload' of a slave or stub zone resulted in + a reference leak. [RT #16867] + +2177. [bug] Array bounds overrun on read (rcodetext) at + debug level 10+. [RT #16798] + +2176. [contrib] dbus update to handle race condition during + initialization (Bugzilla 235809). [RT #16842] + +2175. [bug] win32: windows broadcast condition variable support + was broken. [RT #16592] + +2174. [bug] I/O errors should always be fatal when reading + master files. [RT #16825] + +2173. [port] win32: When compiling with MSVS 2005 SP1 we also + need to ship Microsoft.VC80.MFCLOC. + + --- 9.5.0a4 released --- + +2172. [bug] query_addsoa() was being called with a non zone db. + [RT #16834] + +2171. [bug] Handle breaks in DNSSEC trust chains where the parent + servers are not DS aware (DS queries to the parent + return a referral to the child). + +2170. [func] Add acache processing to test suite. [RT #16711] + +2169. [bug] host, nslookup: when reporting NXDOMAIN report the + given name and not the last name searched for. + [RT #16763] + +2168. [bug] nsupdate: in non-interactive mode treat syntax errors + as fatal errors. [RT #16785] + +2167. [bug] When re-using a automatic zone named failed to + attach it to the new view. [RT #16786] + + --- 9.5.0a3 released --- + +2166. [bug] When running in batch mode, dig could misinterpret + a server address as a name to be looked up, causing + unexpected output. [RT #16743] + +2165. [func] Allow the destination address of a query to determine + if we will answer the query or recurse. + allow-query-on, allow-recursion-on and + allow-query-cache-on. [RT #16291] + +2164. [bug] The code to determine how named-checkzone / + named-compilezone was called failed under windows. + [RT #16764] + +2163. [bug] If only one of query-source and query-source-v6 + specified a port the query pools code broke (change + 2129). [RT #16768] + +2162. [func] Allow "rrset-order fixed" to be disabled at compile + time. [RT #16665] + +2161. [bug] Fix which log messages are emitted for 'rndc flush'. + [RT #16698] + +2160. [bug] libisc wasn't handling NULL ifa_addr pointers returned + from getifaddrs(). [RT #16708] + + --- 9.5.0a2 released --- + +2159. [bug] Array bounds overrun in acache processing. [RT #16710] + +2158. [bug] ns_client_isself() failed to initialize key + leading to a REQUIRE failure. [RT #16688] + +2157. [func] dns_db_transfernode() created. [RT #16685] + +2156. [bug] Fix node reference leaks in lookup.c:lookup_find(), + resolver.c:validated() and resolver.c:cache_name(). + Fix a memory leak in rbtdb.c:free_noqname(). + Make lookup.c:lookup_find() robust against + event leaks. [RT #16685] + +2155. [contrib] SQLite sdb module from jaboydjr@netwalk.com. + [RT #16694] + +2154. [func] Scoped (e.g. IPv6 link-local) addresses may now be + matched in acls by omitting the scope. [RT #16599] + +2153. [bug] nsupdate could leak memory. [RT #16691] + +2152. [cleanup] Use sizeof(buf) instead of fixed number in + dighost.c:get_trusted_key(). [RT #16678] + +2151. [bug] Missing newline in usage message for journalprint. + [RT #16679] + +2150. [bug] 'rrset-order cyclic' uniformly distribute the + starting point for the first response for a given + RRset. [RT #16655] + +2149. [bug] isc_mem_checkdestroyed() failed to abort on + if there were still active memory contexts. + [RT #16672] + +2148. [func] Add positive logging for rndc commands. [RT #14623] + +2147. [bug] libbind: remove potential buffer overflow from + hmac_link.c. [RT #16437] + +2146. [cleanup] Silence Linux's spurious "obsolete setsockopt + SO_BSDCOMPAT" message. [RT #16641] + +2145. [bug] Check DS/DLV digest lengths for known digests. + [RT #16622] + +2144. [cleanup] Suppress logging of SERVFAIL from forwarders. + [RT #16619] + +2143. [bug] We failed to restart the IPv6 client when the + kernel failed to return the destination the + packet was sent to. [RT #16613] + +2142. [bug] Handle master files with a modification time that + matches the epoch. [RT #16612] + +2141. [bug] dig/host should not be setting IDN_ASCCHECK (IDN + equivalent of LDH checks). [RT #16609] + +2140. [bug] libbind: missing unlock on pthread_key_create() + failures. [RT #16654] + +2139. [bug] dns_view_find() was being called with wrong type + in adb.c. [RT #16670] + +2138. [bug] Lock order reversal in resolver.c. [RT #16653] + +2137. [port] Mips little endian and/or mips 64 bit are now + supported for atomic operations. [RT #16648] + +2136. [bug] nslookup/host looped if there was no search list + and the host didn't exist. [RT #16657] + +2135. [bug] Uninitialized rdataset in sdlz.c. [RT #16656] + +2134. [func] Additional statistics support. [RT #16666] + +2133. [port] powerpc: Support both IBM and MacOS Power PC + assembler syntaxes. [RT #16647] + +2132. [bug] Missing unlock on out of memory in + dns_dispatchmgr_setudp(). + +2131. [contrib] dlz/mysql: AXFR was broken. [RT #16630] + +2130. [func] Log if CD or DO were set. [RT #16640] + +2129. [func] Provide a pool of UDP sockets for queries to be + made over. See use-queryport-pool, queryport-pool-ports + and queryport-pool-updateinterval. [RT #16415] + +2128. [doc] xsltproc --nonet, update DTD versions. [RT #16635] + +2127. [port] Improved OpenSSL 0.9.8 support. [RT #16563] + +2126. [security] Serialize validation of type ANY responses. [RT #16555] + +2125. [bug] dns_zone_getzeronosoattl() REQUIRE failure if DLZ + was defined. [RT #16574] + +2124. [security] It was possible to dereference a freed fetch + context. [RT #16584] + + --- 9.5.0a1 released --- + +2123. [func] Use Doxygen to generate internal documentation. + [RT #11398] + +2122. [func] Experimental http server and statistics support + for named via xml. + +2121. [func] Add a 10 slot dead masters cache (LRU) with a 600 + second timeout. [RT #16553] + +2120. [doc] Fix markup on nsupdate man page. [RT #16556] + +2119. [compat] libbind: allow res_init() to succeed enough to + return the default domain even if it was unable + to allocate memory. + +2118. [bug] Handle response with long chains of domain name + compression pointers which point to other compression + pointers. [RT #16427] + +2117. [bug] DNSSEC fixes: named could fail to cache NSEC records + which could lead to validation failures. named didn't + handle negative DS responses that were in the process + of being validated. Check CNAME bit before accepting + NODATA proof. To be able to ignore a child NSEC there + must be SOA (and NS) set in the bitmap. [RT #16399] + +2116. [bug] 'rndc reload' could cause the cache to continually + be cleaned. [RT #16401] + +2115. [bug] 'rndc reconfig' could trigger a INSIST if the + number of masters for a zone was reduced. [RT #16444] + +2114. [bug] dig/host/nslookup: searches for names with multiple + labels were failing. [RT #16447] + +2113. [bug] nsupdate: if a zone is specified it should be used + for server discover. [RT #16455] + +2112. [security] Warn if weak RSA exponent is used. [RT #16460] + +2111. [bug] Fix a number of errors reported by Coverity. + [RT #16507] + +2110. [bug] "minimal-responses yes;" interacted badly with BIND 8 + priming queries. [RT #16491] + +2109. [port] libbind: silence aix 5.3 compiler warnings. [RT #16502] + +2108. [func] DHCID support. [RT #16456] + +2107. [bug] dighost.c: more cleanup of buffers. [RT #16499] + +2106. [func] 'rndc status' now reports named's version. [RT #16426] + +2105. [func] GSS-TSIG support (RFC 3645). + +2104. [port] Fix Solaris SMF error message. + +2103. [port] Add /usr/sfw to list of locations for OpenSSL + under Solaris. + +2102. [port] Silence Solaris 10 warnings. + +2101. [bug] OpenSSL version checks were not quite right. + [RT #16476] + +2100. [port] win32: copy libeay32.dll to Build\Debug. + Copy Debug\named-checkzone to Debug\named-compilezone. + +2099. [port] win32: more manifest issues. + +2098. [bug] Race in rbtdb.c:no_references(), which occasionally + triggered an INSIST failure about the node lock + reference. [RT #16411] + +2097. [bug] named could reference a destroyed memory context + after being reloaded / reconfigured. [RT #16428] + +2096. [bug] libbind: handle applications that fail to detect + res_init() failures better. + +2095. [port] libbind: always prototype inet_cidr_ntop_ipv6() and + net_cidr_ntop_ipv6(). [RT #16388] + +2094. [contrib] Update named-bootconf. [RT #16404] + +2093. [bug] named-checkzone -s was broken. + +2092. [bug] win32: dig, host, nslookup. Use registry config + if resolv.conf does not exist or no nameservers + listed. [RT #15877] + +2091. [port] dighost.c: race condition on cleanup. [RT #16417] + +2090. [port] win32: Visual C++ 2005 command line manifest support. + [RT #16417] + +2089. [security] Raise the minimum safe OpenSSL versions to + OpenSSL 0.9.7l and OpenSSL 0.9.8d. Versions + prior to these have known security flaws which + are (potentially) exploitable in named. [RT #16391] + +2088. [security] Change the default RSA exponent from 3 to 65537. + [RT #16391] + +2087. [port] libisc failed to compile on OS's w/o a vsnprintf. + [RT #16382] + +2086. [port] libbind: FreeBSD now has get*by*_r() functions. + [RT #16403] + +2085. [doc] win32: added index.html and README to zip. [RT #16201] + +2084. [contrib] dbus update for 9.3.3rc2. + +2083. [port] win32: Visual C++ 2005 support. + +2082. [doc] Document 'cache-file' as a test only option. + +2081. [port] libbind: minor 64-bit portability fix in memcluster.c. + [RT #16360] + +2080. [port] libbind: res_init.c did not compile on older versions + of Solaris. [RT #16363] + +2079. [bug] The lame cache was not handling multiple types + correctly. [RT #16361] + +2078. [bug] dnssec-checkzone output style "default" was badly + named. It is now called "relative". [RT #16326] + +2077. [bug] 'dnssec-signzone -O raw' wasn't outputting the + complete signed zone. [RT #16326] + +2076. [bug] Several files were missing #include + causing build failures on OSF. [RT #16341] + +2075. [bug] The spillat timer event handler could leak memory. + [RT #16357] + +2074. [bug] dns_request_createvia2(), dns_request_createvia3(), + dns_request_createraw2() and dns_request_createraw3() + failed to send multiple UDP requests. [RT #16349] + +2073. [bug] Incorrect semantics check for update policy "wildcard". + [RT #16353] + +2072. [bug] We were not generating valid HMAC SHA digests. + [RT #16320] + +2071. [port] Test whether gcc accepts -fno-strict-aliasing. + [RT #16324] + +2070. [bug] The remote address was not always displayed when + reporting dispatch failures. [RT #16315] + +2069. [bug] Cross compiling was not working. [RT #16330] + +2068. [cleanup] Lower incremental tuning message to debug 1. + [RT #16319] + +2067. [bug] 'rndc' could close the socket too early triggering + a INSIST under Windows. [RT #16317] + +2066. [security] Handle SIG queries gracefully. [RT #16300] + +2065. [bug] libbind: probe for HPUX prototypes for + endprotoent_r() and endservent_r(). [RT 16313] + +2064. [bug] libbind: silence AIX compiler warnings. [RT #16218] + +2063. [bug] Change #1955 introduced a bug which caused the first + 'rndc flush' call to not free memory. [RT #16244] + +2062. [bug] 'dig +nssearch' was reusing a buffer before it had + been returned by the socket code. [RT #16307] + +2061. [bug] Accept expired wildcard message reversed. [RT #16296] + +2060. [bug] Enabling DLZ support could leave views partially + configured. [RT #16295] + +2059. [bug] Search into cache rbtdb could trigger an INSIST + failure while cleaning up a stale rdataset. + [RT #16292] + +2058. [bug] Adjust how we calculate rtt estimates in the presence + of authoritative servers that drop EDNS and/or CD + requests. Also fallback to EDNS/512 and plain DNS + faster for zones with less than 3 servers. [RT #16187] + +2057. [bug] Make setting "ra" dependent on both allow-query-cache + and allow-recursion. [RT #16290] + +2056. [bug] dig: ixfr= was not being treated case insensitively + at all times. [RT #15955] + +2055. [bug] Missing goto after dropping multicast query. + [RT #15944] + +2054. [port] freebsd: do not explicitly link against -lpthread. + [RT #16170] + +2053. [port] netbsd:libbind: silence compiler warnings. [RT #16220] + +2052. [bug] 'rndc' improve connect failed message to report + the failing address. [RT #15978] + +2051. [port] More strtol() fixes. [RT #16249] + +2050. [bug] Parsing of NSAP records was not case insensitive. + [RT #16287] + +2049. [bug] Restore SOA before AXFR when falling back from + a attempted IXFR when transferring in a zone. + Allow a initial SOA query before attempting + a AXFR to be requested. [RT #16156] + +2048. [bug] It was possible to loop forever when using + avoid-v4-udp-ports / avoid-v6-udp-ports when + the OS always returned the same local port. + [RT #16182] + +2047. [bug] Failed to initialize the interface flags to zero. + [RT #16245] + +2046. [bug] rbtdb.c:rdataset_setadditional() could cause duplicate + cleanup [RT #16247]. + +2045. [func] Use lock buckets for acache entries to limit memory + consumption. [RT #16183] + +2044. [port] Add support for atomic operations for Itanium. + [RT #16179] + +2043. [port] nsupdate/nslookup: Force the flushing of the prompt + for interactive sessions. [RT #16148] + +2042. [bug] named-checkconf was incorrectly rejecting the + logging category "config". [RT #16117] + +2041. [bug] "configure --with-dlz-bdb=yes" produced a bad + set of libraries to be linked. [RT #16129] + +2040. [bug] rbtdb no_references() could trigger an INSIST + failure with --enable-atomic. [RT #16022] + +2039. [func] Check that all buffers passed to the socket code + have been retrieved when the socket event is freed. + [RT #16122] + +2038. [bug] dig/nslookup/host was unlinking from wrong list + when handling errors. [RT #16122] + +2037. [func] When unlinking the first or last element in a list + check that the list head points to the element to + be unlinked. [RT #15959] + +2036. [bug] 'rndc recursing' could cause trigger a REQUIRE. + [RT #16075] + +2035. [func] Make falling back to TCP on UDP refresh failure + optional. Default "try-tcp-refresh yes;" for BIND 8 + compatibility. [RT #16123] + +2034. [bug] gcc: set -fno-strict-aliasing. [RT #16124] + +2033. [bug] We weren't creating multiple client memory contexts + on demand as expected. [RT #16095] + +2032. [bug] Remove a INSIST in query_addadditional2(). [RT #16074] + +2031. [bug] Emit a error message when "rndc refresh" is called on + a non slave/stub zone. [RT # 16073] + +2030. [bug] We were being overly conservative when disabling + openssl engine support. [RT #16030] + +2029. [bug] host printed out the server multiple times when + specified on the command line. [RT #15992] + +2028. [port] linux: socket.c compatibility for old systems. + [RT #16015] + +2027. [port] libbind: Solaris x86 support. [RT #16020] + +2026. [bug] Rate limit the two recursive client exceeded messages. + [RT #16044] + +2025. [func] Update "zone serial unchanged" message. [RT #16026] + +2024. [bug] named emitted spurious "zone serial unchanged" + messages on reload. [RT #16027] + +2023. [bug] "make install" should create ${localstatedir}/run and + ${sysconfdir} if they do not exist. [RT #16033] + +2022. [bug] If dnssec validation is disabled only assert CD if + CD was requested. [RT #16037] + +2021. [bug] dnssec-enable no; triggered a REQUIRE. [RT #16037] + +2020. [bug] rdataset_setadditional() could leak memory. [RT #16034] + +2019. [tuning] Reduce the amount of work performed per quantum + when cleaning the cache. [RT #15986] + +2018. [bug] Checking if the HMAC MD5 private file was broken. + [RT #15960] + +2017. [bug] allow-query default was not correct. [RT #15946] + +2016. [bug] Return a partial answer if recursion is not + allowed but requested and we had the answer + to the original qname. [RT #15945] + +2015. [cleanup] use-additional-cache is now acache-enable for + consistency. Default acache-enable off in BIND 9.4 + as it requires memory usage to be configured. + It may be enabled by default in BIND 9.5 once we + have more experience with it. + +2014. [func] Statistics about acache now recorded and sent + to log. [RT #15976] + +2013. [bug] Handle unexpected TSIGs on unsigned AXFR/IXFR + responses more gracefully. [RT #15941] + +2012. [func] Don't insert new acache entries if acache is full. + [RT #15970] + +2011. [func] dnssec-signzone can now update the SOA record of + the signed zone, either as an increment or as the + system time(). [RT #15633] + +2010. [placeholder] rt15958 + +2009. [bug] libbind: Coverity fixes. [RT #15808] + +2008. [func] It is now possible to enable/disable DNSSEC + validation from rndc. This is useful for the + mobile hosts where the current connection point + breaks DNSSEC (firewall/proxy). [RT #15592] + + rndc validation newstate [view] + +2007. [func] It is now possible to explicitly enable DNSSEC + validation. default dnssec-validation no; to + be changed to yes in 9.5.0. [RT #15674] + +2006. [security] Allow-query-cache and allow-recursion now default + to the built in acls "localnets" and "localhost". + + This is being done to make caching servers less + attractive as reflective amplifying targets for + spoofed traffic. This still leave authoritative + servers exposed. + + The best fix is for full BCP 38 deployment to + remove spoofed traffic. + +2005. [bug] libbind: Retransmission timeouts should be + based on which attempt it is to the nameserver + and not the nameserver itself. [RT #13548] + +2004. [bug] dns_tsig_sign() could pass a NULL pointer to + dst_context_destroy() when cleaning up after a + error. [RT #15835] + +2003. [bug] libbind: The DNS name/address lookup functions could + occasionally follow a random pointer due to + structures not being completely zeroed. [RT #15806] + +2002. [bug] libbind: tighten the constraints on when + struct addrinfo._ai_pad exists. [RT #15783] + +2001. [func] Check the KSK flag when updating a secure dynamic zone. + New zone option "update-check-ksk yes;". [RT #15817] + +2000. [bug] memmove()/strtol() fix was incomplete. [RT #15812] + +1999. [func] Implement "rrset-order fixed". [RT #13662] + +1998. [bug] Restrict handling of fifos as sockets to just SunOS. + This allows named to connect to entropy gathering + daemons that use fifos instead of sockets. [RT #15840] + +1997. [bug] Named was failing to replace negative cache entries + when a positive one for the type was learnt. + [RT #15818] + +1996. [bug] nsupdate: if a zone has been specified it should + appear in the output of 'show'. [RT #15797] + +1995. [bug] 'host' was reporting multiple "is an alias" messages. + [RT #15702] + +1994. [port] OpenSSL 0.9.8 support. [RT #15694] + +1993. [bug] Log messages, via syslog, were missing the space + after the timestamp if "print-time yes" was specified. + [RT #15844] + +1992. [bug] Not all incoming zone transfer messages included the + view. [RT #15825] + +1991. [cleanup] The configuration data, once read, should be treated + as read only. Expand the use of const to enforce this + at compile time. [RT #15813] + +1990. [bug] libbind: isc's override of broken gettimeofday() + implementations was not always effective. + [RT #15709] + +1989. [bug] win32: don't check the service password when + re-installing. [RT #15882] + +1988. [bug] Remove a bus error from the SHA256/SHA512 support. + [RT #15878] + +1987. [func] DS/DLV SHA256 digest algorithm support. [RT #15608] + +1986. [func] Report when a zone is removed. [RT #15849] + +1985. [protocol] DLV has now been assigned a official type code of + 32769. [RT #15807] + + Note: care should be taken to ensure you upgrade + both named and dnssec-signzone at the same time for + zones with DLV records where named is the master + server for the zone. Also any zones that contain + DLV records should be removed when upgrading a slave + zone. You do not however have to upgrade all + servers for a zone with DLV records simultaneously. + +1984. [func] dig, nslookup and host now advertise a 4096 byte + EDNS UDP buffer size by default. [RT #15855] + +1983. [func] Two new update policies. "selfsub" and "selfwild". + [RT #12895] + +1982. [bug] DNSKEY was being accepted on the parent side of + a delegation. KEY is still accepted there for + RFC 3007 validated updates. [RT #15620] + +1981. [bug] win32: condition.c:wait() could fail to reattain + the mutex lock. + +1980. [func] dnssec-signzone: output the SOA record as the + first record in the signed zone. [RT #15758] + +1979. [port] linux: allow named to drop core after changing + user ids. [RT #15753] + +1978. [port] Handle systems which have a broken recvmsg(). + [RT #15742] + +1977. [bug] Silence noisy log message. [RT #15704] + +1976. [bug] Handle systems with no IPv4 addresses. [RT #15695] + +1975. [bug] libbind: isc_gethexstring() could misparse multi-line + hex strings with comments. [RT #15814] + +1974. [doc] List each of the zone types and associated zone + options separately in the ARM. + +1973. [func] TSIG HMACSHA1, HMACSHA224, HMACSHA256, HMACSHA384 and + HMACSHA512 support. [RT #13606] + +1972. [contrib] DBUS dynamic forwarders integration from + Jason Vas Dias . + +1971. [port] linux: make detection of missing IF_NAMESIZE more + robust. [RT #15443] + +1970. [bug] nsupdate: adjust UDP timeout when falling back to + unsigned SOA query. [RT #15775] + +1969. [bug] win32: the socket code was freeing the socket + structure too early. [RT #15776] + +1968. [bug] Missing lock in resolver.c:validated(). [RT #15739] + +1967. [func] dig/nslookup/host: warn about missing "QR". [RT #15779] + +1966. [bug] Don't set CD when we have fallen back to plain DNS. + [RT #15727] + +1965. [func] Suppress spurious "recursion requested but not + available" warning with 'dig +qr'. [RT #15780]. + +1964. [func] Separate out MX and SRV to CNAME checks. [RT #15723] + +1963. [port] Tru64 4.0E doesn't support send() and recv(). + [RT #15586] + +1962. [bug] Named failed to clear old update-policy when it + was removed. [RT #15491] + +1961. [bug] Check the port and address of responses forwarded + to dispatch. [RT #15474] + +1960. [bug] Update code should set NSEC ttls from SOA MINIMUM. + [RT #15465] + +1959. [func] Control the zeroing of the negative response TTL to + a soa query. Defaults "zero-no-soa-ttl yes;" and + "zero-no-soa-ttl-cache no;". [RT #15460] + +1958. [bug] Named failed to update the zone's secure state + until the zone was reloaded. [RT #15412] + +1957. [bug] Dig mishandled responses to class ANY queries. + [RT #15402] + +1956. [bug] Improve cross compile support, 'gen' is now built + by native compiler. See README for additional + cross compile support information. [RT #15148] + +1955. [bug] Pre-allocate the cache cleaning iterator. [RT #14998] + +1954. [func] Named now falls back to advertising EDNS with a + 512 byte receive buffer if the initial EDNS queries + fail. [RT #14852] + +1953. [func] The maximum EDNS UDP response named will send can + now be set in named.conf (max-udp-size). This is + independent of the advertised receive buffer + (edns-udp-size). [RT #14852] + +1952. [port] hpux: tell the linker to build a runtime link + path "-Wl,+b:". [RT #14816]. + +1951. [security] Drop queries from particular well known ports. + Don't return FORMERR to queries from particular + well known ports. [RT #15636] + +1950. [port] Solaris 2.5.1 and earlier cannot bind() then connect() + a TCP socket. This prevents the source address being + set for TCP connections. [RT #15628] + +1949. [func] Addition memory leakage checks. [RT #15544] + +1948. [bug] If was possible to trigger a REQUIRE failure in + xfrin.c:maybe_free() if named ran out of memory. + [RT #15568] + +1947. [func] It is now possible to configure named to accept + expired RRSIGs. Default "dnssec-accept-expired no;". + Setting "dnssec-accept-expired yes;" leaves named + vulnerable to replay attacks. [RT #14685] + +1946. [bug] resume_dslookup() could trigger a REQUIRE failure + when using forwarders. [RT #15549] + +1945. [cleanup] dnssec-keygen: RSA (RSAMD5) is no longer recommended. + To generate a RSAMD5 key you must explicitly request + RSAMD5. [RT #13780] + +1944. [cleanup] isc_hash_create() does not need a read/write lock. + [RT #15522] + +1943. [bug] Set the loadtime after rolling forward the journal. + [RT #15647] + +1942. [bug] If the name of a DNSKEY match that of one in + trusted-keys do not attempt to validate the DNSKEY + using the parents DS RRset. [RT #15649] + +1941. [bug] ncache_adderesult() should set eresult even if no + rdataset is passed to it. [RT #15642] + +1940. [bug] Fixed a number of error conditions reported by + Coverity. + +1939. [bug] The resolver could dereference a null pointer after + validation if all the queries have timed out. + [RT #15528] + +1938. [bug] The validator was not correctly handling unsecure + negative responses at or below a SEP. [RT #15528] + +1937. [bug] sdlz doesn't handle RRSIG records. [RT #15564] + +1936. [bug] The validator could leak memory. [RT #15544] + +1935. [bug] 'acache' was DO sensitive. [RT #15430] + +1934. [func] Validate pending NS RRsets, in the authority section, + prior to returning them if it can be done without + requiring DNSKEYs to be fetched. [RT #15430] + +1933. [bug] dump_rdataset_raw() had a incorrect INSIST. [RT #15534] + +1932. [bug] hpux: LDFLAGS was getting corrupted. [RT #15530] + +1931. [bug] Per-client mctx could require a huge amount of memory, + particularly for a busy caching server. [RT #15519] + +1930. [port] HPUX: ia64 support. [RT #15473] + +1929. [port] FreeBSD: extend use of PTHREAD_SCOPE_SYSTEM. + +1928. [bug] Race in rbtdb.c:currentversion(). [RT #15517] + +1927. [bug] Access to soanode or nsnode in rbtdb violated the + lock order rule and could cause a dead lock. + [RT #15518] + +1926. [bug] The Windows installer did not check for empty + passwords. BINDinstall was being installed in + the wrong place. [RT #15483] + +1925. [port] All outer level AC_TRY_RUNs need cross compiling + defaults. [RT #15469] + +1924. [port] libbind: hpux ia64 support. [RT #15473] + +1923. [bug] ns_client_detach() called too early. [RT #15499] + +1922. [bug] check-tool.c:setup_logging() missing call to + dns_log_setcontext(). + +1921. [bug] Client memory contexts were not using internal + malloc. [RT #15434] + +1920. [bug] The cache rbtdb lock array was too small to + have the desired performance characteristics. + [RT #15454] + +1919. [contrib] queryperf: a set of new features: collecting/printing + response delays, printing intermediate results, and + adjusting query rate for the "target" qps. + +1918. [bug] Memory leak when checking acls. [RT #15391] + +1917. [doc] funcsynopsisinfo wasn't being treated as verbatim + when generating man pages. [RT #15385] + +1916. [func] Integrate contributed IDN code from JPNIC. [RT #15383] + +1915. [bug] dig +ndots was broken. [RT #15215] + +1914. [protocol] DS is required to accept mnemonic algorithms + (RFC 4034). Still emit numeric algorithms for + compatibility with RFC 3658. [RT #15354] + +1913. [func] Integrate contributed DLZ code into named. [RT #11382] + +1912. [port] aix: atomic locking for powerpc. [RT #15020] + +1911. [bug] Update windows socket code. [RT #14965] + +1910. [bug] dig's +sigchase code overhauled. [RT #14933] + +1909. [bug] The DLV code has been re-worked to make no longer + query order sensitive. [RT #14933] + +1908. [func] dig now warns if 'RA' is not set in the answer when + 'RD' was set in the query. host/nslookup skip servers + that fail to set 'RA' when 'RD' is set unless a server + is explicitly set. [RT #15005] + +1907. [func] host/nslookup now continue (default)/fail on SERVFAIL. + [RT #15006] + +1906. [func] dig now has a '-q queryname' and '+showsearch' options. + [RT #15034] + +1905. [bug] Strings returned from cfg_obj_asstring() should be + treated as read-only. The prototype for + cfg_obj_asstring() has been updated to reflect this. + [RT #15256] + +1904. [func] Automatic empty zone creation for D.F.IP6.ARPA and + friends. Note: RFC 1918 zones are not yet covered by + this but are likely to be in a future release. + + New options: empty-server, empty-contact, + empty-zones-enable and disable-empty-zone. + +1903. [func] ISC string copy API. + +1902. [func] Attempt to make the amount of work performed in a + iteration self tuning. The covers nodes clean from + the cache per iteration, nodes written to disk when + rewriting a master file and nodes destroyed per + iteration when destroying a zone or a cache. + [RT #14996] + +1901. [cleanup] Don't add DNSKEY records to the additional section. + +1900. [bug] ixfr-from-differences failed to ensure that the + serial number increased. [RT #15036] + +1899. [func] named-checkconf now validates update-policy entries. + [RT #14963] + +1898. [bug] Extend ISC_SOCKADDR_FORMATSIZE and + ISC_NETADDR_FORMATSIZE to allow for scope details. + +1897. [func] x86 and x86_64 now have separate atomic locking + implementations. + +1896. [bug] Recursive clients soft quota support wasn't working + as expected. [RT #15103] + +1895. [bug] A escaped character is, potentially, converted to + the output character set too early. [RT #14666] + +1894. [doc] Review ARM for BIND 9.4. + +1893. [port] Use uintptr_t if available. [RT #14606] + +1892. [func] Support for SPF rdata type. [RT #15033] + +1891. [port] freebsd: pthread_mutex_init can fail if it runs out + of memory. [RT #14995] + +1890. [func] Raise the UDP receive buffer size to 32k if it is + less than 32k. [RT #14953] + +1889. [port] sunos: non blocking i/o support. [RT #14951] + +1888. [func] Support for IPSECKEY rdata type. [RT #14967] + +1887. [bug] The cache could delete expired records too fast for + clients with a virtual time in the past. [RT #14991] + +1886. [bug] fctx_create() could return success even though it + failed. [RT #14993] + +1885. [func] dig: report the number of extra bytes still left in + the packet after processing all the records. + +1884. [cleanup] dighost.c: move external declarations into . + +1883. [bug] dnssec-signzone, dnssec-keygen: handle negative debug + levels. [RT #14962] + +1882. [func] Limit the number of recursive clients that can be + waiting for a single query () to + resolve. New options clients-per-query and + max-clients-per-query. + +1881. [func] Add a system test for named-checkconf. [RT #14931] + +1880. [func] The lame cache is now done on a + basis as some servers only appear to be lame for + certain query types. [RT #14916] + +1879. [func] "USE INTERNAL MALLOC" is now runtime selectable. + [RT #14892] + +1878. [func] Detect duplicates of UDP queries we are recursing on + and drop them. New stats category "duplicate". + [RT #2471] + +1877. [bug] Fix unreasonably low quantum on call to + dns_rbt_destroy2(). Remove unnecessary unhash_node() + call. [RT #14919] + +1876. [func] Additional memory debugging support to track size + and mctx arguments. [RT #14814] + +1875. [bug] process_dhtkey() was using the wrong memory context + to free some memory. [RT #14890] + +1874. [port] sunos: portability fixes. [RT #14814] + +1873. [port] win32: isc__errno2result() now reports its caller. + [RT #13753] + +1872. [port] win32: Handle ERROR_NETNAME_DELETED. [RT #13753] + +1871. [placeholder] + +1870. [func] Added framework for handling multiple EDNS versions. + [RT #14873] + +1869. [func] dig can now specify the EDNS version when making + a query. [RT #14873] + +1868. [func] edns-udp-size can now be overridden on a per + server basis. [RT #14851] + +1867. [bug] It was possible to trigger a INSIST in + dlv_validatezonekey(). [RT #14846] + +1866. [bug] resolv.conf parse errors were being ignored by + dig/host/nslookup. [RT #14841] + +1865. [bug] Silently ignore nameservers in /etc/resolv.conf with + bad addresses. [RT #14841] + +1864. [bug] Don't try the alternative transfer source if you + got a answer / transfer with the main source + address. [RT #14802] + +1863. [bug] rrset-order "fixed" error messages not complete. + +1862. [func] Add additional zone data constancy checks. + named-checkzone has extended checking of NS, MX and + SRV record and the hosts they reference. + named has extended post zone load checks. + New zone options: check-mx and integrity-check. + [RT #4940] + +1861. [bug] dig could trigger a INSIST on certain malformed + responses. [RT #14801] + +1860. [port] solaris 2.8: hack_shutup_pthreadmutexinit was + incorrectly set. [RT #14775] + +1859. [func] Add support for CH A record. [RT #14695] + +1858. [bug] The flush-zones-on-shutdown option wasn't being + parsed. [RT #14686] + +1857. [bug] named could trigger a INSIST() if reconfigured / + reloaded too fast. [RT #14673] + +1856. [doc] Switch Docbook toolchain from DSSSL to XSL. + [RT #11398] + +1855. [bug] ixfr-from-differences was failing to detect changes + of ttl due to dns_diff_subtract() was ignoring the ttl + of records. [RT #14616] + +1854. [bug] lwres also needs to know the print format for + (long long). [RT #13754] + +1853. [bug] Rework how DLV interacts with proveunsecure(). + [RT #13605] + +1852. [cleanup] Remove last vestiges of dnssec-signkey and + dnssec-makekeyset (removed from Makefile years ago). + +1851. [doc] Doxygen comment markup. [RT #11398] + +1850. [bug] Memory leak in lwres_getipnodebyaddr(). [RT #14591] + +1849. [doc] All forms of the man pages (docbook, man, html) should + have consistent copyright dates. + +1848. [bug] Improve SMF integration. [RT #13238] + +1847. [bug] isc_ondestroy_init() is called too late in + dns_rbtdb_create()/dns_rbtdb64_create(). + [RT #13661] + +1846. [contrib] query-loc-0.3.0 from Stephane Bortzmeyer + . + +1845. [bug] Improve error reporting to distinguish between + accept()/fcntl() and socket()/fcntl() errors. + [RT #13745] + +1844. [bug] inet_pton() accepted more that 4 hexadecimal digits + for each 16 bit piece of the IPv6 address. The text + representation of a IPv6 address has been tightened + to disallow this (draft-ietf-ipv6-addr-arch-v4-02.txt). + [RT #5662] + +1843. [cleanup] CINCLUDES takes precedence over CFLAGS. This helps + when CFLAGS contains "-I /usr/local/include" + resulting in old header files being used. + +1842. [port] cmsg_len() could produce incorrect results on + some platform. [RT #13744] + +1841. [bug] "dig +nssearch" now makes a recursive query to + find the list of nameservers to query. [RT #13694] + +1840. [func] dnssec-signzone can now randomize signature end times + (dnssec-signzone -j jitter). [RT #13609] + +1839. [bug] was not being installed. + +1838. [cleanup] Don't allow Linux capabilities to be inherited. + [RT #13707] + +1837. [bug] Compile time option ISC_FACILITY was not effective + for 'named -u '. [RT #13714] + +1836. [cleanup] Silence compiler warnings in hash_test.c. + +1835. [bug] Update dnssec-signzone's usage message. [RT #13657] + +1834. [bug] Bad memset in rdata_test.c. [RT #13658] + +1833. [bug] Race condition in isc_mutex_lock_profile(). [RT #13660] + +1832. [bug] named fails to return BADKEY on unknown TSIG algorithm. + [RT #13620] + +1831. [doc] Update named-checkzone documentation. [RT #13604] + +1830. [bug] adb lame cache has sense of test reversed. [RT #13600] + +1829. [bug] win32: "pid-file none;" broken. [RT #13563] + +1828. [bug] isc_rwlock_init() failed to properly cleanup if it + encountered a error. [RT #13549] + +1827. [bug] host: update usage message for '-a'. [RT #37116] + +1826. [bug] Missing DESTROYLOCK() in isc_mem_createx() on out + of memory error. [RT #13537] + +1825. [bug] Missing UNLOCK() on out of memory error from in + rbtdb.c:subtractrdataset(). [RT #13519] + +1824. [bug] Memory leak on dns_zone_setdbtype() failure. + [RT #13510] + +1823. [bug] Wrong macro used to check for point to point interface. + [RT #13418] + +1822. [bug] check-names test for RT was reversed. [RT #13382] + +1821. [placeholder] + +1820. [bug] Gracefully handle acl loops. [RT #13659] + +1819. [bug] The validator needed to check both the algorithm and + digest types of the DS to determine if it could be + used to introduce a secure zone. [RT #13593] + +1818. [bug] 'named-checkconf -z' triggered an INSIST. [RT #13599] + +1817. [func] Add support for additional zone file formats for + improving loading performance. The masterfile-format + option in named.conf can be used to specify a + non-default format. A separate command + named-compilezone was provided to generate zone files + in the new format. Additionally, the -I and -O options + for dnssec-signzone specify the input and output + formats. + +1816. [port] UnixWare: failed to compile lib/isc/unix/net.c. + [RT #13597] + +1815. [bug] nsupdate triggered a REQUIRE if the server was set + without also setting the zone and it encountered + a CNAME and was using TSIG. [RT #13086] + +1814. [func] UNIX domain controls are now supported. + +1813. [func] Restructured the data locking framework using + architecture dependent atomic operations (when + available), improving response performance on + multi-processor machines significantly. + x86, x86_64, alpha, powerpc, and mips are currently + supported. + +1812. [port] win32: IN6_IS_ADDR_UNSPECIFIED macro is incorrect. + [RT #13453] + +1811. [func] Preserve the case of domain names in rdata during + zone transfers. [RT #13547] + +1810. [bug] configure, lib/bind/configure make different default + decisions about whether to do a threaded build. + [RT #13212] + +1809. [bug] "make distclean" failed for libbind if the platform + is not supported. + +1808. [bug] zone.c:notify_zone() contained a race condition, + zone->db could change underneath it. [RT #13511] + +1807. [bug] When forwarding (forward only) set the active domain + from the forward zone name. [RT #13526] + +1806. [bug] The resolver returned the wrong result when a CNAME / + DNAME was encountered when fetching glue from a + secure namespace. [RT #13501] + +1805. [bug] Pending status was not being cleared when DLV was + active. [RT #13501] + +1804. [bug] Ensure that if we are queried for glue that it fits + in the additional section or TC is set to tell the + client to retry using TCP. [RT #10114] + +1803. [bug] dnssec-signzone sometimes failed to remove old + RRSIGs. [RT #13483] + +1802. [bug] Handle connection resets better. [RT #11280] + +1801. [func] Report differences between hints and real NS rrset + and associated address records. + +1800. [bug] Changes #1719 allowed a INSIST to be triggered. + [RT #13428] + +1799. [bug] 'rndc flushname' failed to flush negative cache + entries. [RT #13438] + +1798. [func] The server syntax has been extended to support a + range of servers. [RT #11132] + +1797. [func] named-checkconf now check acls to verify that they + only refer to existing acls. [RT #13101] + +1796. [func] "rndc freeze/thaw" now freezes/thaws all zones. + +1795. [bug] "rndc dumpdb" was not fully documented. Minor + formatting issues with "rndc dumpdb -all". [RT #13396] + +1794. [func] Named and named-checkzone can now both check for + non-terminal wildcard records. + +1793. [func] Extend adjusting TTL warning messages. [RT #13378] + +1792. [func] New zone option "notify-delay". Specify a minimum + delay between sets of NOTIFY messages. + +1791. [bug] 'host -t a' still printed out AAAA and MX records. + [RT #13230] + +1790. [cleanup] Move lib/dns/sec/dst up into lib/dns. This should + allow parallel make to succeed. + +1789. [bug] Prerequisite test for tkey and dnssec could fail + with "configure --with-libtool". + +1788. [bug] libbind9.la/libbind9.so needs to link against + libisccfg.la/libisccfg.so. + +1787. [port] HPUX: both "cc" and "gcc" need -Wl,+vnocompatwarnings. + +1786. [port] AIX: libt_api needs to be taught to look for + T_testlist in the main executable (--with-libtool). + [RT #13239] + +1785. [bug] libbind9.la/libbind9.so needs to link against + libisc.la/libisc.so. + +1784. [cleanup] "libtool -allow-undefined" is the default. + Leave hooks in configure to allow it to be set + if needed in the future. + +1783. [cleanup] We only need one copy of libtool.m4, ltmain.sh in the + source tree. + +1782. [port] OSX: --with-libtool + --enable-libbind broke on + __evOptMonoTime. [RT #13219] + +1781. [port] FreeBSD 5.3: set PTHREAD_SCOPE_SYSTEM. [RT #12810] + +1780. [bug] Update libtool to 1.5.10. + +1779. [port] OSF 5.1: libtool didn't handle -pthread correctly. + +1778. [port] HUX 11.11: fix broken IN6ADDR_ANY_INIT and + IN6ADDR_LOOPBACK_INIT macros. + +1777. [port] OSF 5.1: fix broken IN6ADDR_ANY_INIT and + IN6ADDR_LOOPBACK_INIT macros. + +1776. [port] Solaris 2.9: fix broken IN6ADDR_ANY_INIT and + IN6ADDR_LOOPBACK_INIT macros. + +1775. [bug] Only compile getnetent_r.c when threaded. [RT #13205] + +1774. [port] Aix: Silence compiler warnings / build failures. + [RT #13154] + +1773. [bug] Fast retry on host / net unreachable. [RT #13153] + +1772. [placeholder] + +1771. [placeholder] + +1770. [bug] named-checkconf failed to report missing a missing + file clause for rbt{64} master/hint zones. [RT #13009] + +1769. [port] win32: change compiler flags /MTd ==> /MDd, + /MT ==> /MD. + +1768. [bug] nsecnoexistnodata() could be called with a non-NSEC + rdataset. [RT #12907] + +1767. [port] Builds on IPv6 platforms without IPv6 Advanced API + support for (struct in6_pktinfo) failed. [RT #13077] + +1766. [bug] Update the master file timestamp on successful refresh + as well as the journal's timestamp. [RT #13062] + +1765. [bug] configure --with-openssl=auto failed. [RT #12937] + +1764. [bug] dns_zone_replacedb failed to emit a error message + if there was no SOA record in the replacement db. + [RT #13016] + +1763. [func] Perform sanity checks on NS records which refer to + 'in zone' names. [RT #13002] + +1762. [bug] isc_interfaceiter_create() could return ISC_R_SUCCESS + even when it failed. [RT #12995] + +1761. [bug] 'rndc dumpdb' didn't report unassociated entries. + [RT #12971] + +1760. [bug] Host / net unreachable was not penalising rtt + estimates. [RT #12970] + +1759. [bug] Named failed to startup if the OS supported IPv6 + but had no IPv6 interfaces configured. [RT #12942] + +1758. [func] Don't send notify messages to self. [RT #12933] + +1757. [func] host now can turn on memory debugging flags with '-m'. + +1756. [func] named-checkconf now checks the logging configuration. + [RT #12352] + +1755. [func] allow-update is now settable at the options / view + level. [RT #6636] + +1754. [bug] We weren't always attempting to query the parent + server for the DS records at the zone cut. + [RT #12774] + +1753. [bug] Don't serve a slave zone which has no NS records. + [RT #12894] + +1752. [port] Move isc_app_start() to after ns_os_daemonise() + as some fork() implementations unblock the signals + that are blocked by isc_app_start(). [RT #12810] + +1751. [bug] --enable-getifaddrs failed under linux. [RT #12867] + +1750. [port] lib/bind/make/rules.in:subdirs was not bash friendly. + [RT #12864] + +1749. [bug] 'check-names response ignore;' failed to ignore. + [RT #12866] + +1748. [func] dig now returns the byte count for axfr/ixfr. + +1747. [bug] BIND 8 compatibility: named/named-checkconf failed + to parse "host-statistics-max" in named.conf. + +1746. [func] Make public the function to read a key file, + dst_key_read_public(). [RT #12450] + +1745. [bug] Dig/host/nslookup accept replies from link locals + regardless of scope if no scope was specified when + query was sent. [RT #12745] + +1744. [bug] If tuple2msgname() failed to convert a tuple to + a name a REQUIRE could be triggered. [RT #12796] + +1743. [bug] If isc_taskmgr_create() was not able to create the + requested number of worker threads then destruction + of the manager would trigger an INSIST() failure. + [RT #12790] + +1742. [bug] Deleting all records at a node then adding a + previously existing record, in a single UPDATE + transaction, failed to leave / regenerate the + associated RRSIG records. [RT #12788] + +1741. [bug] Deleting all records at a node in a secure zone + using a update-policy grant failed. [RT #12787] + +1740. [bug] Replace rbt's hash algorithm as it performed badly + with certain zones. [RT #12729] + + NOTE: a hash context now needs to be established + via isc_hash_create() if the application was not + already doing this. + +1739. [bug] dns_rbt_deletetree() could incorrectly return + ISC_R_QUOTA. [RT #12695] + +1738. [bug] Enable overrun checking by default. [RT #12695] + +1737. [bug] named failed if more than 16 masters were specified. + [RT #12627] + +1736. [bug] dst_key_fromnamedfile() could fail to read a + public key. [RT #12687] + +1735. [bug] 'dig +sigtrace' could die with a REQUIRE failure. + [RE #12688] + +1734. [cleanup] 'rndc-confgen -a -t' remove extra '/' in path. + [RT #12588] + +1733. [bug] Return non-zero exit status on initial load failure. + [RT #12658] + +1732. [bug] 'rrset-order name "*"' wasn't being applied to ".". + [RT #12467] + +1731. [port] darwin: relax version test in ifconfig.sh. + [RT #12581] + +1730. [port] Determine the length type used by the socket API. + [RT #12581] + +1729. [func] Improve check-names error messages. + +1728. [doc] Update check-names documentation. + +1727. [bug] named-checkzone: check-names support didn't match + documentation. + +1726. [port] aix5: add support for aix5. + +1725. [port] linux: update error message on interaction of threads, + capabilities and setuid support (named -u). [RT #12541] + +1724. [bug] Look for DNSKEY records with "dig +sigtrace". + [RT #12557] + +1723. [cleanup] Silence compiler warnings from t_tasks.c. [RT #12493] + +1722. [bug] Don't commit the journal on malformed ixfr streams. + [RT #12519] + +1721. [bug] Error message from the journal processing were not + always identifying the relevant journal. [RT #12519] + +1720. [bug] 'dig +chase' did not terminate on a RFC 2308 Type 1 + negative response. [RT #12506] + +1719. [bug] named was not correctly caching a RFC 2308 Type 1 + negative response. [RT #12506] + +1718. [bug] nsupdate was not handling RFC 2308 Type 3 negative + responses when looking for the zone / master server. + [RT #12506] + +1717. [port] solaris: ifconfig.sh did not support Solaris 10. + "ifconfig.sh down" didn't work for Solaris 9. + +1716. [doc] named.conf(5) was being installed in the wrong + location. [RT #12441] + +1715. [func] 'dig +trace' now randomly selects the next servers + to try. Report if there is a bad delegation. + +1714. [bug] dig/host/nslookup were only trying the first + address when a nameserver was specified by name. + [RT #12286] + +1713. [port] linux: extend capset failure message to say: + please ensure that the capset kernel module is + loaded. see insmod(8) + +1712. [bug] Missing FULLCHECK for "trusted-key" in dig. + +1711. [func] 'rndc unfreeze' has been deprecated by 'rndc thaw'. + +1710. [func] 'rndc notify zone [class [view]]' resend the NOTIFY + messages for the specified zone. [RT #9479] + +1709. [port] solaris: add SMF support from Sun. + +1708. [cleanup] Replaced dns_fullname_hash() with dns_name_fullhash() + for conformance to the name space convention. Binary + backward compatibility to the old function name is + provided. [RT #12376] + +1707. [contrib] sdb/ldap updated to version 1.0-beta. + +1706. [bug] 'rndc stop' failed to cause zones to be flushed + sometimes. [RT #12328] + +1705. [func] Allow the journal's name to be changed via named.conf. + +1704. [port] lwres needed a snprintf() implementation for + platforms without snprintf(). Add missing + "#include ". [RT #12321] + +1703. [bug] named would loop sending NOTIFY messages when it + failed to receive a response. [RT #12322] + +1702. [bug] also-notify should not be applied to built in zones. + [RT #12323] + +1701. [doc] A minimal named.conf man page. + +1700. [func] nslookup is no longer to be treated as deprecated. + Remove "deprecated" warning message. Add man page. + +1699. [bug] dnssec-signzone can generate "not exact" errors + when resigning. [RT #12281] + +1698. [doc] Use reserved IPv6 documentation prefix. + +1697. [bug] xxx-source{,-v6} was not effective when it + specified one of listening addresses and a + different port than the listening port. [RT #12257] + +1696. [bug] dnssec-signzone failed to clean out nodes that + consisted of only NSEC and RRSIG records. + [RT #12154] + +1695. [bug] DS records when forwarding require special handling. + [RT #12133] + +1694. [bug] Report if the builtin views of "_default" / "_bind" + are defined in named.conf. [RT #12023] + +1693. [bug] max-journal-size was not effective for master zones + with ixfr-from-differences set. [RT #12024] + +1692. [bug] Don't set -I, -L and -R flags when libcrypto is in + /usr/lib. [RT #11971] + +1691. [bug] sdb's attachversion was not complete. [RT #11990] + +1690. [bug] Delay detaching view from the client until UPDATE + processing completes when shutting down. [RT #11714] + +1689. [bug] DNS_NAME_TOREGION() and DNS_NAME_SPLIT() macros + contained gratuitous semicolons. [RT #11707] + +1688. [bug] LDFLAGS was not supported. + +1687. [bug] Race condition in dispatch. [RT #10272] + +1686. [bug] Named sent a extraneous NOTIFY when it received a + redundant UPDATE request. [RT #11943] + +1685. [bug] Change #1679 loop tests weren't quite right. + +1684. [func] ixfr-from-differences now takes master and slave in + addition to yes and no at the options and view levels. + +1683. [bug] dig +sigchase could leak memory. [RT #11445] + +1682. [port] Update configure test for (long long) printf format. + [RT #5066] + +1681. [bug] Only set SO_REUSEADDR when a port is specified in + isc_socket_bind(). [RT #11742] + +1680. [func] rndc: the source address can now be specified. + +1679. [bug] When there was a single nameserver with multiple + addresses for a zone not all addresses were tried. + [RT #11706] + +1678. [bug] RRSIG should use TYPEXXXXX for unknown types. + +1677. [bug] dig: +aaonly didn't work, +aaflag undocumented. + +1676. [func] New option "allow-query-cache". This lets + allow-query be used to specify the default zone + access level rather than having to have every + zone override the global value. allow-query-cache + can be set at both the options and view levels. + If allow-query-cache is not set allow-query applies. + +1675. [bug] named would sometimes add extra NSEC records to + the authority section. + +1674. [port] linux: increase buffer size used to scan + /proc/net/if_inet6. + +1673. [port] linux: issue a error messages if IPv6 interface + scans fails. + +1672. [cleanup] Tests which only function in a threaded build + now return R:THREADONLY (rather than R:UNTESTED) + in a non-threaded build. + +1671. [contrib] queryperf: add NAPTR to the list of known types. + +1670. [func] Log UPDATE requests to slave zones without an acl as + "disabled" at debug level 3. [RT #11657] + +1669. [placeholder] + +1668. [bug] DIG_SIGCHASE was making bin/dig/host dump core. + +1667. [port] linux: not all versions have IF_NAMESIZE. + +1666. [bug] The optional port on hostnames in dual-stack-servers + was being ignored. + +1665. [func] rndc now allows addresses to be set in the + server clauses. + +1664. [bug] nsupdate needed KEY for SIG(0), not DNSKEY. + +1663. [func] Look for OpenSSL by default. + +1662. [bug] Change #1658 failed to change one use of 'type' + to 'keytype'. + +1661. [bug] Restore dns_name_concatenate() call in + adb.c:set_target(). [RT #11582] + +1660. [bug] win32: connection_reset_fix() was being called + unconditionally. [RT #11595] + +1659. [cleanup] Cleanup some messages that were referring to KEY vs + DNSKEY, NXT vs NSEC and SIG vs RRSIG. + +1658. [func] Update dnssec-keygen to default to KEY for HMAC-MD5 + and DH. Tighten which options apply to KEY and + DNSKEY records. + +1657. [doc] ARM: document query log output. + +1656. [doc] Update DNSSEC description in ARM to cover DS, NSEC + DNSKEY and RRSIG. [RT #11542] + +1655. [bug] Logging multiple versions w/o a size was broken. + [RT #11446] + +1654. [bug] isc_result_totext() contained array bounds read + error. + +1653. [func] Add key type checking to dst_key_fromfilename(), + DST_TYPE_KEY should be used to read TSIG, TKEY and + SIG(0) keys. + +1652. [bug] TKEY still uses KEY. + +1651. [bug] dig: process multiple dash options. + +1650. [bug] dig, nslookup: flush standard out after each command. + +1649. [bug] Silence "unexpected non-minimal diff" message. + [RT #11206] + +1648. [func] Update dnssec-lookaside named.conf syntax to support + multiple dnssec-lookaside namespaces (not yet + implemented). + +1647. [bug] It was possible trigger a INSIST when chasing a DS + record that required walking back over a empty node. + [RT #11445] + +1646. [bug] win32: logging file versions didn't work with + non-UNC filenames. [RT #11486] + +1645. [bug] named could trigger a REQUIRE failure if multiple + masters with keys are specified. + +1644. [bug] Update the journal modification time after a + successful refresh query. [RT #11436] + +1643. [bug] dns_db_closeversion() could leak memory / node + references. [RT #11163] + +1642. [port] Support OpenSSL implementations which don't have + DSA support. [RT #11360] + +1641. [bug] Update the check-names description in ARM. [RT #11389] + +1640. [bug] win32: isc_socket_cancel(ISC_SOCKCANCEL_ACCEPT) was + incorrectly closing the socket. [RT #11291] + +1639. [func] Initial dlv system test. + +1638. [bug] "ixfr-from-differences" could generate a REQUIRE + failure if the journal open failed. [RT #11347] + +1637. [bug] Node reference leak on error in addnoqname(). + +1636. [bug] The dump done callback could get ISC_R_SUCCESS even if + a error had occurred. The database version no longer + matched the version of the database that was dumped. + +1635. [bug] Memory leak on error in query_addds(). + +1634. [bug] named didn't supply a useful error message when it + detected duplicate views. [RT #11208] + +1633. [bug] named should return NOTIMP to update requests to a + slaves without a allow-update-forwarding acl specified. + [RT #11331] + +1632. [bug] nsupdate failed to send prerequisite only UPDATE + messages. [RT #11288] + +1631. [bug] dns_journal_compact() could sometimes corrupt the + journal. [RT #11124] + +1630. [contrib] queryperf: add support for IPv6 transport. + +1629. [func] dig now supports IPv6 scoped addresses with the + extended format in the local-server part. [RT #8753] + +1628. [bug] Typo in Compaq Trucluster support. [RT #11264] + +1627. [bug] win32: sockets were not being closed when the + last external reference was removed. [RT #11179] + +1626. [bug] --enable-getifaddrs was broken. [RT #11259] + +1625. [bug] named failed to load/transfer RFC2535 signed zones + which contained CNAMES. [RT #11237] + +1624. [bug] zonemgr_putio() call should be locked. [RT #11163] + +1623. [bug] A serial number of zero was being displayed in the + "sending notifies" log message when also-notify was + used. [RT #11177] + +1622. [func] probe the system to see if IPV6_(RECV)PKTINFO is + available, and suppress wildcard binding if not. + +1621. [bug] match-destinations did not work for IPv6 TCP queries. + [RT #11156] + +1620. [func] When loading a zone report if it is signed. [RT #11149] + +1619. [bug] Missing ISC_LIST_UNLINK in end_reserved_dispatches(). + [RT #11118] + +1618. [bug] Fencepost errors in dns_name_ishostname() and + dns_name_ismailbox() could trigger a INSIST(). + +1617. [port] win32: VC++ 6.0 support. + +1616. [compat] Ensure that named's version is visible in the core + dump. [RT #11127] + +1615. [port] Define ISC_SOCKADDR_LEN_T based on _BSD_SOCKLEN_T_ if + it is defined. + +1614. [port] win32: silence resource limit messages. [RT #11101] + +1613. [bug] Builds would fail on machines w/o a if_nametoindex(). + Missing #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX/#endif. + [RT #11119] + +1612. [bug] check-names at the option/view level could trigger + an INSIST. [RT #11116] + +1611. [bug] solaris: IPv6 interface scanning failed to cope with + no active IPv6 interfaces. + +1610. [bug] On dual stack machines "dig -b" failed to set the + address type to be looked up with "@server". + [RT #11069] + +1609. [func] dig now has support to chase DNSSEC signature chains. + Requires -DDIG_SIGCHASE=1 to be set in STD_CDEFINES. + + DNSSEC validation code in dig coded by Olivier Courtay + (olivier.courtay@irisa.fr) for the IDsA project + (http://idsa.irisa.fr). + +1608. [func] dig and host now accept -4/-6 to select IP transport + to use when making queries. + +1607. [bug] dig, host and nslookup were still using random() + to generate query ids. [RT #11013] + +1606. [bug] DLV insecurity proof was failing. + +1605. [func] New dns_db_find() option DNS_DBFIND_COVERINGNSEC. + +1604. [bug] A xfrout_ctx_create() failure would result in + xfrout_ctx_destroy() being called with a + partially initialized structure. + +1603. [bug] nsupdate: set interactive based on isatty(). + [RT #10929] + +1602. [bug] Logging to a file failed unless a size was specified. + [RT #10925] + +1601. [bug] Silence spurious warning 'both "recursion no;" and + "allow-recursion" active' warning from view "_bind". + [RT #10920] + +1600. [bug] Duplicate zone pre-load checks were not case + insensitive. + +1599. [bug] Fix memory leak on error path when checking named.conf. + +1598. [func] Specify that certain parts of the namespace must + be secure (dnssec-must-be-secure). + +1597. [func] Allow notify-source and query-source to be specified + on a per server basis similar to transfer-source. + [RT #6496] + +1596. [func] Accept 'notify-source' style syntax for query-source. + +1595. [func] New notify type 'master-only'. Enable notify for + master zones only. + +1594. [bug] 'rndc dumpdb' could prevent named from answering + queries while the dump was in progress. [RT #10565] + +1593. [bug] rndc should return "unknown command" to unknown + commands. [RT #10642] + +1592. [bug] configure_view() could leak a dispatch. [RT #10675] + +1591. [bug] libbind: updated to BIND 8.4.5. + +1590. [port] netbsd: update thread support. + +1589. [func] DNSSEC lookaside validation. + +1588. [bug] win32: TCP sockets could become blocked. [RT #10115] + +1587. [bug] dns_message_settsigkey() failed to clear existing key. + [RT #10590] + +1586. [func] "check-names" is now implemented. + +1585. [placeholder] + +1584. [bug] "make test" failed with a read only source tree. + [RT #10461] + +1583. [bug] Records add via UPDATE failed to get the correct trust + level. [RT #10452] + +1582. [bug] rrset-order failed to work on RRsets with more + than 32 elements. [RT #10381] + +1581. [func] Disable DNSSEC support by default. To enable + DNSSEC specify "dnssec-enable yes;" in named.conf. + +1580. [bug] Zone destruction on final detach takes a long time. + [RT #3746] + +1579. [bug] Multiple task managers could not be created. + +1578. [bug] Don't use CLASS E IPv4 addresses when resolving. + [RT #10346] + +1577. [bug] Use isc_uint32_t in ultrasparc optimizer bug + workaround code. [RT #10331] + +1576. [bug] Race condition in dns_dispatch_addresponse(). + [RT #10272] + +1575. [func] Log TSIG name on TSIG verify failure. [RT #4404] + +1574. [bug] Don't attempt to open the controls socket(s) when + running tests. [RT #9091] + +1573. [port] linux: update to libtool 1.5.2 so that + "make install DESTDIR=/xx" works with + "configure --with-libtool". [RT #9941] + +1572. [bug] nsupdate: sign the soa query to find the enclosing + zone if the server is specified. [RT #10148] + +1571. [bug] rbt:hash_node() could fail leaving the hash table + in an inconsistent state. [RT #10208] + +1570. [bug] nsupdate failed to handle classes other than IN. + New keyword 'class' which sets the default class. + [RT #10202] + +1569. [func] nsupdate new command 'answer' which displays the + complete answer message to the last update. + +1568. [bug] nsupdate now reports that the update failed in + interactive mode. [RT #10236] + +1567. [maint] B.ROOT-SERVERS.NET is now 192.228.79.201. + +1566. [port] Support for the cmsg framework on Solaris and HP/UX. + This also solved the problem that match-destinations + for IPv6 addresses did not work on these systems. + [RT #10221] + +1565. [bug] CD flag should be copied to outgoing queries unless + the query is under a secure entry point in which case + CD should be set. + +1564. [func] Attempt to provide a fallback entropy source to be + used if named is running chrooted and named is unable + to open entropy source within the chroot area. + [RT #10133] + +1563. [bug] Gracefully fail when unable to obtain neither an IPv4 + nor an IPv6 dispatch. [RT #10230] + +1562. [bug] isc_socket_create() and isc_socket_accept() could + leak memory under error conditions. [RT #10230] + +1561. [bug] It was possible to release the same name twice if + named ran out of memory. [RT #10197] + +1560. [port] FreeBSD: work around FreeBSD 5.2 mapping EAI_NODATA + and EAI_NONAME to the same value. + +1559. [port] named should ignore SIGFSZ. + +1558. [func] New DNSSEC 'disable-algorithms'. Support entry into + child zones for which we don't have a supported + algorithm. Such child zones are treated as unsigned. + +1557. [func] Implement missing DNSSEC tests for + * NOQNAME proof with wildcard answers. + * NOWILDARD proof with NXDOMAIN. + Cache and return NOQNAME with wildcard answers. + +1556. [bug] nsupdate now treats all names as fully qualified. + [RT #6427] + +1555. [func] 'rrset-order cyclic' no longer has a random starting + point per query. [RT #7572] + +1554. [bug] dig, host, nslookup failed when no nameservers + were specified in /etc/resolv.conf. [RT #8232] + +1553. [bug] The windows socket code could stop accepting + connections. [RT #10115] + +1552. [bug] Accept NOTIFY requests from mapped masters if + matched-mapped is set. [RT #10049] + +1551. [port] Open "/dev/null" before calling chroot(). + +1550. [port] Call tzset(), if available, before calling chroot(). + +1549. [func] named-checkzone can now write out the zone contents + in a easily parsable format (-D and -o). + +1548. [bug] When parsing APL records it was possible to silently + accept out of range ADDRESSFAMILY values. [RT #9979] + +1547. [bug] Named wasted memory recording duplicate lame zone + entries. [RT #9341] + +1546. [bug] We were rejecting valid secure CNAME to negative + answers. + +1545. [bug] It was possible to leak memory if named was unable to + bind to the specified transfer source and TSIG was + being used. [RT #10120] + +1544. [bug] Named would logged a single entry to a file despite it + being over the specified size limit. + +1543. [bug] Logging using "versions unlimited" did not work. + +1542. [placeholder] + +1541. [func] NSEC now uses new bitmap format. + +1540. [bug] "rndc reload " was silently accepted. + [RT #8934] + +1539. [bug] Open UDP sockets for notify-source and transfer-source + that use reserved ports at startup. [RT #9475] + +1538. [placeholder] rt9997 + +1537. [func] New option "querylog". If set specify whether query + logging is to be enabled or disabled at startup. + +1536. [bug] Windows socket code failed to log a error description + when returning ISC_R_UNEXPECTED. [RT #9998] + +1535. [placeholder] + +1534. [bug] Race condition when priming cache. [RT #9940] + +1533. [func] Warn if both "recursion no;" and "allow-recursion" + are active. [RT #4389] + +1532. [port] netbsd: the configure test for + requires . + +1531. [port] AIX more libtool fixes. + +1530. [bug] It was possible to trigger a INSIST() failure if a + slave master file was removed at just the correct + moment. [RT #9462] + +1529. [bug] "notify explicit;" failed to log that NOTIFY messages + were being sent for the zone. [RT #9442] + +1528. [cleanup] Simplify some dns_name_ functions based on the + deprecation of bitstring labels. + +1527. [cleanup] Reduce the number of gettimeofday() calls without + losing necessary timer granularity. + +1526. [func] Implemented "additional section caching (or acache)", + an internal cache framework for additional section + content to improve response performance. Several + configuration options were provided to control the + behavior. + +1525. [bug] dns_cache_create() could trigger a REQUIRE + failure in isc_mem_put() during error cleanup. + [RT #9360] + +1524. [port] AIX needs to be able to resolve all symbols when + creating shared libraries (--with-libtool). + +1523. [bug] Fix race condition in rbtdb. [RT #9189] + +1522. [bug] dns_db_findnode() relax the requirements on 'name'. + [RT #9286] + +1521. [bug] dns_view_createresolver() failed to check the + result from isc_mem_create(). [RT #9294] + +1520. [protocol] Add SSHFP (SSH Finger Print) type. + +1519. [bug] dnssec-signzone:nsec_setbit() computed the wrong + length of the new bitmap. + +1518. [bug] dns_nsec_buildrdata(), and hence dns_nsec_build(), + contained a off-by-one error when working out the + number of octets in the bitmap. + +1517. [port] Support for IPv6 interface scanning on HP/UX and + TrueUNIX 5.1. + +1516. [func] Roll the DNSSEC types to RRSIG, NSEC and DNSKEY. + +1515. [func] Allow transfer source to be set in a server statement. + [RT #6496] + +1514. [bug] named: isc_hash_destroy() was being called too early. + [RT #9160] + +1513. [doc] Add "US" to root-delegation-only exclude list. + +1512. [bug] Extend the delegation-only logging to return query + type, class and responding nameserver. + +1511. [bug] delegation-only was generating false positives + on negative answers from sub-zones. + +1510. [func] New view option "root-delegation-only". Apply + delegation-only check to all TLDs and root. + Note there are some TLDs that are NOT delegation + only (e.g. DE, LV, US and MUSEUM) these can be excluded + from the checks by using exclude. + + root-delegation-only exclude { + "DE"; "LV"; "US"; "MUSEUM"; + }; + +1509. [bug] Hint zones should accept delegation-only. Forward + zone should not accept delegation-only. + +1508. [bug] Don't apply delegation-only checks to answers from + forwarders. + +1507. [bug] Handle BIND 8 style returns to NS queries to parents + when making delegation-only checks. + +1506. [bug] Wrong return type for dns_view_isdelegationonly(). + +1505. [bug] Uninitialized rdataset in sdb. [RT #8750] + +1504. [func] New zone type "delegation-only". + +1503. [port] win32: install libeay32.dll outside of system32. + +1502. [bug] nsupdate: adjust timeouts for UPDATE requests over TCP. + +1501. [func] Allow TCP queue length to be specified via + named.conf, tcp-listen-queue. + +1500. [bug] host failed to lookup MX records. Also look up + AAAA records. + +1499. [bug] isc_random need to be seeded better if arc4random() + is not used. + +1498. [port] bsdos: 5.x support. + +1497. [placeholder] + +1496. [port] test for pthread_attr_setstacksize(). + +1495. [cleanup] Replace hash functions with universal hash. + +1494. [security] Turn on RSA BLINDING as a precaution. + +1493. [placeholder] + +1492. [cleanup] Preserve rwlock quota context when upgrading / + downgrading. [RT #5599] + +1491. [bug] dns_master_dump*() would produce extraneous $ORIGIN + lines. [RT #6206] + +1490. [bug] Accept reading state as well as working state in + ns_client_next(). [RT #6813] + +1489. [compat] Treat 'allow-update' on slave zones as a warning. + [RT #3469] + +1488. [bug] Don't override trust levels for glue addresses. + [RT #5764] + +1487. [bug] A REQUIRE() failure could be triggered if a zone was + queued for transfer and the zone was then removed. + [RT #6189] + +1486. [bug] isc_print_snprintf() '%%' consumed one too many format + characters. [RT #8230] + +1485. [bug] gen failed to handle high type values. [RT #6225] + +1484. [bug] The number of records reported after a AXFR was wrong. + [RT #6229] + +1483. [bug] dig axfr failed if the message id in the answer failed + to match that in the request. Only the id in the first + message is required to match. [RT #8138] + +1482. [bug] named could fail to start if the kernel supports + IPv6 but no interfaces are configured. Similarly + for IPv4. [RT #6229] + +1481. [bug] Refresh and stub queries failed to use masters keys + if specified. [RT #7391] + +1480. [bug] Provide replay protection for rndc commands. Full + replay protection requires both rndc and named to + be updated. Partial replay protection (limited + exposure after restart) is provided if just named + is updated. + +1479. [bug] cfg_create_tuple() failed to handle out of + memory cleanup. parse_list() would leak memory + on syntax errors. + +1478. [port] ifconfig.sh didn't account for other virtual + interfaces. It now takes a optional argument + to specify the first interface number. [RT #3907] + +1477. [bug] memory leak using stub zones and TSIG. + +1476. [placeholder] + +1475. [port] Probe for old sprintf(). + +1474. [port] Provide strtoul() and memmove() for platforms + without them. + +1473. [bug] create_map() and create_string() failed to handle out + of memory cleanup. [RT #6813] + +1472. [contrib] idnkit-1.0 from JPNIC, replaces mdnkit. + +1471. [bug] libbind: updated to BIND 8.4.0. + +1470. [bug] Incorrect length passed to snprintf. [RT #5966] + +1469. [func] Log end of outgoing zone transfer at same level + as the start of transfer is logged. [RT #4441] + +1468. [func] Internal zones are no longer counted for + 'rndc status'. [RT #4706] + +1467. [func] $GENERATES now supports optional class and ttl. + +1466. [bug] lwresd configuration errors resulted in memory + and lock leaks. [RT #5228] + +1465. [bug] isc_base64_decodestring() and isc_base64_tobuffer() + failed to check that trailing bits were zero allowing + some invalid base64 strings to be accepted. [RT #5397] + +1464. [bug] Preserve "out of zone" data for outgoing zone + transfers. [RT #5192] + +1463. [bug] dns_rdata_from{wire,struct}() failed to catch bad + NXT bit maps. [RT #5577] + +1462. [bug] parse_sizeval() failed to check the token type. + [RT #5586] + +1461. [bug] Remove deadlock from rbtdb code. [RT #5599] + +1460. [bug] inet_pton() failed to reject certain malformed + IPv6 literals. + +1459. [placeholder] + +1458. [cleanup] sprintf() -> snprintf(). + +1457. [port] Provide strlcat() and strlcpy() for platforms without + them. + +1456. [contrib] gen-data-queryperf.py from Stephane Bortzmeyer. + +1455. [bug] missing from server grammar in + doc/misc/options. [RT #5616] + +1454. [port] Use getifaddrs() if available for interface scanning. + --disable-getifaddrs to override. Glibc currently + has a getifaddrs() that does not support IPv6. + Use --enable-getifaddrs=glibc to force the use of + this version under linux machines. + +1453. [doc] ARM: $GENERATE example wasn't accurate. [RT #5298] + +1452. [placeholder] + +1451. [bug] rndc-confgen didn't exit with a error code for all + failures. [RT #5209] + +1450. [bug] Fetching expired glue failed under certain + circumstances. [RT #5124] + +1449. [bug] query_addbestns() didn't handle running out of memory + gracefully. + +1448. [bug] Handle empty wildcards labels. + +1447. [bug] We were casting (unsigned int) to and from (void *). + rdataset->private4 is now rdataset->privateuint4 + to reflect a type change. + +1446. [func] Implemented undocumented alternate transfer sources + from BIND 8. See use-alt-transfer-source, + alt-transfer-source and alt-transfer-source-v6. + + SECURITY: use-alt-transfer-source is ENABLED unless + you are using views. This may cause a security risk + resulting in accidental disclosure of wrong zone + content if the master supplying different source + content based on IP address. If you are not certain + ISC recommends setting use-alt-transfer-source no; + +1445. [bug] DNS_ADBFIND_STARTATROOT broke stub zones. This has + been replaced with DNS_ADBFIND_STARTATZONE which + causes the search to start using the closest zone. + +1444. [func] dns_view_findzonecut2() allows you to specify if the + cache should be searched for zone cuts. + +1443. [func] Masters lists can now be specified and referenced + in zone masters clauses and other masters lists. + +1442. [func] New functions for manipulating port lists: + dns_portlist_create(), dns_portlist_add(), + dns_portlist_remove(), dns_portlist_match(), + dns_portlist_attach() and dns_portlist_detach(). + +1441. [func] It is now possible to tell dig to bind to a specific + source port. + +1440. [func] It is now possible to tell named to avoid using + certain source ports (avoid-v4-udp-ports, + avoid-v6-udp-ports). + +1439. [bug] Named could return NOERROR with certain NOTIFY + failures. Return NOTAUTH if the NOTIFY zone is + not being served. + +1438. [func] Log TSIG (if any) when logging NOTIFY requests. + +1437. [bug] Leave space for stdio to work in. [RT #5033] + +1436. [func] dns_zonemgr_resumexfrs() can be used to restart + stalled transfers. + +1435. [bug] zmgr_resume_xfrs() was being called read locked + rather than write locked. zmgr_resume_xfrs() + was not being called if the zone was being + shutdown. + +1434. [bug] "rndc reconfig" failed to initiate the initial + zone transfer of new slave zones. + +1433. [bug] named could trigger a REQUIRE failure if it could + not get a file descriptor when attempting to write + a master file. [RT #4347] + +1432. [func] The advertised EDNS UDP buffer size can now be set + via named.conf (edns-udp-size). + +1431. [bug] isc_print_snprintf() "%s" with precision could walk off + end of argument. [RT #5191] + +1430. [port] linux: IPv6 interface scanning support. + +1429. [bug] Prevent the cache getting locked to old servers. + +1428. [placeholder] + +1427. [bug] Race condition in adb with threaded build. + +1426. [placeholder] + +1425. [port] linux/libbind: define __USE_MISC when testing *_r() + function prototypes in netdb.h. [RT #4921] + +1424. [bug] EDNS version not being correctly printed. + +1423. [contrib] queryperf: added A6 and SRV. + +1422. [func] Log name/type/class when denying a query. [RT #4663] + +1421. [func] Differentiate updates that don't succeed due to + prerequisites (unsuccessful) vs other reasons + (failed). + +1420. [port] solaris: work around gcc optimizer bug. + +1419. [port] openbsd: use /dev/arandom. [RT #4950] + +1418. [bug] 'rndc reconfig' did not cause new slaves to load. + +1417. [func] ID.SERVER/CHAOS is now a built in zone. + See "server-id" for how to configure. + +1416. [bug] Empty node should return NOERROR NODATA, not NXDOMAIN. + [RT #4715] + +1415. [func] DS TTL now derived from NS ttl. NXT TTL now derived + from SOA MINIMUM. + +1414. [func] Support for KSK flag. + +1413. [func] Explicitly request the (re-)generation of DS records + from keysets (dnssec-signzone -g). + +1412. [func] You can now specify servers to be tried if a nameserver + has IPv6 address and you only support IPv4 or the + reverse. See dual-stack-servers. + +1411. [bug] empty nodes should stop wildcard matches. [RT #4802] + +1410. [func] Handle records that live in the parent zone, e.g. DS. + +1409. [bug] DS should have attribute DNS_RDATATYPEATTR_DNSSEC. + +1408. [bug] "make distclean" was not complete. [RT #4700] + +1407. [bug] lfsr incorrectly implements the shift register. + [RT #4617] + +1406. [bug] dispatch initializes one of the LFSR's with a incorrect + polynomial. [RT #4617] + +1405. [func] Use arc4random() if available. + +1404. [bug] libbind: ns_name_ntol() could overwrite a zero length + buffer. + +1403. [func] dnssec-signzone, dnssec-keygen, dnssec-makekeyset + dnssec-signkey now report their version in the + usage message. + +1402. [cleanup] A6 has been moved to experimental and is no longer + fully supported. + +1401. [bug] adb wasn't clearing state when the timer expired. + +1400. [bug] Block the addition of wildcard NS records by IXFR + or UPDATE. [RT #3502] + +1399. [bug] Use serial number arithmetic when testing SIG + timestamps. [RT #4268] + +1398. [doc] ARM: notify-also should have been also-notify. + [RT #4345] + +1397. [maint] J.ROOT-SERVERS.NET is now 192.58.128.30. + +1396. [func] dnssec-signzone: adjust the default signing time by + 1 hour to allow for clock skew. + +1395. [port] OpenSSL 0.9.7 defines CRYPTO_LOCK_ENGINE but doesn't + have a working implementation. [RT #4079] + +1394. [func] It is now possible to check if a particular element is + in a acl. Remove duplicate entries from the localnets + acl. + +1393. [port] Bind to individual IPv6 interfaces if IPV6_IPV6ONLY + is not available in the kernel to prevent accidentally + listening on IPv4 interfaces. + +1392. [bug] named-checkzone: update usage. + +1391. [func] Add support for IPv6 scoped addresses in named. + +1390. [func] host now supports ixfr. + +1389. [bug] named could fail to rotate long log files. [RT #3666] + +1388. [port] irix: check for sys/sysctl.h and NET_RT_IFLIST before + defining HAVE_IFLIST_SYSCTL. [RT #3770] + +1387. [bug] named could crash due to an access to invalid memory + space (which caused an assertion failure) in + incremental cleaning. [RT #3588] + +1386. [bug] named-checkzone -z stopped on errors in a zone. + [RT #3653] + +1385. [bug] Setting serial-query-rate to 10 would trigger a + REQUIRE failure. + +1384. [bug] host was incompatible with BIND 8 in its exit code and + in the output with the -l option. [RT #3536] + +1383. [func] Track the serial number in a IXFR response and log if + a mismatch occurs. This is a more specific error than + "not exact". [RT #3445] + +1382. [bug] make install failed with --enable-libbind. [RT #3656] + +1381. [bug] named failed to correctly process answers that + contained DNAME records where the resulting CNAME + resulted in a negative answer. + +1380. [func] 'rndc recursing' dump recursing queries to + 'recursing-file = "named.recursing";'. + +1379. [func] 'rndc status' now reports tcp and recursion quota + states. + +1378. [func] Improved positive feedback for 'rndc {reload|refresh}. + +1377. [func] dns_zone_load{new}() now reports if the zone was + loaded, queued for loading to up to date. + +1376. [func] New function dns_zone_logc() to log to specified + category. + +1375. [func] 'rndc dumpdb' now dumps the adb cache along with the + data cache. + +1374. [func] dns_adb_dump() now logs the lame zones associated + with each server. + +1373. [bug] Recovery from expired glue failed under certain + circumstances. + +1372. [bug] named crashes with an assertion failure on exit when + sharing the same port for listening and querying, and + changing listening addresses several times. [RT #3509] + +1371. [bug] notify-source-v6, transfer-source-v6 and + query-source-v6 with explicit addresses and using the + same ports as named was listening on could interfere + with named's ability to answer queries sent to those + addresses. + +1370. [bug] dig '+[no]recurse' was incorrectly documented. + +1369. [bug] Adding an NS record as the lexicographically last + record in a secure zone didn't work. + +1368. [func] remove support for bitstring labels. + +1367. [func] Use response times to select forwarders. + +1366. [contrib] queryperf usage was incomplete. Add '-h' for help. + +1365. [func] "localhost" and "localnets" acls now include IPv6 + addresses / prefixes. + +1364. [func] Log file name when unable to open memory statistics + and dump database files. [RT #3437] + +1363. [func] Listen-on-v6 now supports specific addresses. + +1362. [bug] remove IFF_RUNNING test when scanning interfaces. + +1361. [func] log the reason for rejecting a server when resolving + queries. + +1360. [bug] --enable-libbind would fail when not built in the + source tree for certain OS's. + +1359. [security] Support patches OpenSSL libraries. + http://www.cert.org/advisories/CA-2002-23.html + +1358. [bug] It was possible to trigger a INSIST when debugging + large dynamic updates. [RT #3390] + +1357. [bug] nsupdate was extremely wasteful of memory. + +1356. [tuning] Reduce the number of events / quantum for zone tasks. + +1355. [bug] Fix DNSSEC wildcard proof for CNAME/DNAME. + +1354. [doc] lwres man pages had illegal nroff. + +1353. [contrib] sdb/ldap to version 0.9. + +1352. [bug] dig, host, nslookup when falling back to TCP use the + current search entry (if any). [RT #3374] + +1351. [bug] lwres_getipnodebyname() returned the wrong name + when given a IPv4 literal, af=AF_INET6 and AI_MAPPED + was set. + +1350. [bug] dns_name_fromtext() failed to handle too many labels + gracefully. + +1349. [security] Minimum OpenSSL version now 0.9.6e (was 0.9.5a). + http://www.cert.org/advisories/CA-2002-23.html + +1348. [port] win32: Rewrote code to use I/O Completion Ports + in socket.c and eliminating a host of socket + errors. Performance is enhanced. + +1347. [placeholder] + +1346. [placeholder] + +1345. [port] Use a explicit -Wformat with gcc. Not all versions + include it in -Wall. + +1344. [func] Log if the serial number on the master has gone + backwards. + If you have multiple machines specified in the masters + clause you may want to set 'multi-master yes;' to + suppress this warning. + +1343. [func] Log successful notifies received (info). Adjust log + level for failed notifies to notice. + +1342. [func] Log remote address with TCP dispatch failures. + +1341. [func] Allow a rate limiter to be stalled. + +1340. [bug] Delay and spread out the startup refresh load. + +1339. [func] dig, host and nslookup now use IP6.ARPA for nibble + lookups. Bit string lookups are no longer attempted. + +1338. [placeholder] + +1337. [placeholder] + +1336. [func] Nibble lookups under IP6.ARPA are now supported by + dns_byaddr_create(). dns_byaddr_createptrname() is + deprecated, use dns_byaddr_createptrname2() instead. + +1335. [bug] When performing a nonexistence proof, the validator + should discard parent NXTs from higher in the DNS. + +1334. [bug] When signing/verifying rdatasets, duplicate rdatas + need to be suppressed. + +1333. [contrib] queryperf now reports a summary of returned + rcodes (-c), rcodes are printed in mnemonic form (-v). + +1332. [func] Report the current serial with periodic commits when + rolling forward the journal. + +1331. [func] Generate DNSSEC wildcard proofs. + +1330. [bug] When processing events (non-threaded) only allow + the task one chance to use to use its quantum. + +1329. [func] named-checkzone will now check if nameservers that + appear to be IP addresses. Available modes "fail", + "warn" (default) and "ignore" the results of the + check. + +1328. [bug] The validator could incorrectly verify an invalid + negative proof. + +1327. [bug] The validator would incorrectly mark data as insecure + when seeing a bogus signature before a correct + signature. + +1326. [bug] DNAME/CNAME signatures were not being cached when + validation was not being performed. [RT #3284] + +1325. [bug] If the tcpquota was exhausted it was possible to + to trigger a INSIST() failure. + +1324. [port] darwin: ifconfig.sh now supports darwin. + +1323. [port] linux: Slackware 4.0 needs . [RT #3205] + +1322. [bug] dnssec-signzone usage message was misleading. + +1321. [bug] If the last RRset in a zone is glue, dnssec-signzone + would incorrectly duplicate its output and sign it. + +1320. [doc] query-source-v6 was missing from options section. + [RT #3218] + +1319. [func] libbind: log attempts to exploit #1318. + +1318. [bug] libbind: Remote buffer overrun. + +1317. [port] libbind: TrueUNIX 5.1 does not like __align as a + element name. + +1316. [bug] libbind: gethostans() could get out of sync parsing + the response if there was a very long CNAME chain. + +1315. [bug] Options should apply to the internal _bind view. + +1314. [port] Handle ECONNRESET from sendmsg() [unix]. + +1313. [func] Query log now says if the query was signed (S) or + if EDNS was used (E). + +1312. [func] Log TSIG key used w/ outgoing zone transfers. + +1311. [bug] lwres_getrrsetbyname leaked memory. [RT #3159] + +1310. [bug] 'rndc stop' failed to cause zones to be flushed + sometimes. [RT #3157] + +1309. [func] Log that a zone transfer was covered by a TSIG. + +1308. [func] DS (delegation signer) support. + +1307. [bug] nsupdate: allow white space base64 key data. + +1306. [bug] Badly encoded LOC record when the size, horizontal + precision or vertical precision was 0.1m. + +1305. [bug] Document that internal zones are included in the + rndc status results. + +1304. [func] New function: dns_zone_name(). + +1303. [func] Option 'flush-zones-on-shutdown ;'. + +1302. [func] Extended rndc dumpdb to support dumping of zones and + view selection: 'dumpdb [-all|-zones|-cache] [view]'. + +1301. [func] New category 'update-security'. + +1300. [port] Compaq Trucluster support. + +1299. [bug] Set AI_ADDRCONFIG when looking up addresses + via getaddrinfo() (affects dig, host, nslookup, rndc + and nsupdate). + +1298. [bug] The CINCLUDES macro in lib/dns/sec/dst/Makefile + could be left with a trailing "\" after configure + has been run. + +1297. [port] linux: make handling EINVAL from socket() no longer + conditional on #ifdef LINUX. + +1296. [bug] isc_log_closefilelogs() needed to lock the log + context. + +1295. [bug] isc_log_setdebuglevel() needed to lock the log + context. + +1294. [func] libbind: no longer attempts bit string labels for + IPv6 reverse resolution. Try IP6.ARPA then IP6.INT + for nibble style resolution. + +1293. [func] Entropy can now be retrieved from EGDs. [RT #2438] + +1292. [func] Enable IPv6 support when using ioctl style interface + scanning and OS supports SIOCGLIFADDR using struct + if_laddrreq. + +1291. [func] Enable IPv6 support when using sysctl style interface + scanning. + +1290. [func] "dig axfr" now reports the number of messages + as well as the number of records. + +1289. [port] See if -ldl is required for OpenSSL? [RT #2672] + +1288. [bug] Adjusted REQUIRE's in lib/dns/name.c to better + reflect written requirements. + +1287. [bug] REQUIRE that DNS_DBADD_MERGE only be set when adding + a rdataset to a zone db in the rbtdb implementation of + addrdataset. + +1286. [bug] dns_name_downcase() enforce requirement that + target != NULL or name->buffer != NULL. + +1285. [func] lwres: probe the system to see what address families + are currently in use. + +1284. [bug] The RTT estimate on unused servers was not aged. + [RT #2569] + +1283. [func] Use "dataready" accept filter if available. + +1282. [port] libbind: hpux 11.11 interface scanning. + +1281. [func] Log zone when unable to get private keys to update + zone. Log zone when NXT records are missing from + secure zone. + +1280. [bug] libbind: escape '(' and ')' when converting to + presentation form. + +1279. [port] Darwin uses (unsigned long) for size_t. [RT #2590] + +1278. [func] dig: now supports +[no]cl +[no]ttlid. + +1277. [func] You can now create your own customized printing + styles: dns_master_stylecreate() and + dns_master_styledestroy(). + +1276. [bug] libbind: const pointer conflicts in res_debug.c. + +1275. [port] libbind: hpux: treat all hpux systems as BIG_ENDIAN. + +1274. [bug] Memory leak in lwres_gnbarequest_parse(). + +1273. [port] libbind: solaris: 64 bit binary compatibility. + +1272. [contrib] Berkeley DB 4.0 sdb implementation from + Nuno Miguel Rodrigues . + +1271. [bug] "recursion available: {denied,approved}" was too + confusing. + +1270. [bug] Check that system inet_pton() and inet_ntop() support + AF_INET6. + +1269. [port] Openserver: ifconfig.sh support. + +1268. [port] Openserver: the value FD_SETSIZE depends on whether + is included or not. Be consistent. + +1267. [func] isc_file_openunique() now creates file using mode + 0666 rather than 0600. + +1266. [bug] ISC_LINK_INIT, ISC_LINK_UNLINK, ISC_LIST_DEQUEUE, + __ISC_LINK_UNLINKUNSAFE and __ISC_LIST_DEQUEUEUNSAFE + are not C++ compatible, use *_TYPE versions instead. + +1265. [bug] libbind: LINK_INIT and UNLINK were not compatible with + C++, use LINK_INIT_TYPE and UNLINK_TYPE instead. + +1264. [placeholder] + +1263. [bug] Reference after free error if dns_dispatchmgr_create() + failed. + +1262. [bug] ns_server_destroy() failed to set *serverp to NULL. + +1261. [func] libbind: ns_sign2() and ns_sign_tcp() now provide + support for compressed TSIG owner names. + +1260. [func] libbind: res_update can now update IPv6 servers, + new function res_findzonecut2(). + +1259. [bug] libbind: get_salen() IPv6 support was broken for OSs + w/o sa_len. + +1258. [bug] libbind: res_nametotype() and res_nametoclass() were + broken. + +1257. [bug] Failure to write pid-file should not be fatal on + reload. [RT #2861] + +1256. [contrib] 'queryperf' now has EDNS (-e) + DNSSEC DO (-D) support. + +1255. [bug] When verifying that an NXT proves nonexistence, check + the rcode of the message and only do the matching NXT + check. That is, for NXDOMAIN responses, check that + the name is in the range between the NXT owner and + next name, and for NOERROR NODATA responses, check + that the type is not present in the NXT bitmap. + +1254. [func] preferred-glue option from BIND 8.3. + +1253. [bug] The dnssec system test failed to remove the correct + files. + +1252. [bug] Dig, host and nslookup were not checking the address + the answer was coming from against the address it was + sent to. [RT #2692] + +1251. [port] win32: a make file contained absolute version specific + references. + +1250. [func] Nsupdate will report the address the update was + sent to. + +1249. [bug] Missing masters clause was not handled gracefully. + [RT #2703] + +1248. [bug] DESTDIR was not being propagated between makes. + +1247. [bug] Don't reset the interface index for link/site local + addresses. [RT #2576] + +1246. [func] New functions isc_sockaddr_issitelocal(), + isc_sockaddr_islinklocal(), isc_netaddr_issitelocal() + and isc_netaddr_islinklocal(). + +1245. [bug] Treat ENOBUFS, ENOMEM and ENFILE as soft errors for + accept(). + +1244. [bug] Receiving a TCP message from a blackhole address would + prevent further messages being received over that + interface. + +1243. [bug] It was possible to trigger a REQUIRE() in + dns_message_findtype(). [RT #2659] + +1242. [bug] named-checkzone failed if a journal existed. [RT #2657] + +1241. [bug] Drop received UDP messages with a zero source port + as these are invariably forged. [RT #2621] + +1240. [bug] It was possible to leak zone references by + specifying an incorrect zone to rndc. + +1239. [bug] Under certain circumstances named could continue to + use a name after it had been freed triggering + INSIST() failures. [RT #2614] + +1238. [bug] It is possible to lockup the server when shutting down + if notifies were being processed. [RT #2591] + +1237. [bug] nslookup: "set q=type" failed. + +1236. [bug] dns_rdata{class,type}_fromtext() didn't handle non + NULL terminated text regions. [RT #2588] + +1235. [func] Report 'out of memory' errors from openssl. + +1234. [bug] contrib/sdb: 'zonetodb' failed to call + dns_result_register(). DNS_R_SEENINCLUDE should not + be fatal. + +1233. [bug] The flags field of a KEY record can be expressed in + hex as well as decimal. + +1232. [bug] unix/errno2result() didn't handle EADDRNOTAVAIL. + +1231. [port] HPUX 11.11 recvmsg() can return spurious EADDRNOTAVAIL. + +1230. [bug] isccc_cc_isreply() and isccc_cc_isack() were broken. + +1229. [bug] named would crash if it received a TSIG signed + query as part of an AXFR response. [RT #2570] + +1228. [bug] 'make install' did not depend on 'make all'. [RT #2559] + +1227. [bug] dns_lex_getmastertoken() now returns ISC_R_BADNUMBER + if a number was expected and some other token was + found. [RT #2532] + +1226. [func] Use EDNS for zone refresh queries. [RT #2551] + +1225. [func] dns_message_setopt() no longer requires that + dns_message_renderbegin() to have been called. + +1224. [bug] 'rrset-order' and 'sortlist' should be additive + not exclusive. + +1223. [func] 'rrset-order' partially works 'cyclic' and 'random' + are supported. + +1222. [bug] Specifying 'port *' did not always result in a system + selected (non-reserved) port being used. [RT #2537] + +1221. [bug] Zone types 'master', 'slave' and 'stub' were not being + compared case insensitively. [RT #2542] + +1220. [func] Support for APL rdata type. + +1219. [func] Named now reports the TSIG extended error code when + signature verification fails. [RT #1651] + +1218. [bug] Named incorrectly returned SERVFAIL rather than + NOTAUTH when there was a TSIG BADTIME error. [RT #2519] + +1217. [func] Report locations of previous key definition when a + duplicate is detected. + +1216. [bug] Multiple server clauses for the same server were not + reported. [RT #2514] + +1215. [port] solaris: add support to ifconfig.sh for x86 2.5.1 + +1214. [bug] Win32: isc_file_renameunique() could leave zero length + files behind. + +1213. [func] Report view associated with client if it is not a + standard view (_default or _bind). + +1212. [port] libbind: 64k answer buffers were causing stack space + to be exceeded for certain OS. Use heap space instead. + +1211. [bug] dns_name_fromtext() incorrectly handled certain + valid octal bitlabels. [RT #2483] + +1210. [bug] libbind: getnameinfo() failed to lookup IPv4 mapped / + compatible addresses. [RT #2461] + +1209. [bug] Dig, host, nslookup were not checking the message ids + on the responses. [RT #2454] + +1208. [bug] dns_master_load*() failed to log a error message if + an error was detected when parsing the owner name of + a record. [RT #2448] + +1207. [bug] libbind: getaddrinfo() could call freeaddrinfo() with + an invalid pointer. + +1206. [bug] SERVFAIL and NOTIMP responses to an EDNS query should + trigger a non-EDNS retry. + +1205. [bug] OPT, TSIG and TKEY cannot be used to set the "class" + of the message. [RT #2449] + +1204. [bug] libbind: res_nupdate() failed to update the name + server addresses before sending the update. + +1203. [func] Report locations of previous acl and zone definitions + when a duplicate is detected. + +1202. [func] New functions: cfg_obj_line() and cfg_obj_file(). + +1201. [bug] Require that if 'callbacks' is passed to + dns_rdata_fromtext(), callbacks->error and + callbacks->warn are initialized. + +1200. [bug] Log 'errno' that we are unable to convert to + isc_result_t. [RT #2404] + +1199. [doc] ARM reference to RFC 2157 should have been RFC 1918. + [RT #2436] + +1198. [bug] OPT printing style was not consistent with the way the + header fields are printed. The DO bit was not reported + if set. Report if any of the MBZ bits are set. + +1197. [bug] Attempts to define the same acl multiple times were not + detected. + +1196. [contrib] update mdnkit to 2.2.3. + +1195. [bug] Attempts to redefine builtin acls should be caught. + [RT #2403] + +1194. [bug] Not all duplicate zone definitions were being detected + at the named.conf checking stage. [RT #2431] + +1193. [bug] dig +besteffort parsing didn't handle packet + truncation. dns_message_parse() has new flag + DNS_MESSAGE_IGNORETRUNCATION. + +1192. [bug] The seconds fields in LOC records were restricted + to three decimal places. More decimal places should + be allowed but warned about. + +1191. [bug] A dynamic update removing the last non-apex name in + a secure zone would fail. [RT #2399] + +1190. [func] Add the "rndc freeze" and "rndc unfreeze" commands. + [RT #2394] + +1189. [bug] On some systems, malloc(0) returns NULL, which + could cause the caller to report an out of memory + error. [RT #2398] + +1188. [bug] Dynamic updates of a signed zone would fail if + some of the zone private keys were unavailable. + +1187. [bug] named was incorrectly returning DNSSEC records + in negative responses when the DO bit was not set. + +1186. [bug] isc_hex_tobuffer(,,length = 0) failed to unget the + EOL token when reading to end of line. + +1185. [bug] libbind: don't assume statp->_u._ext.ext is valid + unless RES_INIT is set when calling res_*init(). + +1184. [bug] libbind: call res_ndestroy() if RES_INIT is set + when res_*init() is called. + +1183. [bug] Handle ENOSR error when writing to the internal + control pipe. [RT #2395] + +1182. [bug] The server could throw an assertion failure when + constructing a negative response packet. + +1181. [func] Add the "key-directory" configuration statement, + which allows the server to look for online signing + keys in alternate directories. + +1180. [func] dnssec-keygen should always generate keys with + protocol 3 (DNSSEC), since it's less confusing + that way. + +1179. [func] Add SIG(0) support to nsupdate. + +1178. [bug] Follow and cache (if appropriate) A6 and other + data chains to completion in the additional section. + +1177. [func] Report view when loading zones if it is not a + standard view (_default or _bind). [RT #2270] + +1176. [doc] Document that allow-v6-synthesis is only performed + for clients that are supplied recursive service. + [RT #2260] + +1175. [bug] named-checkzone and named-checkconf failed to call + dns_result_register() at startup which could + result in runtime exceptions when printing + "out of memory" errors. [RT #2335] + +1174. [bug] Win32: add WSAECONNRESET to the expected errors + from connect(). [RT #2308] + +1173. [bug] Potential memory leaks in isc_log_create() and + isc_log_settag(). [RT #2336] + +1172. [doc] Add CERT, GPOS, KX, NAPTR, NSAP, PX and TXT to + table of RR types in ARM. + +1171. [func] Added function isc_region_compare(), updated files in + lib/dns to use this function instead of local one. + +1170. [bug] Don't attempt to print the token when a I/O error + occurs when parsing named.conf. [RT #2275] + +1169. [func] Identify recursive queries in the query log. + +1168. [bug] Empty also-notify clauses were not handled. [RT #2309] + +1167. [contrib] nslint-2.1a3 (from author). + +1166. [bug] "Not Implemented" should be reported as NOTIMP, + not NOTIMPL. [RT #2281] + +1165. [bug] We were rejecting notify-source{-v6} in zone clauses. + +1164. [bug] Empty masters clauses in slave / stub zones were not + handled gracefully. [RT #2262] + +1163. [func] isc_time_formattimestamp() now includes the year. + +1162. [bug] The allow-notify option was not accepted in slave + zone statements. + +1161. [bug] named-checkzone looped on unbalanced brackets. + [RT #2248] + +1160. [bug] Generating Diffie-Hellman keys longer than 1024 + bits could fail. [RT #2241] + +1159. [bug] MD and MF are not permitted to be loaded by RFC1123. + +1158. [func] Report the client's address when logging notify + messages. + +1157. [func] match-clients and match-destinations now accept + keys. [RT #2045] + +1156. [port] The configure test for strsep() incorrectly + succeeded on certain patched versions of + AIX 4.3.3. [RT #2190] + +1155. [func] Recover from master files being removed from under + us. + +1154. [bug] Don't attempt to obtain the netmask of a interface + if there is no address configured. [RT #2176] + +1153. [func] 'rndc {stop|halt} -p' now reports the process id + of the instance of named being shutdown. + +1152. [bug] libbind: read buffer overflows. + +1151. [bug] nslookup failed to check that the arguments to + the port, timeout, and retry options were + valid integers and in range. [RT #2099] + +1150. [bug] named incorrectly accepted TTL values + containing plus or minus signs, such as + 1d+1h-1s. + +1149. [func] New function isc_parse_uint32(). + +1148. [func] 'rndc-confgen -a' now provides positive feedback. + +1147. [func] Set IPV6_V6ONLY on IPv6 sockets if supported by + the OS. listen-on-v6 { any; }; should no longer + result in IPv4 queries be accepted. Similarly + control { inet :: ... }; should no longer result + in IPv4 connections being accepted. This can be + overridden at compile time by defining + ISC_ALLOW_MAPPED=1. + +1146. [func] Allow IPV6_IPV6ONLY to be set/cleared on a socket if + supported by the OS by a new function + isc_socket_ipv6only(). + +1145. [func] "host" no longer reports a NOERROR/NODATA response + by printing nothing. [RT #2065] + +1144. [bug] rndc-confgen would crash if both the -a and -t + options were specified. [RT #2159] + +1143. [bug] When a trusted-keys statement was present and named + was built without crypto support, it would leak memory. + +1142. [bug] dnssec-signzone would fail to delete temporary files + in some failure cases. [RT #2144] + +1141. [bug] When named rejected a control message, it would + leak a file descriptor and memory. It would also + fail to respond, causing rndc to hang. + [RT #2139, #2164] + +1140. [bug] rndc-confgen did not accept IPv6 addresses as arguments + to the -s option. [RT #2138] + +1139. [func] It is now possible to flush a given name from the + cache(s) via 'rndc flushname name [view]'. [RT #2051] + +1138. [func] It is now possible to flush a given name from the + cache by calling the new function + dns_cache_flushname(). + +1137. [func] It is now possible to flush a given name from the + ADB by calling the new function dns_adb_flushname(). + +1136. [bug] CNAME records synthesized from DNAMEs did not + have a TTL of zero as required by RFC2672. + [RT #2129] + +1135. [func] You can now override the default syslog() facility for + named/lwresd at compile time. [RT #1982] + +1134. [bug] Multi-threaded servers could deadlock in ferror() + when reloading zone files. [RT #1951, #1998] + +1133. [bug] IN6_IS_ADDR_LOOPBACK was not portably defined on + platforms without IN6_IS_ADDR_LOOPBACK. [RT #2106] + +1132. [func] Improve UPDATE prerequisite failure diagnostic messages. + +1131. [bug] The match-destinations view option did not work with + IPv6 destinations. [RT #2073, #2074] + +1130. [bug] Log messages reporting an out-of-range serial number + did not include the out-of-range number but the + following token. [RT #2076] + +1129. [bug] Multi-threaded servers could crash under heavy + resolution load due to a race condition. [RT #2018] + +1128. [func] sdb drivers can now provide RR data in either text + or wire format, the latter using the new functions + dns_sdb_putrdata() and dns_sdb_putnamedrdata(). + +1127. [func] rndc: If the server to contact has multiple addresses, + try all of them. + +1126. [bug] The server could access a freed event if shut + down while a client start event was pending + delivery. [RT #2061] + +1125. [bug] rndc: -k option was missing from usage message. + [RT #2057] + +1124. [doc] dig: +[no]dnssec, +[no]besteffort and +[no]fail + are now documented. [RT #2052] + +1123. [bug] dig +[no]fail did not match description. [RT #2052] + +1122. [tuning] Resolution timeout reduced from 90 to 30 seconds. + [RT #2046] + +1121. [bug] The server could attempt to access a NULL zone + table if shut down while resolving. + [RT #1587, #2054] + +1120. [bug] Errors in options were not fatal. [RT #2002] + +1119. [func] Added support in Win32 for NTFS file/directory ACL's + for access control. + +1118. [bug] On multi-threaded servers, a race condition + could cause an assertion failure in resolver.c + during resolver shutdown. [RT #2029] + +1117. [port] The configure check for in6addr_loopback incorrectly + succeeded on AIX 4.3 when compiling with -O2 + because the test code was optimized away. + [RT #2016] + +1116. [bug] Setting transfers in a server clause, transfers-in, + or transfers-per-ns to a value greater than + 2147483647 disabled transfers. [RT #2002] + +1115. [func] Set maximum values for cleaning-interval, + heartbeat-interval, interface-interval, + max-transfer-idle-in, max-transfer-idle-out, + max-transfer-time-in, max-transfer-time-out, + statistics-interval of 28 days and + sig-validity-interval of 3660 days. [RT #2002] + +1114. [port] Ignore more accept() errors. [RT #2021] + +1113. [bug] The allow-update-forwarding option was ignored + when specified in a view. [RT #2014] + +1112. [placeholder] + +1111. [bug] Multi-threaded servers could deadlock processing + recursive queries due to a locking hierarchy + violation in adb.c. [RT #2017] + +1110. [bug] dig should only accept valid abbreviations of +options. + [RT #2003] + +1109. [bug] nsupdate accepted illegal ttl values. + +1108. [bug] On Win32, rndc was hanging when named was not running + due to failure to select for exceptional conditions + in select(). [RT #1870] + +1107. [bug] nsupdate could catch an assertion failure if an + invalid domain name was given as the argument to + the "zone" command. + +1106. [bug] After seeing an out of range TTL, nsupdate would + treat all TTLs as out of range. [RT #2001] + +1105. [port] OpenUNIX 8 enable threads by default. [RT #1970] + +1104. [bug] Invalid arguments to the transfer-format option + could cause an assertion failure. [RT #1995] + +1103. [port] OpenUNIX 8 support (ifconfig.sh). [RT #1970] + +1102. [doc] Note that query logging is enabled by directing the + queries category to a channel. + +1101. [bug] Array bounds read error in lwres_gai_strerror. + +1100. [bug] libbind: DNSSEC key ids were computed incorrectly. + +1099. [cleanup] libbind: defining REPORT_ERRORS in lib/bind/dst caused + compile time errors. + +1098. [bug] libbind: HMAC-MD5 key files are now mode 0600. + +1097. [func] libbind: RES_PRF_TRUNC for dig. + +1096. [func] libbind: "DNSSEC OK" (DO) support. + +1095. [func] libbind: resolver option: no-tld-query. disables + trying unqualified as a tld. no_tld_query is also + supported for FreeBSD compatibility. + +1094. [func] libbind: add support gcc's format string checking. + +1093. [doc] libbind: miscellaneous nroff fixes. + +1092. [bug] libbind: get*by*() failed to check if res_init() had + been called. + +1091. [bug] libbind: misplaced va_end(). + +1090. [bug] libbind: dns_ho.c:add_hostent() was not returning + the amount of memory consumed resulting in garbage + address being returned. Alignment calculations were + wasting space. We weren't suppressing duplicate + addresses. + +1089. [func] libbind: inet_{cidr,net}_{pton,ntop}() now have IPv6 + support. + +1088. [port] libbind: MPE/iX C.70 (incomplete) + +1087. [bug] libbind: struct __res_state too large on 64 bit arch. + +1086. [port] libbind: sunos: old sprintf. + +1085. [port] libbind: solaris: sys_nerr and sys_errlist do not + exist when compiling in 64 bit mode. + +1084. [cleanup] libbind: gai_strerror() rewritten. + +1083. [bug] The default control channel listened on the + wildcard address, not the loopback as documented. + [RT #1975] + +1082. [bug] The -g option to named incorrectly caused logging + to be sent to syslog in addition to stderr. + [RT #1974] + +1081. [bug] Multicast queries were incorrectly identified + based on the source address, not the destination + address. + +1080. [bug] BIND 8 compatibility: accept bare IP prefixes + as the second element of a two-element top level + sort list statement. [RT #1964] + +1079. [bug] BIND 8 compatibility: accept bare elements at top + level of sort list treating them as if they were + a single element list. [RT #1963] + +1078. [bug] We failed to correct bad tv_usec values in one case. + [RT #1966] + +1077. [func] Do not accept further recursive clients when + the total number of recursive lookups being + processed exceeds max-recursive-clients, even + if some of the lookups are internally generated. + [RT #1915, #1938] + +1076. [bug] A badly defined global key could trigger an assertion + on load/reload if views were used. [RT #1947] + +1075. [bug] Out-of-range network prefix lengths were not + reported. [RT #1954] + +1074. [bug] Running out of memory in dump_rdataset() could + cause an assertion failure. [RT #1946] + +1073. [bug] The ADB cache cleaning should also be space driven. + [RT #1915, #1938] + +1072. [bug] The TCP client quota could be exceeded when + recursion occurred. [RT #1937] + +1071. [bug] Sockets listening for TCP DNS connections + specified an excessive listen backlog. [RT #1937] + +1070. [bug] Copy DNSSEC OK (DO) to response as specified by + draft-ietf-dnsext-dnssec-okbit-03.txt. + +1069. [placeholder] + +1068. [bug] errno could be overwritten by catgets(). [RT #1921] + +1067. [func] Allow quotas to be soft, isc_quota_soft(). + +1066. [bug] Provide a thread safe wrapper for strerror(). + [RT #1689] + +1065. [func] Runtime support to select new / old style interface + scanning using ioctls. + +1064. [bug] Do not shut down active network interfaces if we + are unable to scan the interface list. [RT #1921] + +1063. [bug] libbind: "make install" was failing on IRIX. + [RT #1919] + +1062. [bug] If the control channel listener socket was shut + down before server exit, the listener object could + be freed twice. [RT #1916] + +1061. [bug] If periodic cache cleaning happened to start + while cleaning due to reaching the configured + maximum cache size was in progress, the server + could catch an assertion failure. [RT #1912] + +1060. [func] Move refresh, stub and notify UDP retry processing + into dns_request. + +1059. [func] dns_request now support will now retry UDP queries, + dns_request_createvia2() and dns_request_createraw2(). + +1058. [func] Limited lifetime ticker timers are now available, + isc_timertype_limited. + +1057. [bug] Reloading the server after adding a "file" clause + to a zone statement could cause the server to + crash due to a typo in change 1016. + +1056. [bug] Rndc could catch an assertion failure on SIGINT due + to an uninitialized variable. [RT #1908] + +1055. [func] Version and hostname queries can now be disabled + using "version none;" and "hostname none;", + respectively. + +1054. [bug] On Win32, cfg_categories and cfg_modules need to be + exported from the libisccfg DLL. + +1053. [bug] Dig did not increase its timeout when receiving + AXFRs unless the +time option was used. [RT #1904] + +1052. [bug] Journals were not being created in binary mode + resulting in "journal format not recognized" error + under Win32. [RT #1889] + +1051. [bug] Do not ignore a network interface completely just + because it has a noncontiguous netmask. Instead, + omit it from the localnets ACL and issue a warning. + [RT #1891] + +1050. [bug] Log messages reporting malformed IP addresses in + address lists such as that of the forwarders option + failed to include the correct error code, file + name, and line number. [RT #1890] + +1049. [func] "pid-file none;" will disable writing a pid file. + [RT #1848] + +1048. [bug] Servers built with -DISC_MEM_USE_INTERNAL_MALLOC=1 + didn't work. + +1047. [bug] named was incorrectly refusing all requests signed + with a TSIG key derived from an unsigned TKEY + negotiation with a NOERROR response. [RT #1886] + +1046. [bug] The help message for the --with-openssl configure + option was inaccurate. [RT #1880] + +1045. [bug] It was possible to skip saving glue for a nameserver + for a stub zone. + +1044. [bug] Specifying allow-transfer, notify-source, or + notify-source-v6 in a stub zone was not treated + as an error. + +1043. [bug] Specifying a transfer-source or transfer-source-v6 + option in the zone statement for a master zone was + not treated as an error. [RT #1876] + +1042. [bug] The "config" logging category did not work properly. + [RT #1873] + +1041. [bug] Dig/host/nslookup could catch an assertion failure + on SIGINT due to an uninitialized variable. [RT #1867] + +1040. [bug] Multiple listen-on-v6 options with different ports + were not accepted. [RT #1875] + +1039. [bug] Negative responses with CNAMEs in the answer section + were cached incorrectly. [RT #1862] + +1038. [bug] In servers configured with a tkey-domain option, + TKEY queries with an owner name other than the root + could cause an assertion failure. [RT #1866, #1869] + +1037. [bug] Negative responses whose authority section contain + SOA or NS records whose owner names are not equal + equal to or parents of the query name should be + rejected. [RT #1862] + +1036. [func] Silently drop requests received via multicast as + long as there is no final multicast DNS standard. + +1035. [bug] If we respond to multicast queries (which we + currently do not), respond from a unicast address + as specified in RFC 1123. [RT #137] + +1034. [bug] Ignore the RD bit on multicast queries as specified + in RFC 1123. [RT #137] + +1033. [bug] Always respond to requests with an unsupported opcode + with NOTIMP, even if we don't have a matching view + or cannot determine the class. + +1032. [func] hostname.bind/txt/chaos now returns the name of + the machine hosting the nameserver. This is useful + in diagnosing problems with anycast servers. + +1031. [bug] libbind.a: isc__gettimeofday() infinite recursion. + [RT #1858] + +1030. [bug] On systems with no resolv.conf file, nsupdate + exited with an error rather than defaulting + to using the loopback address. [RT #1836] + +1029. [bug] Some named.conf errors did not cause the loading + of the configuration file to return a failure + status even though they were logged. [RT #1847] + +1028. [bug] On Win32, dig/host/nslookup looked for resolv.conf + in the wrong directory. [RT #1833] + +1027. [bug] RRs having the reserved type 0 should be rejected. + [RT #1471] + +1026. [placeholder] + +1025. [bug] Don't use multicast addresses to resolve iterative + queries. [RT #101] + +1024. [port] Compilation failed on HP-UX 11.11 due to + incompatible use of the SIOCGLIFCONF macro + name. [RT #1831] + +1023. [func] Accept hints without TTLs. + +1022. [bug] Don't report empty root hints as "extra data". + [RT #1802] + +1021. [bug] On Win32, log message timestamps were one month + later than they should have been, and the server + would exhibit unspecified behavior in December. + +1020. [bug] IXFR log messages did not distinguish between + true IXFRs, AXFR-style IXFRs, and mere version + polls. [RT #1811] + +1019. [bug] The value of the lame-ttl option was limited to 18000 + seconds, not 1800 seconds as documented. [RT #1803] + +1018. [bug] The default log channel was not always initialized + correctly. [RT #1813] + +1017. [bug] When specifying TSIG keys to dig and nsupdate using + the -k option, they must be HMAC-MD5 keys. [RT #1810] + +1016. [bug] Slave zones with no backup file were re-transferred + on every server reload. + +1015. [bug] Log channels that had a "versions" option but no + "size" option failed to create numbered log + files. [RT #1783] + +1014. [bug] Some queries would cause statistics counters to + increment more than once or not at all. [RT #1321] + +1013. [bug] It was possible to cancel a query twice when marking + a server as bogus or by having a blackhole acl. + [RT #1776] + +1012. [bug] The -p option to named did not behave as documented. + +1011. [cleanup] Removed isc_dir_current(). + +1010. [bug] The server could attempt to execute a command channel + command after initiating server shutdown, causing + an assertion failure. [RT #1766] + +1009. [port] OpenUNIX 8 support. [RT #1728] + +1008. [port] libtool.m4, ltmain.sh from libtool-1.4.2. + +1007. [port] config.guess, config.sub from autoconf-2.52. + +1006. [bug] If a KEY RR was found missing during DNSSEC validation, + an assertion failure could subsequently be triggered + in the resolver. [RT #1763] + +1005. [bug] Don't copy nonzero RCODEs from request to response. + [RT #1765] + +1004. [port] Deal with recvfrom() returning EHOSTDOWN. [RT #1770] + +1003. [func] Add the +retry option to dig. + +1002. [bug] When reporting an unknown class name in named.conf, + including the file name and line number. [RT #1759] + +1001. [bug] win32 socket code doio_recv was not catching a + WSACONNRESET error when a client was timing out + the request and closing its socket. [RT #1745] + +1000. [bug] BIND 8 compatibility: accept "HESIOD" as an alias + for class "HS". [RT #1759] + + 999. [func] "rndc retransfer zone [class [view]]" added. + [RT #1752] + + 998. [func] named-checkzone now has arguments to specify the + chroot directory (-t) and working directory (-w). + [RT #1755] + + 997. [func] Add support for RSA-SHA1 keys (RFC3110). + + 996. [func] Issue warning if the configuration filename contains + the chroot path. + + 995. [bug] dig, host, nslookup: using a raw IPv6 address as a + target address should be fatal on a IPv4 only system. + + 994. [func] Treat non-authoritative responses to queries for type + NS as referrals even if the NS records are in the + answer section, because BIND 8 servers incorrectly + send them that way. This is necessary for DNSSEC + validation of the NS records of a secure zone to + succeed when the parent is a BIND 8 server. [RT #1706] + + 993. [func] dig: -v now reports the version. + + 992. [doc] dig: ~/.digrc is now documented. + + 991. [func] Lower UDP refresh timeout messages to level + debug 1. + + 990. [bug] The rndc-confgen man page was not installed. + + 989. [bug] Report filename if $INCLUDE fails for file related + errors. [RT #1736] + + 988. [bug] 'additional-from-auth no;' did not work reliably + in the case of queries answered from the cache. + [RT #1436] + + 987. [bug] "dig -help" didn't show "+[no]stats". + + 986. [bug] "dig +noall" failed to clear stats and command + printing. + + 985. [func] Consider network interfaces to be up iff they have + a nonzero IP address rather than based on the + IFF_UP flag. [RT #1160] + + 984. [bug] Multi-threading should be enabled by default on + Solaris 2.7 and newer, but it wasn't. + + 983. [func] The server now supports generating IXFR difference + sequences for non-dynamic zones by comparing zone + versions, when enabled using the new config + option "ixfr-from-differences". [RT #1727] + + 982. [func] If "memstatistics-file" is set in options the memory + statistics will be written to it. + + 981. [func] The dnssec tools can now take multiple '-r randomfile' + arguments. + + 980. [bug] Incoming zone transfers restarting after an error + could trigger an assertion failure. [RT #1692] + + 979. [func] Incremental master file dumping. dns_master_dumpinc(), + dns_master_dumptostreaminc(), dns_dumpctx_attach(), + dns_dumpctx_detach(), dns_dumpctx_cancel(), + dns_dumpctx_db() and dns_dumpctx_version(). + + 978. [bug] dns_db_attachversion() had an invalid REQUIRE() + condition. + + 977. [bug] Improve "not at top of zone" error message. + + 976. [func] named-checkconf can now test load master zones + (named-checkconf -z). [RT #1468] + + 975. [bug] "max-cache-size default;" as a view option + caused an assertion failure. + + 974. [bug] "max-cache-size unlimited;" as a global option + was not accepted. + + 973. [bug] Failed to log the question name when logging: + "bad zone transfer request: non-authoritative zone + (NOTAUTH)". + + 972. [bug] The file modification time code in zone.c was using the + wrong epoch. [RT #1667] + + 971. [placeholder] + + 970. [func] 'max-journal-size' can now be used to set a target + size for a journal. + + 969. [func] dig now supports the undocumented dig 8 feature + of allowing arbitrary labels, not just dotted + decimal quads, with the -x option. This can be + used to conveniently look up RFC2317 names as in + "dig -x 10.0.0.0-127". [RT #827, #1576, #1598] + + 968. [bug] On win32, the isc_time_now() function was unnecessarily + calling strtime(). [RT #1671] + + 967. [bug] On win32, the link for bindevt was not including the + required resource file to enable the event viewer + to interpret the error messages in the event log, + [RT #1668] + + 966. [placeholder] + + 965. [bug] Including data other than root server NS and A + records in the root hint file could cause a rbtdb + node reference leak. [RT #1581, #1618] + + 964. [func] Warn if data other than root server NS and A records + are found in the root hint file. [RT #1581, #1618] + + 963. [bug] Bad ISC_LANG_ENDDECLS. [RT #1645] + + 962. [bug] libbind: bad "#undef", don't attempt to install + non-existent nlist.h. [RT #1640] + + 961. [bug] Tried to use a IPV6 feature when ISC_PLATFORM_HAVEIPV6 + was not defined. [RT #1482] + + 960. [port] liblwres failed to build on systems with support for + getrrsetbyname() in the OS. [RT #1592] + + 959. [port] On FreeBSD, determine the number of CPUs by calling + sysctlbyname(). [RT #1584] + + 958. [port] ssize_t is not available on all platforms. [RT #1607] + + 957. [bug] sys/select.h inclusion was broken on older platforms. + [RT #1607] + + 956. [bug] ns_g_autorndcfile changed to ns_g_keyfile + in named/win32/os.c due to code changes in + change #953. win32 .make file for rndc-confgen + updated to add include path for os.h header. + + --- 9.2.0rc1 released --- + + 955. [bug] When using views, the zone's class was not being + inherited from the view's class. [RT #1583] + + 954. [bug] When requesting AXFRs or IXFRs using dig, host, or + nslookup, the RD bit should not be set as zone + transfers are inherently non-recursive. [RT #1575] + + 953. [func] The /var/run/named.key file from change #843 + has been replaced by /etc/rndc.key. Both + named and rndc will look for this file and use + it to configure a default control channel key + if not already configured using a different + method (rndc.conf / controls). Unlike + named.key, rndc.key is not created automatically; + it must be created by manually running + "rndc-confgen -a". + + 952. [bug] The server required manual intervention to serve the + affected zones if it died between creating a journal + and committing the first change to it. + + 951. [bug] CFLAGS was not passed to the linker when + linking some of the test programs under + bin/tests. [RT #1555]. + + 950. [bug] Explicit TTLs did not properly override $TTL + due to a bug in change 834. [RT #1558] + + 949. [bug] host was unable to print records larger than 512 + bytes. [RT #1557] + + --- 9.2.0b2 released --- + + 948. [port] Integrated support for building on Windows NT / + Windows 2000. + + 947. [bug] dns_rdata_soa_t had a badly named element "mname" which + was really the RNAME field from RFC1035. To avoid + confusion and silent errors that would occur it the + "origin" and "mname" elements were given their correct + names "mname" and "rname" respectively, the "mname" + element is renamed to "contact". + + 946. [cleanup] doc/misc/options is now machine-generated from the + configuration parser syntax tables, and therefore + more likely to be correct. + + 945. [func] Add the new view-specific options + "match-destinations" and "match-recursive-only". + + 944. [func] Check for expired signatures on load. + + 943. [bug] The server could crash when receiving a command + via rndc if the configuration file listed only + nonexistent keys in the controls statement. [RT #1530] + + 942. [port] libbind: GETNETBYADDR_ADDR_T was not correctly + defined on some platforms. + + 941. [bug] The configuration checker crashed if a slave + zone didn't contain a masters statement. [RT #1514] + + 940. [bug] Double zone locking failure on error path. [RT #1510] + + --- 9.2.0b1 released --- + + 939. [port] Add the --disable-linux-caps option to configure for + systems that manage capabilities outside of named. + [RT #1503] + + 938. [placeholder] + + 937. [bug] A race when shutting down a zone could trigger a + INSIST() failure. [RT #1034] + + 936. [func] Warn about IPv4 addresses that are not complete + dotted quads. [RT #1084] + + 935. [bug] inet_pton failed to reject leading zeros. + + 934. [port] Deal with systems where accept() spuriously returns + ECONNRESET. + + 933. [bug] configure failed doing libbind on platforms not + supported by BIND 8. [RT #1496] + + --- 9.2.0a3 released --- + + 932. [bug] Use INSTALL_SCRIPT, not INSTALL_PROGRAM, + when installing isc-config.sh. + [RT #198, #1466] + + 931. [bug] The controls statement only attempted to verify + messages using the first key in the key list. + (9.2.0a1/a2 only). + + 930. [func] Query performance testing tool added as + contrib/queryperf. + + 929. [placeholder] + + 928. [bug] nsupdate would send empty update packets if the + send (or empty line) command was run after + another send but before any new updates or + prerequisites were specified. It should simply + ignore this command. + + 927. [bug] Don't hold the zone lock for the entire dump to disk. + [RT #1423] + + 926. [bug] The resolver could deadlock with the ADB when + shutting down (multi-threaded builds only). + [RT #1324] + + 925. [cleanup] Remove openssl from the distribution; require that + --with-openssl be specified if DNSSEC is needed. + + 924. [port] Extend support for pre-RFC2133 IPv6 implementation. + [RT #987] + + 923. [bug] Multiline TSIG secrets (and other multiline strings) + were not accepted in named.conf. [RT #1469] + + 922. [func] Added two new lwres_getrrsetbyname() result codes, + ERR_NONAME and ERR_NODATA. + + 921. [bug] lwres returned an incorrect error code if it received + a truncated message. + + 920. [func] Increase the lwres receive buffer size to 16K. + [RT #1451] + + 919. [placeholder] + + 918. [func] In nsupdate, TSIG errors are no longer treated as + fatal errors. + + 917. [func] New nsupdate command 'key', allowing TSIG keys to + be specified in the nsupdate command stream rather + than the command line. + + 916. [bug] Specifying type ixfr to dig without specifying + a serial number failed in unexpected ways. + + 915. [func] The named-checkconf and named-checkzone programs + now have a '-v' option for printing their version. + [RT #1151] + + 914. [bug] Global 'server' statements were rejected when + using views, even though they were accepted + in 9.1. [RT #1368] + + 913. [bug] Cache cleaning was not sufficiently aggressive. + [RT #1441, #1444] + + 912. [bug] Attempts to set the 'additional-from-cache' or + 'additional-from-auth' option to 'no' in a + server with recursion enabled will now + be ignored and cause a warning message. + [RT #1145] + + 911. [placeholder] + + 910. [port] Some pre-RFC2133 IPv6 implementations do not define + IN6ADDR_ANY_INIT. [RT #1416] + + 909. [placeholder] + + 908. [func] New program, rndc-confgen, to simplify setting up rndc. + + 907. [func] The ability to get entropy from either the + random device, a user-provided file or from + the keyboard was migrated from the DNSSEC tools + to libisc as isc_entropy_usebestsource(). + + 906. [port] Separated the system independent portion of + lib/isc/unix/entropy.c into lib/isc/entropy.c + and added lib/isc/win32/entropy.c. + + 905. [bug] Configuring a forward "zone" for the root domain + did not work. [RT #1418] + + 904. [bug] The server would leak memory if attempting to use + an expired TSIG key. [RT #1406] + + 903. [bug] dig should not crash when receiving a TCP packet + of length 0. + + 902. [bug] The -d option was ignored if both -t and -g were also + specified. + + 901. [placeholder] + + 900. [bug] A config.guess update changed the system identification + string of FreeBSD systems; configure and + bin/tests/system/ifconfig.sh now recognize the new + string. + + --- 9.2.0a2 released --- + + 899. [bug] lib/dns/soa.c failed to compile on many platforms + due to inappropriate use of a void value. + [RT #1372, #1373, #1386, #1387, #1395] + + 898. [bug] "dig" failed to set a nonzero exit status + on UDP query timeout. [RT #1323] + + 897. [bug] A config.guess update changed the system identification + string of UnixWare systems; configure now recognizes + the new string. + + 896. [bug] If a configuration file is set on named's command line + and it has a relative pathname, the current directory + (after any possible jailing resulting from named -t) + will be prepended to it so that reloading works + properly even when a directory option is present. + + 895. [func] New function, isc_dir_current(), akin to POSIX's + getcwd(). + + 894. [bug] When using the DNSSEC tools, a message intended to warn + when the keyboard was being used because of the lack + of a suitable random device was not being printed. + + 893. [func] Removed isc_file_test() and added isc_file_exists() + for the basic functionality that was being added + with isc_file_test(). + + 892. [placeholder] + + 891. [bug] Return an error when a SIG(0) signed response to + an unsigned query is seen. This should actually + do the verification, but it's not currently + possible. [RT #1391] + + 890. [cleanup] The man pages no longer require the mandoc macros + and should now format cleanly using most versions of + nroff, and HTML versions of the man pages have been + added. Both are generated from DocBook source. + + 889. [port] Eliminated blank lines before .TH in nroff man + pages since they cause problems with some versions + of nroff. [RT #1390] + + 888. [bug] Don't die when using TKEY to delete a nonexistent + TSIG key. [RT #1392] + + 887. [port] Detect broken compilers that can't call static + functions from inline functions. [RT #1212] + + 886. [placeholder] + + 885. [placeholder] + + 884. [placeholder] + + 883. [placeholder] + + 882. [placeholder] + + 881. [placeholder] + + 880. [placeholder] + + 879. [placeholder] + + 878. [placeholder] + + 877. [placeholder] + + 876. [placeholder] + + 875. [placeholder] + + 874. [placeholder] + + 873. [placeholder] + + 872. [placeholder] + + 871. [placeholder] + + 870. [placeholder] + + 869. [placeholder] + + 868. [placeholder] + + 867. [placeholder] + + 866. [func] Close debug only file channels when debug is set to + zero. [RT #1246] + + 865. [bug] The new configuration parser did not allow + the optional debug level in a "severity debug" + clause of a logging channel to be omitted. + This is now allowed and treated as "severity + debug 1;" like it does in BIND 8.2.4, not as + "severity debug 0;" like it did in BIND 9.1. + [RT #1367] + + 864. [cleanup] Multi-threading is now enabled by default on + OSF1, Solaris 2.7 and newer, AIX, IRIX, and HP-UX. + + 863. [bug] If an error occurred while an outgoing zone transfer + was starting up, the server could access a domain + name that had already been freed when logging a + message saying that the transfer was starting. + [RT #1383] + + 862. [bug] Use after realloc(), non portable pointer arithmetic in + grmerge(). + + 861. [port] Add support for Mac OS X, by making it equivalent + to Darwin. This was derived from the config.guess + file shipped with Mac OS X. [RT #1355] + + 860. [func] Drop cross class glue in zone transfers. + + 859. [bug] Cache cleaning now won't swamp the CPU if there + is a persistent over limit condition. + + 858. [func] isc_mem_setwater() no longer requires that when the + callback function is non-NULL then its hi_water + argument must be greater than its lo_water argument + (they can now be equal) or that they be non-zero. + + 857. [cleanup] Use ISC_MAGIC() to define all magic numbers for + structs, for our friends in EBCDIC-land. + + 856. [func] Allow partial rdatasets to be returned in answer and + authority sections to help non-TCP capable clients + recover from truncation. [RT #1301] + + 855. [bug] Stop spurious "using RFC 1035 TTL semantics" warnings. + + 854. [bug] The config parser didn't properly handle config + options that were specified in units of time other + than seconds. [RT #1372] + + 853. [bug] configure_view_acl() failed to detach existing acls. + [RT #1374] + + 852. [bug] Handle responses from servers which do not know + about IXFR. + + 851. [cleanup] The obsolete support-ixfr option was not properly + ignored. + + --- 9.2.0a1 released --- + + 850. [bug] dns_rbt_findnode() would not find nodes that were + split on a bitstring label somewhere other than in + the last label of the node. [RT #1351] + + 849. [func] will ensure INADDR_LOOPBACK is defined. + + 848. [func] A minimum max-cache-size of two megabytes is enforced + by the cache cleaner. + + 847. [func] Added isc_file_test(), which currently only has + some very basic functionality to test for the + existence of a file, whether a pathname is absolute, + or whether a pathname is the fundamental representation + of the current directory. It is intended that this + function can be expanded to test other things a + programmer might want to know about a file. + + 846. [func] A non-zero 'param' to dst_key_generate() when making an + hmac-md5 key means that good entropy is not required. + + 845. [bug] The access rights on the public file of a symmetric + key are now restricted as soon as the file is opened, + rather than after it has been written and closed. + + 844. [func] will ensure INADDR_LOOPBACK is defined, + just as does. + + 843. [func] If no controls statement is present in named.conf, + or if any inet phrase of a controls statement is + lacking a keys clause, then a key will be automatically + generated by named and an rndc.conf-style file + named named.key will be written that uses it. rndc + will use this file only if its normal configuration + file, or one provided on the command line, does not + exist. + + 842. [func] 'rndc flush' now takes an optional view. + + 841. [bug] When sdb modules were not declared threadsafe, their + create and destroy functions were not serialized. + + 840. [bug] The config file parser could print the wrong file + name if an error was detected after an included file + was parsed. [RT #1353] + + 839. [func] Dump packets for which there was no view or that the + class could not be determined to category "unmatched". + + 838. [port] UnixWare 7.x.x is now supported by + bin/tests/system/ifconfig.sh. + + 837. [cleanup] Multi-threading is now enabled by default only on + OSF1, Solaris 2.7 and newer, and AIX. + + 836. [func] Upgraded libtool to 1.4. + + 835. [bug] The dispatcher could enter a busy loop if + it got an I/O error receiving on a UDP socket. + [RT #1293] + + 834. [func] Accept (but warn about) master files beginning with + an SOA record without an explicit TTL field and + lacking a $TTL directive, by using the SOA MINTTL + as a default TTL. This is for backwards compatibility + with old versions of BIND 8, which accepted such + files without warning although they are illegal + according to RFC1035. + + 833. [cleanup] Moved dns_soa_*() from to + , and extended them to support + all the integer-valued fields of the SOA RR. + + 832. [bug] The default location for named.conf in named-checkconf + should depend on --sysconfdir like it does in named. + [RT #1258] + + 831. [placeholder] + + 830. [func] Implement 'rndc status'. + + 829. [bug] The DNS_R_ZONECUT result code should only be returned + when an ANY query is made with DNS_DBFIND_GLUEOK set. + In all other ANY query cases, returning the delegation + is better. + + 828. [bug] The errno value from recvfrom() could be overwritten + by logging code. [RT #1293] + + 827. [bug] When an IXFR protocol error occurs, the slave + should retry with AXFR. + + 826. [bug] Some IXFR protocol errors were not detected. + + 825. [bug] zone.c:ns_query() detached from the wrong zone + reference. [RT #1264] + + 824. [bug] Correct line numbers reported by dns_master_load(). + [RT #1263] + + 823. [func] The output of "dig -h" now goes to stdout so that it + can easily be piped through "more". [RT #1254] + + 822. [bug] Sending nxrrset prerequisites would crash nsupdate. + [RT #1248] + + 821. [bug] The program name used when logging to syslog should + be stripped of leading path components. + [RT #1178, #1232] + + 820. [bug] Name server address lookups failed to follow + A6 chains into the glue of local authoritative + zones. + + 819. [bug] In certain cases, the resolver's attempts to + restart an address lookup at the root could cause + the fetch to deadlock (with itself) instead of + restarting. [RT #1225] + + 818. [bug] Certain pathological responses to ANY queries could + cause an assertion failure. [RT #1218] + + 817. [func] Adjust timeouts for dialup zone queries. + + 816. [bug] Report potential problems with log file accessibility + at configuration time, since such problems can't + reliably be reported at the time they actually occur. + + 815. [bug] If a log file was specified with a path separator + character (i.e. "/") in its name and the directory + did not exist, the log file's name was treated as + though it were the directory name. [RT #1189] + + 814. [bug] Socket objects left over from accept() failures + were incorrectly destroyed, causing corruption + of socket manager data structures. + + 813. [bug] File descriptors exceeding FD_SETSIZE were handled + badly. [RT #1192] + + 812. [bug] dig sometimes printed incomplete IXFR responses + due to an uninitialized variable. [RT #1188] + + 811. [bug] Parentheses were not quoted in zone dumps. [RT #1194] + + 810. [bug] The signer name in SIG records was not properly + down-cased when signing/verifying records. [RT #1186] + + 809. [bug] Configuring a non-local address as a transfer-source + could cause an assertion failure during load. + + 808. [func] Add 'rndc flush' to flush the server's cache. + + 807. [bug] When setting up TCP connections for incoming zone + transfers, the transfer-source port was not + ignored like it should be. + + 806. [bug] DNS_R_SEENINCLUDE was failing to propagate back up + the calling stack to the zone maintenance level, + causing zones to not reload when an included file was + touched but the top-level zone file was not. + + 805. [bug] When using "forward only", missing root hints should + not cause queries to fail. [RT #1143] + + 804. [bug] Attempting to obtain entropy could fail in some + situations. This would be most common on systems + with user-space threads. [RT #1131] + + 803. [bug] Treat all SIG queries as if they have the CD bit set, + otherwise no data will be returned [RT #749] + + 802. [bug] DNSSEC key tags were computed incorrectly in almost + all cases. [RT #1146] + + 801. [bug] nsupdate should treat lines beginning with ';' as + comments. [RT #1139] + + 800. [bug] dnssec-signzone produced incorrect statistics for + large zones. [RT #1133] + + 799. [bug] The ADB didn't find AAAA glue in a zone unless A6 + glue was also present. + + 798. [bug] nsupdate should be able to reject bad input lines + and continue. [RT #1130] + + 797. [func] Issue a warning if the 'directory' option contains + a relative path. [RT #269] + + 796. [func] When a size limit is associated with a log file, + only roll it when the size is reached, not every + time the log file is opened. [RT #1096] + + 795. [func] Add the +multiline option to dig. [RT #1095] + + 794. [func] Implement the "port" and "default-port" statements + in rndc.conf. + + 793. [cleanup] The DNSSEC tools could create filenames that were + illegal or contained shell meta-characters. They + now use a different text encoding of names that + doesn't have these problems. [RT #1101] + + 792. [cleanup] Replace the OMAPI command channel protocol with a + simpler one. + + 791. [bug] The command channel now works over IPv6. + + 790. [bug] Wildcards created using dynamic update or IXFR + could fail to match. [RT #1111] + + 789. [bug] The "localhost" and "localnets" ACLs did not match + when used as the second element of a two-element + sortlist item. + + 788. [func] Add the "match-mapped-addresses" option, which + causes IPv6 v4mapped addresses to be treated as + IPv4 addresses for the purpose of acl matching. + + 787. [bug] The DNSSEC tools failed to downcase domain + names when mapping them into file names. + + 786. [bug] When DNSSEC signing/verifying data, owner names were + not properly down-cased. + + 785. [bug] A race condition in the resolver could cause + an assertion failure. [RT #673, #872, #1048] + + 784. [bug] nsupdate and other programs would not quit properly + if some signals were blocked by the caller. [RT #1081] + + 783. [bug] Following CNAMEs could cause an assertion failure + when either using an sdb database or under very + rare conditions. + + 782. [func] Implement the "serial-query-rate" option. + + 781. [func] Avoid error packet loops by dropping duplicate FORMERR + responses. [RT #1006] + + 780. [bug] Error handling code dealing with out of memory or + other rare errors could lead to assertion failures + by calling functions on uninitialized names. [RT #1065] + + 779. [func] Added the "minimal-responses" option. + + 778. [bug] When starting cache cleaning, cleaning_timer_action() + returned without first pausing the iterator, which + could cause deadlock. [RT #998] + + 777. [bug] An empty forwarders list in a zone failed to override + global forwarders. [RT #995] + + 776. [func] Improved error reporting in denied messages. [RT #252] + + 775. [placeholder] + + 774. [func] max-cache-size is implemented. + + 773. [func] Added isc_rwlock_trylock() to attempt to lock without + blocking. + + 772. [bug] Owner names could be incorrectly omitted from cache + dumps in the presence of negative caching entries. + [RT #991] + + 771. [cleanup] TSIG errors related to unsynchronized clocks + are logged better. [RT #919] + + 770. [func] Add the "edns yes_or_no" statement to the server + clause. [RT #524] + + 769. [func] Improved error reporting when parsing rdata. [RT #740] + + 768. [bug] The server did not emit an SOA when a CNAME + or DNAME chain ended in NXDOMAIN in an + authoritative zone. + + 767. [placeholder] + + 766. [bug] A few cases in query_find() could leak fname. + This would trigger the mpctx->allocated == 0 + assertion when the server exited. + [RT #739, #776, #798, #812, #818, #821, #845, + #892, #935, #966] + + 765. [func] ACL names are once again case insensitive, like + in BIND 8. [RT #252] + + 764. [func] Configuration files now allow "include" directives + in more places, such as inside the "view" statement. + [RT #377, #728, #860] + + 763. [func] Configuration files no longer have reserved words. + [RT #731, #753] + + 762. [cleanup] The named.conf and rndc.conf file parsers have + been completely rewritten. + + 761. [bug] _REENTRANT was still defined when building with + --disable-threads. + + 760. [contrib] Significant enhancements to the pgsql sdb driver. + + 759. [bug] The resolver didn't turn off "avoid fetches" mode + when restarting, possibly causing resolution + to fail when it should not. This bug only affected + platforms which support both IPv4 and IPv6. [RT #927] + + 758. [bug] The "avoid fetches" code did not treat negative + cache entries correctly, causing fetches that would + be useful to be avoided. This bug only affected + platforms which support both IPv4 and IPv6. [RT #927] + + 757. [func] Log zone transfers. + + 756. [bug] dns_zone_load() could "return" success when no master + file was configured. + + 755. [bug] Fix incorrectly formatted log messages in zone.c. + + 754. [bug] Certain failure conditions sending UDP packets + could cause the server to retry the transmission + indefinitely. [RT #902] + + 753. [bug] dig, host, and nslookup would fail to contact a + remote server if getaddrinfo() returned an IPv6 + address on a system that doesn't support IPv6. + [RT #917] + + 752. [func] Correct bad tv_usec elements returned by + gettimeofday(). + + 751. [func] Log successful zone loads / transfers. [RT #898] + + 750. [bug] A query should not match a DNAME whose trust level + is pending. [RT #916] + + 749. [bug] When a query matched a DNAME in a secure zone, the + server did not return the signature of the DNAME. + [RT #915] + + 748. [doc] List supported RFCs in doc/misc/rfc-compliance. + [RT #781] + + 747. [bug] The code to determine whether an IXFR was possible + did not properly check for a database that could + not have a journal. [RT #865, #908] + + 746. [bug] The sdb didn't clone rdatasets properly, causing + a crash when the server followed delegations. [RT #905] + + 745. [func] Report the owner name of records that fail + semantic checks while loading. + + 744. [bug] When returning DNS_R_CNAME or DNS_R_DNAME as the + result of an ANY or SIG query, the resolver failed + to setup the return event's rdatasets, causing an + assertion failure in the query code. [RT #881] + + 743. [bug] Receiving a large number of certain malformed + answers could cause named to stop responding. + [RT #861] + + 742. [placeholder] + + 741. [port] Support openssl-engine. [RT #709] + + 740. [port] Handle openssl library mismatches slightly better. + + 739. [port] Look for /dev/random in configure, rather than + assuming it will be there for only a predefined + set of OSes. + + 738. [bug] If a non-threadsafe sdb driver supported AXFR and + received an AXFR request, it would deadlock or die + with an assertion failure. [RT #852] + + 737. [port] stdtime.c failed to compile on certain platforms. + + 736. [func] New functions isc_task_{begin,end}exclusive(). + + 735. [doc] Add BIND 4 migration notes. + + 734. [bug] An attempt to re-lock the zone lock could occur if + the server was shutdown during a zone transfer. + [RT #830] + + 733. [bug] Reference counts of dns_acl_t objects need to be + locked but were not. [RT #801, #821] + + 732. [bug] Glue with 0 TTL could also cause SERVFAIL. [RT #828] + + 731. [bug] Certain zone errors could cause named-checkzone to + fail ungracefully. [RT #819] + + 730. [bug] lwres_getaddrinfo() returns the correct result when + it fails to contact a server. [RT #768] + + 729. [port] pthread_setconcurrency() needs to be called on Solaris. + + 728. [bug] Fix comment processing on master file directives. + [RT #757] + + 727. [port] Work around OS bug where accept() succeeds but + fails to fill in the peer address of the accepted + connection, by treating it as an error rather than + an assertion failure. [RT #809] + + 726. [func] Implement the "trace" and "notrace" commands in rndc. + + 725. [bug] Installing man pages could fail. + + 724. [func] New libisc functions isc_netaddr_any(), + isc_netaddr_any6(). + + 723. [bug] Referrals whose NS RRs had a 0 TTL caused the resolver + to return DNS_R_SERVFAIL. [RT #783] + + 722. [func] Allow incremental loads to be canceled. + + 721. [cleanup] Load manager and dns_master_loadfilequota() are no + more. + + 720. [bug] Server could enter infinite loop in + dispatch.c:do_cancel(). [RT #733] + + 719. [bug] Rapid reloads could trigger an assertion failure. + [RT #743, #763] + + 718. [cleanup] "internal" is no longer a reserved word in named.conf. + [RT #753, #731] + + 717. [bug] Certain TKEY processing failure modes could + reference an uninitialized variable, causing the + server to crash. [RT #750] + + 716. [bug] The first line of a $INCLUDE master file was lost if + an origin was specified. [RT #744] + + 715. [bug] Resolving some A6 chains could cause an assertion + failure in adb.c. [RT #738] + + 714. [bug] Preserve interval timers across reloads unless changed. + [RT #729] + + 713. [func] named-checkconf takes '-t directory' similar to named. + [RT #726] + + 712. [bug] Sending a large signed update message caused an + assertion failure. [RT #718] + + 711. [bug] The libisc and liblwres implementations of + inet_ntop contained an off by one error. + + 710. [func] The forwarders statement now takes an optional + port. [RT #418] + + 709. [bug] ANY or SIG queries for data with a TTL of 0 + would return SERVFAIL. [RT #620] + + 708. [bug] When building with --with-openssl, the openssl headers + included with BIND 9 should not be used. [RT #702] + + 707. [func] The "filename" argument to named-checkzone is no + longer optional, to reduce confusion. [RT #612] + + 706. [bug] Zones with an explicit "allow-update { none; };" + were considered dynamic and therefore not reloaded + on SIGHUP or "rndc reload". + + 705. [port] Work out resource limit type for use where rlim_t is + not available. [RT #695] + + 704. [port] RLIMIT_NOFILE is not available on all platforms. + [RT #695] + + 703. [port] sys/select.h is needed on older platforms. [RT #695] + + 702. [func] If the address 0.0.0.0 is seen in resolv.conf, + use 127.0.0.1 instead. [RT #693] + + 701. [func] Root hints are now fully optional. Class IN + views use compiled-in hints by default, as + before. Non-IN views with no root hints now + provide authoritative service but not recursion. + A warning is logged if a view has neither root + hints nor authoritative data for the root. [RT #696] + + 700. [bug] $GENERATE range check was wrong. [RT #688] + + 699. [bug] The lexer mishandled empty quoted strings. [RT #694] + + 698. [bug] Aborting nsupdate with ^C would lead to several + race conditions. + + 697. [bug] nsupdate was not compatible with the undocumented + BIND 8 behavior of ignoring TTLs in "update delete" + commands. [RT #693] + + 696. [bug] lwresd would die with an assertion failure when passed + a zero-length name. [RT #692] + + 695. [bug] If the resolver attempted to query a blackholed or + bogus server, the resolution would fail immediately. + + 694. [bug] $GENERATE did not produce the last entry. + [RT #682, #683] + + 693. [bug] An empty lwres statement in named.conf caused + the server to crash while loading. + + 692. [bug] Deal with systems that have getaddrinfo() but not + gai_strerror(). [RT #679] + + 691. [bug] Configuring per-view forwarders caused an assertion + failure. [RT #675, #734] + + 690. [func] $GENERATE now supports DNAME. [RT #654] + + 689. [doc] man pages are now installed. [RT #210] + + 688. [func] "make tags" now works on systems with the + "Exuberant Ctags" etags. + + 687. [bug] Only say we have IPv6, with sufficient functionality, + if it has actually been tested. [RT #586] + + 686. [bug] dig and nslookup can now be properly aborted during + blocking operations. [RT #568] + + 685. [bug] nslookup should use the search list/domain options + from resolv.conf by default. [RT #405, #630] + + 684. [bug] Memory leak with view forwarders. [RT #656] + + 683. [bug] File descriptor leak in isc_lex_openfile(). + + 682. [bug] nslookup displayed SOA records incorrectly. [RT #665] + + 681. [bug] $GENERATE specifying output format was broken. [RT #653] + + 680. [bug] dns_rdata_fromstruct() mishandled options bigger + than 255 octets. + + 679. [bug] $INCLUDE could leak memory and file descriptors on + reload. [RT #639] + + 678. [bug] "transfer-format one-answer;" could trigger an assertion + failure. [RT #646] + + 677. [bug] dnssec-signzone would occasionally use the wrong ttl + for database operations and fail. [RT #643] + + 676. [bug] Log messages about lame servers to category + 'lame-servers' rather than 'resolver', so as not + to be gratuitously incompatible with BIND 8. + + 675. [bug] TKEY queries could cause the server to leak + memory. + + 674. [func] Allow messages to be TSIG signed / verified using + a offset from the current time. + + 673. [func] The server can now convert RFC1886-style recursive + lookup requests into RFC2874-style lookups, when + enabled using the new option "allow-v6-synthesis". + + 672. [bug] The wrong time was in the "time signed" field when + replying with BADTIME error. + + 671. [bug] The message code was failing to parse a message with + no question section and a TSIG record. [RT #628] + + 670. [bug] The lwres replacements for getaddrinfo and + getipnodebyname didn't properly check for the + existence of the sockaddr sa_len field. + + 669. [bug] dnssec-keygen now makes the public key file + non-world-readable for symmetric keys. [RT #403] + + 668. [func] named-checkzone now reports multiple errors in master + files. + + 667. [bug] On Linux, running named with the -u option and a + non-world-readable configuration file didn't work. + [RT #626] + + 666. [bug] If a request sent by dig is longer than 512 bytes, + use TCP. + + 665. [bug] Signed responses were not sent when the size of the + TSIG + question exceeded the maximum message size. + [RT #628] + + 664. [bug] The t_tasks and t_timers module tests are now skipped + when building without threads, since they require + threads. + + 663. [func] Accept a size_spec, not just an integer, in the + (unimplemented and ignored) max-ixfr-log-size option + for compatibility with recent versions of BIND 8. + [RT #613] + + 662. [bug] dns_rdata_fromtext() failed to log certain errors. + + 661. [bug] Certain UDP IXFR requests caused an assertion failure + (mpctx->allocated == 0). [RT #355, #394, #623] + + 660. [port] Detect multiple CPUs on HP-UX and IRIX. + + 659. [performance] Rewrite the name compression code to be much faster. + + 658. [cleanup] Remove all vestiges of 16 bit global compression. + + 657. [bug] When a listen-on statement in an lwres block does not + specify a port, use 921, not 53. Also update the + listen-on documentation. [RT #616] + + 656. [func] Treat an unescaped newline in a quoted string as + an error. This means that TXT records with missing + close quotes should have meaningful errors printed. + + 655. [bug] Improve error reporting on unexpected eof when loading + zones. [RT #611] + + 654. [bug] Origin was being forgotten in TCP retries in dig. + [RT #574] + + 653. [bug] +defname option in dig was reversed in sense. + [RT #549] + + 652. [bug] zone_saveunique() did not report the new name. + + 651. [func] The AD bit in responses now has the meaning + specified in . + + 650. [bug] SIG(0) records were being generated and verified + incorrectly. [RT #606] + + 649. [bug] It was possible to join to an already running fctx + after it had "cloned" its events, but before it sent + them. In this case, the event of the newly joined + fetch would not contain the answer, and would + trigger the INSIST() in fctx_sendevents(). In + BIND 9.0, this bug did not trigger an INSIST(), but + caused the fetch to fail with a SERVFAIL result. + [RT #588, #597, #605, #607] + + 648. [port] Add support for pre-RFC2133 IPv6 implementations. + + 647. [bug] Resolver queries sent after following multiple + referrals had excessively long retransmission + timeouts due to incorrectly counting the referrals + as "restarts". + + 646. [bug] The UnixWare ISC_PLATFORM_FIXIN6INADDR fix in isc/net.h + didn't _cleanly_ fix the problem it was trying to fix. + + 645. [port] BSD/OS 3.0 needs pthread_init(). [RT #603] + + 644. [bug] #622 needed more work. [RT #562] + + 643. [bug] xfrin error messages made more verbose, added class + of the zone. [RT #599] + + 642. [bug] Break the exit_check() race in the zone module. + [RT #598] + + --- 9.1.0b2 released --- + + 641. [bug] $GENERATE caused a uninitialized link to be used. + [RT #595] + + 640. [bug] Memory leak in error path could cause + "mpctx->allocated == 0" failure. [RT #584] + + 639. [bug] Reading entropy from the keyboard would sometimes fail. + [RT #591] + + 638. [port] lib/isc/random.c needed to explicitly include time.h + to get a prototype for time() when pthreads was not + being used. [RT #592] + + 637. [port] Use isc_u?int64_t instead of (unsigned) long long in + lib/isc/print.c. Also allow lib/isc/print.c to + be compiled even if the platform does not need it. + [RT #592] + + 636. [port] Shut up MSVC++ about a possible loss of precision + in the ISC__BUFFER_PUTUINT*() macros. [RT #592] + + 635. [bug] Reloading a server with a configured blackhole list + would cause an assertion. [RT #590] + + 634. [bug] A log file will completely stop being written when + it reaches the maximum size in all cases, not just + when versioning is also enabled. [RT #570] + + 633. [port] Cope with rlim_t missing on BSD/OS systems. [RT #575] + + 632. [bug] The index array of the journal file was + corrupted as it was written to disk. + + 631. [port] Build without thread support on systems without + pthreads. + + 630. [bug] Locking failure in zone code. [RT #582] + + 629. [bug] 9.1.0b1 dereferenced a null pointer and crashed + when responding to a UDP IXFR request. + + 628. [bug] If the root hints contained only AAAA addresses, + named would be unable to perform resolution. + + 627. [bug] The EDNS0 blackhole detection code of change 324 + waited for three retransmissions to each server, + which takes much too long when a domain has many + name servers and all of them drop EDNS0 queries. + Now we retry without EDNS0 after three consecutive + timeouts, even if they are all from different + servers. [RT #143] + + 626. [bug] The lightweight resolver daemon no longer crashes + when asked for a SIG rrset. [RT #558] + + 625. [func] Zones now inherit their class from the enclosing view. + + 624. [bug] The zone object could get timer events after it had + been destroyed, causing a server crash. [RT #571] + + 623. [func] Added "named-checkconf" and "named-checkzone" program + for syntax checking named.conf files and zone files, + respectively. + + 622. [bug] A canceled request could be destroyed before + dns_request_destroy() was called. [RT #562] + + 621. [port] Disable IPv6 at runtime if IPv6 sockets are unusable. + This mostly affects Red Hat Linux 7.0, which has + conflicts between libc and the kernel. + + 620. [bug] dns_master_load*inc() now require 'task' and 'load' + to be non-null. Also 'done' will not be called if + dns_master_load*inc() fails immediately. [RT #565] + + 619. [placeholder] + + 618. [bug] Queries to a signed zone could sometimes cause + an assertion failure. + + 617. [bug] When using dynamic update to add a new RR to an + existing RRset with a different TTL, the journal + entries generated from the update did not include + explicit deletions and re-additions of the existing + RRs to update their TTL to the new value. + + 616. [func] dnssec-signzone -t output now includes performance + statistics. + + 615. [bug] dnssec-signzone did not like child keysets signed + by multiple keys. + + 614. [bug] Checks for uninitialized link fields were prone + to false positives, causing assertion failures. + The checks are now disabled by default and may + be re-enabled by defining ISC_LIST_CHECKINIT. + + 613. [bug] "rndc reload zone" now reloads primary zones. + It previously only updated slave and stub zones, + if an SOA query indicated an out of date serial. + + 612. [cleanup] Shutup a ridiculously noisy HP-UX compiler that + complains relentlessly about how its treatment + of 'const' has changed as well as how casting + sometimes tightens alignment constraints. + + 611. [func] allow-notify can be used to permit processing of + notify messages from hosts other than a slave's + masters. + + 610. [func] rndc dumpdb is now supported. + + 609. [bug] getrrsetbyname() would crash lwresd if the server + found more SIGs than answers. [RT #554] + + 608. [func] dnssec-signzone now adds a comment to the zone + with the time the file was signed. + + 607. [bug] nsupdate would fail if it encountered a CNAME or + DNAME in a response to an SOA query. [RT #515] + + 606. [bug] Compiling with --disable-threads failed due + to isc_thread_self() being incorrectly defined + as an integer rather than a function. + + 605. [func] New function isc_lex_getlasttokentext(). + + 604. [bug] The named.conf parser could print incorrect line + numbers when long comments were present. + + 603. [bug] Make dig handle multiple types or classes on the same + query more correctly. + + 602. [func] Cope automatically with UnixWare's broken + IN6_IS_ADDR_* macros. [RT #539] + + 601. [func] Return a non-zero exit code if an update fails + in nsupdate. + + 600. [bug] Reverse lookups sometimes failed in dig, etc... + + 599. [func] Added four new functions to the libisc log API to + support i18n messages. isc_log_iwrite(), + isc_log_ivwrite(), isc_log_iwrite1() and + isc_log_ivwrite1() were added. + + 598. [bug] An update-policy statement would cause the server + to assert while loading. [RT #536] + + 597. [func] dnssec-signzone is now multi-threaded. + + 596. [bug] DNS_RDATASLAB_FORCE and DNS_RDATASLAB_EXACT are + not mutually exclusive. + + 595. [port] On Linux 2.2, socket() returns EINVAL when it + should return EAFNOSUPPORT. Work around this. + [RT #531] + + 594. [func] sdb drivers are now assumed to not be thread-safe + unless the DNS_SDBFLAG_THREADSAFE flag is supplied. + + 593. [bug] If a secure zone was missing all its NXTs and + a dynamic update was attempted, the server entered + an infinite loop. + + 592. [bug] The sig-validity-interval option now specifies a + number of days, not seconds. This matches the + documentation. [RT #529] + + --- 9.1.0b1 released --- + + 591. [bug] Work around non-reentrancy in openssl by disabling + pre-computation in keys. + + 590. [doc] There are now man pages for the lwres library in + doc/man/lwres. + + 589. [bug] The server could deadlock if a zone was updated + while being transferred out. + + 588. [bug] ctx->in_use was not being correctly initialized when + when pushing a file for $INCLUDE. [RT #523] + + 587. [func] A warning is now printed if the "allow-update" + option allows updates based on the source IP + address, to alert users to the fact that this + is insecure and becoming increasingly so as + servers capable of update forwarding are being + deployed. + + 586. [bug] multiple views with the same name were fatal. [RT #516] + + 585. [func] dns_db_addrdataset() and dns_rdataslab_merge() + now support 'exact' additions in a similar manner to + dns_db_subtractrdataset() and dns_rdataslab_subtract(). + + 584. [func] You can now say 'notify explicit'; to suppress + notification of the servers listed in NS records + and notify only those servers listed in the + 'also-notify' option. + + 583. [func] "rndc querylog" will now toggle logging of + queries, like "ndc querylog" in BIND 8. + + 582. [bug] dns_zone_idetach() failed to lock the zone. + [RT #199, #463] + + 581. [bug] log severity was not being correctly processed. + [RT #485] + + 580. [func] Ignore trailing garbage on incoming DNS packets, + for interoperability with broken server + implementations. [RT #491] + + 579. [bug] nsupdate did not take a filename to read update from. + [RT #492] + + 578. [func] New config option "notify-source", to specify the + source address for notify messages. + + 577. [func] Log illegal RDATA combinations. e.g. multiple + singleton types, cname and other data. + + 576. [doc] isc_log_create() description did not match reality. + + 575. [bug] isc_log_create() was not setting internal state + correctly to reflect the default channels created. + + 574. [bug] TSIG signed queries sent by the resolver would fail to + have their responses validated and would leak memory. + + 573. [bug] The journal files of IXFRed slave zones were + inadvertently discarded on server reload, causing + "journal out of sync with zone" errors on subsequent + reloads. [RT #482] + + 572. [bug] Quoted strings were not accepted as key names in + address match lists. + + 571. [bug] It was possible to create an rdataset of singleton + type which had more than one rdata. [RT #154] + [RT #279] + + 570. [bug] rbtdb.c allowed zones containing nodes which had + both a CNAME and "other data". [RT #154] + + 569. [func] The DNSSEC AD bit will not be set on queries which + have not requested a DNSSEC response. + + 568. [func] Add sample simple database drivers in contrib/sdb. + + 567. [bug] Setting the zone transfer timeout to zero caused an + assertion failure. [RT #302] + + 566. [func] New public function dns_timer_setidle(). + + 565. [func] Log queries more like BIND 8: query logging is now + done to category "queries", level "info". [RT #169] + + 564. [func] Add sortlist support to lwresd. + + 563. [func] New public functions dns_rdatatype_format() and + dns_rdataclass_format(), for convenient formatting + of rdata type/class mnemonics in log messages. + + 562. [cleanup] Moved lib/dns/*conf.c to bin/named where they belong. + + 561. [func] The 'datasize', 'stacksize', 'coresize' and 'files' + clauses of the options{} statement are now implemented. + + 560. [bug] dns_name_split did not properly the resulting prefix + when a maximal length bitstring label was split which + was preceded by another bitstring label. [RT #429] + + 559. [bug] dns_name_split did not properly create the suffix + when splitting within a maximal length bitstring label. + + 558. [func] New functions, isc_resource_getlimit and + isc_resource_setlimit. + + 557. [func] Symbolic constants for libisc integral types. + + 556. [func] The DNSSEC OK bit in the EDNS extended flags + is now implemented. Responses to queries without + this bit set will not contain any DNSSEC records. + + 555. [bug] A slave server attempting a zone transfer could + crash with an assertion failure on certain + malformed responses from the master. [RT #457] + + 554. [bug] In some cases, not all of the dnssec tools were + properly installed. + + 553. [bug] Incoming zone transfers deferred due to quota + were not started when quota was increased but + only when a transfer in progress finished. [RT #456] + + 552. [bug] We were not correctly detecting the end of all c-style + comments. [RT #455] + + 551. [func] Implemented the 'sortlist' option. + + 550. [func] Support unknown rdata types and classes. + + 549. [bug] "make" did not immediately abort the build when a + subdirectory make failed [RT #450]. + + 548. [func] The lexer now ungets tokens more correctly. + + 547. [placeholder] + + 546. [func] Option 'lame-ttl' is now implemented. + + 545. [func] Name limit and counting options removed from dig; + they didn't work properly, and cannot be correctly + implemented without significant changes. + + 544. [func] Add statistics option, enable statistics-file option, + add RNDC option "dump-statistics" to write out a + query statistics file. + + 543. [doc] The 'port' option is now documented. + + 542. [func] Add support for update forwarding as required for + full compliance with RFC2136. It is turned off + by default and can be enabled using the + 'allow-update-forwarding' option. + + 541. [func] Add bogus server support. + + 540. [func] Add dialup support. + + 539. [func] Support the blackhole option. + + 538. [bug] fix buffer overruns by 1 in lwres_getnameinfo(). + + 537. [placeholder] + + 536. [func] Use transfer-source{-v6} when sending refresh queries. + Transfer-source{-v6} now take a optional port + parameter for setting the UDP source port. The port + parameter is ignored for TCP. + + 535. [func] Use transfer-source{-v6} when forwarding update + requests. + + 534. [func] Ancestors have been removed from RBT chains. Ancestor + information can be discerned via node parent pointers. + + 533. [func] Incorporated name hashing into the RBT database to + improve search speed. + + 532. [func] Implement DNS UPDATE pseudo records using + DNS_RDATA_UPDATE flag. + + 531. [func] Rdata really should be initialized before being assigned + to (dns_rdata_fromwire(), dns_rdata_fromtext(), + dns_rdata_clone(), dns_rdata_fromregion()), + check that it is. + + 530. [func] New function dns_rdata_invalidate(). + + 529. [bug] 521 contained a bug which caused zones to always + reload. [RT #410] + + 528. [func] The ISC_LIST_XXXX macros now perform sanity checks + on their arguments. ISC_LIST_XXXXUNSAFE can be use + to skip the checks however use with caution. + + 527. [func] New function dns_rdata_clone(). + + 526. [bug] nsupdate incorrectly refused to add RRs with a TTL + of 0. + + 525. [func] New arguments 'options' for dns_db_subtractrdataset(), + and 'flags' for dns_rdataslab_subtract() allowing you + to request that the RR's must exist prior to deletion. + DNS_R_NOTEXACT is returned if the condition is not met. + + 524. [func] The 'forward' and 'forwarders' statement in + non-forward zones should work now. + + 523. [doc] The source to the Administrator Reference Manual is + now an XML file using the DocBook DTD, and is included + in the distribution. The plain text version of the + ARM is temporarily unavailable while we figure out + how to generate readable plain text from the XML. + + 522. [func] The lightweight resolver daemon can now use + a real configuration file, and its functionality + can be provided by a name server. Also, the -p and -P + options to lwresd have been reversed. + + 521. [bug] Detect master files which contain $INCLUDE and always + reload. [RT #196] + + 520. [bug] Upgraded libtool to 1.3.5, which makes shared + library builds almost work on AIX (and possibly + others). + + 519. [bug] dns_name_split() would improperly split some bitstring + labels, zeroing a few of the least significant bits in + the prefix part. When such an improperly created + prefix was returned to the RBT database, the bogus + label was dutifully stored, corrupting the tree. + [RT #369] + + 518. [bug] The resolver did not realize that a DNAME which was + "the answer" to the client's query was "the answer", + and such queries would fail. [RT #399] + + 517. [bug] The resolver's DNAME code would trigger an assertion + if there was more than one DNAME in the chain. + [RT #399] + + 516. [bug] Cache lookups which had a NULL node pointer, e.g. + those by dns_view_find(), and which would match a + DNAME, would trigger an INSIST(!search.need_cleanup) + assertion. [RT #399] + + 515. [bug] The ssu table was not being attached / detached + by dns_zone_[sg]etssutable. [RT #397] + + 514. [func] Retry refresh and notify queries if they timeout. + [RT #388] + + 513. [func] New functionality added to rdnc and server to allow + individual zones to be refreshed or reloaded. + + 512. [bug] The zone transfer code could throw an exception with + an invalid IXFR stream. + + 511. [bug] The message code could throw an assertion on an + out of memory failure. [RT #392] + + 510. [bug] Remove spurious view notify warning. [RT #376] + + 509. [func] Add support for write of zone files on shutdown. + + 508. [func] dns_message_parse() can now do a best-effort + attempt, which should allow dig to print more invalid + messages. + + 507. [func] New functions dns_zone_flush(), dns_zt_flushanddetach() + and dns_view_flushanddetach(). + + 506. [func] Do not fail to start on errors in zone files. + + 505. [bug] nsupdate was printing "unknown result code". [RT #373] + + 504. [bug] The zone was not being marked as dirty when updated via + IXFR. + + 503. [bug] dumptime was not being set along with + DNS_ZONEFLG_NEEDDUMP. + + 502. [func] On a SERVFAIL reply, DiG will now try the next server + in the list, unless the +fail option is specified. + + 501. [bug] Incorrect port numbers were being displayed by + nslookup. [RT #352] + + 500. [func] Nearly useless +details option removed from DiG. + + 499. [func] In DiG, specifying a class with -c or type with -t + changes command-line parsing so that classes and + types are only recognized if following -c or -t. + This allows hosts with the same name as a class or + type to be looked up. + + 498. [doc] There is now a man page for "dig" + in doc/man/bin/dig.1. + + 497. [bug] The error messages printed when an IP match list + contained a network address with a nonzero host + part where not sufficiently detailed. [RT #365] + + 496. [bug] named didn't sanity check numeric parameters. [RT #361] + + 495. [bug] nsupdate was unable to handle large records. [RT #368] + + 494. [func] Do not cache NXDOMAIN responses for SOA queries. + + 493. [func] Return non-cachable (ttl = 0) NXDOMAIN responses + for SOA queries. This makes it easier to locate + the containing zone without polluting intermediate + caches. + + 492. [bug] attempting to reload a zone caused the server fail + to shutdown cleanly. [RT #360] + + 491. [bug] nsupdate would segfault when sending certain + prerequisites with empty RDATA. [RT #356] + + 490. [func] When a slave/stub zone has not yet successfully + obtained an SOA containing the zone's configured + retry time, perform the SOA query retries using + exponential backoff. [RT #337] + + 489. [func] The zone manager now has a "i/o" queue. + + 488. [bug] Locks weren't properly destroyed in some cases. + + 487. [port] flockfile() is not defined on all systems. + + 486. [bug] nslookup: "set all" and "server" commands showed + the incorrect port number if a port other than 53 + was specified. [RT #352] + + 485. [func] When dig had more than one server to query, it would + send all of the messages at the same time. Add + rate limiting of the transmitted messages. + + 484. [bug] When the server was reloaded after removing addresses + from the named.conf "listen-on" statement, sockets + were still listening on the removed addresses due + to reference count loops. [RT #325] + + 483. [bug] nslookup: "set all" showed a "search" option but it + was not settable. + + 482. [bug] nslookup: a plain "server" or "lserver" should be + treated as a lookup. + + 481. [bug] nslookup:get_next_command() stack size could exceed + per thread limit. + + 480. [bug] strtok() is not thread safe. [RT #349] + + 479. [func] The test suite can now be run by typing "make check" + or "make test" at the top level. + + 478. [bug] "make install" failed if the directory specified with + --prefix did not already exist. + + 477. [bug] The the isc-config.sh script could be installed before + its directory was created. [RT #324] + + 476. [bug] A zone could expire while a zone transfer was in + progress triggering a INSIST failure. [RT #329] + + 475. [bug] query_getzonedb() sometimes returned a non-null version + on failure. This caused assertion failures when + generating query responses where names subject to + additional section processing pointed to a zone + to which access had been denied by means of the + allow-query option. [RT #336] + + 474. [bug] The mnemonic of the CHAOS class is CH according to + RFC1035, but it was printed and read only as CHAOS. + We now accept both forms as input, and print it + as CH. [RT #305] + + 473. [bug] nsupdate overran the end of the list of name servers + when no servers could be reached, typically causing + it to print the error message "dns_request_create: + not implemented". + + 472. [bug] Off-by-one error caused isc_time_add() to sometimes + produce invalid time values. + + 471. [bug] nsupdate didn't compile on HP/UX 10.20 + + 470. [func] $GENERATE is now supported. See also + doc/misc/migration. + + 469. [bug] "query-source address * port 53;" now works. + + 468. [bug] dns_master_load*() failed to report file and line + number in certain error conditions. + + 467. [bug] dns_master_load*() failed to log an error if + pushfile() failed. + + 466. [bug] dns_master_load*() could return success when it failed. + + 465. [cleanup] Allow 0 to be set as an omapi_value_t value by + omapi_value_storeint(). + + 464. [cleanup] Build with openssl's RSA code instead of dnssafe. + + 463. [bug] nsupdate sent malformed SOA queries to the second + and subsequent name servers in resolv.conf if the + query sent to the first one failed. + + 462. [bug] --disable-ipv6 should work now. + + 461. [bug] Specifying an unknown key in the "keys" clause of the + "controls" statement caused a NULL pointer dereference. + [RT #316] + + 460. [bug] Much of the DNSSEC code only worked with class IN. + + 459. [bug] Nslookup processed the "set" command incorrectly. + + 458. [bug] Nslookup didn't properly check class and type values. + [RT #305] + + 457. [bug] Dig/host/hslookup didn't properly handle connect + timeouts in certain situations, causing an + unnecessary warning message to be printed. + + 456. [bug] Stub zones were not resetting the refresh and expire + counters, loadtime or clearing the DNS_ZONE_REFRESH + (refresh in progress) flag upon successful update. + This disabled further refreshing of the stub zone, + causing it to eventually expire. [RT #300] + + 455. [doc] Document IPv4 prefix notation does not require a + dotted decimal quad but may be just dotted decimal. + + 454. [bug] Enforce dotted decimal and dotted decimal quad where + documented as such in named.conf. [RT #304, RT #311] + + 453. [bug] Warn if the obsolete option "maintain-ixfr-base" + is specified in named.conf. [RT #306] + + 452. [bug] Warn if the unimplemented option "statistics-file" + is specified in named.conf. [RT #301] + + 451. [func] Update forwarding implemented. + + 450. [func] New function ns_client_sendraw(). + + 449. [bug] isc_bitstring_copy() only works correctly if the + two bitstrings have the same lsb0 value, but this + requirement was not documented, nor was there a + REQUIRE for it. + + 448. [bug] Host output formatting change, to match v8. [RT #255] + + 447. [bug] Dig didn't properly retry in TCP mode after + a truncated reply. [RT #277] + + 446. [bug] Confusing notify log message. [RT #298] + + 445. [bug] Doing a 0 bit isc_bitstring_copy() of an lsb0 + bitstring triggered a REQUIRE statement. The REQUIRE + statement was incorrect. [RT #297] + + 444. [func] "recursion denied" messages are always logged at + debug level 1, now, rather than sometimes at ERROR. + This silences these warnings in the usual case, where + some clients set the RD bit in all queries. + + 443. [bug] When loading a master file failed because of an + unrecognized RR type name, the error message + did not include the file name and line number. + [RT #285] + + 442. [bug] TSIG signed messages that did not match any view + crashed the server. [RT #290] + + 441. [bug] Nodes obscured by a DNAME were inaccessible even + when DNS_DBFIND_GLUEOK was set. + + 440. [func] New function dns_zone_forwardupdate(). + + 439. [func] New function dns_request_createraw(). + + 438. [func] New function dns_message_getrawmessage(). + + 437. [func] Log NOTIFY activity to the notify channel. + + 436. [bug] If recvmsg() returned EHOSTUNREACH or ENETUNREACH, + which sometimes happens on Linux, named would enter + a busy loop. Also, unexpected socket errors were + not logged at a high enough logging level to be + useful in diagnosing this situation. [RT #275] + + 435. [bug] dns_zone_dump() overwrote existing zone files + rather than writing to a temporary file and + renaming. This could lead to empty or partial + zone files being left around in certain error + conditions involving the initial transfer of a + slave zone, interfering with subsequent server + startup. [RT #282] + + 434. [func] New function isc_file_isabsolute(). + + 433. [func] isc_base64_decodestring() now accepts newlines + within the base64 data. This makes it possible + to break up the key data in a "trusted-keys" + statement into multiple lines. [RT #284] + + 432. [func] Added refresh/retry jitter. The actual refresh/ + retry time is now a random value between 75% and + 100% of the configured value. + + 431. [func] Log at ISC_LOG_INFO when a zone is successfully + loaded. + + 430. [bug] Rewrote the lightweight resolver client management + code to handle shutdown correctly and general + cleanup. + + 429. [bug] The space reserved for a TSIG record in a response + was 2 bytes too short, leading to message + generation failures. + + 428. [bug] rbtdb.c:find_closest_nxt() erroneously returned + DNS_R_BADDB for nodes which had neither NXT nor SIG NXT + (e.g. glue). This could cause SERVFAILs when + generating negative responses in a secure zone. + + 427. [bug] Avoid going into an infinite loop when the validator + gets a negative response to a key query where the + records are signed by the missing key. + + 426. [bug] Attempting to generate an oversized RSA key could + cause dnssec-keygen to dump core. + + 425. [bug] Warn about the auth-nxdomain default value change + if there is no auth-nxdomain statement in the + config file. [RT #287] + + 424. [bug] notify_createmessage() could trigger an assertion + failure when creating the notify message failed, + e.g. due to corrupt zones with multiple SOA records. + [RT #279] + + 423. [bug] When responding to a recursive query, errors that occur + after following a CNAME should cause the query to fail. + [RT #274] + + 422. [func] get rid of isc_random_t, and make isc_random_get() + and isc_random_jitter() use rand() internally + instead of local state. Note that isc_random_*() + functions are only for weak, non-critical "randomness" + such as timing jitter and such. + + 421. [bug] nslookup would exit when given a blank line as input. + + 420. [bug] nslookup failed to implement the "exit" command. + + 419. [bug] The certificate type PKIX was misspelled as SKIX. + + 418. [bug] At debug levels >= 10, getting an unexpected + socket receive error would crash the server + while trying to log the error message. + + 417. [func] Add isc_app_block() and isc_app_unblock(), which + allow an application to handle signals while + blocking. + + 416. [bug] Slave zones with no master file tried to use a + NULL pointer for a journal file name when they + received an IXFR. [RT #273] + + 415. [bug] The logging code leaked file descriptors. + + 414. [bug] Server did not shut down until all incoming zone + transfers were finished. + + 413. [bug] Notify could attempt to use the zone database after + it had been unloaded. [RT #267] + + 412. [bug] named -v didn't print the version. + + 411. [bug] A typo in the HS A code caused an assertion failure. + + 410. [bug] lwres_gethostbyname() and company set lwres_h_errno + to a random value on success. + + 409. [bug] If named was shut down early in the startup + process, ns_omapi_shutdown() would attempt to lock + an uninitialized mutex. [RT #262] + + 408. [bug] stub zones could leak memory and reference counts if + all the masters were unreachable. + + 407. [bug] isc_rwlock_lock() would needlessly block + readers when it reached the read quota even + if no writers were waiting. + + 406. [bug] Log messages were occasionally lost or corrupted + due to a race condition in isc_log_doit(). + + 405. [func] Add support for selective forwarding (forward zones) + + 404. [bug] The request library didn't completely work with IPv6. + + 403. [bug] "host" did not use the search list. + + 402. [bug] Treat undefined acls as errors, rather than + warning and then later throwing an assertion. + [RT #252] + + 401. [func] Added simple database API. + + 400. [bug] SIG(0) signing and verifying was done incorrectly. + [RT #249] + + 399. [bug] When reloading the server with a config file + containing a syntax error, it could catch an + assertion failure trying to perform zone + maintenance on, or sending notifies from, + tentatively created zones whose views were + never fully configured and lacked an address + database and request manager. + + 398. [bug] "dig" sometimes caught an assertion failure when + using TSIG, depending on the key length. + + 397. [func] Added utility functions dns_view_gettsig() and + dns_view_getpeertsig(). + + 396. [doc] There is now a man page for "nsupdate" + in doc/man/bin/nsupdate.8. + + 395. [bug] nslookup printed incorrect RR type mnemonics + for RRs of type >= 21 [RT #237]. + + 394. [bug] Current name was not propagated via $INCLUDE. + + 393. [func] Initial answer while loading (awl) support. + Entry points: dns_master_loadfileinc(), + dns_master_loadstreaminc(), dns_master_loadbufferinc(). + Note: calls to dns_master_load*inc() should be rate + be rate limited so as to not use up all file + descriptors. + + 392. [func] Add ISC_R_FAMILYNOSUPPORT. Returned when OS does + not support the given address family requested. + + 391. [clarity] ISC_R_FAMILY -> ISC_R_FAMILYMISMATCH. + + 390. [func] The function dns_zone_setdbtype() now takes + an argc/argv style vector of words and sets + both the zone database type and its arguments, + making the functions dns_zone_adddbarg() + and dns_zone_cleardbargs() unnecessary. + + 389. [bug] Attempting to send a request over IPv6 using + dns_request_create() on a system without IPv6 + support caused an assertion failure [RT #235]. + + 388. [func] dig and host can now do reverse ipv6 lookups. + + 387. [func] Add dns_byaddr_createptrname(), which converts + an address into the name used by a PTR query. + + 386. [bug] Missing strdup() of ACL name caused random + ACL matching failures [RT #228]. + + 385. [cleanup] Removed functions dns_zone_equal(), dns_zone_print(), + and dns_zt_print(). + + 384. [bug] nsupdate was incorrectly limiting TTLs to 65535 instead + of 2147483647. + + 383. [func] When writing a master file, print the SOA and NS + records (and their SIGs) before other records. + + 382. [bug] named -u failed on many Linux systems where the + libc provided kernel headers do not match + the current kernel. + + 381. [bug] Check for IPV6_RECVPKTINFO and use it instead of + IPV6_PKTINFO if found. [RT #229] + + 380. [bug] nsupdate didn't work with IPv6. + + 379. [func] New library function isc_sockaddr_anyofpf(). + + 378. [func] named and lwresd will log the command line arguments + they were started with in the "starting ..." message. + + 377. [bug] When additional data lookups were refused due to + "allow-query", the databases were still being + attached causing reference leaks. + + 376. [bug] The server should always use good entropy when + performing cryptographic functions needing entropy. + + 375. [bug] Per-zone "allow-query" did not properly override the + view/global one for CNAME targets and additional + data [RT #220]. + + 374. [bug] SOA in authoritative negative responses had wrong TTL. + + 373. [func] nslookup is now installed by "make install". + + 372. [bug] Deal with Microsoft DNS servers appending two bytes of + garbage to zone transfer requests. + + 371. [bug] At high debug levels, doing an outgoing zone transfer + of a very large RRset could cause an assertion failure + during logging. + + 370. [bug] The error messages for roll-forward failures were + overly terse. + + 369. [func] Support new named.conf options, view and zone + statements: + + max-retry-time, min-retry-time, + max-refresh-time, min-refresh-time. + + 368. [func] Restructure the internal ".bind" view so that more + zones can be added to it. + + 367. [bug] Allow proper selection of server on nslookup command + line. + + 366. [func] Allow use of '-' batch file in dig for stdin. + + 365. [bug] nsupdate -k leaked memory. + + 364. [func] Added additional-from-{cache,auth} + + 363. [placeholder] + + 362. [bug] rndc no longer aborts if the configuration file is + missing an options statement. [RT #209] + + 361. [func] When the RBT find or chain functions set the name and + origin for a node that stores the root label + the name is now set to an empty name, instead of ".", + to simplify later use of the name and origin by + dns_name_concatenate(), dns_name_totext() or + dns_name_format(). + + 360. [func] dns_name_totext() and dns_name_format() now allow + an empty name to be passed, which is formatted as "@". + + 359. [bug] dnssec-signzone occasionally signed glue records. + + 358. [cleanup] Rename the intermediate files used by the dnssec + programs. + + 357. [bug] The zone file parser crashed if the argument + to $INCLUDE was a quoted string. + + 356. [cleanup] isc_task_send no longer requires event->sender to + be non-null. + + 355. [func] Added isc_dir_createunique(), similar to mkdtemp(). + + 354. [doc] Man pages for the dnssec tools are now included in + the distribution, in doc/man/dnssec. + + 353. [bug] double increment in lwres/gethost.c:copytobuf(). + [RT #187] + + 352. [bug] Race condition in dns_client_t startup could cause + an assertion failure. + + 351. [bug] Constructing a response with rcode SERVFAIL to a TSIG + signed query could crash the server. + + 350. [bug] Also-notify lists specified in the global options + block were not correctly reference counted, causing + a memory leak. + + 349. [bug] Processing a query with the CD bit set now works + as expected. + + 348. [func] New boolean named.conf options 'additional-from-auth' + and 'additional-from-cache' now supported in view and + global options statement. + + 347. [bug] Don't crash if an argument is left off options in dig. + + 346. [placeholder] + + 345. [bug] Large-scale changes/cleanups to dig: + * Significantly improve structure handling + * Don't pre-load entire batch files + * Add name/rr counting/limiting + * Fix SIGINT handling + * Shorten timeouts to match v8's behavior + + 344. [bug] When shutting down, lwresd sometimes tried + to shut down its client tasks twice, + triggering an assertion. + + 343. [bug] Although zone maintenance SOA queries and + notify requests were signed with TSIG keys + when configured for the server in case, + the TSIG was not verified on the response. + + 342. [bug] The wrong name was being passed to + dns_name_dup() when generating a TSIG + key using TKEY. + + 341. [func] Support 'key' clause in named.conf zone masters + statement to allow authentication via TSIG keys: + + masters { + 10.0.0.1 port 5353 key "foo"; + 10.0.0.2 ; + }; + + 340. [bug] The top-level COPYRIGHT file was missing from + the distribution. + + 339. [bug] DNSSEC validation of the response to an ANY + query at a name with a CNAME RR in a secure + zone triggered an assertion failure. + + 338. [bug] lwresd logged to syslog as named, not lwresd. + + 337. [bug] "dig" did not recognize "nsap-ptr" as an RR type + on the command line. + + 336. [bug] "dig -f" used 64 k of memory for each line in + the file. It now uses much less, though still + proportionally to the file size. + + 335. [bug] named would occasionally attempt recursion when + it was disallowed or undesired. + + 334. [func] Added hmac-md5 to libisc. + + 333. [bug] The resolver incorrectly accepted referrals to + domains that were not parents of the query name, + causing assertion failures. + + 332. [func] New function dns_name_reset(). + + 331. [bug] Only log "recursion denied" if RD is set. [RT #178] + + 330. [bug] Many debugging messages were partially formatted + even when debugging was turned off, causing a + significant decrease in query performance. + + 329. [func] omapi_auth_register() now takes a size_t argument for + the length of a key's secret data. Previously + OMAPI only stored secrets up to the first NUL byte. + + 328. [func] Added isc_base64_decodestring(). + + 327. [bug] rndc.conf parser wasn't correctly recognizing an IP + address where a host specification was required. + + 326. [func] 'keys' in an 'inet' control statement is now + required and must have at least one item in it. + A "not supported" warning is now issued if a 'unix' + control channel is defined. + + 325. [bug] isc_lex_gettoken was processing octal strings when + ISC_LEXOPT_CNUMBER was not set. + + 324. [func] In the resolver, turn EDNS0 off if there is no + response after a number of retransmissions. + This is to allow queries some chance of succeeding + even if all the authoritative servers of a zone + silently discard EDNS0 requests instead of + sending an error response like they ought to. + + 323. [bug] dns_rbt_findname() did not ignore empty rbt nodes. + Because of this, servers authoritative for a parent + and grandchild zone but not authoritative for the + intervening child zone did not correctly issue + referrals to the servers of the child zone. + + 322. [bug] Queries for KEY RRs are now sent to the parent + server before the authoritative one, making + DNSSEC insecurity proofs work in many cases + where they previously didn't. + + 321. [bug] When synthesizing a CNAME RR for a DNAME + response, query_addcname() failed to initialize + the type and class of the CNAME dns_rdata_t, + causing random failures. + + 320. [func] Multiple rndc changes: parses an rndc.conf file, + uses authentication to talk to named, command + line syntax changed. This will all be described + in the ARM. + + 319. [func] The named.conf "controls" statement is now used + to configure the OMAPI command channel. + + 318. [func] dns_c_ndcctx_destroy() could never return anything + except ISC_R_SUCCESS; made it have void return instead. + + 317. [func] Use callbacks from libomapi to determine if a + new connection is valid, and if a key requested + to be used with that connection is valid. + + 316. [bug] Generate a warning if we detect an unexpected + but treat as . + + 315. [bug] Handle non-empty blanks lines. [RT #163] + + 314. [func] The named.conf controls statement can now have + more than one key specified for the inet clause. + + 313. [bug] When parsing resolv.conf, don't terminate on an + error. Instead, parse as much as possible, but + still return an error if one was found. + + 312. [bug] Increase the number of allowed elements in the + resolv.conf search path from 6 to 8. If there + are more than this, ignore the remainder rather + than returning a failure in lwres_conf_parse. + + 311. [bug] lwres_conf_parse failed when the first line of + resolv.conf was empty or a comment. + + 310. [func] Changes to named.conf "controls" statement (inet + subtype only) + + - support "keys" clause + + controls { + inet * port 1024 + allow { any; } keys { "foo"; } + } + + - allow "port xxx" to be left out of statement, + in which case it defaults to omapi's default port + of 953. + + 309. [bug] When sending a referral, the server did not look + for name server addresses as glue in the zone + holding the NS RRset in the case where this zone + was not the same as the one where it looked for + name server addresses as authoritative data. + + 308. [bug] Treat a SOA record not at top of zone as an error + when loading a zone. [RT #154] + + 307. [bug] When canceling a query, the resolver didn't check for + isc_socket_sendto() calls that did not yet have their + completion events posted, so it could (rarely) end up + destroying the query context and then want to use + it again when the send event posted, triggering an + assertion as it tried to cancel an already-canceled + query. [RT #77] + + 306. [bug] Reading HMAC-MD5 private key files didn't work. + + 305. [bug] When reloading the server with a config file + containing a syntax error, it could catch an + assertion failure trying to perform zone + maintenance on tentatively created zones whose + views were never fully configured and lacked + an address database. + + 304. [bug] If more than LWRES_CONFMAXNAMESERVERS servers + are listed in resolv.conf, silently ignore them + instead of returning failure. + + 303. [bug] Add additional sanity checks to differentiate a AXFR + response vs a IXFR response. [RT #157] + + 302. [bug] In dig, host, and nslookup, MXNAME should be large + enough to hold any legal domain name in presentation + format + terminating NULL. + + 301. [bug] Uninitialized pointer in host:printmessage(). [RT #159] + + 300. [bug] Using both and didn't work + on platforms lacking IPv6 because each included their + own ipv6 header file for the missing definitions. Now + each library's ipv6.h defines the wrapper symbol of + the other (ISC_IPV6_H and LWRES_IPV6_H). + + 299. [cleanup] Get the user and group information before changing the + root directory, so the administrator does not need to + keep a copy of the user and group databases in the + chroot'ed environment. Suggested by Hakan Olsson. + + 298. [bug] A mutex deadlock occurred during shutdown of the + interface manager under certain conditions. + Digital Unix systems were the most affected. + + 297. [bug] Specifying a key name that wasn't fully qualified + in certain parts of the config file could cause + an assertion failure. + + 296. [bug] "make install" from a separate build directory + failed unless configure had been run in the source + directory, too. + + 295. [bug] When invoked with type==CNAME and a message + not constructed by dns_message_parse(), + dns_message_findname() failed to find anything + due to checking for attribute bits that are set + only in dns_message_parse(). This caused an + infinite loop when constructing the response to + an ANY query at a CNAME in a secure zone. + + 294. [bug] If we run out of space in while processing glue + when reading a master file and commit "current name" + reverts to "name_current" instead of staying as + "name_glue". + + 293. [port] Add support for FreeBSD 4.0 system tests. + + 292. [bug] Due to problems with the way some operating systems + handle simultaneous listening on IPv4 and IPv6 + addresses, the server no longer listens on IPv6 + addresses by default. To revert to the previous + behavior, specify "listen-on-v6 { any; };" in + the config file. + + 291. [func] Caching servers no longer send outgoing queries + over TCP just because the incoming recursive query + was a TCP one. + + 290. [cleanup] +twiddle option to dig (for testing only) removed. + + 289. [cleanup] dig is now installed in $bindir instead of $sbindir. + host is now installed in $bindir. (Be sure to remove + any $sbindir/dig from a previous release.) + + 288. [func] rndc is now installed by "make install" into $sbindir. + + 287. [bug] rndc now works again as "rndc 127.1 reload" (for + only that task). Parsing its configuration file and + using digital signatures for authentication has been + disabled until named supports the "controls" statement, + post-9.0.0. + + 286. [bug] On Solaris 2, when named inherited a signal state + where SIGHUP had the SIG_IGN action, SIGHUP would + be ignored rather than causing the server to reload + its configuration. + + 285. [bug] A change made to the dst API for beta4 inadvertently + broke OMAPI's creation of a dst key from an incoming + message, causing an assertion to be triggered. Fixed. + + 284. [func] The DNSSEC key generation and signing tools now + generate randomness from keyboard input on systems + that lack /dev/random. + + 283. [cleanup] The 'lwresd' program is now a link to 'named'. + + 282. [bug] The lexer now returns ISC_R_RANGE if parsed integer is + too big for an unsigned long. + + 281. [bug] Fixed list of recognized config file category names. + + 280. [func] Add isc-config.sh, which can be used to more + easily build applications that link with + our libraries. + + 279. [bug] Private omapi function symbols shared between + two or more files in libomapi.a were not namespace + protected using the ISC convention of starting with + the library name and two underscores ("omapi__"...) + + 278. [bug] bin/named/logconf.c:category_fromconf() didn't take + note of when isc_log_categorybyname() wasn't able + to find the category name and would then apply the + channel list of the unknown category to all categories. + + 277. [bug] isc_log_categorybyname() and isc_log_modulebyname() + would fail to find the first member of any category + or module array apart from the internal defaults. + Thus, for example, the "notify" category was improperly + configured by named. + + 276. [bug] dig now supports maximum sized TCP messages. + + 275. [bug] The definition of lwres_gai_strerror() was missing + the lwres_ prefix. + + 274. [bug] TSIG AXFR verify failed when talking to a BIND 8 + server. + + 273. [func] The default for the 'transfer-format' option is + now 'many-answers'. This will break zone transfers + to BIND 4.9.5 and older unless there is an explicit + 'one-answer' configuration. + + 272. [bug] The sending of large TCP responses was canceled + in mid-transmission due to a race condition + caused by the failure to set the client object's + "newstate" variable correctly when transitioning + to the "working" state. + + 271. [func] Attempt to probe the number of cpus in named + if unspecified rather than defaulting to 1. + + 270. [func] Allow maximum sized TCP answers. + + 269. [bug] Failed DNSSEC validations could cause an assertion + failure by causing clone_results() to be called with + with hevent->node == NULL. + + 268. [doc] A plain text version of the Administrator + Reference Manual is now included in the distribution, + as doc/arm/Bv9ARM.txt. + + 267. [func] Nsupdate is now provided in the distribution. + + 266. [bug] zone.c:save_nsrrset() node was not initialized. + + 265. [bug] dns_request_create() now works for TCP. + + 264. [func] Dispatch can not take TCP sockets in connecting + state. Set DNS_DISPATCHATTR_CONNECTED when calling + dns_dispatch_createtcp() for connected TCP sockets + or call dns_dispatch_starttcp() when the socket is + connected. + + 263. [func] New logging channel type 'stderr' + + channel some-name { + stderr; + severity error; + } + + 262. [bug] 'master' was not initialized in zone.c:stub_callback(). + + 261. [func] Add dns_zone_markdirty(). + + 260. [bug] Running named as a non-root user failed on Linux + kernels new enough to support retaining capabilities + after setuid(). + + 259. [func] New random-device and random-seed-file statements + for global options block of named.conf. Both accept + a single string argument. + + 258. [bug] Fixed printing of lwres_addr_t.address field. + + 257. [bug] The server detached the last zone manager reference + too early, while it could still be in use by queries. + This manifested itself as assertion failures during the + shutdown process for busy name servers. [RT #133] + + 256. [func] isc_ratelimiter_t now has attach/detach semantics, and + isc_ratelimiter_shutdown guarantees that the rate + limiter is detached from its task. + + 255. [func] New function dns_zonemgr_attach(). + + 254. [bug] Suppress "query denied" messages on additional data + lookups. + + --- 9.0.0b4 released --- + + 253. [func] resolv.conf parser now recognizes ';' and '#' as + comments (anywhere in line, not just as the beginning). + + 252. [bug] resolv.conf parser mishandled masks on sortlists. + It also aborted when an unrecognized keyword was seen, + now it silently ignores the entire line. + + 251. [bug] lwresd caught an assertion failure on startup. + + 250. [bug] fixed handling of size+unit when value would be too + large for internal representation. + + 249. [cleanup] max-cache-size config option now takes a size-spec + like 'datasize', except 'default' is not allowed. + + 248. [bug] global lame-ttl option was not being printed when + config structures were written out. + + 247. [cleanup] Rename cache-size config option to max-cache-size. + + 246. [func] Rename global option cachesize to cache-size and + add corresponding option to view statement. + + 245. [bug] If an uncompressed name will take more than 255 + bytes and the buffer is sufficiently long, + dns_name_fromwire should return DNS_R_FORMERR, + not ISC_R_NOSPACE. This bug caused cause the + server to catch an assertion failure when it + received a query for a name longer than 255 + bytes. + + 244. [bug] empty named.conf file and empty options statement are + now parsed properly. + + 243. [func] new cachesize option for named.conf + + 242. [cleanup] fixed incorrect warning about auth-nxdomain usage. + + 241. [cleanup] nscount and soacount have been removed from the + dns_master_*() argument lists. + + 240. [func] databases now come in three flavours: zone, cache + and stub. + + 239. [func] If ISC_MEM_DEBUG is enabled, the variable + isc_mem_debugging controls whether messages + are printed or not. + + 238. [cleanup] A few more compilation warnings have been quieted: + + missing sigwait prototype on BSD/OS 4.0/4.0.1. + + PTHREAD_ONCE_INIT unbraced initializer warnings on + Solaris 2.8. + + IN6ADDR_ANY_INIT unbraced initializer warnings on + BSD/OS 4.*, Linux and Solaris 2.8. + + 237. [bug] If connect() returned ENOBUFS when the resolver was + initiating a TCP query, the socket didn't get + destroyed, and the server did not shut down cleanly. + + 236. [func] Added new listen-on-v6 config file statement. + + 235. [func] Consider it a config file error if a listen-on + statement has an IPv6 address in it, or a + listen-on-v6 statement has an IPv4 address in it. + + 234. [bug] Allow a trusted-key's first field (domain-name) be + either a quoted or an unquoted string, instead of + requiring a quoted string. + + 233. [cleanup] Convert all config structure integer values to unsigned + integer (isc_uint32_t) to match grammar. + + 232. [bug] Allow slave zones to not have a file. + + 231. [func] Support new 'port' clause in config file options + section. Causes 'listen-on', 'masters' and + 'also-notify' statements to use its value instead of + default (53). + + 230. [func] Replace the dst sign/verify API with a cleaner one. + + 229. [func] Support config file sig-validity-interval statement + in options, views and zone statements (master + zones only). + + 228. [cleanup] Logging messages in config module stripped of + trailing period. + + 227. [cleanup] The enumerated identifiers dns_rdataclass_*, + dns_rcode_*, dns_opcode_*, and dns_trust_* are + also now cast to their appropriate types, as with + dns_rdatatype_* in item number 225 below. + + 226. [func] dns_name_totext() now always prints the root name as + '.', even when omit_final_dot is true. + + 225. [cleanup] The enumerated dns_rdatatype_* identifiers are now + cast to dns_rdatatype_t via macros of their same name + so that they are of the proper integral type wherever + a dns_rdatatype_t is needed. + + 224. [cleanup] The entire project builds cleanly with gcc's + -Wcast-qual and -Wwrite-strings warnings enabled, + which is now the default when using gcc. (Warnings + from confparser.c, because of yacc's code, are + unfortunately to be expected.) + + 223. [func] Several functions were re-prototyped to qualify one + or more of their arguments with "const". Similarly, + several functions that return pointers now have + those pointers qualified with const. + + 222. [bug] The global 'also-notify' option was ignored. + + 221. [bug] An uninitialized variable was sometimes passed to + dns_rdata_freestruct() when loading a zone, causing + an assertion failure. + + 220. [cleanup] Set the default outgoing port in the view, and + set it in sockaddrs returned from the ADB. + [31-May-2000 explorer] + + 219. [bug] Signed truncated messages more correctly follow + the respective specs. + + 218. [func] When an rdataset is signed, its ttl is normalized + based on the signature validity period. + + 217. [func] Also-notify and trusted-keys can now be used in + the 'view' statement. + + 216. [func] The 'max-cache-ttl' and 'max-ncache-ttl' options + now work. + + 215. [bug] Failures at certain points in request processing + could cause the assertion INSIST(client->lockview + == NULL) to be triggered. + + 214. [func] New public function isc_netaddr_format(), for + formatting network addresses in log messages. + + 213. [bug] Don't leak memory when reloading the zone if + an update-policy clause was present in the old zone. + + 212. [func] Added dns_message_get/settsigkey, to make TSIG + key management reasonable. + + 211. [func] The 'key' and 'server' statements can now occur + inside 'view' statements. + + 210. [bug] The 'allow-transfer' option was ignored for slave + zones, and the 'transfers-per-ns' option was + was ignored for all zones. + + 209. [cleanup] Upgraded openssl files to new version 0.9.5a + + 208. [func] Added ISC_OFFSET_MAXIMUM for the maximum value + of an isc_offset_t. + + 207. [func] The dnssec tools properly use the logging subsystem. + + 206. [cleanup] dst now stores the key name as a dns_name_t, not + a char *. + + 205. [cleanup] On IRIX, turn off the mostly harmless warnings 1692 + ("prototyped function redeclared without prototype") + and 1552 ("variable ... set but not used") when + compiling in the lib/dns/sec/{dnssafe,openssl} + directories, which contain code imported from outside + sources. + + 204. [cleanup] On HP/UX, pass +vnocompatwarnings to the linker + to quiet the warnings that "The linked output may not + run on a PA 1.x system." + + 203. [func] notify and zone soa queries are now tsig signed when + appropriate. + + 202. [func] isc_lex_getsourceline() changed from returning int + to returning unsigned long, the type of its underlying + counter. + + 201. [cleanup] Removed the test/sdig program, it has been + replaced by bin/dig/dig. + + --- 9.0.0b3 released --- + + 200. [bug] Failures in sending query responses to clients + (e.g., running out of network buffers) were + not logged. + + 199. [bug] isc_heap_delete() sometimes violated the heap + invariant, causing timer events not to be posted + when due. + + 198. [func] Dispatch managers hold memory pools which + any managed dispatcher may use. This allows + us to avoid dipping into the memory context for + most allocations. [19-May-2000 explorer] + + 197. [bug] When an incoming AXFR or IXFR completes, the + zone's internal state is refreshed from the + SOA data. [19-May-2000 explorer] + + 196. [func] Dispatchers can be shared easily between views + and/or interfaces. [19-May-2000 explorer] + + 195. [bug] Including the NXT record of the root domain + in a negative response caused an assertion + failure. + + 194. [doc] The PDF version of the Administrator's Reference + Manual is no longer included in the ISC BIND9 + distribution. + + 193. [func] changed dst_key_free() prototype. + + 192. [bug] Zone configuration validation is now done at end + of config file parsing, and before loading + callbacks. + + 191. [func] Patched to compile on UnixWare 7.x. This platform + is not directly supported by the ISC. + + 190. [cleanup] The DNSSEC tools have been moved to a separate + directory dnssec/ and given the following new, + more descriptive names: + + dnssec-keygen + dnssec-signzone + dnssec-signkey + dnssec-makekeyset + + Their command line arguments have also been changed to + be more consistent. dnssec-keygen now prints the + name of the generated key files (sans extension) + on standard output to simplify its use in automated + scripts. + + 189. [func] isc_time_secondsastimet(), a new function, will ensure + that the number of seconds in an isc_time_t does not + exceed the range of a time_t, or return ISC_R_RANGE. + Similarly, isc_time_now(), isc_time_nowplusinterval(), + isc_time_add() and isc_time_subtract() now check the + range for overflow/underflow. In the case of + isc_time_subtract, this changed a calling requirement + (ie, something that could generate an assertion) + into merely a condition that returns an error result. + isc_time_add() and isc_time_subtract() were void- + valued before but now return isc_result_t. + + 188. [func] Log a warning message when an incoming zone transfer + contains out-of-zone data. + + 187. [func] isc_ratelimiter_enqueue() has an additional argument + 'task'. + + 186. [func] dns_request_getresponse() has an additional argument + 'preserve_order'. + + 185. [bug] Fixed up handling of ISC_MEMCLUSTER_LEGACY. Several + public functions did not have an isc__ prefix, and + referred to functions that had previously been + renamed. + + 184. [cleanup] Variables/functions which began with two leading + underscores were made to conform to the ANSI/ISO + standard, which says that such names are reserved. + + 183. [func] ISC_LOG_PRINTTAG option for log channels. Useful + for logging the program name or other identifier. + + 182. [cleanup] New command-line parameters for dnssec tools + + 181. [func] Added dst_key_buildfilename and dst_key_parsefilename + + 180. [func] New isc_result_t ISC_R_RANGE. Supersedes DNS_R_RANGE. + + 179. [func] options named.conf statement *must* now come + before any zone or view statements. + + 178. [func] Post-load of named.conf check verifies a slave zone + has non-empty list of masters defined. + + 177. [func] New per-zone boolean: + + enable-zone yes | no ; + + intended to let a zone be disabled without having + to comment out the entire zone statement. + + 176. [func] New global and per-view option: + + max-cache-ttl number + + 175. [func] New global and per-view option: + + additional-data internal | minimal | maximal; + + 174. [func] New public function isc_sockaddr_format(), for + formatting socket addresses in log messages. + + 173. [func] Keep a queue of zones waiting for zone transfer + quota so that a new transfer can be dispatched + immediately whenever quota becomes available. + + 172. [bug] $TTL directive was sometimes missing from dumped + master files because totext_ctx_init() failed to + initialize ctx->current_ttl_valid. + + 171. [cleanup] On NetBSD systems, the mit-pthreads or + unproven-pthreads library is now always used + unless --with-ptl2 is explicitly specified on + the configure command line. The + --with-mit-pthreads option is no longer needed + and has been removed. + + 170. [cleanup] Remove inter server consistency checks from zone, + these should return as a separate module in 9.1. + dns_zone_checkservers(), dns_zone_checkparents(), + dns_zone_checkchildren(), dns_zone_checkglue(). + + Remove dns_zone_setadb(), dns_zone_setresolver(), + dns_zone_setrequestmgr() these should now be found + via the view. + + 169. [func] ratelimiter can now process N events per interval. + + 168. [bug] include statements in named.conf caused syntax errors + due to not consuming the semicolon ending the include + statement before switching input streams. + + 167. [bug] Make lack of masters for a slave zone a soft error. + + 166. [bug] Keygen was overwriting existing keys if key_id + conflicted, now it will retry, and non-null keys + with key_id == 0 are not generated anymore. Key + was not able to generate NOAUTHCONF DSA key, + increased RSA key size to 2048 bits. + + 165. [cleanup] Silence "end-of-loop condition not reached" warnings + from Solaris compiler. + + 164. [func] Added functions isc_stdio_open(), isc_stdio_close(), + isc_stdio_seek(), isc_stdio_read(), isc_stdio_write(), + isc_stdio_flush(), isc_stdio_sync(), isc_file_remove() + to encapsulate nonportable usage of errno and sync. + + 163. [func] Added result codes ISC_R_FILENOTFOUND and + ISC_R_FILEEXISTS. + + 162. [bug] Ensure proper range for arguments to ctype.h functions. + + 161. [cleanup] error in yyparse prototype that only HPUX caught. + + 160. [cleanup] getnet*() are not going to be implemented at this + stage. + + 159. [func] Redefinition of config file elements is now an + error (instead of a warning). + + 158. [bug] Log channel and category list copy routines + weren't assigning properly to output parameter. + + 157. [port] Fix missing prototype for getopt(). + + 156. [func] Support new 'database' statement in zone. + + database "quoted-string"; + + 155. [bug] ns_notify_start() was not detaching the found zone. + + 154. [func] The signer now logs libdns warnings to stderr even when + not verbose, and in a nicer format. + + 153. [func] dns_rdata_tostruct() 'mctx' is now optional. If 'mctx' + is NULL then you need to preserve the 'rdata' until + you have finished using the structure as there may be + references to the associated memory. If 'mctx' is + non-NULL it is guaranteed that there are no references + to memory associated with 'rdata'. + + dns_rdata_freestruct() must be called if 'mctx' was + non-NULL and may safely be called if 'mctx' was NULL. + + 152. [bug] keygen dumped core if domain name argument was omitted + from command line. + + 151. [func] Support 'disabled' statement in zone config (causes + zone to be parsed and then ignored). Currently must + come after the 'type' clause. + + 150. [func] Support optional ports in masters and also-notify + statements: + + masters [ port xxx ] { y.y.y.y [ port zzz ] ; } + + 149. [cleanup] Removed unused argument 'olist' from + dns_c_view_unsetordering(). + + 148. [cleanup] Stop issuing some warnings about some configuration + file statements that were not implemented, but now are. + + 147. [bug] Changed yacc union size to be smaller for yaccs that + put yacc-stack on the real stack. + + 146. [cleanup] More general redundant header file cleanup. Rather + than continuing to itemize every header which changed, + this changelog entry just notes that if a header file + did not need another header file that it was including + in order to provide its advertised functionality, the + inclusion of the other header file was removed. See + util/check-includes for how this was tested. + + 145. [cleanup] Added and ISC_LANG_BEGINDECLS/ + ISC_LANG_ENDDECLS to header files that had function + prototypes, and removed it from those that did not. + + 144. [cleanup] libdns header files too numerous to name were made + to conform to the same style for multiple inclusion + protection. + + 143. [func] Added function dns_rdatatype_isknown(). + + 142. [cleanup] does not need or + . + + 141. [bug] Corrupt requests with multiple questions could + cause an assertion failure. + + 140. [cleanup] does not need or . + + 139. [cleanup] now includes instead of + and . + + 138. [cleanup] isc_strtouq moved from str.[ch] to string.[ch] and + renamed isc_string_touint64. isc_strsep moved from + strsep.c to string.c and renamed isc_string_separate. + + 137. [cleanup] , , + , and + made to conform to the same style for multiple + inclusion protection. + + 136. [cleanup] , , + and Win32's needed + ISC_LANG_BEGINDECLS/ISC_LANG_ENDDECLS. + + 135. [cleanup] Win32's did not need + or , now uses in place + of , and needed ISC_LANG_BEGINDECLS + and ISC_LANG_ENDDECLS. + + 134. [cleanup] does not need . + + 133. [cleanup] needs . + + 132. [cleanup] does not need , but does + need . + + 131. [cleanup] and need + for ISC_R_* codes used in macros. + + 130. [cleanup] does not need or + , and now includes + instead of . + + 129. [bug] The 'default_debug' log channel was not set up when + 'category default' was present in the config file + + 128. [cleanup] had ISC_LANG_BEGINDECLS instead of + ISC_LANG_ENDDECLS at end of header. + + 127. [cleanup] The contracts for the comparison routines + dns_name_fullcompare(), dns_name_compare(), + dns_name_rdatacompare(), and dns_rdata_compare() now + specify that the order value returned is < 0, 0, or > 0 + instead of -1, 0, or 1. + + 126. [cleanup] and need . + + 125. [cleanup] , , , + , , , and + do not need . + + 124. [func] signer now imports parent's zone key signature + and creates null keys/sets zone status bit for + children when necessary + + 123. [cleanup] does not need . + + 122. [cleanup] does not need or + . + + 121. [cleanup] does not need or + . Multiple inclusion protection + symbol fixed from ISC_SYMBOL_H to ISC_SYMTAB_H. + isc_symtab_t moved to . + + 120. [cleanup] does not need , + , , or + . + + 119. [cleanup] structure definitions for generic rdata structures do + not have _generic_ in their names. + + 118. [cleanup] libdns.a is now namespace-clean, on NetBSD, excepting + YACC crust (yyparse, etc) [2000-apr-27 explorer] + + 117. [cleanup] libdns.a changes: + dns_zone_clearnotify() and dns_zone_addnotify() + are replaced by dns_zone_setnotifyalso(). + dns_zone_clearmasters() and dns_zone_addmaster() + are replaced by dns_zone_setmasters(). + + 116. [func] Added for isc_offset_t (aka off_t + on Unix systems). + + 115. [port] Shut up the -Wmissing-declarations warning about + 's __sputaux on BSD/OS pre-4.1. + + 114. [cleanup] does not need or + . + + 113. [func] Utility programs dig and host added. + + 112. [cleanup] does not need . + + 111. [cleanup] does not need or + . + + 110. [cleanup] does not need or + . + + 109. [bug] "make depend" did nothing for + bin/tests/{db,mem,sockaddr,tasks,timers}/. + + 108. [cleanup] DNS_SETBIT/DNS_GETBIT/DNS_CLEARBIT moved from + to and renamed to + DNS_BIT_SET/DNS_BIT_GET/DNS_BIT_CLEAR. + + 107. [func] Add keysigner and keysettool. + + 106. [func] Allow dnssec verifications to ignore the validity + period. Used by several of the dnssec tools. + + 105. [doc] doc/dev/coding.html expanded with other + implicit conventions the developers have used. + + 104. [bug] Made compress_add and compress_find static to + lib/dns/compress.c. + + 103. [func] libisc buffer API changes for : + Added: + isc_buffer_base(b) (pointer) + isc_buffer_current(b) (pointer) + isc_buffer_active(b) (pointer) + isc_buffer_used(b) (pointer) + isc_buffer_length(b) (int) + isc_buffer_usedlength(b) (int) + isc_buffer_consumedlength(b) (int) + isc_buffer_remaininglength(b) (int) + isc_buffer_activelength(b) (int) + isc_buffer_availablelength(b) (int) + Removed: + ISC_BUFFER_USEDCOUNT(b) + ISC_BUFFER_AVAILABLECOUNT(b) + isc_buffer_type(b) + Changed names: + isc_buffer_used(b, r) -> + isc_buffer_usedregion(b, r) + isc_buffer_available(b, r) -> + isc_buffer_available_region(b, r) + isc_buffer_consumed(b, r) -> + isc_buffer_consumedregion(b, r) + isc_buffer_active(b, r) -> + isc_buffer_activeregion(b, r) + isc_buffer_remaining(b, r) -> + isc_buffer_remainingregion(b, r) + + Buffer types were removed, so the ISC_BUFFERTYPE_* + macros are no more, and the type argument to + isc_buffer_init and isc_buffer_allocate were removed. + isc_buffer_putstr is now void (instead of isc_result_t) + and requires that the caller ensure that there + is enough available buffer space for the string. + + 102. [port] Correctly detect inet_aton, inet_pton and inet_ptop + on BSD/OS 4.1. + + 101. [cleanup] Quieted EGCS warnings from lib/isc/print.c. + + 100. [cleanup] does not need or + . isc_random_t moved to . + + 99. [cleanup] Rate limiter now has separate shutdown() and + destroy() functions, and it guarantees that all + queued events are delivered even in the shutdown case. + + 98. [cleanup] does not need or + unless ISC_PLATFORM_NEEDVSNPRINTF is defined. + + 97. [cleanup] does not need or + . + + 96. [cleanup] does not need . + + 95. [cleanup] does not need . + + 94. [cleanup] Some installed header files did not compile as C++. + + 93. [cleanup] does not need . + + 92. [cleanup] does not need , , + or . + + 91. [cleanup] does not need or + . + + 90. [cleanup] Removed unneeded ISC_LANG_BEGINDECLS/ISC_LANG_ENDDECLS + from . + + 89. [cleanup] does not need . + + 88. [cleanup] does not need or + . isc_interface_t and isc_interfaceiter_t + moved to . + + 87. [cleanup] does not need , + or . + + 86. [cleanup] isc_bufferlist_t moved from to + . + + 85. [cleanup] does not need , + , , or + . + + 84. [func] allow-query ACL checks now apply to all data + added to a response. + + 83. [func] If the server is authoritative for both a + delegating zone and its (nonsecure) delegatee, and + a query is made for a KEY RR at the top of the + delegatee, then the server will look for a KEY + in the delegator if it is not found in the delegatee. + + 82. [cleanup] does not need . + + 81. [cleanup] and do not need + . + + 80. [cleanup] does not need or . + + 79. [cleanup] does not need . + + 78. [cleanup] lwres_conftest renamed to lwresconf_test for + consistency with other *_test programs. + + 77. [cleanup] typedef of isc_time_t and isc_interval_t moved from + to . + + 76. [cleanup] Rewrote keygen. + + 75. [func] Don't load a zone if its database file is older + than the last time the zone was loaded. + + 74. [cleanup] Removed mktemplate.o and ufile.o from libisc.a, + subsumed by file.o. + + 73. [func] New "file" API in libisc, including new function + isc_file_getmodtime, isc_mktemplate renamed to + isc_file_mktemplate and isc_ufile renamed to + isc_file_openunique. By no means an exhaustive API, + it is just what's needed for now. + + 72. [func] DNS_RBTFIND_NOPREDECESSOR and DNS_RBTFIND_NOOPTIONS + added for dns_rbt_findnode, the former to disable the + setting of the chain to the predecessor, and the + latter to make clear when no options are set. + + 71. [cleanup] Made explicit the implicit REQUIREs of + isc_time_seconds, isc_time_nanoseconds, and + isc_time_subtract. + + 70. [func] isc_time_set() added. + + 69. [bug] The zone object's master and also-notify lists grew + longer with each server reload. + + 68. [func] Partial support for SIG(0) on incoming messages. + + 67. [performance] Allow use of alternate (compile-time supplied) + OpenSSL libraries/headers. + + 66. [func] Data in authoritative zones should have a trust level + beyond secure. + + 65. [cleanup] Removed obsolete typedef of dns_zone_callbackarg_t + from . + + 64. [func] The RBT, DB, and zone table APIs now allow the + caller find the most-enclosing superdomain of + a name. + + 63. [func] Generate NOTIFY messages. + + 62. [func] Add UDP refresh support. + + 61. [cleanup] Use single quotes consistently in log messages. + + 60. [func] Catch and disallow singleton types on message + parse. + + 59. [bug] Cause net/host unreachable to be a hard error + when sending and receiving. + + 58. [bug] bin/named/query.c could sometimes trigger the + (client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) + == 0 assertion in query_newname(). + + 57. [func] Added dns_nxt_typepresent() + + 56. [bug] SIG records were not properly returned in cached + negative answers. + + 55. [bug] Responses containing multiple names in the authority + section were not negatively cached. + + 54. [bug] If a fetch with sigrdataset==NULL joined one with + sigrdataset!=NULL or vice versa, the resolver + could catch an assertion or lose signature data, + respectively. + + 53. [port] freebsd 4.0: lib/isc/unix/socket.c requires + . + + 52. [bug] rndc: taskmgr and socketmgr were not initialized + to NULL. + + 51. [cleanup] dns/compress.h and dns/zt.h did not need to include + dns/rbt.h; it was needed only by compress.c and zt.c. + + 50. [func] RBT deletion no longer requires a valid chain to work, + and dns_rbt_deletenode was added. + + 49. [func] Each cache now has its own mctx. + + 48. [func] isc_task_create() no longer takes an mctx. + isc_task_mem() has been eliminated. + + 47. [func] A number of modules now use memory context reference + counting. + + 46. [func] Memory contexts are now reference counted. + Added isc_mem_inuse() and isc_mem_preallocate(). + Renamed isc_mem_destroy_check() to + isc_mem_setdestroycheck(). + + 45. [bug] The trusted-key statement incorrectly loaded keys. + + 44. [bug] Don't include authority data if it would force us + to unset the AD bit in the message. + + 43. [bug] DNSSEC verification of cached rdatasets was failing. + + 42. [cleanup] Simplified logging of messages with embedded domain + names by introducing a new convenience function + dns_name_format(). + + 41. [func] Use PR_SET_KEEPCAPS on Linux 2.3.99-pre3 and later + to allow 'named' to run as a non-root user while + retaining the ability to bind() to privileged + ports. + + 40. [func] Introduced new logging category "dnssec" and + logging module "dns/validator". + + 39. [cleanup] Moved the typedefs for isc_region_t, isc_textregion_t, + and isc_lex_t to . + + 38. [bug] TSIG signed incoming zone transfers work now. + + 37. [bug] If the first RR in an incoming zone transfer was + not an SOA, the server died with an assertion failure + instead of just reporting an error. + + 36. [cleanup] Change DNS_R_SUCCESS (and others) to ISC_R_SUCCESS + + 35. [performance] Log messages which are of a level too high to be + logged by any channel in the logging configuration + will not cause the log mutex to be locked. + + 34. [bug] Recursion was allowed even with 'recursion no'. + + 33. [func] The RBT now maintains a parent pointer at each node. + + 32. [cleanup] bin/lwresd/client.c needs for memset() + prototype. + + 31. [bug] Use ${LIBTOOL} to compile bin/named/main.@O@. + + 30. [func] config file grammar change to support optional + class type for a view. + + 29. [func] support new config file view options: + + auth-nxdomain recursion query-source + query-source-v6 transfer-source + transfer-source-v6 max-transfer-time-out + max-transfer-idle-out transfer-format + request-ixfr provide-ixfr cleaning-interval + fetch-glue notify rfc2308-type1 lame-ttl + max-ncache-ttl min-roots + + 28. [func] support lame-ttl, min-roots and serial-queries + config global options. + + 27. [bug] Only include on BSD/OS 4.[01]*. + Including it on other platforms (eg, NetBSD) can + cause a forced #error from the C preprocessor. + + 26. [func] new match-clients statement in config file view. + + 25. [bug] make install failed to install and + . + + 24. [cleanup] Eliminate some unnecessary #includes of header + files from header files. + + 23. [cleanup] Provide more context in log messages about client + requests, using a new function ns_client_log(). + + 22. [bug] SIGs weren't returned in the answer section when + the query resulted in a fetch. + + 21. [port] Look at STD_CINCLUDES after CINCLUDES during + compilation, so additional system include directories + can be searched but header files in the bind9 source + tree with conflicting names take precedence. This + avoids issues with installed versions of dnssafe and + openssl. + + 20. [func] Configuration file post-load validation of zones + failed if there were no zones. + + 19. [bug] dns_zone_notifyreceive() failed to unlock the zone + lock in certain error cases. + + 18. [bug] Use AC_TRY_LINK rather than AC_TRY_COMPILE in + configure.in to check for presence of in6addr_any. + + 17. [func] Do configuration file post-load validation of zones. + + 16. [bug] put quotes around key names on config file + output to avoid possible keyword clashes. + + 15. [func] Add dns_name_dupwithoffsets(). This function is + improves comparison performance for duped names. + + 14. [bug] free_rbtdb() could have 'put' unallocated memory in + an unlikely error path. + + 13. [bug] lib/dns/master.c and lib/dns/xfrin.c didn't ignore + out-of-zone data. + + 12. [bug] Fixed possible uninitialized variable error. + + 11. [bug] axfr_rrstream_first() didn't check the result code of + db_rr_iterator_first(), possibly causing an assertion + to be triggered later. + + 10. [bug] A bug in the code which makes EDNS0 OPT records in + bin/named/client.c and lib/dns/resolver.c could + trigger an assertion. + + 9. [cleanup] replaced bit-setting code in confctx.c and replaced + repeated code with macro calls. + + 8. [bug] Shutdown of incoming zone transfer accessed + freed memory. + + 7. [cleanup] removed 'listen-on' from view statement. + + 6. [bug] quote RR names when generating config file to + prevent possible clash with config file keywords + (such as 'key'). + + 5. [func] syntax change to named.conf file: new ssu grant/deny + statements must now be enclosed by an 'update-policy' + block. + + 4. [port] bin/named/unix/os.c didn't compile on systems with + linux 2.3 kernel includes due to conflicts between + C library includes and the kernel includes. We now + get only what we need from , and + avoid pulling in other linux kernel .h files. + + 3. [bug] TKEYs go in the answer section of responses, not + the additional section. + + 2. [bug] Generating cryptographic randomness failed on + systems without /dev/random. + + 1. [bug] The installdirs rule in + lib/isc/unix/include/isc/Makefile.in had a typo which + prevented the isc directory from being created if it + didn't exist. + + --- 9.0.0b2 released --- + +# This tells Emacs to use hard tabs in this file. +# Local Variables: +# indent-tabs-mode: t +# End: diff --git a/CODE_OF_CONDUCT b/CODE_OF_CONDUCT new file mode 100644 index 0000000..b5a630a --- /dev/null +++ b/CODE_OF_CONDUCT @@ -0,0 +1,79 @@ +CODE OF CONDUCT + +BIND 9 Code of Conduct + +Like the technical community as a whole, the BIND 9 team and community is +made up of a mixture of professionals and volunteers from all over the +world, working on every aspect of the mission - including mentorship, +teaching, and connecting people. + +Diversity is one of our huge strengths, but it can also lead to +communication issues and unhappiness. To that end, we have a few ground +rules that we ask people to adhere to. This code applies equally to the +core development team, open source contributors and those seeking help and +guidance. + +This isn't an exhaustive list of things that you can't do. Rather, take it +in the spirit in which it's intended - a guide to make it easier to enrich +all of us and the technical communities in which we participate. + +This code of conduct applies to all spaces managed by the BIND 9 project +or Internet Systems Consortium. This includes chat, the mailing lists, the +issue tracker, and any other fora created by the project team which the +community uses for communication. In addition, violations of this code +outside these spaces may affect a person's ability to participate within +them. + +If you believe someone is violating the code of conduct, we ask that you +report it by emailing conduct@isc.org. For more details please see our +Reporting Guidelines. + + * Be friendly and patient. + * Be welcoming. We strive to be a community that welcomes and supports + people of all backgrounds and identities. This includes, but is not + limited to members of any race, ethnicity, culture, national origin, + colour, immigration status, social and economic class, educational + level, sex, sexual orientation, gender identity and expression, age, + size, family status, political belief, religion, and mental and + physical ability. + * Be considerate. Your work will be used by other people, and you in + turn will depend on the work of others. Any decision you take will + affect users and colleagues, and you should take those consequences + into account when making decisions. Remember that we're a world-wide + community, so you might not be communicating in someone else's primary + language. + * Be respectful. Not all of us will agree all the time, but disagreement + is no excuse for poor behavior and poor manners. We might all + experience some frustration now and then, but we cannot allow that + frustration to turn into a personal attack. It's important to remember + that a community where people feel uncomfortable or threatened is not + a productive one. Members of the BIND 9 community should be respectful + when dealing with other members as well as with people outside the + BIND 9 community. + * Be careful in the words that you choose. We are a community of + professionals, and we conduct ourselves professionally. Be kind to + others. Do not insult or put down other participants. Harassment and + other exclusionary behavior aren't acceptable. This includes, but is + not limited to: + + Violent threats or language directed against another person. + + Discriminatory jokes and language. + + Posting sexually explicit or violent material. + + Posting (or threatening to post) other people's personally + identifying information ("doxing"). + + Personal insults, especially those using racist or sexist terms. + + Unwelcome sexual attention. + + Advocating for, or encouraging, any of the above behavior. + + Repeated harassment of others. In general, if someone asks you to + stop, then stop. + * When we disagree, try to understand why. Disagreements, both social + and technical, happen all the time and BIND 9 is no exception. It is + important that we resolve disagreements and differing views + constructively. Remember that we're different. The strength of BIND 9 + comes from its varied community, people from a wide range of + backgrounds. Different people have different perspectives on issues. + Being unable to understand why someone holds a viewpoint doesn't mean + that they're wrong. Don't forget that it is human to err and blaming + each other doesn't get us anywhere. Instead, focus on helping to + resolve issues and learning from mistakes. + +Original text courtesy of the Django Code of Conduct project. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..153305e --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,84 @@ + + +# BIND 9 Code of Conduct + +Like the technical community as a whole, the BIND 9 team and community is made +up of a mixture of professionals and volunteers from all over the world, working +on every aspect of the mission - including mentorship, teaching, and connecting +people. + +Diversity is one of our huge strengths, but it can also lead to communication +issues and unhappiness. To that end, we have a few ground rules that we ask +people to adhere to. This code applies equally to the core development team, +open source contributors and those seeking help and guidance. + +This isn't an exhaustive list of things that you can't do. Rather, take it in +the spirit in which it's intended - a guide to make it easier to enrich all of +us and the technical communities in which we participate. + +This code of conduct applies to all spaces managed by the BIND 9 project or +Internet Systems Consortium. This includes chat, the mailing lists, the issue +tracker, and any other fora created by the project team which the +community uses for communication. In addition, violations of this code outside +these spaces may affect a person's ability to participate within them. + +If you believe someone is violating the code of conduct, we ask that you report +it by emailing [conduct@isc.org](conduct@isc.org). For more details please see +our [Reporting Guidelines](https://www.isc.org/conductreporting/). + +* **Be friendly and patient.** +* **Be welcoming.** We strive to be a community that welcomes and supports + people of all backgrounds and identities. This includes, but is not limited to + members of any race, ethnicity, culture, national origin, colour, immigration + status, social and economic class, educational level, sex, sexual orientation, + gender identity and expression, age, size, family status, political belief, + religion, and mental and physical ability. +* **Be considerate.** Your work will be used by other people, and you in turn + will depend on the work of others. Any decision you take will affect users and + colleagues, and you should take those consequences into account when making + decisions. Remember that we're a world-wide community, so you might not be + communicating in someone else's primary language. +* **Be respectful.** Not all of us will agree all the time, but disagreement is + no excuse for poor behavior and poor manners. We might all experience some + frustration now and then, but we cannot allow that frustration to turn into a + personal attack. It's important to remember that a community where people feel + uncomfortable or threatened is not a productive one. Members of the BIND 9 + community should be respectful when dealing with other members as well as with + people outside the BIND 9 community. +* **Be careful in the words that you choose.** We are a community of + professionals, and we conduct ourselves professionally. Be kind to others. Do + not insult or put down other participants. Harassment and other exclusionary + behavior aren't acceptable. This includes, but is not limited to: + * Violent threats or language directed against another person. + * Discriminatory jokes and language. + * Posting sexually explicit or violent material. + * Posting (or threatening to post) other people's personally identifying + information ("doxing"). + * Personal insults, especially those using racist or sexist terms. + * Unwelcome sexual attention. + * Advocating for, or encouraging, any of the above behavior. + * Repeated harassment of others. In general, if someone asks you to stop, then + stop. +* **When we disagree, try to understand why.** Disagreements, both social and + technical, happen all the time and BIND 9 is no exception. It is important + that we resolve disagreements and differing views constructively. Remember + that we're different. The strength of BIND 9 comes from its varied community, + people from a wide range of backgrounds. Different people have different + perspectives on issues. Being unable to understand why someone holds a + viewpoint doesn't mean that they're wrong. Don't forget that it is human to + err and blaming each other doesn't get us anywhere. Instead, focus on helping + to resolve issues and learning from mistakes. + +Original text courtesy of the [Django Code of Conduct](https://www.djangoproject.com/conduct/) +project. diff --git a/CONTRIBUTING b/CONTRIBUTING new file mode 100644 index 0000000..928ee67 --- /dev/null +++ b/CONTRIBUTING @@ -0,0 +1,189 @@ +CONTRIBUTING + +BIND 9 Source Access and Contributor Guidelines + +May 28, 2020 + +Contents + + 1. Access to source code + 2. Reporting bugs + 3. Contributing code + +Introduction + +Thank you for using BIND 9! + +BIND is open source software that implements the Domain Name System (DNS) +protocols for the Internet. It is a reference implementation of those +protocols, but it is also production-grade software, suitable for use in +high-volume and high-reliability applications. It is very widely used DNS +software, providing a robust and stable platform on top of which +organizations can build distributed computing systems with the knowledge +that those systems are fully compliant with published DNS standards. + +BIND is and will always remain free and openly available. It can be used +and modified in any way by anyone. + +BIND is maintained by Internet Systems Consortium, a public-benefit 501(c) +(3) nonprofit, using a "managed open source" approach: anyone can see the +source, but only ISC employees have commit access. In the past, the source +could only be seen once ISC had published a release; read access to the +source repository was restricted just as commit access was. That has +changed, as ISC now provides a public git repository of the BIND source +tree (see below). + +At ISC, we're committed to building communities that are welcoming and +inclusive: environments where people are encouraged to share ideas, treat +each other with respect, and collaborate towards the best solutions. To +reinforce our commitment, ISC has adopted a slightly modified version of +the Django Code of Conduct for the BIND 9 project, as well as for the +conduct of our developers throughout the industry. + +Access to source code + +Public BIND releases are always available from the ISC FTP site. + +A public-access git repository is also available at https://gitlab.isc.org +. This repository contains all public release branches. Upcoming releases +can be viewed in their current state at any time. Short-lived development +branches contain unreviewed work in progress. Commits which address +security vulnerablilities are withheld until after public disclosure. + +You can browse the source online via https://gitlab.isc.org/isc-projects/ +bind9 + +To clone the repository, use: + + $ git clone https://gitlab.isc.org/isc-projects/bind9.git + +Release branch names are of the form bind-9.X, where X represents the +second number in the BIND 9 version number. So, to check out the BIND 9.18 +branch, use: + + $ git checkout bind-9.18 + +Whenever a branch is ready for publication, a tag is placed of the form +v9.X.Y. The 9.18.0 release, for instance, is tagged as v9.18.0. + +The branch in which the next major release is being developed is called +main. + +Reporting bugs + +Reports of flaws in the BIND package, including software bugs, errors in +the documentation, missing files in the tarball, suggested changes or +requests for new features, etc., can be filed using https://gitlab.isc.org +/isc-projects/bind9/issues. + +Due to a large ticket backlog, we are sometimes slow to respond, +especially if a bug is cosmetic or if a feature request is vague or low in +priority, but we try at least to acknowledge legitimate bug reports within +a week. + +ISC's GitLab system is publicly readable; however, you must have an +account to create a new issue. You can either register locally or use +credentials from an existing account at GitHub, GitLab, Google, Twitter, +or Facebook. + +Reporting possible security issues + +If you think you may be seeing a potential security vulnerability in BIND +(for example, a crash with REQUIRE, INSIST, or ASSERT failure), please +report it immediately by emailing to security-officer@isc.org. Plain-text +e-mail is not a secure choice for communications concerning undisclosed +security issues so please encrypt your communications to us if possible, +using the ISC Security Officer public key. + +Do not discuss undisclosed security vulnerabilities on any public mailing +list. ISC has a long history of handling reported vulnerabilities promptly +and effectively and we respect and acknowledge responsible reporters. + +ISC's Security Vulnerability Disclosure Policy is documented at https:// +kb.isc.org/docs/aa-00861. + +If you have a crash, you may want to consult "What to do if your BIND or +DHCP server has crashed." + +Contributing code + +BIND is licensed under the Mozilla Public License 2.0. Earlier versions +(BIND 9.10 and earlier) were licensed under the ISC License + +ISC does not require an explicit copyright assignment for patch +contributions. However, by submitting a patch to ISC, you implicitly +certify that you are the author of the code, that you intend to relinquish +exclusive copyright, and that you grant permission to publish your work +under the open source license used for the BIND version(s) to which your +patch will be applied. + +BIND code + +Patches for BIND may be submitted directly via merge requests in ISC's +GitLab source repository for BIND. + +Patches can also be submitted as diffs against a specific version of BIND +-- preferably the current top of the main branch. Diffs may be generated +using either git format-patch or git diff. + +Those wanting to write code for BIND may be interested in the developer +information page, which includes information about BIND design and coding +practices, including discussion of internal APIs and overall system +architecture. + +Every patch submitted is reviewed by ISC engineers following our code +review process before it is merged. + +It may take considerable time to review patch submissions, especially if +they don't meet ISC style and quality guidelines. If a patch is a good +idea, we can and will do additional work to bring it up to par, but if +we're busy with other work, it may take us a long time to get to it. + +To ensure your patch is acted on as promptly as possible, please: + + * Try to adhere to the BIND 9 coding style. + * Run make check to ensure your change hasn't caused any functional + regressions. + * Document your work, both in the patch itself and in the accompanying + email. + * In patches that make non-trivial functional changes, include system + tests if possible; when introducing or substantially altering a + library API, include unit tests. See Testing for more information. + +Changes to configure + +If you need to make changes to configure, you should not edit it directly; +instead, edit configure.in, then run autoconf. Similarly, instead of +editing config.h.in directly, edit configure.in and run autoheader. + +When submitting a patch as a diff, it's fine to omit the configure diffs +to save space. Just send the configure.in diffs and we'll generate the new +configure during the review process. + +Documentation + +All functional changes should be documented. There are three types of +documentation in the BIND source tree: + + * Man pages are kept alongside the source code for the commands they + document, in files ending in .rst: for example, the named man page is + bin/named/named.rst. + * The BIND 9 Administrator Reference Manual is in the .rst files in doc/ + arm/; the PDF and HTML versions are automatically generated from the + .rst files. + * API documentation is in the header file describing the API, in + Doxygen-formatted comments. + +Patches to improve existing documentation are also very welcome! + +Tests + +BIND is a large and complex project. We rely heavily on continuous +automated testing and cannot merge new code without adequate test +coverage. Please see the "Testing" section of doc/dev/dev.md for more +information. + +Thanks + +Thank you for your interest in contributing to the ongoing development of +BIND 9. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4b3db89 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,208 @@ + +## BIND 9 Source Access and Contributor Guidelines +*May 28, 2020* + +### Contents + +1. [Access to source code](#access) +1. [Reporting bugs](#bugs) +1. [Contributing code](#contrib) + +### Introduction + +Thank you for using BIND 9! + +BIND is open source software that implements the Domain Name System (DNS) +protocols for the Internet. It is a reference implementation of those +protocols, but it is also production-grade software, suitable for use in +high-volume and high-reliability applications. It is very +widely used DNS software, providing a robust and stable platform on top of +which organizations can build distributed computing systems with the +knowledge that those systems are fully compliant with published DNS +standards. + +BIND is and will always remain free and openly available. It can be +used and modified in any way by anyone. + +BIND is maintained by [Internet Systems Consortium](https://www.isc.org), +a public-benefit 501(c)(3) nonprofit, using a "managed open source" approach: +anyone can see the source, but only ISC employees have commit access. +In the past, the source could only be seen once ISC had published +a release; read access to the source repository was restricted just +as commit access was. That has changed, as ISC now provides a +public git repository of the BIND source tree (see below). + +At ISC, we're committed to +building communities that are welcoming and inclusive: environments where people +are encouraged to share ideas, treat each other with respect, and collaborate +towards the best solutions. To reinforce our commitment, ISC +has adopted a slightly modified version of the Django +[Code of Conduct](https://gitlab.isc.org/isc-projects/bind9/-/blob/main/CODE_OF_CONDUCT.md) +for the BIND 9 project, as well as for the conduct of our developers throughout +the industry. + +### Access to source code + +Public BIND releases are always available from the +[ISC FTP site](ftp://ftp.isc.org/isc/bind9). + +A public-access git repository is also available at +[https://gitlab.isc.org](https://gitlab.isc.org). This repository +contains all public release branches. Upcoming releases can be viewed in +their current state at any time. Short-lived development branches +contain unreviewed work in progress. Commits which address security +vulnerablilities are withheld until after public disclosure. + +You can browse the source online via +[https://gitlab.isc.org/isc-projects/bind9](https://gitlab.isc.org/isc-projects/bind9) + +To clone the repository, use: + +> $ git clone https://gitlab.isc.org/isc-projects/bind9.git + +Release branch names are of the form `bind-9.X`, where X represents the second +number in the BIND 9 version number. So, to check out the BIND 9.18 +branch, use: + +> $ git checkout bind-9.18 + +Whenever a branch is ready for publication, a tag is placed of the +form `v9.X.Y`. The 9.18.0 release, for instance, is tagged as `v9.18.0`. + +The branch in which the next major release is being developed is called +`main`. + +### Reporting bugs + +Reports of flaws in the BIND package, including software bugs, errors +in the documentation, missing files in the tarball, suggested changes +or requests for new features, etc., can be filed using +[https://gitlab.isc.org/isc-projects/bind9/issues](https://gitlab.isc.org/isc-projects/bind9/issues). + +Due to a large ticket backlog, we are sometimes slow to respond, +especially if a bug is cosmetic or if a feature request is vague or +low in priority, but we try at least to acknowledge legitimate +bug reports within a week. + +ISC's GitLab system is publicly readable; however, you must have +an account to create a new issue. You can either register locally or +use credentials from an existing account at GitHub, GitLab, Google, +Twitter, or Facebook. + +### Reporting possible security issues + +If you think you may be seeing a potential security vulnerability in BIND +(for example, a crash with REQUIRE, INSIST, or ASSERT failure), please +report it immediately by emailing to security-officer@isc.org. Plain-text +e-mail is not a secure choice for communications concerning undisclosed +security issues so please encrypt your communications to us if possible, +using the [ISC Security Officer public key](https://www.isc.org/pgpkey/). + +Do not discuss undisclosed security vulnerabilities on any public mailing list. +ISC has a long history of handling reported vulnerabilities promptly and +effectively and we respect and acknowledge responsible reporters. + +ISC's Security Vulnerability Disclosure Policy is documented at +[https://kb.isc.org/docs/aa-00861](https://kb.isc.org/docs/aa-00861). + +If you have a crash, you may want to consult +["What to do if your BIND or DHCP server has crashed."](https://kb.isc.org/docs/aa-00340) + +### Contributing code + +BIND is licensed under the +[Mozilla Public License 2.0](https://www.mozilla.org/en-US/MPL/2.0/). +Earlier versions (BIND 9.10 and earlier) were licensed under the +[ISC License](https://www.isc.org/licenses/) + +ISC does not require an explicit copyright assignment for patch +contributions. However, by submitting a patch to ISC, you implicitly +certify that you are the author of the code, that you intend to relinquish +exclusive copyright, and that you grant permission to publish your work +under the open source license used for the BIND version(s) to which your +patch will be applied. + +#### BIND code + +Patches for BIND may be submitted directly via merge requests in +[ISC's GitLab](https://gitlab.isc.org/isc-projects/bind9/) source +repository for BIND. + +Patches can also be submitted as diffs against a specific version of +BIND -- preferably the current top of the `main` branch. Diffs may +be generated using either `git format-patch` or `git diff`. + +Those wanting to write code for BIND may be interested in the +[developer information](doc/dev/dev.md) page, which includes information +about BIND design and coding practices, including discussion of internal +APIs and overall system architecture. + +Every patch submitted is reviewed by ISC engineers following our +[code review process](doc/dev/dev.md#reviews) before it is merged. + +It may take considerable time to review patch submissions, especially if +they don't meet ISC style and quality guidelines. If a patch is a good +idea, we can and will do additional work to bring it up to par, but if +we're busy with other work, it may take us a long time to get to it. + +To ensure your patch is acted on as promptly as possible, please: + +* Try to adhere to the [BIND 9 coding style](doc/dev/style.md). +* Run `make check` to ensure your change hasn't caused any + functional regressions. +* Document your work, both in the patch itself and in the + accompanying email. +* In patches that make non-trivial functional changes, include system + tests if possible; when introducing or substantially altering a + library API, include unit tests. See [Testing](doc/dev/dev.md#testing) + for more information. + +##### Changes to `configure` + +If you need to make changes to `configure`, you should not edit it +directly; instead, edit `configure.in`, then run `autoconf`. Similarly, +instead of editing `config.h.in` directly, edit `configure.in` and run +`autoheader`. + +When submitting a patch as a diff, it's fine to omit the `configure` +diffs to save space. Just send the `configure.in` diffs and we'll +generate the new `configure` during the review process. + +##### Documentation + +All functional changes should be documented. There are three types +of documentation in the BIND source tree: + +* Man pages are kept alongside the source code for the commands + they document, in files ending in `.rst`: for example, the + `named` man page is `bin/named/named.rst`. +* The *BIND 9 Administrator Reference Manual* is in the .rst files in + `doc/arm/`; the PDF and HTML versions are automatically generated from + the `.rst` files. +* API documentation is in the header file describing the API, in + Doxygen-formatted comments. + +Patches to improve existing documentation are also very welcome! + +##### Tests + +BIND is a large and complex project. We rely heavily on continuous +automated testing and cannot merge new code without adequate test coverage. +Please see [the "Testing" section of doc/dev/dev.md](doc/dev/dev.md#testing) +for more information. + +#### Thanks + +Thank you for your interest in contributing to the ongoing development +of BIND 9. diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000..c6e4d03 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,369 @@ +Copyright (C) 1996-2023 Internet Systems Consortium, Inc. ("ISC") + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, you can obtain one at https://mozilla.org/MPL/2.0/. + + ----------------------------------------------------------------------------- + + Portions of this code release fall under one or more of the + following Copyright notices. Please see individual source + files for details. + + For binary releases also see: OpenSSL-LICENSE. + +Copyright (C) 1996-2001 Nominum, Inc. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ----------------------------------------------------------------------------- + +Copyright (C) 1995-2000 by Network Associates, Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS +ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE +FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ----------------------------------------------------------------------------- + +Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the +above copyright notice and this permission notice appear in all +copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE +USE OR PERFORMANCE OF THIS SOFTWARE. + +The development of Dynamically Loadable Zones (DLZ) for Bind 9 was +conceived and contributed by Rob Butler. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the +above copyright notice and this permission notice appear in all +copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE +USE OR PERFORMANCE OF THIS SOFTWARE. + + ----------------------------------------------------------------------------- + +Copyright (c) 1987, 1990, 1993, 1994 + The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + ----------------------------------------------------------------------------- + +Copyright (C) The Internet Society 2005. This version of +this module is part of RFC 4178; see the RFC itself for +full legal notices. + +(The above copyright notice is per RFC 3978 5.6 (a), q.v.) + + ----------------------------------------------------------------------------- + +Copyright (c) 2004 Masarykova universita +(Masaryk University, Brno, Czech Republic) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + ----------------------------------------------------------------------------- + +Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan +(Royal Institute of Technology, Stockholm, Sweden). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the Institute nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + ----------------------------------------------------------------------------- + +Copyright (c) 1993 by Digital Equipment Corporation. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies, and that +the name of Digital Equipment Corporation not be used in advertising or +publicity pertaining to distribution of the document or software without +specific, written prior permission. + +THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + + ----------------------------------------------------------------------------- + +Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + ----------------------------------------------------------------------------- + +Copyright (c) 1999-2000 by Nortel Networks Corporation + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND NORTEL NETWORKS DISCLAIMS +ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NORTEL NETWORKS +BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + + ----------------------------------------------------------------------------- + +Copyright (C) 2004 Nominet, Ltd. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND NOMINET DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + + ----------------------------------------------------------------------------- + +Copyright (c) 1996, David Mazieres +Copyright (c) 2008, Damien Miller + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +----------------------------------------------------------------------------- + +Copyright (c) 1995, 1997, 1998 The NetBSD Foundation, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- + +Copyright (C) 2008-2011 Red Hat, Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND Red Hat DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL Red Hat BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +----------------------------------------------------------------------------- + +Copyright (c) 2013-2014, Farsight Security, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- + +Copyright (c) 2014 by Farsight Security, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/HISTORY b/HISTORY new file mode 100644 index 0000000..0485c38 --- /dev/null +++ b/HISTORY @@ -0,0 +1,600 @@ +HISTORY + +Functional enhancements from prior major releases of BIND 9 + +BIND 9.14 + +BIND 9.14 (a stable branch based on the 9.13 development branch) includes +a number of changes from BIND 9.12 and earlier releases. New features +include: + + * A new "plugin" mechanism has been added to allow query functionality + to be extended using dynamically loadable libraries. The "filter-aaaa" + feature has been removed from named and is now implemented as a + plugin. + * Socket and task code has been refactored to improve performance. + * QNAME minimization, as described in RFC 7816, is now supported. + * "Root key sentinel" support, enabling validating resolvers to indicate + via a special query which trust anchors are configured for the root + zone. + * Secondary zones can now be configured as "mirror" zones; their + contents are transferred in as with traditional slave zones, but are + subject to DNSSEC validation and are not treated as authoritative data + when answering. This makes it easier to configure a local copy of the + root zone as described in RFC 7706. + * The "validate-except" option allows configuration of domains below + which DNSSEC validation should not be performed. + * The default value of "dnssec-validation" is now "auto". + * IDNA2008 is now supported when linking with libidn2. + * "named -V" now outputs the default paths for files used by named and + other tools. + +In addition, workarounds that were formerly in place to enable resolution +of domains whose authoritative servers did not respond to EDNS queries +have been removed. See https://dnsflagday.net for more details. + +Cryptographic support has been modernized. BIND now uses the best +available pseudo-random number generator for the platform on which it's +built. Very old versions of OpenSSL are no longer supported. Cryptography +is now mandatory: building BIND without DNSSEC is no longer supported. + +Special code to support certain legacy operating systems has also been +removed; see the doc/arm/platforms.rst file for details of supported +platforms. In addition to OpenSSL, BIND now requires support for IPv6, +threads, and standard atomic operations provided by the C compiler. + +BIND 9.12 + +BIND 9.12 includes a number of changes from BIND 9.11 and earlier +releases. New features include: + + * named and related libraries have been substantially refactored for + improved query performance -- particularly on delegation heavy zones + -- and for improved readability, maintainability, and testability. + * Code implementing the name server query processing logic has been + moved into a new libns library, for easier testing and use in tools + other than named. + * Cached, validated NSEC and other records can now be used to synthesize + NXDOMAIN responses. + * The DNS Response Policy Service API (DNSRPS) is now supported. + * Setting 'max-journal-size default' now limits the size of journal + files to twice the size of the zone. + * dnstap-read -x prints a hex dump of the wire format of each logged DNS + message. + * dnstap output files can now be configured to roll automatically when + reaching a given size. + * Log file timestamps can now also be formatted in ISO 8601 (local) or + ISO 8601 (UTC) formats. + * Logging channels and dnstap output files can now be configured to use + a timestamp as the suffix when rolling to a new file. + * 'named-checkconf -l' lists zones found in named.conf. + * Added support for the EDNS Padding and Keepalive options. + * 'new-zones-directory' option sets the location where the configuration + data for zones added by rndc addzone is stored. + * The default key algorithm in rndc-confgen is now hmac-sha256. + * filter-aaaa-on-v4 and filter-aaaa-on-v6 options are now available by + default without a configure option. + * The obsolete isc-hmac-fixup command has been removed. + +BIND 9.11 + +BIND 9.11.0 includes a number of changes from BIND 9.10 and earlier +releases. New features include: + + * Added support for Catalog Zones, a new method for provisioning + servers: a list of zones to be served is stored in a DNS zone, along + with their configuration parameters. Changes to the catalog zone are + propagated to slaves via normal AXFR/IXFR, whereupon the zones that + are listed in it are automatically added, deleted or reconfigured. + * Added support for "dnstap", a fast and flexible method of capturing + and logging DNS traffic. + * Added support for "dyndb", a new API for loading zone data from an + external database, developed by Red Hat for the FreeIPA project. + * "fetchlimit" quotas are now compiled in by default. These are for the + use of recursive resolvers that are are under high query load for + domains whose authoritative servers are nonresponsive or are + experiencing a denial of service attack: + + "fetches-per-server" limits the number of simultaneous queries + that can be sent to any single authoritative server. The + configured value is a starting point; it is automatically adjusted + downward if the server is partially or completely non-responsive. + The algorithm used to adjust the quota can be configured via the + "fetch-quota-params" option. + + "fetches-per-zone" limits the number of simultaneous queries that + can be sent for names within a single domain. (Note: Unlike + "fetches-per-server", this value is not self-tuning.) + + New stats counters have been added to count queries spilled due to + these quotas. + * Added a new "dnssec-keymgr" key mainenance utility, which can generate + or update keys as needed to ensure that a zone's keys match a defined + DNSSEC policy. + * The experimental "SIT" feature in BIND 9.10 has been renamed "COOKIE" + and is no longer optional. EDNS COOKIE is a mechanism enabling clients + to detect off-path spoofed responses, and servers to detect + spoofed-source queries. Clients that identify themselves using COOKIE + options are not subject to response rate limiting (RRL) and can + receive larger UDP responses. + * SERVFAIL responses can now be cached for a limited time (defaulting to + 1 second, with an upper limit of 30). This can reduce the frequency of + retries when a query is persistently failing. + * Added an "nsip-wait-recurse" switch to RPZ. This causes NSIP rules to + be skipped if a name server IP address isn't in the cache yet; the + address will be looked up and the rule will be applied on future + queries. + * Added a Python RNDC module. This allows multiple commands to sent over + a persistent RNDC channel, which saves time. + * The "controls" block in named.conf can now grant read-only "rndc" + access to specified clients or keys. Read-only clients could, for + example, check "rndc status" but could not reconfigure or shut down + the server. + * "rndc" commands can now return arbitrarily large amounts of text to + the caller. + * The zone serial number of a dynamically updatable zone can now be set + via "rndc signing -serial ". This allows inline-signing zones to be + set to a specific serial number. + * The new "rndc nta" command can be used to set a Negative Trust Anchor + (NTA), disabling DNSSEC validation for a specific domain; this can be + used when responses from a domain are known to be failing validation + due to administrative error rather than because of a spoofing attack. + Negative trust anchors are strictly temporary; by default they expire + after one hour, but can be configured to last up to one week. + * "rndc delzone" can now be used on zones that were not originally + created by "rndc addzone". + * "rndc modzone" reconfigures a single zone, without requiring the + entire server to be reconfigured. + * "rndc showzone" displays the current configuration of a zone. + * "rndc managed-keys" can be used to check the status of RFC 5011 + managed trust anchors, or to force trust anchors to be refreshed. + * "max-cache-size" can now be set to a percentage of available memory. + The default is 90%. + * Update forwarding performance has been improved by allowing a single + TCP connection to be shared by multiple updates. + * The EDNS Client Subnet (ECS) option is now supported for authoritative + servers; if a query contains an ECS option then ACLs containing + "geoip" or "ecs" elements can match against the the address encoded in + the option. This can be used to select a view for a query, so that + different answers can be provided depending on the client network. + * The EDNS EXPIRE option has been implemented on the client side, + allowing a slave server to set the expiration timer correctly when + transferring zone data from another slave server. + * The key generation and manipulation tools (dnssec-keygen, + dnssec-settime, dnssec-importkey, dnssec-keyfromlabel) now take + "-Psync" and "-Dsync" options to set the publication and deletion + times of CDS and CDNSKEY parent-synchronization records. Both named + and dnssec-signzone can now publish and remove these records at the + scheduled times. + * A new "minimal-any" option reduces the size of UDP responses for query + type ANY by returning a single arbitrarily selected RRset instead of + all RRsets. + * A new "masterfile-style" zone option controls the formatting of text + zone files: When set to "full", a zone file is dumped in + single-line-per-record format. + * "serial-update-method" can now be set to "date". On update, the serial + number will be set to the current date in YYYYMMDDNN format. + * "dnssec-signzone -N date" sets the serial number to YYYYMMDDNN. + * "named -L " causes named to send log messages to the specified file by + default instead of to the system log. + * "dig +ttlunits" prints TTL values with time-unit suffixes: w, d, h, m, + s for weeks, days, hours, minutes, and seconds. + * "dig +unknownformat" prints dig output in RFC 3597 "unknown record" + presentation format. + * "dig +ednsopt" allows dig to set arbitrary EDNS options on requests. + * "dig +ednsflags" allows dig to set yet-to-be-defined EDNS flags on + requests. + * "mdig" is an alternate version of dig which sends multiple pipelined + TCP queries to a server. Instead of waiting for a response after + sending a query, it sends all queries immediately and displays + responses in the order received. + * "serial-query-rate" no longer controls NOTIFY messages. These are + separately controlled by "notify-rate" and "startup-notify-rate". + * "nsupdate" now performs "check-names" processing by default on records + to be added. This can be disabled with "check-names no". + * The statistics channel now supports DEFLATE compression, reducing the + size of the data sent over the network when querying statistics. + * New counters have been added to the statistics channel to track the + sizes of incoming queries and outgoing responses in histogram buckets, + as specified in RSSAC002. + * A new NXDOMAIN redirect method (option "nxdomain-redirect") has been + added, allowing redirection to a specified DNS namespace instead of a + single redirect zone. + * When starting up, named now ensures that no other named process is + already running. + * Files created by named to store information, including "mkeys" and + "nzf" files, are now named after their corresponding views unless the + view name contains characters incompatible with use as a filename. Old + style filenames (based on the hash of the view name) will still work. + +BIND 9.10.0 + +BIND 9.10.0 includes a number of changes from BIND 9.9 and earlier +releases. New features include: + + * DNS Response-rate limiting (DNS RRL), which blunts the impact of + reflection and amplification attacks, is always compiled in and no + longer requires a compile-time option to enable it. + * An experimental "Source Identity Token" (SIT) EDNS option is now + available. Similar to DNS Cookies as invented by Donald Eastlake 3rd, + these are designed to enable clients to detect off-path spoofed + responses, and to enable servers to detect spoofed-source queries. + Servers can be configured to send smaller responses to clients that + have not identified themselves using a SIT option, reducing the + effectiveness of amplification attacks. RRL processing has also been + updated; clients proven to be legitimate via SIT are not subject to + rate limiting. Use "configure --enable-sit" to enable this feature in + BIND. + * A new zone file format, "map", stores zone data in a format that can + be mapped directly into memory, allowing significantly faster zone + loading. + * "delv" (domain entity lookup and validation) is a new tool with + dig-like semantics for looking up DNS data and performing internal + DNSSEC validation. This allows easy validation in environments where + the resolver may not be trustworthy, and assists with troubleshooting + of DNSSEC problems. (NOTE: In previous development releases of BIND + 9.10, this utility was called "delve". The spelling has been changed + to avoid confusion with the "delve" utility included with the Xapian + search engine.) + * Improved EDNS(0) processing for better resolver performance and + reliability over slow or lossy connections. + * A new "configure --with-tuning=large" option tunes certain compiled-in + constants and default settings to values better suited to large + servers with abundant memory. This can improve performance on such + servers, but will consume more memory and may degrade performance on + smaller systems. + * Substantial improvement in response-policy zone (RPZ) performance. Up + to 32 response-policy zones can be configured with minimal performance + loss. + * To improve recursive resolver performance, cache records which are + still being requested by clients can now be automatically refreshed + from the authoritative server before they expire, reducing or + eliminating the time window in which no answer is available in the + cache. + * New "rpz-client-ip" triggers and drop policies allowing response + policies based on the IP address of the client. + * ACLs can now be specified based on geographic location using the + MaxMind GeoIP databases. Use "configure --with-geoip" to enable. + * Zone data can now be shared between views, allowing multiple views to + serve the same zones authoritatively without storing multiple copies + in memory. + * New XML schema (version 3) for the statistics channel includes many + new statistics and uses a flattened XML tree for faster parsing. The + older schema is now deprecated. + * A new stylesheet, based on the Google Charts API, displays XML + statistics in charts and graphs on javascript-enabled browsers. + * The statistics channel can now provide data in JSON format as well as + XML. + * New stats counters track TCP and UDP queries received per zone, and + EDNS options received in total. + * The internal and export versions of the BIND libraries (libisc, + libdns, etc) have been unified so that external library clients can + use the same libraries as BIND itself. + * A new compile-time option, "configure --enable-native-pkcs11", allows + BIND 9 cryptography functions to use the PKCS#11 API natively, so that + BIND can drive a cryptographic hardware service module (HSM) directly + instead of using a modified OpenSSL as an intermediary. (Note: This + feature requires an HSM to have a full implementation of the PKCS#11 + API; many current HSMs only have partial implementations. The new + "pkcs11-tokens" command can be used to check API completeness. Native + PKCS#11 is known to work with the Thales nShield HSM and with SoftHSM + version 2 from the Open DNSSEC project.) + * The new "max-zone-ttl" option enforces maximum TTLs for zones. This + can simplify the process of rolling DNSSEC keys by guaranteeing that + cached signatures will have expired within the specified amount of + time. + * "dig +subnet" sends an EDNS CLIENT-SUBNET option when querying. + * "dig +expire" sends an EDNS EXPIRE option when querying. When this + option is sent with an SOA query to a server that supports it, it will + report the expiry time of a slave zone. + * New "dnssec-coverage" tool to check DNSSEC key coverage for a zone and + report if a lapse in signing coverage has been inadvertently + scheduled. + * Signing algorithm flexibility and other improvements for the "rndc" + control channel. + * "named-checkzone" and "named-compilezone" can now read journal files, + allowing them to process dynamic zones. + * Multiple DLZ databases can now be configured. Individual zones can be + configured to be served from a specific DLZ database. DLZ databases + now serve zones of type "master" and "redirect". + * "rndc zonestatus" reports information about a specified zone. + * "named" now listens on IPv6 as well as IPv4 interfaces by default. + * "named" now preserves the capitalization of names when responding to + queries: for instance, a query for "example.com" may be answered with + "example.COM" if the name was configured that way in the zone file. + Some clients have a bug causing them to depend on the older behavior, + in which the case of the answer always matched the case of the query, + rather than the case of the name configured in the DNS. Such clients + can now be specified in the new "no-case-compress" ACL; this will + restore the older behavior of "named" for those clients only. + * new "dnssec-importkey" command allows the use of offline DNSSEC keys + with automatic DNSKEY management. + * New "named-rrchecker" tool to verify the syntactic correctness of + individual resource records. + * When re-signing a zone, the new "dnssec-signzone -Q" option drops + signatures from keys that are still published but are no longer + active. + * "named-checkconf -px" will print the contents of configuration files + with the shared secrets obscured, making it easier to share + configuration (e.g. when submitting a bug report) without revealing + private information. + * "rndc scan" causes named to re-scan network interfaces for changes in + local addresses. + * On operating systems with support for routing sockets, network + interfaces are re-scanned automatically whenever they change. + * "tsig-keygen" is now available as an alternate command name to use for + "ddns-confgen". + +BIND 9.9.0 + +BIND 9.9.0 includes a number of changes from BIND 9.8 and earlier +releases. New features include: + + * Inline signing, allowing automatic DNSSEC signing of master zones + without modification of the zonefile, or "bump in the wire" signing in + slaves. + * NXDOMAIN redirection. + * New 'rndc flushtree' command clears all data under a given name from + the DNS cache. + * New 'rndc sync' command dumps pending changes in a dynamic zone to + disk without a freeze/thaw cycle. + * New 'rndc signing' command displays or clears signing status records + in 'auto-dnssec' zones. + * NSEC3 parameters for 'auto-dnssec' zones can now be set prior to + signing, eliminating the need to initially sign with NSEC. + * Startup time improvements on large authoritative servers. + * Slave zones are now saved in raw format by default. + * Several improvements to response policy zones (RPZ). + * Improved hardware scalability by using multiple threads to listen for + queries and using finer-grained client locking + * The 'also-notify' option now takes the same syntax as 'masters', so it + can used named masterlists and TSIG keys. + * 'dnssec-signzone -D' writes an output file containing only DNSSEC + data, which can be included by the primary zone file. + * 'dnssec-signzone -R' forces removal of signatures that are not expired + but were created by a key which no longer exists. + * 'dnssec-signzone -X' allows a separate expiration date to be specified + for DNSKEY signatures from other signatures. + * New '-L' option to dnssec-keygen, dnssec-settime, and + dnssec-keyfromlabel sets the default TTL for the key. + * dnssec-dsfromkey now supports reading from standard input, to make it + easier to convert DNSKEY to DS. + * RFC 1918 reverse zones have been added to the empty-zones table per + RFC 6303. + * Dynamic updates can now optionally set the zone's SOA serial number to + the current UNIX time. + * DLZ modules can now retrieve the source IP address of the querying + client. + * 'request-ixfr' option can now be set at the per-zone level. + * 'dig +rrcomments' turns on comments about DNSKEY records, indicating + their key ID, algorithm and function + * Simplified nsupdate syntax and added readline support + +BIND 9.8.0 + +BIND 9.8.0 includes a number of changes from BIND 9.7 and earlier +releases. New features include: + + * Built-in trust anchor for the root zone, which can be switched on via + "dnssec-validation auto;" + * Support for DNS64. + * Support for response policy zones (RPZ). + * Support for writable DLZ zones. + * Improved ease of configuration of GSS/TSIG for interoperability with + Active Directory + * Support for GOST signing algorithm for DNSSEC. + * Removed RTT Banding from server selection algorithm. + * New "static-stub" zone type. + * Allow configuration of resolver timeouts via "resolver-query-timeout" + option. + * The DLZ "dlopen" driver is now built by default. + * Added a new include file with function typedefs for the DLZ "dlopen" + driver. + * Made "--with-gssapi" default. + * More verbose error reporting from DLZ LDAP. + +BIND 9.7.0 + +BIND 9.7.0 includes a number of changes from BIND 9.6 and earlier +releases. Most are intended to simplify DNSSEC configuration. New features +include: + + * Fully automatic signing of zones by "named". + * Simplified configuration of DNSSEC Lookaside Validation (DLV). + * Simplified configuration of Dynamic DNS, using the "ddns-confgen" + command line tool or the "local" update-policy option. (As a side + effect, this also makes it easier to configure automatic zone + re-signing.) + * New named option "attach-cache" that allows multiple views to share a + single cache. + * DNS rebinding attack prevention. + * New default values for dnssec-keygen parameters. + * Support for RFC 5011 automated trust anchor maintenance + * Smart signing: simplified tools for zone signing and key maintenance. + * The "statistics-channels" option is now available on Windows. + * A new DNSSEC-aware libdns API for use by non-BIND9 applications + * On some platforms, named and other binaries can now print out a stack + backtrace on assertion failure, to aid in debugging. + * A "tools only" installation mode on Windows, which only installs dig, + host, nslookup and nsupdate. + * Improved PKCS#11 support, including Keyper support and explicit + OpenSSL engine selection. + +BIND 9.6.0 + + * Full NSEC3 support + * Automatic zone re-signing + * New update-policy methods tcp-self and 6to4-self + * The BIND 8 resolver library, libbind, has been removed from the BIND 9 + distribution and is now available as a separate download. + * Change the default pid file location from /var/run to /var/run/ + {named,lwresd} for improved chroot/setuid support. + +BIND 9.5.0 + + * GSS-TSIG support (RFC 3645). + * DHCID support. + * Experimental http server and statistics support for named via xml. + * More detailed statistics counters including those supported in BIND 8. + * Faster ACL processing. + * Use Doxygen to generate internal documentation. + * Efficient LRU cache-cleaning mechanism. + * NSID support. + +BIND 9.4.0 + + * Implemented "additional section caching (or acache)", an internal + cache framework for additional section content to improve response + performance. Several configuration options were provided to control + the behavior. + * New notify type 'master-only'. Enable notify for master zones only. + * Accept 'notify-source' style syntax for query-source. + * rndc now allows addresses to be set in the server clauses. + * New option "allow-query-cache". This lets "allow-query" be used to + specify the default zone access level rather than having to have every + zone override the global value. "allow-query-cache" can be set at both + the options and view levels. If "allow-query-cache" is not set then + "allow-recursion" is used if set, otherwise "allow-query" is used if + set unless "recursion no;" is set in which case "none;" is used, + otherwise the default (localhost; localnets;) is used. + * rndc: the source address can now be specified. + * ixfr-from-differences now takes master and slave in addition to yes + and no at the options and view levels. + * Allow the journal's name to be changed via named.conf. + * 'rndc notify zone [class [view]]' resend the NOTIFY messages for the + specified zone. + * 'dig +trace' now randomly selects the next servers to try. Report if + there is a bad delegation. + * Improve check-names error messages. + * Make public the function to read a key file, dst_key_read_public(). + * dig now returns the byte count for axfr/ixfr. + * allow-update is now settable at the options / view level. + * named-checkconf now checks the logging configuration. + * host now can turn on memory debugging flags with '-m'. + * Don't send notify messages to self. + * Perform sanity checks on NS records which refer to 'in zone' names. + * New zone option "notify-delay". Specify a minimum delay between sets + of NOTIFY messages. + * Extend adjusting TTL warning messages. + * Named and named-checkzone can now both check for non-terminal wildcard + records. + * "rndc freeze/thaw" now freezes/thaws all zones. + * named-checkconf now check acls to verify that they only refer to + existing acls. + * The server syntax has been extended to support a range of servers. + * Report differences between hints and real NS rrset and associated + address records. + * Preserve the case of domain names in rdata during zone transfers. + * Restructured the data locking framework using architecture dependent + atomic operations (when available), improving response performance on + multi-processor machines significantly. x86, x86_64, alpha, powerpc, + and mips are currently supported. + * UNIX domain controls are now supported. + * Add support for additional zone file formats for improving loading + performance. The masterfile-format option in named.conf can be used to + specify a non-default format. A separate command named-compilezone was + provided to generate zone files in the new format. Additionally, the + -I and -O options for dnssec-signzone specify the input and output + formats. + * dnssec-signzone can now randomize signature end times (dnssec-signzone + -j jitter). + * Add support for CH A record. + * Add additional zone data constancy checks. named-checkzone has + extended checking of NS, MX and SRV record and the hosts they + reference. named has extended post zone load checks. New zone options: + check-mx and integrity-check. + * edns-udp-size can now be overridden on a per server basis. + * dig can now specify the EDNS version when making a query. + * Added framework for handling multiple EDNS versions. + * Additional memory debugging support to track size and mctx arguments. + * Detect duplicates of UDP queries we are recursing on and drop them. + New stats category "duplicates". + * "USE INTERNAL MALLOC" is now runtime selectable. + * The lame cache is now done on a basis as some + servers only appear to be lame for certain query types. + * Limit the number of recursive clients that can be waiting for a single + query () to resolve. New options clients-per-query + and max-clients-per-query. + * dig: report the number of extra bytes still left in the packet after + processing all the records. + * Support for IPSECKEY rdata type. + * Raise the UDP receive buffer size to 32k if it is less than 32k. + * x86 and x86_64 now have separate atomic locking implementations. + * named-checkconf now validates update-policy entries. + * Attempt to make the amount of work performed in a iteration self + tuning. The covers nodes clean from the cache per iteration, nodes + written to disk when rewriting a master file and nodes destroyed per + iteration when destroying a zone or a cache. + * ISC string copy API. + * Automatic empty zone creation for D.F.IP6.ARPA and friends. Note: RFC + 1918 zones are not yet covered by this but are likely to be in a + future release. + * New options: empty-server, empty-contact, empty-zones-enable and + disable-empty-zone. + * dig now has a '-q queryname' and '+showsearch' options. + * host/nslookup now continue (default)/fail on SERVFAIL. + * dig now warns if 'RA' is not set in the answer when 'RD' was set in + the query. host/nslookup skip servers that fail to set 'RA' when 'RD' + is set unless a server is explicitly set. + * Integrate contributed DLZ code into named. + * Integrate contributed IDN code from JPNIC. + * libbind: corresponds to that from BIND 8.4.7. + +BIND 9.3.0 + + * DNSSEC is now DS based (RFC 3658). + * DNSSEC lookaside validation. + * check-names is now implemented. + * rrset-order is more complete. + * IPv4/IPv6 transition support, dual-stack-servers. + * IXFR deltas can now be generated when loading master files, + ixfr-from-differences. + * It is now possible to specify the size of a journal, max-journal-size. + * It is now possible to define a named set of master servers to be used + in masters clause, masters. + * The advertised EDNS UDP size can now be set, edns-udp-size. + * allow-v6-synthesis has been obsoleted. + * Zones containing MD and MF will now be rejected. + * dig, nslookup name. now report "Not Implemented" as NOTIMP rather than + NOTIMPL. This will have impact on scripts that are looking for + NOTIMPL. + * libbind: corresponds to that from BIND 8.4.5. + +BIND 9.2.0 + + * The size of the cache can now be limited using the "max-cache-size" + option. + * The server can now automatically convert RFC1886-style recursive + lookup requests into RFC2874-style lookups, when enabled using the new + option "allow-v6-synthesis". This allows stub resolvers that support + AAAA records but not A6 record chains or binary labels to perform + lookups in domains that make use of these IPv6 DNS features. + * Performance has been improved. + * The man pages now use the more portable "man" macros rather than the + "mandoc" macros, and are installed by "make install". + * The named.conf parser has been completely rewritten. It now supports + "include" directives in more places such as inside "view" statements, + and it no longer has any reserved words. + * The "rndc status" command is now implemented. + * rndc can now be configured automatically. + * A BIND 8 compatible stub resolver library is now included in lib/bind. + * OpenSSL has been removed from the distribution. This means that to use + DNSSEC, OpenSSL must be installed and the --with-openssl option must + be supplied to configure. This does not apply to the use of TSIG, + which does not require OpenSSL. + * The source distribution now builds on Windows. See win32utils/ + readme1.txt and win32utils/win32-build.txt for details. + * This distribution also includes a new lightweight stub resolver + library and associated resolver daemon that fully support forward and + reverse lookups of both IPv4 and IPv6 addresses. This library is + considered experimental and is not a complete replacement for the BIND + 8 resolver library. Applications that use the BIND 8 res_* functions + to perform DNS lookups or dynamic updates still need to be linked + against the BIND 8 libraries. For DNS lookups, they can also use the + new "getrrsetbyname()" API. + * BIND 9.2 is capable of acting as an authoritative server for DNSSEC + secured zones. This functionality is believed to be stable and + complete except for lacking support for verifications involving + wildcard records in secure zones. + * When acting as a caching server, BIND 9.2 can be configured to perform + DNSSEC secure resolution on behalf of its clients. This part of the + DNSSEC implementation is still considered experimental. For detailed + information about the state of the DNSSEC implementation, see the file + doc/misc/dnssec. diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 0000000..3a0f897 --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,617 @@ + +### Functional enhancements from prior major releases of BIND 9 + +#### BIND 9.14 + +BIND 9.14 (a stable branch based on the 9.13 development branch) +includes a number of changes from BIND 9.12 and earlier releases. +New features include: + +* A new "plugin" mechanism has been added to allow query functionality + to be extended using dynamically loadable libraries. The "filter-aaaa" + feature has been removed from named and is now implemented as a plugin. +* Socket and task code has been refactored to improve performance. +* QNAME minimization, as described in RFC 7816, is now supported. +* "Root key sentinel" support, enabling validating resolvers to indicate + via a special query which trust anchors are configured for the root zone. +* Secondary zones can now be configured as "mirror" zones; their contents + are transferred in as with traditional slave zones, but are subject to + DNSSEC validation and are not treated as authoritative data when + answering. This makes it easier to configure a local copy of the root + zone as described in RFC 7706. +* The "validate-except" option allows configuration of domains below which + DNSSEC validation should not be performed. +* The default value of "dnssec-validation" is now "auto". +* IDNA2008 is now supported when linking with `libidn2`. +* "named -V" now outputs the default paths for files used by named + and other tools. + +In addition, workarounds that were formerly in place to enable resolution +of domains whose authoritative servers did not respond to EDNS queries +have been removed. See [https://dnsflagday.net](https://dnsflagday.net) +for more details. + +Cryptographic support has been modernized. BIND now uses the +best available pseudo-random number generator for the platform on which +it's built. Very old versions of OpenSSL are no longer supported. +Cryptography is now mandatory: building BIND without DNSSEC is no +longer supported. + +Special code to support certain legacy operating systems has also +been removed; see the [doc/arm/platforms.rst](platforms) file for details +of supported platforms. In addition to OpenSSL, BIND now requires +support for IPv6, threads, and standard atomic operations provided +by the C compiler. + +#### BIND 9.12 + +BIND 9.12 includes a number of changes from BIND 9.11 and earlier releases. +New features include: + +* `named` and related libraries have been substantially refactored for + improved query performance -- particularly on delegation heavy zones -- + and for improved readability, maintainability, and testability. +* Code implementing the name server query processing logic has been moved + into a new `libns` library, for easier testing and use in tools other + than `named`. +* Cached, validated NSEC and other records can now be used to synthesize + NXDOMAIN responses. +* The DNS Response Policy Service API (DNSRPS) is now supported. +* Setting `'max-journal-size default'` now limits the size of journal files + to twice the size of the zone. +* `dnstap-read -x` prints a hex dump of the wire format of each logged + DNS message. +* `dnstap` output files can now be configured to roll automatically when + reaching a given size. +* Log file timestamps can now also be formatted in ISO 8601 (local) or ISO + 8601 (UTC) formats. +* Logging channels and `dnstap` output files can now be configured to use a + timestamp as the suffix when rolling to a new file. +* `'named-checkconf -l'` lists zones found in `named.conf`. +* Added support for the EDNS Padding and Keepalive options. +* 'new-zones-directory' option sets the location where the configuration + data for zones added by rndc addzone is stored. +* The default key algorithm in `rndc-confgen` is now hmac-sha256. +* `filter-aaaa-on-v4` and `filter-aaaa-on-v6` options are now available + by default without a configure option. +* The obsolete `isc-hmac-fixup` command has been removed. + +#### BIND 9.11 + +BIND 9.11.0 includes a number of changes from BIND 9.10 and earlier +releases. New features include: + +- Added support for Catalog Zones, a new method for provisioning servers: a + list of zones to be served is stored in a DNS zone, along with their + configuration parameters. Changes to the catalog zone are propagated to + slaves via normal AXFR/IXFR, whereupon the zones that are listed in it + are automatically added, deleted or reconfigured. +- Added support for "dnstap", a fast and flexible method of capturing and + logging DNS traffic. +- Added support for "dyndb", a new API for loading zone data from an + external database, developed by Red Hat for the FreeIPA project. +- "fetchlimit" quotas are now compiled in by default. These are for the + use of recursive resolvers that are are under high query load for domains + whose authoritative servers are nonresponsive or are experiencing a + denial of service attack: + - "fetches-per-server" limits the number of simultaneous queries that + can be sent to any single authoritative server. The configured value + is a starting point; it is automatically adjusted downward if the + server is partially or completely non-responsive. The algorithm used + to adjust the quota can be configured via the "fetch-quota-params" + option. + - "fetches-per-zone" limits the number of simultaneous queries that can + be sent for names within a single domain. (Note: Unlike + "fetches-per-server", this value is not self-tuning.) + - New stats counters have been added to count queries spilled due to + these quotas. +- Added a new "dnssec-keymgr" key mainenance utility, which can generate or + update keys as needed to ensure that a zone's keys match a defined DNSSEC + policy. +- The experimental "SIT" feature in BIND 9.10 has been renamed "COOKIE" and + is no longer optional. EDNS COOKIE is a mechanism enabling clients to + detect off-path spoofed responses, and servers to detect spoofed-source + queries. Clients that identify themselves using COOKIE options are not + subject to response rate limiting (RRL) and can receive larger UDP + responses. +- SERVFAIL responses can now be cached for a limited time (defaulting to 1 + second, with an upper limit of 30). This can reduce the frequency of + retries when a query is persistently failing. +- Added an "nsip-wait-recurse" switch to RPZ. This causes NSIP rules to be + skipped if a name server IP address isn't in the cache yet; the address + will be looked up and the rule will be applied on future queries. +- Added a Python RNDC module. This allows multiple commands to sent over a + persistent RNDC channel, which saves time. +- The "controls" block in named.conf can now grant read-only "rndc" access + to specified clients or keys. Read-only clients could, for example, check + "rndc status" but could not reconfigure or shut down the server. +- "rndc" commands can now return arbitrarily large amounts of text to the + caller. +- The zone serial number of a dynamically updatable zone can now be set via + "rndc signing -serial ". This allows inline-signing + zones to be set to a specific serial number. +- The new "rndc nta" command can be used to set a Negative Trust Anchor + (NTA), disabling DNSSEC validation for a specific domain; this can be + used when responses from a domain are known to be failing validation due + to administrative error rather than because of a spoofing attack. + Negative trust anchors are strictly temporary; by default they expire + after one hour, but can be configured to last up to one week. +- "rndc delzone" can now be used on zones that were not originally created + by "rndc addzone". +- "rndc modzone" reconfigures a single zone, without requiring the entire + server to be reconfigured. +- "rndc showzone" displays the current configuration of a zone. +- "rndc managed-keys" can be used to check the status of RFC 5011 managed + trust anchors, or to force trust anchors to be refreshed. +- "max-cache-size" can now be set to a percentage of available memory. The + default is 90%. +- Update forwarding performance has been improved by allowing a single TCP + connection to be shared by multiple updates. +- The EDNS Client Subnet (ECS) option is now supported for authoritative + servers; if a query contains an ECS option then ACLs containing "geoip" + or "ecs" elements can match against the the address encoded in the + option. This can be used to select a view for a query, so that different + answers can be provided depending on the client network. +- The EDNS EXPIRE option has been implemented on the client side, allowing + a slave server to set the expiration timer correctly when transferring + zone data from another slave server. +- The key generation and manipulation tools (dnssec-keygen, dnssec-settime, + dnssec-importkey, dnssec-keyfromlabel) now take "-Psync" and "-Dsync" + options to set the publication and deletion times of CDS and CDNSKEY + parent-synchronization records. Both named and dnssec-signzone can now + publish and remove these records at the scheduled times. +- A new "minimal-any" option reduces the size of UDP responses for query + type ANY by returning a single arbitrarily selected RRset instead of all + RRsets. +- A new "masterfile-style" zone option controls the formatting of text zone + files: When set to "full", a zone file is dumped in + single-line-per-record format. +- "serial-update-method" can now be set to "date". On update, the serial + number will be set to the current date in YYYYMMDDNN format. +- "dnssec-signzone -N date" sets the serial number to YYYYMMDDNN. +- "named -L " causes named to send log messages to the specified + file by default instead of to the system log. +- "dig +ttlunits" prints TTL values with time-unit suffixes: w, d, h, m, s + for weeks, days, hours, minutes, and seconds. +- "dig +unknownformat" prints dig output in RFC 3597 "unknown record" + presentation format. +- "dig +ednsopt" allows dig to set arbitrary EDNS options on requests. +- "dig +ednsflags" allows dig to set yet-to-be-defined EDNS flags on + requests. +- "mdig" is an alternate version of dig which sends multiple pipelined TCP + queries to a server. Instead of waiting for a response after sending a + query, it sends all queries immediately and displays responses in the + order received. +- "serial-query-rate" no longer controls NOTIFY messages. These are + separately controlled by "notify-rate" and "startup-notify-rate". +- "nsupdate" now performs "check-names" processing by default on records to + be added. This can be disabled with "check-names no". +- The statistics channel now supports DEFLATE compression, reducing the + size of the data sent over the network when querying statistics. +- New counters have been added to the statistics channel to track the sizes + of incoming queries and outgoing responses in histogram buckets, as + specified in RSSAC002. +- A new NXDOMAIN redirect method (option "nxdomain-redirect") has been + added, allowing redirection to a specified DNS namespace instead of a + single redirect zone. +- When starting up, named now ensures that no other named process is + already running. +- Files created by named to store information, including "mkeys" and "nzf" + files, are now named after their corresponding views unless the view name + contains characters incompatible with use as a filename. Old style + filenames (based on the hash of the view name) will still work. + +#### BIND 9.10.0 + +BIND 9.10.0 includes a number of changes from BIND 9.9 and earlier +releases. New features include: + + - DNS Response-rate limiting (DNS RRL), which blunts the + impact of reflection and amplification attacks, is always + compiled in and no longer requires a compile-time option + to enable it. + - An experimental "Source Identity Token" (SIT) EDNS option + is now available. Similar to DNS Cookies as invented by + Donald Eastlake 3rd, these are designed to enable clients + to detect off-path spoofed responses, and to enable servers + to detect spoofed-source queries. Servers can be configured + to send smaller responses to clients that have not identified + themselves using a SIT option, reducing the effectiveness of + amplification attacks. RRL processing has also been updated; + clients proven to be legitimate via SIT are not subject to + rate limiting. Use "configure --enable-sit" to enable this + feature in BIND. + - A new zone file format, "map", stores zone data in a + format that can be mapped directly into memory, allowing + significantly faster zone loading. + - "delv" (domain entity lookup and validation) is a new tool + with dig-like semantics for looking up DNS data and performing + internal DNSSEC validation. This allows easy validation in + environments where the resolver may not be trustworthy, and + assists with troubleshooting of DNSSEC problems. (NOTE: + In previous development releases of BIND 9.10, this utility + was called "delve". The spelling has been changed to avoid + confusion with the "delve" utility included with the Xapian + search engine.) + - Improved EDNS(0) processing for better resolver performance + and reliability over slow or lossy connections. + - A new "configure --with-tuning=large" option tunes certain + compiled-in constants and default settings to values better + suited to large servers with abundant memory. This can + improve performance on such servers, but will consume more + memory and may degrade performance on smaller systems. + - Substantial improvement in response-policy zone (RPZ) + performance. Up to 32 response-policy zones can be + configured with minimal performance loss. + - To improve recursive resolver performance, cache records + which are still being requested by clients can now be + automatically refreshed from the authoritative server + before they expire, reducing or eliminating the time + window in which no answer is available in the cache. + - New "rpz-client-ip" triggers and drop policies allowing + response policies based on the IP address of the client. + - ACLs can now be specified based on geographic location + using the MaxMind GeoIP databases. Use "configure + --with-geoip" to enable. + - Zone data can now be shared between views, allowing + multiple views to serve the same zones authoritatively + without storing multiple copies in memory. + - New XML schema (version 3) for the statistics channel + includes many new statistics and uses a flattened XML tree + for faster parsing. The older schema is now deprecated. + - A new stylesheet, based on the Google Charts API, displays + XML statistics in charts and graphs on javascript-enabled + browsers. + - The statistics channel can now provide data in JSON + format as well as XML. + - New stats counters track TCP and UDP queries received + per zone, and EDNS options received in total. + - The internal and export versions of the BIND libraries + (libisc, libdns, etc) have been unified so that external + library clients can use the same libraries as BIND itself. + - A new compile-time option, "configure --enable-native-pkcs11", + allows BIND 9 cryptography functions to use the PKCS#11 API + natively, so that BIND can drive a cryptographic hardware + service module (HSM) directly instead of using a modified + OpenSSL as an intermediary. (Note: This feature requires an + HSM to have a full implementation of the PKCS#11 API; many + current HSMs only have partial implementations. The new + "pkcs11-tokens" command can be used to check API completeness. + Native PKCS#11 is known to work with the Thales nShield HSM + and with SoftHSM version 2 from the Open DNSSEC project.) + - The new "max-zone-ttl" option enforces maximum TTLs for + zones. This can simplify the process of rolling DNSSEC keys + by guaranteeing that cached signatures will have expired + within the specified amount of time. + - "dig +subnet" sends an EDNS CLIENT-SUBNET option when + querying. + - "dig +expire" sends an EDNS EXPIRE option when querying. + When this option is sent with an SOA query to a server + that supports it, it will report the expiry time of + a slave zone. + - New "dnssec-coverage" tool to check DNSSEC key coverage + for a zone and report if a lapse in signing coverage has + been inadvertently scheduled. + - Signing algorithm flexibility and other improvements + for the "rndc" control channel. + - "named-checkzone" and "named-compilezone" can now read + journal files, allowing them to process dynamic zones. + - Multiple DLZ databases can now be configured. Individual + zones can be configured to be served from a specific DLZ + database. DLZ databases now serve zones of type "master" + and "redirect". + - "rndc zonestatus" reports information about a specified zone. + - "named" now listens on IPv6 as well as IPv4 interfaces + by default. + - "named" now preserves the capitalization of names + when responding to queries: for instance, a query for + "example.com" may be answered with "example.COM" if the + name was configured that way in the zone file. Some + clients have a bug causing them to depend on the older + behavior, in which the case of the answer always matched + the case of the query, rather than the case of the name + configured in the DNS. Such clients can now be specified + in the new "no-case-compress" ACL; this will restore the + older behavior of "named" for those clients only. + - new "dnssec-importkey" command allows the use of offline + DNSSEC keys with automatic DNSKEY management. + - New "named-rrchecker" tool to verify the syntactic + correctness of individual resource records. + - When re-signing a zone, the new "dnssec-signzone -Q" option + drops signatures from keys that are still published but are + no longer active. + - "named-checkconf -px" will print the contents of configuration + files with the shared secrets obscured, making it easier to + share configuration (e.g. when submitting a bug report) + without revealing private information. + - "rndc scan" causes named to re-scan network interfaces for + changes in local addresses. + - On operating systems with support for routing sockets, + network interfaces are re-scanned automatically whenever + they change. + - "tsig-keygen" is now available as an alternate command + name to use for "ddns-confgen". + +#### BIND 9.9.0 + +BIND 9.9.0 includes a number of changes from BIND 9.8 and earlier +releases. New features include: + +- Inline signing, allowing automatic DNSSEC signing of + master zones without modification of the zonefile, or + "bump in the wire" signing in slaves. +- NXDOMAIN redirection. +- New 'rndc flushtree' command clears all data under a given + name from the DNS cache. +- New 'rndc sync' command dumps pending changes in a dynamic + zone to disk without a freeze/thaw cycle. +- New 'rndc signing' command displays or clears signing status + records in 'auto-dnssec' zones. +- NSEC3 parameters for 'auto-dnssec' zones can now be set prior + to signing, eliminating the need to initially sign with NSEC. +- Startup time improvements on large authoritative servers. +- Slave zones are now saved in raw format by default. +- Several improvements to response policy zones (RPZ). +- Improved hardware scalability by using multiple threads + to listen for queries and using finer-grained client locking +- The 'also-notify' option now takes the same syntax as + 'masters', so it can used named masterlists and TSIG keys. +- 'dnssec-signzone -D' writes an output file containing only DNSSEC + data, which can be included by the primary zone file. +- 'dnssec-signzone -R' forces removal of signatures that are + not expired but were created by a key which no longer exists. +- 'dnssec-signzone -X' allows a separate expiration date to + be specified for DNSKEY signatures from other signatures. +- New '-L' option to dnssec-keygen, dnssec-settime, and + dnssec-keyfromlabel sets the default TTL for the key. +- dnssec-dsfromkey now supports reading from standard input, + to make it easier to convert DNSKEY to DS. +- RFC 1918 reverse zones have been added to the empty-zones + table per RFC 6303. +- Dynamic updates can now optionally set the zone's SOA serial + number to the current UNIX time. +- DLZ modules can now retrieve the source IP address of + the querying client. +- 'request-ixfr' option can now be set at the per-zone level. +- 'dig +rrcomments' turns on comments about DNSKEY records, + indicating their key ID, algorithm and function +- Simplified nsupdate syntax and added readline support + +#### BIND 9.8.0 + +BIND 9.8.0 includes a number of changes from BIND 9.7 and earlier +releases. New features include: + +- Built-in trust anchor for the root zone, which can be + switched on via "dnssec-validation auto;" +- Support for DNS64. +- Support for response policy zones (RPZ). +- Support for writable DLZ zones. +- Improved ease of configuration of GSS/TSIG for + interoperability with Active Directory +- Support for GOST signing algorithm for DNSSEC. +- Removed RTT Banding from server selection algorithm. +- New "static-stub" zone type. +- Allow configuration of resolver timeouts via + "resolver-query-timeout" option. +- The DLZ "dlopen" driver is now built by default. +- Added a new include file with function typedefs + for the DLZ "dlopen" driver. +- Made "--with-gssapi" default. +- More verbose error reporting from DLZ LDAP. + +#### BIND 9.7.0 + +BIND 9.7.0 includes a number of changes from BIND 9.6 and earlier +releases. Most are intended to simplify DNSSEC configuration. +New features include: + +- Fully automatic signing of zones by "named". +- Simplified configuration of DNSSEC Lookaside Validation (DLV). +- Simplified configuration of Dynamic DNS, using the "ddns-confgen" + command line tool or the "local" update-policy option. (As a side + effect, this also makes it easier to configure automatic zone + re-signing.) +- New named option "attach-cache" that allows multiple views to + share a single cache. +- DNS rebinding attack prevention. +- New default values for dnssec-keygen parameters. +- Support for RFC 5011 automated trust anchor maintenance +- Smart signing: simplified tools for zone signing and key + maintenance. +- The "statistics-channels" option is now available on Windows. +- A new DNSSEC-aware libdns API for use by non-BIND9 applications +- On some platforms, named and other binaries can now print out + a stack backtrace on assertion failure, to aid in debugging. +- A "tools only" installation mode on Windows, which only installs + dig, host, nslookup and nsupdate. +- Improved PKCS#11 support, including Keyper support and explicit + OpenSSL engine selection. + +#### BIND 9.6.0 + +- Full NSEC3 support +- Automatic zone re-signing +- New update-policy methods tcp-self and 6to4-self +- The BIND 8 resolver library, libbind, has been removed from the BIND 9 + distribution and is now available as a separate download. +- Change the default pid file location from /var/run to + /var/run/{named,lwresd} for improved chroot/setuid support. + +#### BIND 9.5.0 + +- GSS-TSIG support (RFC 3645). +- DHCID support. +- Experimental http server and statistics support for named via xml. +- More detailed statistics counters including those supported in BIND 8. +- Faster ACL processing. +- Use Doxygen to generate internal documentation. +- Efficient LRU cache-cleaning mechanism. +- NSID support. + +BIND 9.4.0 + +- Implemented "additional section caching (or acache)", an internal cache + framework for additional section content to improve response performance. + Several configuration options were provided to control the behavior. +- New notify type 'master-only'. Enable notify for master zones only. +- Accept 'notify-source' style syntax for query-source. +- rndc now allows addresses to be set in the server clauses. +- New option "allow-query-cache". This lets "allow-query" be used to + specify the default zone access level rather than having to have every + zone override the global value. "allow-query-cache" can be set at both + the options and view levels. If "allow-query-cache" is not set then + "allow-recursion" is used if set, otherwise "allow-query" is used if set + unless "recursion no;" is set in which case "none;" is used, otherwise + the default (localhost; localnets;) is used. +- rndc: the source address can now be specified. +- ixfr-from-differences now takes master and slave in addition to yes and + no at the options and view levels. +- Allow the journal's name to be changed via named.conf. +- 'rndc notify zone [class [view]]' resend the NOTIFY messages for the + specified zone. +- 'dig +trace' now randomly selects the next servers to try. Report if + there is a bad delegation. +- Improve check-names error messages. +- Make public the function to read a key file, dst_key_read_public(). +- dig now returns the byte count for axfr/ixfr. +- allow-update is now settable at the options / view level. +- named-checkconf now checks the logging configuration. +- host now can turn on memory debugging flags with '-m'. +- Don't send notify messages to self. +- Perform sanity checks on NS records which refer to 'in zone' names. +- New zone option "notify-delay". Specify a minimum delay between sets of + NOTIFY messages. +- Extend adjusting TTL warning messages. +- Named and named-checkzone can now both check for non-terminal wildcard + records. +- "rndc freeze/thaw" now freezes/thaws all zones. +- named-checkconf now check acls to verify that they only refer to existing + acls. +- The server syntax has been extended to support a range of servers. +- Report differences between hints and real NS rrset and associated address + records. +- Preserve the case of domain names in rdata during zone transfers. +- Restructured the data locking framework using architecture dependent + atomic operations (when available), improving response performance on + multi-processor machines significantly. x86, x86_64, alpha, powerpc, and + mips are currently supported. +- UNIX domain controls are now supported. +- Add support for additional zone file formats for improving loading + performance. The masterfile-format option in named.conf can be used to + specify a non-default format. A separate command named-compilezone was + provided to generate zone files in the new format. Additionally, the -I + and -O options for dnssec-signzone specify the input and output formats. +- dnssec-signzone can now randomize signature end times (dnssec-signzone -j + jitter). +- Add support for CH A record. +- Add additional zone data constancy checks. named-checkzone has extended + checking of NS, MX and SRV record and the hosts they reference. named + has extended post zone load checks. New zone options: check-mx and + integrity-check. +- edns-udp-size can now be overridden on a per server basis. +- dig can now specify the EDNS version when making a query. +- Added framework for handling multiple EDNS versions. +- Additional memory debugging support to track size and mctx arguments. +- Detect duplicates of UDP queries we are recursing on and drop them. New + stats category "duplicates". +- "USE INTERNAL MALLOC" is now runtime selectable. +- The lame cache is now done on a basis as some + servers only appear to be lame for certain query types. +- Limit the number of recursive clients that can be waiting for a single + query () to resolve. New options clients-per-query + and max-clients-per-query. +- dig: report the number of extra bytes still left in the packet after + processing all the records. +- Support for IPSECKEY rdata type. +- Raise the UDP receive buffer size to 32k if it is less than 32k. +- x86 and x86_64 now have separate atomic locking implementations. +- named-checkconf now validates update-policy entries. +- Attempt to make the amount of work performed in a iteration self tuning. + The covers nodes clean from the cache per iteration, nodes written to + disk when rewriting a master file and nodes destroyed per iteration when + destroying a zone or a cache. +- ISC string copy API. +- Automatic empty zone creation for D.F.IP6.ARPA and friends. Note: RFC + 1918 zones are not yet covered by this but are likely to be in a future + release. +- New options: empty-server, empty-contact, empty-zones-enable and + disable-empty-zone. +- dig now has a '-q queryname' and '+showsearch' options. +- host/nslookup now continue (default)/fail on SERVFAIL. +- dig now warns if 'RA' is not set in the answer when 'RD' was set in the + query. host/nslookup skip servers that fail to set 'RA' when 'RD' is set + unless a server is explicitly set. +- Integrate contributed DLZ code into named. +- Integrate contributed IDN code from JPNIC. +- libbind: corresponds to that from BIND 8.4.7. + +#### BIND 9.3.0 + +- DNSSEC is now DS based (RFC 3658). +- DNSSEC lookaside validation. +- check-names is now implemented. +- rrset-order is more complete. +- IPv4/IPv6 transition support, dual-stack-servers. +- IXFR deltas can now be generated when loading master files, + ixfr-from-differences. +- It is now possible to specify the size of a journal, max-journal-size. +- It is now possible to define a named set of master servers to be used in + masters clause, masters. +- The advertised EDNS UDP size can now be set, edns-udp-size. +- allow-v6-synthesis has been obsoleted. +- Zones containing MD and MF will now be rejected. +- dig, nslookup name. now report "Not Implemented" as NOTIMP rather than + NOTIMPL. This will have impact on scripts that are looking for NOTIMPL. +- libbind: corresponds to that from BIND 8.4.5. + +#### BIND 9.2.0 + +- The size of the cache can now be limited using the "max-cache-size" + option. +- The server can now automatically convert RFC1886-style recursive lookup + requests into RFC2874-style lookups, when enabled using the new option + "allow-v6-synthesis". This allows stub resolvers that support AAAA + records but not A6 record chains or binary labels to perform lookups in + domains that make use of these IPv6 DNS features. +- Performance has been improved. +- The man pages now use the more portable "man" macros rather than the + "mandoc" macros, and are installed by "make install". +- The named.conf parser has been completely rewritten. It now supports + "include" directives in more places such as inside "view" statements, and + it no longer has any reserved words. +- The "rndc status" command is now implemented. +- rndc can now be configured automatically. +- A BIND 8 compatible stub resolver library is now included in lib/bind. +- OpenSSL has been removed from the distribution. This means that to use + DNSSEC, OpenSSL must be installed and the --with-openssl option must be + supplied to configure. This does not apply to the use of TSIG, which + does not require OpenSSL. +- The source distribution now builds on Windows. See + win32utils/readme1.txt and win32utils/win32-build.txt for details. +- This distribution also includes a new lightweight stub resolver library + and associated resolver daemon that fully support forward and reverse + lookups of both IPv4 and IPv6 addresses. This library is considered + experimental and is not a complete replacement for the BIND 8 resolver + library. Applications that use the BIND 8 `res_*` functions to perform + DNS lookups or dynamic updates still need to be linked against the BIND 8 + libraries. For DNS lookups, they can also use the new "getrrsetbyname()" + API. +- BIND 9.2 is capable of acting as an authoritative server for DNSSEC + secured zones. This functionality is believed to be stable and complete + except for lacking support for verifications involving wildcard records + in secure zones. +- When acting as a caching server, BIND 9.2 can be configured to perform + DNSSEC secure resolution on behalf of its clients. This part of the + DNSSEC implementation is still considered experimental. For detailed + information about the state of the DNSSEC implementation, see the file + doc/misc/dnssec. diff --git a/Kyuafile b/Kyuafile new file mode 100644 index 0000000..083136a --- /dev/null +++ b/Kyuafile @@ -0,0 +1,15 @@ +-- Copyright (C) Internet Systems Consortium, Inc. ("ISC") +-- +-- SPDX-License-Identifier: MPL-2.0 +-- +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this +-- file, you can obtain one at https://mozilla.org/MPL/2.0/. +-- +-- See the COPYRIGHT file distributed with this work for additional +-- information regarding copyright ownership. + +syntax(2) +test_suite('bind9') + +include('lib/Kyuafile') diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7bad356 --- /dev/null +++ b/LICENSE @@ -0,0 +1,362 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000..137069b --- /dev/null +++ b/LICENSES/Apache-2.0.txt @@ -0,0 +1,73 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSES/Autoconf-exception-3.0.txt b/LICENSES/Autoconf-exception-3.0.txt new file mode 100644 index 0000000..f212f9c --- /dev/null +++ b/LICENSES/Autoconf-exception-3.0.txt @@ -0,0 +1,26 @@ +AUTOCONF CONFIGURE SCRIPT EXCEPTION + +Version 3.0, 18 August 2009 +Copyright © 2009 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +This Exception is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). It applies to a given file that bears a notice placed by the copyright holder of the file stating that the file is governed by GPLv3 along with this Exception. + +The purpose of this Exception is to allow distribution of Autoconf's typical output under terms of the recipient's choice (including proprietary). + +0. Definitions. + +"Covered Code" is the source or object code of a version of Autoconf that is a covered work under this License. + +"Normally Copied Code" for a version of Autoconf means all parts of its Covered Code which that version can copy from its code (i.e., not from its input file) into its minimally verbose, non-debugging and non-tracing output. + +"Ineligible Code" is Covered Code that is not Normally Copied Code. + +1. Grant of Additional Permission. + +You have permission to propagate output of Autoconf, even if such propagation would otherwise violate the terms of GPLv3. However, if by modifying Autoconf you cause any Ineligible Code of the version you received to become Normally Copied Code of your modified version, then you void this Exception for the resulting covered work. If you convey that resulting covered work, you must remove this Exception in accordance with the second paragraph of Section 7 of GPLv3. + +2. No Weakening of Autoconf Copyleft. + +The availability of this Exception does not imply any general presumption that third-party software is unaffected by the copyleft requirements of the license of Autoconf. diff --git a/LICENSES/BSD-2-Clause.txt b/LICENSES/BSD-2-Clause.txt new file mode 100644 index 0000000..b0e20f5 --- /dev/null +++ b/LICENSES/BSD-2-Clause.txt @@ -0,0 +1,9 @@ +Copyright (c) All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt new file mode 100644 index 0000000..6c9eef8 --- /dev/null +++ b/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,11 @@ +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/LICENSES/CC0-1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/LICENSES/FSFAP.txt b/LICENSES/FSFAP.txt new file mode 100644 index 0000000..32bc8a8 --- /dev/null +++ b/LICENSES/FSFAP.txt @@ -0,0 +1 @@ +Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. diff --git a/LICENSES/GPL-3.0-or-later.txt b/LICENSES/GPL-3.0-or-later.txt new file mode 100644 index 0000000..d41c0bd --- /dev/null +++ b/LICENSES/GPL-3.0-or-later.txt @@ -0,0 +1,232 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright © 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +Preamble + +The GNU General Public License is a free, copyleft license for software and other kinds of works. + +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. + +Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS + +0. Definitions. + +“This License†refers to version 3 of the GNU General Public License. + +“Copyright†also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. + +“The Program†refers to any copyrightable work licensed under this License. Each licensee is addressed as “youâ€. “Licensees†and “recipients†may be individuals or organizations. + +To “modify†a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version†of the earlier work or a work “based on†the earlier work. + +A “covered work†means either the unmodified Program or a work based on the Program. + +To “propagate†a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. + +To “convey†a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays “Appropriate Legal Notices†to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. + +1. Source Code. +The “source code†for a work means the preferred form of the work for making modifications to it. “Object code†means any non-source form of a work. + +A “Standard Interface†means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. + +The “System Libraries†of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Componentâ€, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. + +The “Corresponding Source†for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +2. Basic Permissions. +All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. +No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. + +4. Conveying Verbatim Copies. +You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. + +5. Conveying Modified Source Versions. +You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all noticesâ€. + + c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate†if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. + +6. Conveying Non-Source Forms. +You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: + + a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. + + d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. + +A “User Product†is either (1) a “consumer productâ€, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used†refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. + +“Installation Information†for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. + +7. Additional Terms. +“Additional permissions†are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or authors of the material; or + + e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. + +All other non-permissive additional terms are considered “further restrictions†within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. + +8. Termination. +You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. + +9. Acceptance Not Required for Having Copies. +You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. + +10. Automatic Licensing of Downstream Recipients. +Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. + +An “entity transaction†is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. + +11. Patents. +A “contributor†is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor versionâ€. + +A contributor's “essential patent claims†are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control†includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. + +In the following three paragraphs, a “patent license†is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant†such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying†means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. + +A patent license is “discriminatory†if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. +If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. + +13. Use with the GNU Affero General Public License. +Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. + +14. Revised Versions of this License. +The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version†applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. + +15. Disclaimer of Warranty. +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS†WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +17. Interpretation of Sections 15 and 16. +If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright†line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about boxâ€. + +You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer†for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . + +The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . diff --git a/LICENSES/ISC.txt b/LICENSES/ISC.txt new file mode 100644 index 0000000..b9c199c --- /dev/null +++ b/LICENSES/ISC.txt @@ -0,0 +1,8 @@ +ISC License: + +Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1995-2003 by Internet Software Consortium + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/LICENSES/LLVM-exception.txt b/LICENSES/LLVM-exception.txt new file mode 100644 index 0000000..fa4b725 --- /dev/null +++ b/LICENSES/LLVM-exception.txt @@ -0,0 +1,15 @@ +---- LLVM Exceptions to the Apache 2.0 License ---- + + As an exception, if, as a result of your compiling your source code, portions + of this Software are embedded into an Object form of such source code, you + may redistribute such embedded portions in such Object form without complying + with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + + In addition, if you combine or link compiled forms of this Software with + software that is licensed under the GPLv2 ("Combined Software") and if a + court of competent jurisdiction determines that the patent provision (Section + 3), the indemnity provision (Section 9) or other Section of the License + conflicts with the conditions of the GPLv2, you may retroactively and + prospectively choose to deem waived or otherwise exclude such Section(s) of + the License, but only in their entirety and only with respect to the Combined + Software. diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 0000000..2071b23 --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSES/MPL-2.0.txt b/LICENSES/MPL-2.0.txt new file mode 100644 index 0000000..6c949ea --- /dev/null +++ b/LICENSES/MPL-2.0.txt @@ -0,0 +1,144 @@ +Mozilla Public License Version 2.0 + +1. Definitions + + 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. + + 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. + + 1.3. "Contribution" means Covered Software of a particular Contributor. + + 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. + + 1.5. "Incompatible With Secondary Licenses" means + + (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. + + 1.6. "Executable Form" means any form of the work other than Source Code Form. + + 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. + + 1.8. "License" means this document. + + 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. + + 1.10. "Modifications" means any of the following: + + (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or + + (b) any new file in Source Code Form that contains any Covered Software. + + 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. + + 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. + + 1.13. "Source Code Form" means the form of the work preferred for making modifications. + + 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants and Conditions + + 2.1. Grants + Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and + + (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. + + 2.2. Effective Date + The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. + + 2.3. Limitations on Grant Scope + The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: + + (a) for any code that a Contributor has removed from Covered Software; or + + (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or + + (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. + + This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). + + 2.4. Subsequent Licenses + No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). + + 2.5. Representation + Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. + + 2.6. Fair Use + This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. + + 2.7. Conditions + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. + +3. Responsibilities + + 3.1. Distribution of Source Form + All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. + + 3.2. Distribution of Executable Form + If You distribute Covered Software in Executable Form then: + + (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and + + (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. + + 3.3. Distribution of a Larger Work + You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). + + 3.4. Notices + You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. + + 3.5. Application of Additional Terms + You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. + +5. Termination + + 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. + + 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. + + 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. + +6. Disclaimer of Warranty +Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. + +7. Limitation of Liability +Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation +Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. + +9. Miscellaneous +This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. + +10. Versions of the License + + 10.1. New Versions + Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. + + 10.2. Effect of New Versions + You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. + + 10.3. Modified Versions + If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). + + 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, you can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..282415d --- /dev/null +++ b/Makefile.in @@ -0,0 +1,111 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ + +PANDOC = @PANDOC@ +W3M = @W3M@ + +VERSION=@BIND9_VERSION@ + +SUBDIRS = make lib fuzz bin doc +TARGETS = +PREREQS = bind.keys.h + +MANOBJS = README HISTORY OPTIONS CONTRIBUTING CODE_OF_CONDUCT + +@BIND9_MAKE_RULES@ + +newrr: + cd lib/dns; ${MAKE} newrr + +bind.keys.h: ${top_srcdir}/bind.keys ${srcdir}/util/bindkeys.pl + ${PERL} ${srcdir}/util/bindkeys.pl < ${top_srcdir}/bind.keys > $@ + +distclean:: + rm -f config.cache config.h config.log config.status TAGS + rm -f libtool configure.lineno + rm -f util/conf.sh docutil/docbook2man-wrapper.sh + +# XXX we should clean libtool stuff too. Only do this after we add rules +# to make it. +maintainer-clean:: + rm -f configure + rm -f bind.keys.h + +docclean manclean maintainer-clean:: + rm -f ${MANOBJS} + +doc man:: ${MANOBJS} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sysconfdir} + +install:: installdirs + ${INSTALL_DATA} ${top_srcdir}/bind.keys ${DESTDIR}${sysconfdir} + +uninstall:: + rm -f ${DESTDIR}${sysconfdir}/bind.keys + +test check: + @if test -n "`${PERL} ${top_srcdir}/bin/tests/system/testsock.pl 2>/dev/null || echo fail`"; then \ + echo I: NOTE: The tests were not run because they require that; \ + echo I: the IP addresses 10.53.0.1 through 10.53.0.8 are configured; \ + echo I: as alias addresses on the loopback interface. Please run; \ + echo I: \'bin/tests/system/ifconfig.sh up\' as root to configure; \ + echo I: them, then rerun the tests. Run make force-test to run the; \ + echo I: tests anyway.; \ + exit 1; \ + fi + ${MAKE} test-force + +force-test: test-force + +test-force: + status=0; \ + (cd fuzz && ${MAKE} check) || status=1; \ + (cd bin/tests && ${MAKE} ${MAKEDEFS} test) || status=1; \ + (test -f ${top_builddir}/unit/unittest.sh && \ + $(SHELL) ${top_builddir}/unit/unittest.sh) || status=1; \ + exit $$status + +README: README.md + ${PANDOC} --email-obfuscation=none -s --metadata title="README" -f markdown-smart -t html README.md | \ + ${W3M} -dump -cols 75 -O ascii -T text/html | \ + sed -e '$${/^$$/d;}' > $@ + +HISTORY: HISTORY.md + ${PANDOC} --email-obfuscation=none -s --metadata title="HISTORY" -f markdown-smart -t html HISTORY.md | \ + ${W3M} -dump -cols 75 -O ascii -T text/html | \ + sed -e '$${/^$$/d;}' > $@ + +OPTIONS: OPTIONS.md + ${PANDOC} --email-obfuscation=none -s --metadata title="OPTIONS" -f markdown-smart -t html OPTIONS.md | \ + ${W3M} -dump -cols 75 -O ascii -T text/html | \ + sed -e '$${/^$$/d;}' > $@ + +CONTRIBUTING: CONTRIBUTING.md + ${PANDOC} --email-obfuscation=none -s --metadata title="CONTRIBUTING" -f markdown-smart -t html CONTRIBUTING.md | \ + ${W3M} -dump -cols 75 -O ascii -T text/html | \ + sed -e '$${/^$$/d;}' > $@ + +CODE_OF_CONDUCT: CODE_OF_CONDUCT.md + ${PANDOC} --email-obfuscation=none -s --metadata title="CODE OF CONDUCT" -f markdown-smart -t html CODE_OF_CONDUCT.md | \ + ${W3M} -dump -cols 75 -O ascii -T text/html | \ + sed -e '$${/^$$/d;}' > $@ + +unit:: + sh ${top_builddir}/unit/unittest.sh + +clean:: diff --git a/OPTIONS b/OPTIONS new file mode 100644 index 0000000..811cf7c --- /dev/null +++ b/OPTIONS @@ -0,0 +1,28 @@ +OPTIONS + +Setting the STD_CDEFINES environment variable before running configure can +be used to enable certain compile-time options that are not explicitly +defined in configure. + +Some of these settings are: + + Setting Description + Overwrite memory with tag values when allocating +-DISC_MEM_DEFAULTFILL=1 or freeing it; this impairs performance but + makes debugging of memory problems easier. + Don't track memory allocations by file and line +-DISC_MEM_TRACKLINES=0 number; this improves performance but makes + debugging more difficult. +-DISC_FACILITY=LOG_LOCAL0 Change the default syslog facility for named +-DNS_CLIENT_DROPPORT=0 Disable dropping queries from particular + well-known ports: +-DCHECK_SIBLING=0 Don't check sibling glue in named-checkzone +-DCHECK_LOCAL=0 Don't check out-of-zone addresses in + named-checkzone +-DNS_RUN_PID_DIR=0 Create default PID files in ${localstatedir}/run + rather than ${localstatedir}/run/named/ + Disable the use of inline functions to implement +-DISC_BUFFER_USEINLINE=0 the isc_buffer API: this reduces performance but + may be useful when debugging +-DISC_HEAP_CHECK Test heap consistency after every heap + operation; used when debugging diff --git a/OPTIONS.md b/OPTIONS.md new file mode 100644 index 0000000..16029e7 --- /dev/null +++ b/OPTIONS.md @@ -0,0 +1,29 @@ + +Setting the `STD_CDEFINES` environment variable before running `configure` +can be used to enable certain compile-time options that are not explicitly +defined in `configure`. + +Some of these settings are: + +|Setting |Description | +|-----------------------------------|----------------------------------------| +|`-DISC_MEM_DEFAULTFILL=1`|Overwrite memory with tag values when allocating or freeing it; this impairs performance but makes debugging of memory problems easier.| +|`-DISC_MEM_TRACKLINES=0`|Don't track memory allocations by file and line number; this improves performance but makes debugging more difficult.| +|`-DISC_FACILITY=LOG_LOCAL0`|Change the default syslog facility for `named`| +|`-DNS_CLIENT_DROPPORT=0`|Disable dropping queries from particular well-known ports:| +|`-DCHECK_SIBLING=0`|Don't check sibling glue in `named-checkzone`| +|`-DCHECK_LOCAL=0`|Don't check out-of-zone addresses in `named-checkzone`| +|`-DNS_RUN_PID_DIR=0`|Create default PID files in `${localstatedir}/run` rather than `${localstatedir}/run/named/`| +|`-DISC_BUFFER_USEINLINE=0`|Disable the use of inline functions to implement the `isc_buffer` API: this reduces performance but may be useful when debugging | +|`-DISC_HEAP_CHECK`|Test heap consistency after every heap operation; used when debugging| diff --git a/README b/README new file mode 100644 index 0000000..cac2dd0 --- /dev/null +++ b/README @@ -0,0 +1,244 @@ +README + +BIND 9 + +Contents + + 1. Introduction + 2. Reporting bugs and getting help + 3. Contributing to BIND + 4. BIND 9.16 features + 5. Building BIND + 6. macOS + 7. Dependencies + 8. Compile-time options + 9. Automated testing +10. Documentation +11. Change log +12. Acknowledgments + +Introduction + +BIND (Berkeley Internet Name Domain) is a complete, highly portable +implementation of the DNS (Domain Name System) protocol. + +The BIND name server, named, is able to serve as an authoritative name +server, recursive resolver, DNS forwarder, or all three simultaneously. It +implements views for split-horizon DNS, automatic DNSSEC zone signing and +key management, catalog zones to facilitate provisioning of zone data +throughout a name server constellation, response policy zones (RPZ) to +protect clients from malicious data, response rate limiting (RRL) and +recursive query limits to reduce distributed denial of service attacks, +and many other advanced DNS features. BIND also includes a suite of +administrative tools, including the dig and delv DNS lookup tools, +nsupdate for dynamic DNS zone updates, rndc for remote name server +administration, and more. + +BIND 9 began as a complete re-write of the BIND architecture that was used +in versions 4 and 8. Internet Systems Consortium (https://www.isc.org), a +501(c)(3) public benefit corporation dedicated to providing software and +services in support of the Internet infrastructure, developed BIND 9 and +is responsible for its ongoing maintenance and improvement. BIND is open +source software licensed under the terms of the Mozilla Public License, +version 2.0. + +For a summary of features introduced in past major releases of BIND, see +the file HISTORY. + +For a detailed list of changes made throughout the history of BIND 9, see +the file CHANGES. See below for details on the CHANGES file format. + +For up-to-date versions and release notes, see https://www.isc.org/ +download/. + +For information about supported platforms, see the "Supported Platforms" +section in the BIND 9 Administrator Reference Manual. + +Reporting bugs and getting help + +To report non-security-sensitive bugs or request new features, you may +open an Issue in the BIND 9 project on the ISC GitLab server at https:// +gitlab.isc.org/isc-projects/bind9. + +Please note that, unless you explicitly mark the newly created Issue as +"confidential", it will be publicly readable. Please do not include any +information in bug reports that you consider to be confidential unless the +issue has been marked as such. In particular, if submitting the contents +of your configuration file in a non-confidential Issue, it is advisable to +obscure key secrets: this can be done automatically by using +named-checkconf -px. + +If the bug you are reporting is a potential security issue, such as an +assertion failure or other crash in named, please do NOT use GitLab to +report it. Instead, send mail to security-officer@isc.org using our +OpenPGP key to secure your message. (Information about OpenPGP and links +to our key can be found at https://www.isc.org/pgpkey.) Please do not +discuss the bug on any public mailing list. + +For a general overview of ISC security policies, read the Knowledge Base +article at https://kb.isc.org/docs/aa-00861. + +Professional support and training for BIND are available from ISC at +https://www.isc.org/support. + +To join the BIND Users mailing list, or view the archives, visit https:// +lists.isc.org/mailman/listinfo/bind-users. + +If you're planning on making changes to the BIND 9 source code, you may +also want to join the BIND Workers mailing list, at https://lists.isc.org/ +mailman/listinfo/bind-workers. + +Contributing to BIND + +ISC maintains a public git repository for BIND; details can be found at +http://www.isc.org/git/. + +Information for BIND contributors can be found in the following files: - +General information: CONTRIBUTING.md - Code of Conduct: CODE_OF_CONDUCT.md +- BIND 9 code style: doc/dev/style.md - BIND architecture and developer +guide: doc/dev/dev.md + +Patches for BIND may be submitted as merge requests in the ISC GitLab +server at at https://gitlab.isc.org/isc-projects/bind9/merge_requests. + +By default, external contributors don't have ability to fork BIND in the +GitLab server, but if you wish to contribute code to BIND, you may request +permission to do so. Thereafter, you can create git branches and directly +submit requests that they be reviewed and merged. + +If you prefer, you may also submit code by opening a GitLab Issue and +including your patch as an attachment, preferably generated by git +format-patch. + +BIND 9.16 features + +BIND 9.16 is the current stable branch of BIND 9. It includes all changes +from the 9.15 development branch, updating the previous stable branch, +9.14. New features include: + + * New dnssec-policy statement to configure a key and signing policy for + zones, enabling automatic key regeneration and rollover. + * New network manager based on libuv. + * Added support for the new GeoIP2 geolocation API, libmaxminddb. + * Improved DNSSEC trust anchor configuration using the trust-anchors + statement, permitting configuration of trust anchors in DS as well as + DNSKEY format. + * YAML output for dig, mdig, and delv. + +Building BIND + +For information about building BIND 9, see the "Building BIND 9" section +in the BIND 9 Administrator Reference Manual. + +Automated testing + +A system test suite can be run with make test. The system tests require +you to configure a set of virtual IP addresses on your system (this allows +multiple servers to run locally and communicate with one another). These +IP addresses can be configured by running the command bin/tests/system/ +ifconfig.sh up as root. + +Some tests require Perl and the Net::DNS and/or IO::Socket::INET6 modules, +and will be skipped if these are not available. Some tests require Python +and the dnspython module and will be skipped if these are not available. +See bin/tests/system/README for further details. + +Unit tests are implemented using the CMocka unit testing framework. To +build them, use configure --with-cmocka. Execution of tests is done by the +Kyua test execution engine; if the kyua command is available, then unit +tests can be run via make test or make unit. + +Documentation + +The BIND 9 Administrator Reference Manual is included with the source +distribution, in DocBook XML, HTML, and PDF format, in the doc/arm +directory. + +Some of the programs in the BIND 9 distribution have man pages in their +directories. In particular, the command line options of named are +documented in bin/named/named.8. + +Frequently (and not-so-frequently) asked questions and their answers can +be found in the ISC Knowledge Base at https://kb.isc.org. + +Additional information on various subjects can be found in other README +files throughout the source tree. + +Change log + +A detailed list of all changes that have been made throughout the +development BIND 9 is included in the file CHANGES, with the most recent +changes listed first. Change notes include tags indicating the category of +the change that was made; these categories are: + + Category Description +[func] New feature +[bug] General bug fix +[security] Fix for a significant security flaw +[experimental] Used for new features when the syntax or other aspects of + the design are still in flux and may change +[port] Portability enhancement +[maint] Updates to built-in data such as root server addresses and + keys +[tuning] Changes to built-in configuration defaults and constants to + improve performance +[performance] Other changes to improve server performance +[protocol] Updates to the DNS protocol such as new RR types +[test] Changes to the automatic tests, not affecting server + functionality +[cleanup] Minor corrections and refactoring +[doc] Documentation +[contrib] Changes to the contributed tools and libraries in the + 'contrib' subdirectory + Used in the main development branch to reserve change +[placeholder] numbers for use in other branches, e.g., when fixing a bug + that only exists in older releases + +In general, [func] and [experimental] tags will only appear in new-feature +releases (i.e., those with version numbers ending in zero). Some new +functionality may be backported to older releases on a case-by-case basis. +All other change types may be applied to all currently-supported releases. + +Bug report identifiers + +Most notes in the CHANGES file include a reference to a bug report or +issue number. Prior to 2018, these were usually of the form [RT #NNN] and +referred to entries in the "bind9-bugs" RT database, which was not open to +the public. More recent entries use the form [GL #NNN] or, less often, [GL +!NNN], which, respectively, refer to issues or merge requests in the +GitLab database. Most of these are publicly readable, unless they include +information which is confidential or security sensitive. + +To look up a GitLab issue by its number, use the URL https:// +gitlab.isc.org/isc-projects/bind9/issues/NNN. To look up a merge request, +use https://gitlab.isc.org/isc-projects/bind9/merge_requests/NNN. + +In rare cases, an issue or merge request number may be followed with the +letter "P". This indicates that the information is in the private ISC +GitLab instance, which is not visible to the public. + +Acknowledgments + + * The original development of BIND 9 was underwritten by the following + organizations: + + Sun Microsystems, Inc. + Hewlett Packard + Compaq Computer Corporation + IBM + Process Software Corporation + Silicon Graphics, Inc. + Network Associates, Inc. + U.S. Defense Information Systems Agency + USENIX Association + Stichting NLnet - NLnet Foundation + Nominum, Inc. + + * This product includes software developed by the OpenSSL Project for + use in the OpenSSL Toolkit. http://www.OpenSSL.org/ + + * This product includes cryptographic software written by Eric Young + (eay@cryptsoft.com) + + * This product includes software written by Tim Hudson + (tjh@cryptsoft.com) diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a6ff6e --- /dev/null +++ b/README.md @@ -0,0 +1,259 @@ + +# BIND 9 + +### Contents + +1. [Introduction](#intro) +1. [Reporting bugs and getting help](#help) +1. [Contributing to BIND](#contrib) +1. [BIND 9.16 features](#features) +1. [Building BIND](#build) +1. [macOS](#macos) +1. [Dependencies](#dependencies) +1. [Compile-time options](#opts) +1. [Automated testing](#testing) +1. [Documentation](#doc) +1. [Change log](#changes) +1. [Acknowledgments](#ack) + +### Introduction + +BIND (Berkeley Internet Name Domain) is a complete, highly portable +implementation of the DNS (Domain Name System) protocol. + +The BIND name server, `named`, is able to serve as an authoritative name +server, recursive resolver, DNS forwarder, or all three simultaneously. It +implements views for split-horizon DNS, automatic DNSSEC zone signing and +key management, catalog zones to facilitate provisioning of zone data +throughout a name server constellation, response policy zones (RPZ) to +protect clients from malicious data, response rate limiting (RRL) and +recursive query limits to reduce distributed denial of service attacks, +and many other advanced DNS features. BIND also includes a suite of +administrative tools, including the `dig` and `delv` DNS lookup tools, +`nsupdate` for dynamic DNS zone updates, `rndc` for remote name server +administration, and more. + +BIND 9 began as a complete re-write of the BIND architecture that was +used in versions 4 and 8. Internet Systems Consortium +([https://www.isc.org](https://www.isc.org)), a 501(c)(3) public benefit +corporation dedicated to providing software and services in support of the +Internet infrastructure, developed BIND 9 and is responsible for its +ongoing maintenance and improvement. BIND is open source software +licensed under the terms of the Mozilla Public License, version 2.0. + +For a summary of features introduced in past major releases of BIND, +see the file [HISTORY](HISTORY.md). + +For a detailed list of changes made throughout the history of BIND 9, see +the file [CHANGES](CHANGES). See [below](#changes) for details on the +CHANGES file format. + +For up-to-date versions and release notes, see +[https://www.isc.org/download/](https://www.isc.org/download/). + +For information about supported platforms, see the +["Supported Platforms"](doc/arm/platforms.rst) section in the BIND 9 +Administrator Reference Manual. + +### Reporting bugs and getting help + +To report non-security-sensitive bugs or request new features, you may +open an Issue in the BIND 9 project on the +[ISC GitLab server](https://gitlab.isc.org) at +[https://gitlab.isc.org/isc-projects/bind9](https://gitlab.isc.org/isc-projects/bind9). + +Please note that, unless you explicitly mark the newly created Issue as +"confidential", it will be publicly readable. Please do not include any +information in bug reports that you consider to be confidential unless +the issue has been marked as such. In particular, if submitting the +contents of your configuration file in a non-confidential Issue, it is +advisable to obscure key secrets: this can be done automatically by +using `named-checkconf -px`. + +If the bug you are reporting is a potential security issue, such as an +assertion failure or other crash in `named`, please do *NOT* use GitLab to +report it. Instead, send mail to +[security-officer@isc.org](mailto:security-officer@isc.org) using our +OpenPGP key to secure your message. (Information about OpenPGP and links +to our key can be found at +[https://www.isc.org/pgpkey](https://www.isc.org/pgpkey).) Please do not +discuss the bug on any public mailing list. + +For a general overview of ISC security policies, read the Knowledge Base +article at [https://kb.isc.org/docs/aa-00861](https://kb.isc.org/docs/aa-00861). + +Professional support and training for BIND are available from +ISC at [https://www.isc.org/support](https://www.isc.org/support). + +To join the __BIND Users__ mailing list, or view the archives, visit +[https://lists.isc.org/mailman/listinfo/bind-users](https://lists.isc.org/mailman/listinfo/bind-users). + +If you're planning on making changes to the BIND 9 source code, you +may also want to join the __BIND Workers__ mailing list, at +[https://lists.isc.org/mailman/listinfo/bind-workers](https://lists.isc.org/mailman/listinfo/bind-workers). + +### Contributing to BIND + +ISC maintains a public git repository for BIND; details can be found +at [http://www.isc.org/git/](http://www.isc.org/git/). + +Information for BIND contributors can be found in the following files: +- General information: [CONTRIBUTING.md](CONTRIBUTING.md) +- Code of Conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) +- BIND 9 code style: [doc/dev/style.md](doc/dev/style.md) +- BIND architecture and developer guide: [doc/dev/dev.md](doc/dev/dev.md) + +Patches for BIND may be submitted as +[merge requests](https://gitlab.isc.org/isc-projects/bind9/merge_requests) +in the [ISC GitLab server](https://gitlab.isc.org) at +at [https://gitlab.isc.org/isc-projects/bind9/merge_requests](https://gitlab.isc.org/isc-projects/bind9/merge_requests). + +By default, external contributors don't have ability to fork BIND in the +GitLab server, but if you wish to contribute code to BIND, you may request +permission to do so. Thereafter, you can create git branches and directly +submit requests that they be reviewed and merged. + +If you prefer, you may also submit code by opening a +[GitLab Issue](https://gitlab.isc.org/isc-projects/bind9/issues) and +including your patch as an attachment, preferably generated by +`git format-patch`. + +### BIND 9.16 features + +BIND 9.16 is the current stable branch of BIND 9. It includes all +changes from the 9.15 development branch, updating the previous stable +branch, 9.14. New features include: + +* New `dnssec-policy` statement to configure a key and signing policy + for zones, enabling automatic key regeneration and rollover. +* New network manager based on `libuv`. +* Added support for the new GeoIP2 geolocation API, `libmaxminddb`. +* Improved DNSSEC trust anchor configuration using the `trust-anchors` + statement, permitting configuration of trust anchors in DS as well as + DNSKEY format. +* YAML output for `dig`, `mdig`, and `delv`. + +### Building BIND + +For information about building BIND 9, see the +["Building BIND 9"](doc/arm/build.rst) section in the BIND 9 +Administrator Reference Manual. + +### Automated testing + +A system test suite can be run with `make test`. The system tests require +you to configure a set of virtual IP addresses on your system (this allows +multiple servers to run locally and communicate with one another). These +IP addresses can be configured by running the command +`bin/tests/system/ifconfig.sh up` as root. + +Some tests require Perl and the `Net::DNS` and/or `IO::Socket::INET6` modules, +and will be skipped if these are not available. Some tests require Python +and the `dnspython` module and will be skipped if these are not available. +See bin/tests/system/README for further details. + +Unit tests are implemented using the [CMocka unit testing framework](https://cmocka.org/). +To build them, use `configure --with-cmocka`. Execution of tests is done +by the [Kyua test execution engine](https://github.com/jmmv/kyua); if the +`kyua` command is available, then unit tests can be run via `make test` +or `make unit`. + +### Documentation + +The *BIND 9 Administrator Reference Manual* is included with the source +distribution, in DocBook XML, HTML, and PDF format, in the `doc/arm` +directory. + +Some of the programs in the BIND 9 distribution have man pages in their +directories. In particular, the command line options of `named` are +documented in `bin/named/named.8`. + +Frequently (and not-so-frequently) asked questions and their answers +can be found in the ISC Knowledge Base at +[https://kb.isc.org](https://kb.isc.org). + +Additional information on various subjects can be found in other +`README` files throughout the source tree. + +### Change log + +A detailed list of all changes that have been made throughout the +development BIND 9 is included in the file CHANGES, with the most recent +changes listed first. Change notes include tags indicating the category of +the change that was made; these categories are: + +|Category |Description | +|-------------- |-----------------------------------------------| +| [func] | New feature | +| [bug] | General bug fix | +| [security] | Fix for a significant security flaw | +| [experimental] | Used for new features when the syntax or other aspects of the design are still in flux and may change | +| [port] | Portability enhancement | +| [maint] | Updates to built-in data such as root server addresses and keys | +| [tuning] | Changes to built-in configuration defaults and constants to improve performance | +| [performance] | Other changes to improve server performance | +| [protocol] | Updates to the DNS protocol such as new RR types | +| [test] | Changes to the automatic tests, not affecting server functionality | +| [cleanup] | Minor corrections and refactoring | +| [doc] | Documentation | +| [contrib] | Changes to the contributed tools and libraries in the 'contrib' subdirectory | +| [placeholder] | Used in the main development branch to reserve change numbers for use in other branches, e.g., when fixing a bug that only exists in older releases | + +In general, [func] and [experimental] tags will only appear in new-feature +releases (i.e., those with version numbers ending in zero). Some new +functionality may be backported to older releases on a case-by-case basis. +All other change types may be applied to all currently-supported releases. + +#### Bug report identifiers + +Most notes in the CHANGES file include a reference to a bug report or +issue number. Prior to 2018, these were usually of the form `[RT #NNN]` +and referred to entries in the "bind9-bugs" RT database, which was not open +to the public. More recent entries use the form `[GL #NNN]` or, less often, +`[GL !NNN]`, which, respectively, refer to issues or merge requests in the +GitLab database. Most of these are publicly readable, unless they include +information which is confidential or security sensitive. + +To look up a GitLab issue by its number, use the URL +[https://gitlab.isc.org/isc-projects/bind9/issues/NNN](https://gitlab.isc.org/isc-projects/bind9/issues). +To look up a merge request, use +[https://gitlab.isc.org/isc-projects/bind9/merge_requests/NNN](https://gitlab.isc.org/isc-projects/bind9/merge_requests). + +In rare cases, an issue or merge request number may be followed with the +letter "P". This indicates that the information is in the private ISC +GitLab instance, which is not visible to the public. + +### Acknowledgments + +* The original development of BIND 9 was underwritten by the + following organizations: + + Sun Microsystems, Inc. + Hewlett Packard + Compaq Computer Corporation + IBM + Process Software Corporation + Silicon Graphics, Inc. + Network Associates, Inc. + U.S. Defense Information Systems Agency + USENIX Association + Stichting NLnet - NLnet Foundation + Nominum, Inc. + +* This product includes software developed by the OpenSSL Project for use + in the OpenSSL Toolkit. + [http://www.OpenSSL.org/](http://www.OpenSSL.org/) +* This product includes cryptographic software written by Eric Young + (eay@cryptsoft.com) +* This product includes software written by Tim Hudson (tjh@cryptsoft.com) diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..6977695 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,388 @@ +# generated automatically by aclocal 1.16.3 -*- Autoconf -*- + +# Copyright (C) 1996-2020 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 12 (pkg-config-0.29.2) + +dnl Copyright © 2004 Scott James Remnant . +dnl Copyright © 2012-2015 Dan Nicholson +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.2]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have to call PKG_CHECK_EXISTS manually +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $2]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Copyright (C) 2006-2020 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +m4_include([m4/ax_check_compile_flag.m4]) +m4_include([m4/ax_check_openssl.m4]) +m4_include([m4/ax_gcc_func_attribute.m4]) +m4_include([m4/ax_posix_shell.m4]) +m4_include([m4/ax_pthread.m4]) +m4_include([m4/ax_restore_flags.m4]) +m4_include([m4/ax_save_flags.m4]) +m4_include([m4/libtool.m4]) +m4_include([m4/ltoptions.m4]) +m4_include([m4/ltsugar.m4]) +m4_include([m4/ltversion.m4]) +m4_include([m4/lt~obsolete.m4]) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..2562151 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +# Run this script after modifying configure.in to generate configure +autoreconf -f -i diff --git a/bin/Makefile.in b/bin/Makefile.in new file mode 100644 index 0000000..4eb2f34 --- /dev/null +++ b/bin/Makefile.in @@ -0,0 +1,20 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +SUBDIRS = named rndc dig delv dnssec tools nsupdate check confgen \ + @NZD_TOOLS@ @PYTHON_TOOLS@ @PKCS11_TOOLS@ plugins tests +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/bin/check/Makefile.in b/bin/check/Makefile.in new file mode 100644 index 0000000..e907c7d --- /dev/null +++ b/bin/check/Makefile.in @@ -0,0 +1,88 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = ${NS_INCLUDES} ${BIND9_INCLUDES} ${DNS_INCLUDES} \ + ${ISCCFG_INCLUDES} ${ISC_INCLUDES} ${OPENSSL_CFLAGS} + +CDEFINES = -DNAMED_CONFFILE=\"${sysconfdir}/named.conf\" +CWARNINGS = + +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +BIND9LIBS = ../../lib/bind9/libbind9.@A@ +NSLIBS = ../../lib/ns/libns.@A@ + +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ +NSDEPENDLIBS = ../../lib/ns/libns.@A@ + +LIBS = ${ISCLIBS} @LIBS@ +NOSYMLIBS = ${ISCNOSYMLIBS} @LIBS@ + +SUBDIRS = + +# Alphabetically +TARGETS = named-checkconf@EXEEXT@ named-checkzone@EXEEXT@ + +# Alphabetically +SRCS = named-checkconf.c named-checkzone.c check-tool.c + +@BIND9_MAKE_RULES@ + +named-checkconf.@O@: named-checkconf.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -c ${srcdir}/named-checkconf.c + +named-checkzone.@O@: named-checkzone.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -c ${srcdir}/named-checkzone.c + +named-checkconf@EXEEXT@: named-checkconf.@O@ check-tool.@O@ ${ISCDEPLIBS} \ + ${NSDEPENDLIBS} ${DNSDEPLIBS} ${ISCCFGDEPLIBS} ${BIND9DEPLIBS} + export BASEOBJS="named-checkconf.@O@ check-tool.@O@"; \ + export LIBS0="${BIND9LIBS} ${NSLIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \ + ${FINALBUILDCMD} + +named-checkzone@EXEEXT@: named-checkzone.@O@ check-tool.@O@ ${ISCDEPLIBS} \ + ${NSDEPENDLIBS} ${DNSDEPLIBS} + export BASEOBJS="named-checkzone.@O@ check-tool.@O@"; \ + export LIBS0="${NSLIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \ + ${FINALBUILDCMD} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} + +install:: named-checkconf@EXEEXT@ named-checkzone@EXEEXT@ installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-checkconf@EXEEXT@ ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-checkzone@EXEEXT@ ${DESTDIR}${sbindir} + (cd ${DESTDIR}${sbindir}; rm -f named-compilezone@EXEEXT@; ${LINK_PROGRAM} named-checkzone@EXEEXT@ named-compilezone@EXEEXT@) + +uninstall:: + rm -f ${DESTDIR}${sbindir}/named-compilezone@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${sbindir}/named-checkconf@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${sbindir}/named-checkzone@EXEEXT@ + +clean distclean:: + rm -f ${TARGETS} r1.htm diff --git a/bin/check/check-tool.c b/bin/check/check-tool.c new file mode 100644 index 0000000..cad2185 --- /dev/null +++ b/bin/check/check-tool.c @@ -0,0 +1,812 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#ifdef _WIN32 +#include +#endif /* ifdef _WIN32 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "check-tool.h" + +#ifndef CHECK_SIBLING +#define CHECK_SIBLING 1 +#endif /* ifndef CHECK_SIBLING */ + +#ifndef CHECK_LOCAL +#define CHECK_LOCAL 1 +#endif /* ifndef CHECK_LOCAL */ + +#define CHECK(r) \ + do { \ + result = (r); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +#define ERR_IS_CNAME 1 +#define ERR_NO_ADDRESSES 2 +#define ERR_LOOKUP_FAILURE 3 +#define ERR_EXTRA_A 4 +#define ERR_EXTRA_AAAA 5 +#define ERR_MISSING_GLUE 5 +#define ERR_IS_MXCNAME 6 +#define ERR_IS_SRVCNAME 7 + +static const char *dbtype[] = { "rbt" }; + +int debug = 0; +const char *journal = NULL; +bool nomerge = true; +#if CHECK_LOCAL +bool docheckmx = true; +bool dochecksrv = true; +bool docheckns = true; +#else /* if CHECK_LOCAL */ +bool docheckmx = false; +bool dochecksrv = false; +bool docheckns = false; +#endif /* if CHECK_LOCAL */ +dns_zoneopt_t zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_CHECKMX | + DNS_ZONEOPT_MANYERRORS | DNS_ZONEOPT_CHECKNAMES | + DNS_ZONEOPT_CHECKINTEGRITY | +#if CHECK_SIBLING + DNS_ZONEOPT_CHECKSIBLING | +#endif /* if CHECK_SIBLING */ + DNS_ZONEOPT_CHECKWILDCARD | + DNS_ZONEOPT_WARNMXCNAME | DNS_ZONEOPT_WARNSRVCNAME; + +/* + * This needs to match the list in bin/named/log.c. + */ +static isc_logcategory_t categories[] = { { "", 0 }, + { "unmatched", 0 }, + { NULL, 0 } }; + +static isc_symtab_t *symtab = NULL; +static isc_mem_t *sym_mctx; + +static void +freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) { + UNUSED(type); + UNUSED(value); + isc_mem_free(userarg, key); +} + +static void +add(char *key, int value) { + isc_result_t result; + isc_symvalue_t symvalue; + + if (sym_mctx == NULL) { + isc_mem_create(&sym_mctx); + } + + if (symtab == NULL) { + result = isc_symtab_create(sym_mctx, 100, freekey, sym_mctx, + false, &symtab); + if (result != ISC_R_SUCCESS) { + return; + } + } + + key = isc_mem_strdup(sym_mctx, key); + + symvalue.as_pointer = NULL; + result = isc_symtab_define(symtab, key, value, symvalue, + isc_symexists_reject); + if (result != ISC_R_SUCCESS) { + isc_mem_free(sym_mctx, key); + } +} + +static bool +logged(char *key, int value) { + isc_result_t result; + + if (symtab == NULL) { + return (false); + } + + result = isc_symtab_lookup(symtab, key, value, NULL); + if (result == ISC_R_SUCCESS) { + return (true); + } + return (false); +} + +static bool +checkns(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner, + dns_rdataset_t *a, dns_rdataset_t *aaaa) { + dns_rdataset_t *rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + struct addrinfo hints, *ai, *cur; + char namebuf[DNS_NAME_FORMATSIZE + 1]; + char ownerbuf[DNS_NAME_FORMATSIZE]; + char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")]; + bool answer = true; + bool match; + const char *type; + void *ptr = NULL; + int result; + + REQUIRE(a == NULL || !dns_rdataset_isassociated(a) || + a->type == dns_rdatatype_a); + REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) || + aaaa->type == dns_rdatatype_aaaa); + + if (a == NULL || aaaa == NULL) { + return (answer); + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + /* + * Turn off search. + */ + if (dns_name_countlabels(name) > 1U) { + strlcat(namebuf, ".", sizeof(namebuf)); + } + dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); + + result = getaddrinfo(namebuf, NULL, &hints, &ai); + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + switch (result) { + case 0: + /* + * Work around broken getaddrinfo() implementations that + * fail to set ai_canonname on first entry. + */ + cur = ai; + while (cur != NULL && cur->ai_canonname == NULL && + cur->ai_next != NULL) + { + cur = cur->ai_next; + } + if (cur != NULL && cur->ai_canonname != NULL && + strcasecmp(cur->ai_canonname, namebuf) != 0 && + !logged(namebuf, ERR_IS_CNAME)) + { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/NS '%s' (out of zone) " + "is a CNAME '%s' (illegal)", + ownerbuf, namebuf, cur->ai_canonname); + /* XXX950 make fatal for 9.5.0 */ + /* answer = false; */ + add(namebuf, ERR_IS_CNAME); + } + break; + case EAI_NONAME: +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */ + if (!logged(namebuf, ERR_NO_ADDRESSES)) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/NS '%s' (out of zone) " + "has no addresses records (A or AAAA)", + ownerbuf, namebuf); + add(namebuf, ERR_NO_ADDRESSES); + } + /* XXX950 make fatal for 9.5.0 */ + return (true); + + default: + if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { + dns_zone_log(zone, ISC_LOG_WARNING, + "getaddrinfo(%s) failed: %s", namebuf, + gai_strerror(result)); + add(namebuf, ERR_LOOKUP_FAILURE); + } + return (true); + } + + /* + * Check that all glue records really exist. + */ + if (!dns_rdataset_isassociated(a)) { + goto checkaaaa; + } + result = dns_rdataset_first(a); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(a, &rdata); + match = false; + for (cur = ai; cur != NULL; cur = cur->ai_next) { + if (cur->ai_family != AF_INET) { + continue; + } + ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr; + if (memcmp(ptr, rdata.data, rdata.length) == 0) { + match = true; + break; + } + } + if (!match && !logged(namebuf, ERR_EXTRA_A)) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/NS '%s' " + "extra GLUE A record (%s)", + ownerbuf, namebuf, + inet_ntop(AF_INET, rdata.data, addrbuf, + sizeof(addrbuf))); + add(namebuf, ERR_EXTRA_A); + /* XXX950 make fatal for 9.5.0 */ + /* answer = false; */ + } + dns_rdata_reset(&rdata); + result = dns_rdataset_next(a); + } + +checkaaaa: + if (!dns_rdataset_isassociated(aaaa)) { + goto checkmissing; + } + result = dns_rdataset_first(aaaa); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(aaaa, &rdata); + match = false; + for (cur = ai; cur != NULL; cur = cur->ai_next) { + if (cur->ai_family != AF_INET6) { + continue; + } + ptr = &((struct sockaddr_in6 *)(cur->ai_addr)) + ->sin6_addr; + if (memcmp(ptr, rdata.data, rdata.length) == 0) { + match = true; + break; + } + } + if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/NS '%s' " + "extra GLUE AAAA record (%s)", + ownerbuf, namebuf, + inet_ntop(AF_INET6, rdata.data, addrbuf, + sizeof(addrbuf))); + add(namebuf, ERR_EXTRA_AAAA); + /* XXX950 make fatal for 9.5.0. */ + /* answer = false; */ + } + dns_rdata_reset(&rdata); + result = dns_rdataset_next(aaaa); + } + +checkmissing: + /* + * Check that all addresses appear in the glue. + */ + if (!logged(namebuf, ERR_MISSING_GLUE)) { + bool missing_glue = false; + for (cur = ai; cur != NULL; cur = cur->ai_next) { + switch (cur->ai_family) { + case AF_INET: + rdataset = a; + ptr = &((struct sockaddr_in *)(cur->ai_addr)) + ->sin_addr; + type = "A"; + break; + case AF_INET6: + rdataset = aaaa; + ptr = &((struct sockaddr_in6 *)(cur->ai_addr)) + ->sin6_addr; + type = "AAAA"; + break; + default: + continue; + } + match = false; + if (dns_rdataset_isassociated(rdataset)) { + result = dns_rdataset_first(rdataset); + } else { + result = ISC_R_FAILURE; + } + while (result == ISC_R_SUCCESS && !match) { + dns_rdataset_current(rdataset, &rdata); + if (memcmp(ptr, rdata.data, rdata.length) == 0) + { + match = true; + } + dns_rdata_reset(&rdata); + result = dns_rdataset_next(rdataset); + } + if (!match) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/NS '%s' " + "missing GLUE %s record (%s)", + ownerbuf, namebuf, type, + inet_ntop(cur->ai_family, ptr, + addrbuf, + sizeof(addrbuf))); + /* XXX950 make fatal for 9.5.0. */ + /* answer = false; */ + missing_glue = true; + } + } + if (missing_glue) { + add(namebuf, ERR_MISSING_GLUE); + } + } + freeaddrinfo(ai); + return (answer); +} + +static bool +checkmx(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) { + struct addrinfo hints, *ai, *cur; + char namebuf[DNS_NAME_FORMATSIZE + 1]; + char ownerbuf[DNS_NAME_FORMATSIZE]; + int result; + int level = ISC_LOG_ERROR; + bool answer = true; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + /* + * Turn off search. + */ + if (dns_name_countlabels(name) > 1U) { + strlcat(namebuf, ".", sizeof(namebuf)); + } + dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); + + result = getaddrinfo(namebuf, NULL, &hints, &ai); + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + switch (result) { + case 0: + /* + * Work around broken getaddrinfo() implementations that + * fail to set ai_canonname on first entry. + */ + cur = ai; + while (cur != NULL && cur->ai_canonname == NULL && + cur->ai_next != NULL) + { + cur = cur->ai_next; + } + if (cur != NULL && cur->ai_canonname != NULL && + strcasecmp(cur->ai_canonname, namebuf) != 0) + { + if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0) { + level = ISC_LOG_WARNING; + } + if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) { + if (!logged(namebuf, ERR_IS_MXCNAME)) { + dns_zone_log(zone, level, + "%s/MX '%s' (out of zone)" + " is a CNAME '%s' " + "(illegal)", + ownerbuf, namebuf, + cur->ai_canonname); + add(namebuf, ERR_IS_MXCNAME); + } + if (level == ISC_LOG_ERROR) { + answer = false; + } + } + } + freeaddrinfo(ai); + return (answer); + + case EAI_NONAME: +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */ + if (!logged(namebuf, ERR_NO_ADDRESSES)) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/MX '%s' (out of zone) " + "has no addresses records (A or AAAA)", + ownerbuf, namebuf); + add(namebuf, ERR_NO_ADDRESSES); + } + /* XXX950 make fatal for 9.5.0. */ + return (true); + + default: + if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { + dns_zone_log(zone, ISC_LOG_WARNING, + "getaddrinfo(%s) failed: %s", namebuf, + gai_strerror(result)); + add(namebuf, ERR_LOOKUP_FAILURE); + } + return (true); + } +} + +static bool +checksrv(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) { + struct addrinfo hints, *ai, *cur; + char namebuf[DNS_NAME_FORMATSIZE + 1]; + char ownerbuf[DNS_NAME_FORMATSIZE]; + int result; + int level = ISC_LOG_ERROR; + bool answer = true; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + /* + * Turn off search. + */ + if (dns_name_countlabels(name) > 1U) { + strlcat(namebuf, ".", sizeof(namebuf)); + } + dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); + + result = getaddrinfo(namebuf, NULL, &hints, &ai); + dns_name_format(name, namebuf, sizeof(namebuf) - 1); + switch (result) { + case 0: + /* + * Work around broken getaddrinfo() implementations that + * fail to set ai_canonname on first entry. + */ + cur = ai; + while (cur != NULL && cur->ai_canonname == NULL && + cur->ai_next != NULL) + { + cur = cur->ai_next; + } + if (cur != NULL && cur->ai_canonname != NULL && + strcasecmp(cur->ai_canonname, namebuf) != 0) + { + if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0) { + level = ISC_LOG_WARNING; + } + if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) { + if (!logged(namebuf, ERR_IS_SRVCNAME)) { + dns_zone_log(zone, level, + "%s/SRV '%s'" + " (out of zone) is a " + "CNAME '%s' (illegal)", + ownerbuf, namebuf, + cur->ai_canonname); + add(namebuf, ERR_IS_SRVCNAME); + } + if (level == ISC_LOG_ERROR) { + answer = false; + } + } + } + freeaddrinfo(ai); + return (answer); + + case EAI_NONAME: +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */ + if (!logged(namebuf, ERR_NO_ADDRESSES)) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/SRV '%s' (out of zone) " + "has no addresses records (A or AAAA)", + ownerbuf, namebuf); + add(namebuf, ERR_NO_ADDRESSES); + } + /* XXX950 make fatal for 9.5.0. */ + return (true); + + default: + if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { + dns_zone_log(zone, ISC_LOG_WARNING, + "getaddrinfo(%s) failed: %s", namebuf, + gai_strerror(result)); + add(namebuf, ERR_LOOKUP_FAILURE); + } + return (true); + } +} + +isc_result_t +setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) { + isc_logdestination_t destination; + isc_logconfig_t *logconfig = NULL; + isc_log_t *log = NULL; + + isc_log_create(mctx, &log, &logconfig); + isc_log_registercategories(log, categories); + isc_log_setcontext(log); + dns_log_init(log); + dns_log_setcontext(log); + cfg_log_init(log); + ns_log_init(log); + + destination.file.stream = errout; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, 0); + + RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL) == + ISC_R_SUCCESS); + + *logp = log; + return (ISC_R_SUCCESS); +} + +/*% scan the zone for oversize TTLs */ +static isc_result_t +check_ttls(dns_zone_t *zone, dns_ttl_t maxttl) { + isc_result_t result; + dns_db_t *db = NULL; + dns_dbversion_t *version = NULL; + dns_dbnode_t *node = NULL; + dns_dbiterator_t *dbiter = NULL; + dns_rdatasetiter_t *rdsiter = NULL; + dns_rdataset_t rdataset; + dns_fixedname_t fname; + dns_name_t *name; + name = dns_fixedname_initname(&fname); + dns_rdataset_init(&rdataset); + + CHECK(dns_zone_getdb(zone, &db)); + INSIST(db != NULL); + + CHECK(dns_db_newversion(db, &version)); + CHECK(dns_db_createiterator(db, 0, &dbiter)); + + for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS; + result = dns_dbiterator_next(dbiter)) + { + result = dns_dbiterator_current(dbiter, &node, name); + if (result == DNS_R_NEWORIGIN) { + result = ISC_R_SUCCESS; + } + CHECK(result); + + CHECK(dns_db_allrdatasets(db, node, version, 0, 0, &rdsiter)); + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) + { + dns_rdatasetiter_current(rdsiter, &rdataset); + if (rdataset.ttl > maxttl) { + char nbuf[DNS_NAME_FORMATSIZE]; + char tbuf[255]; + isc_buffer_t b; + isc_region_t r; + + dns_name_format(name, nbuf, sizeof(nbuf)); + isc_buffer_init(&b, tbuf, sizeof(tbuf) - 1); + CHECK(dns_rdatatype_totext(rdataset.type, &b)); + isc_buffer_usedregion(&b, &r); + r.base[r.length] = 0; + + dns_zone_log(zone, ISC_LOG_ERROR, + "%s/%s TTL %d exceeds " + "maximum TTL %d", + nbuf, tbuf, rdataset.ttl, maxttl); + dns_rdataset_disassociate(&rdataset); + CHECK(ISC_R_RANGE); + } + dns_rdataset_disassociate(&rdataset); + } + if (result == ISC_R_NOMORE) { + result = ISC_R_SUCCESS; + } + CHECK(result); + + dns_rdatasetiter_destroy(&rdsiter); + dns_db_detachnode(db, &node); + } + + if (result == ISC_R_NOMORE) { + result = ISC_R_SUCCESS; + } + +cleanup: + if (node != NULL) { + dns_db_detachnode(db, &node); + } + if (rdsiter != NULL) { + dns_rdatasetiter_destroy(&rdsiter); + } + if (dbiter != NULL) { + dns_dbiterator_destroy(&dbiter); + } + if (version != NULL) { + dns_db_closeversion(db, &version, false); + } + if (db != NULL) { + dns_db_detach(&db); + } + + return (result); +} + +/*% load the zone */ +isc_result_t +load_zone(isc_mem_t *mctx, const char *zonename, const char *filename, + dns_masterformat_t fileformat, const char *classname, + dns_ttl_t maxttl, dns_zone_t **zonep) { + isc_result_t result; + dns_rdataclass_t rdclass; + isc_textregion_t region; + isc_buffer_t buffer; + dns_fixedname_t fixorigin; + dns_name_t *origin; + dns_zone_t *zone = NULL; + + REQUIRE(zonep == NULL || *zonep == NULL); + + if (debug) { + fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n", + zonename, filename, classname); + } + + CHECK(dns_zone_create(&zone, mctx)); + + dns_zone_settype(zone, dns_zone_primary); + + isc_buffer_constinit(&buffer, zonename, strlen(zonename)); + isc_buffer_add(&buffer, strlen(zonename)); + origin = dns_fixedname_initname(&fixorigin); + CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL)); + CHECK(dns_zone_setorigin(zone, origin)); + dns_zone_setdbtype(zone, 1, (const char *const *)dbtype); + CHECK(dns_zone_setfile(zone, filename, fileformat, + &dns_master_style_default)); + if (journal != NULL) { + CHECK(dns_zone_setjournal(zone, journal)); + } + + DE_CONST(classname, region.base); + region.length = strlen(classname); + CHECK(dns_rdataclass_fromtext(&rdclass, ®ion)); + + dns_zone_setclass(zone, rdclass); + dns_zone_setoption(zone, zone_options, true); + dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge); + + dns_zone_setmaxttl(zone, maxttl); + + if (docheckmx) { + dns_zone_setcheckmx(zone, checkmx); + } + if (docheckns) { + dns_zone_setcheckns(zone, checkns); + } + if (dochecksrv) { + dns_zone_setchecksrv(zone, checksrv); + } + + CHECK(dns_zone_load(zone, false)); + + /* + * When loading map files we can't catch oversize TTLs during + * load, so we check for them here. + */ + if (fileformat == dns_masterformat_map && maxttl != 0) { + CHECK(check_ttls(zone, maxttl)); + } + + if (zonep != NULL) { + *zonep = zone; + zone = NULL; + } + +cleanup: + if (zone != NULL) { + dns_zone_detach(&zone); + } + return (result); +} + +/*% dump the zone */ +isc_result_t +dump_zone(const char *zonename, dns_zone_t *zone, const char *filename, + dns_masterformat_t fileformat, const dns_master_style_t *style, + const uint32_t rawversion) { + isc_result_t result; + FILE *output = stdout; + const char *flags; + + flags = (fileformat == dns_masterformat_text) ? "w" : "wb"; + + if (debug) { + if (filename != NULL && strcmp(filename, "-") != 0) { + fprintf(stderr, "dumping \"%s\" to \"%s\"\n", zonename, + filename); + } else { + fprintf(stderr, "dumping \"%s\"\n", zonename); + } + } + + if (filename != NULL && strcmp(filename, "-") != 0) { + result = isc_stdio_open(filename, flags, &output); + + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "could not open output " + "file \"%s\" for writing\n", + filename); + return (ISC_R_FAILURE); + } + } + + result = dns_zone_dumptostream(zone, output, fileformat, style, + rawversion); + if (output != stdout) { + (void)isc_stdio_close(output); + } + + return (result); +} + +#ifdef _WIN32 +void +InitSockets(void) { + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD(2, 0); + + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + fprintf(stderr, "WSAStartup() failed: %d\n", err); + exit(1); + } +} + +void +DestroySockets(void) { + WSACleanup(); +} +#endif /* ifdef _WIN32 */ diff --git a/bin/check/check-tool.h b/bin/check/check-tool.h new file mode 100644 index 0000000..735ad43 --- /dev/null +++ b/bin/check/check-tool.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef CHECK_TOOL_H +#define CHECK_TOOL_H + +/*! \file */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp); + +isc_result_t +load_zone(isc_mem_t *mctx, const char *zonename, const char *filename, + dns_masterformat_t fileformat, const char *classname, + dns_ttl_t maxttl, dns_zone_t **zonep); + +isc_result_t +dump_zone(const char *zonename, dns_zone_t *zone, const char *filename, + dns_masterformat_t fileformat, const dns_master_style_t *style, + const uint32_t rawversion); + +#ifdef _WIN32 +void +InitSockets(void); +void +DestroySockets(void); +#endif /* ifdef _WIN32 */ + +extern int debug; +extern const char *journal; +extern bool nomerge; +extern bool docheckmx; +extern bool docheckns; +extern bool dochecksrv; +extern dns_zoneopt_t zone_options; + +ISC_LANG_ENDDECLS + +#endif /* ifndef CHECK_TOOL_H */ diff --git a/bin/check/named-checkconf.c b/bin/check/named-checkconf.c new file mode 100644 index 0000000..9e54d34 --- /dev/null +++ b/bin/check/named-checkconf.c @@ -0,0 +1,771 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "check-tool.h" + +static const char *program = "named-checkconf"; + +static bool loadplugins = true; + +isc_log_t *logc = NULL; + +#define CHECK(r) \ + do { \ + result = (r); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +/*% usage */ +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, + "usage: %s [-chijlvz] [-p [-x]] [-t directory] " + "[named.conf]\n", + program); + exit(1); +} + +/*% directory callback */ +static isc_result_t +directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { + isc_result_t result; + const char *directory; + + REQUIRE(strcasecmp("directory", clausename) == 0); + + UNUSED(arg); + UNUSED(clausename); + + /* + * Change directory. + */ + directory = cfg_obj_asstring(obj); + result = isc_dir_chdir(directory); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(obj, logc, ISC_LOG_ERROR, + "change directory to '%s' failed: %s\n", directory, + isc_result_totext(result)); + return (result); + } + + return (ISC_R_SUCCESS); +} + +static bool +get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) { + int i; + for (i = 0;; i++) { + if (maps[i] == NULL) { + return (false); + } + if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) { + return (true); + } + } +} + +static bool +get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) { + const cfg_listelt_t *element; + const cfg_obj_t *checknames; + const cfg_obj_t *type; + const cfg_obj_t *value; + isc_result_t result; + int i; + + for (i = 0;; i++) { + if (maps[i] == NULL) { + return (false); + } + checknames = NULL; + result = cfg_map_get(maps[i], "check-names", &checknames); + if (result != ISC_R_SUCCESS) { + continue; + } + if (checknames != NULL && !cfg_obj_islist(checknames)) { + *obj = checknames; + return (true); + } + for (element = cfg_list_first(checknames); element != NULL; + element = cfg_list_next(element)) + { + value = cfg_listelt_value(element); + type = cfg_tuple_get(value, "type"); + if ((strcasecmp(cfg_obj_asstring(type), "primary") != + 0) && + (strcasecmp(cfg_obj_asstring(type), "master") != 0)) + { + continue; + } + *obj = cfg_tuple_get(value, "mode"); + return (true); + } + } +} + +static isc_result_t +configure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) { + isc_result_t result; + dns_db_t *db = NULL; + dns_rdataclass_t rdclass; + isc_textregion_t r; + + if (zfile == NULL) { + return (ISC_R_FAILURE); + } + + DE_CONST(zclass, r.base); + r.length = strlen(zclass); + result = dns_rdataclass_fromtext(&rdclass, &r); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = dns_rootns_create(mctx, rdclass, zfile, &db); + if (result != ISC_R_SUCCESS) { + return (result); + } + + dns_db_detach(&db); + return (ISC_R_SUCCESS); +} + +/*% configure the zone */ +static isc_result_t +configure_zone(const char *vclass, const char *view, const cfg_obj_t *zconfig, + const cfg_obj_t *vconfig, const cfg_obj_t *config, + isc_mem_t *mctx, bool list) { + int i = 0; + isc_result_t result; + const char *zclass; + const char *zname; + const char *zfile = NULL; + const cfg_obj_t *maps[4]; + const cfg_obj_t *primariesobj = NULL; + const cfg_obj_t *inviewobj = NULL; + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *classobj = NULL; + const cfg_obj_t *typeobj = NULL; + const cfg_obj_t *fileobj = NULL; + const cfg_obj_t *dlzobj = NULL; + const cfg_obj_t *dbobj = NULL; + const cfg_obj_t *obj = NULL; + const cfg_obj_t *fmtobj = NULL; + dns_masterformat_t masterformat; + dns_ttl_t maxttl = 0; + + zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS; + + zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + classobj = cfg_tuple_get(zconfig, "class"); + if (!cfg_obj_isstring(classobj)) { + zclass = vclass; + } else { + zclass = cfg_obj_asstring(classobj); + } + + zoptions = cfg_tuple_get(zconfig, "options"); + maps[i++] = zoptions; + if (vconfig != NULL) { + maps[i++] = cfg_tuple_get(vconfig, "options"); + } + if (config != NULL) { + cfg_map_get(config, "options", &obj); + if (obj != NULL) { + maps[i++] = obj; + } + } + maps[i] = NULL; + + cfg_map_get(zoptions, "in-view", &inviewobj); + if (inviewobj != NULL && list) { + const char *inview = cfg_obj_asstring(inviewobj); + printf("%s %s %s in-view %s\n", zname, zclass, view, inview); + } + if (inviewobj != NULL) { + return (ISC_R_SUCCESS); + } + + cfg_map_get(zoptions, "type", &typeobj); + if (typeobj == NULL) { + return (ISC_R_FAILURE); + } + + if (list) { + const char *ztype = cfg_obj_asstring(typeobj); + printf("%s %s %s %s\n", zname, zclass, view, ztype); + return (ISC_R_SUCCESS); + } + + /* + * Skip checks when using an alternate data source. + */ + cfg_map_get(zoptions, "database", &dbobj); + if (dbobj != NULL && strcmp("rbt", cfg_obj_asstring(dbobj)) != 0 && + strcmp("rbt64", cfg_obj_asstring(dbobj)) != 0) + { + return (ISC_R_SUCCESS); + } + + cfg_map_get(zoptions, "dlz", &dlzobj); + if (dlzobj != NULL) { + return (ISC_R_SUCCESS); + } + + cfg_map_get(zoptions, "file", &fileobj); + if (fileobj != NULL) { + zfile = cfg_obj_asstring(fileobj); + } + + /* + * Check hints files for hint zones. + * Skip loading checks for any type other than + * master and redirect + */ + if (strcasecmp(cfg_obj_asstring(typeobj), "hint") == 0) { + return (configure_hint(zfile, zclass, mctx)); + } else if ((strcasecmp(cfg_obj_asstring(typeobj), "primary") != 0) && + (strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) && + (strcasecmp(cfg_obj_asstring(typeobj), "redirect") != 0)) + { + return (ISC_R_SUCCESS); + } + + /* + * Is the redirect zone configured as a slave? + */ + if (strcasecmp(cfg_obj_asstring(typeobj), "redirect") == 0) { + cfg_map_get(zoptions, "primaries", &primariesobj); + if (primariesobj == NULL) { + cfg_map_get(zoptions, "masters", &primariesobj); + } + + if (primariesobj != NULL) { + return (ISC_R_SUCCESS); + } + } + + if (zfile == NULL) { + return (ISC_R_FAILURE); + } + + obj = NULL; + if (get_maps(maps, "check-dup-records", &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_CHECKDUPRR; + zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + zone_options |= DNS_ZONEOPT_CHECKDUPRR; + zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options &= ~DNS_ZONEOPT_CHECKDUPRR; + zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL; + } else { + UNREACHABLE(); + } + } else { + zone_options |= DNS_ZONEOPT_CHECKDUPRR; + zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL; + } + + obj = NULL; + if (get_maps(maps, "check-mx", &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_CHECKMX; + zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + zone_options |= DNS_ZONEOPT_CHECKMX; + zone_options |= DNS_ZONEOPT_CHECKMXFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options &= ~DNS_ZONEOPT_CHECKMX; + zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; + } else { + UNREACHABLE(); + } + } else { + zone_options |= DNS_ZONEOPT_CHECKMX; + zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; + } + + obj = NULL; + if (get_maps(maps, "check-integrity", &obj)) { + if (cfg_obj_asboolean(obj)) { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + } else { + zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY; + } + } else { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + } + + obj = NULL; + if (get_maps(maps, "check-mx-cname", &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + zone_options &= ~DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options |= DNS_ZONEOPT_IGNOREMXCNAME; + } else { + UNREACHABLE(); + } + } else { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } + + obj = NULL; + if (get_maps(maps, "check-srv-cname", &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options |= DNS_ZONEOPT_IGNORESRVCNAME; + } else { + UNREACHABLE(); + } + } else { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } + + obj = NULL; + if (get_maps(maps, "check-sibling", &obj)) { + if (cfg_obj_asboolean(obj)) { + zone_options |= DNS_ZONEOPT_CHECKSIBLING; + } else { + zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; + } + } + + obj = NULL; + if (get_maps(maps, "check-spf", &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_CHECKSPF; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options &= ~DNS_ZONEOPT_CHECKSPF; + } else { + UNREACHABLE(); + } + } else { + zone_options |= DNS_ZONEOPT_CHECKSPF; + } + + obj = NULL; + if (get_maps(maps, "check-wildcard", &obj)) { + if (cfg_obj_asboolean(obj)) { + zone_options |= DNS_ZONEOPT_CHECKWILDCARD; + } else { + zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD; + } + } else { + zone_options |= DNS_ZONEOPT_CHECKWILDCARD; + } + + obj = NULL; + if (get_checknames(maps, &obj)) { + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + zone_options |= DNS_ZONEOPT_CHECKNAMES; + zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + zone_options |= DNS_ZONEOPT_CHECKNAMES; + zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + zone_options &= ~DNS_ZONEOPT_CHECKNAMES; + zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; + } else { + UNREACHABLE(); + } + } else { + zone_options |= DNS_ZONEOPT_CHECKNAMES; + zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL; + } + + masterformat = dns_masterformat_text; + fmtobj = NULL; + if (get_maps(maps, "masterfile-format", &fmtobj)) { + const char *masterformatstr = cfg_obj_asstring(fmtobj); + if (strcasecmp(masterformatstr, "text") == 0) { + masterformat = dns_masterformat_text; + } else if (strcasecmp(masterformatstr, "raw") == 0) { + masterformat = dns_masterformat_raw; + } else if (strcasecmp(masterformatstr, "map") == 0) { + masterformat = dns_masterformat_map; + } else { + UNREACHABLE(); + } + } + + obj = NULL; + if (get_maps(maps, "max-zone-ttl", &obj)) { + maxttl = cfg_obj_asduration(obj); + zone_options |= DNS_ZONEOPT_CHECKTTL; + } + + result = load_zone(mctx, zname, zfile, masterformat, zclass, maxttl, + NULL); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass, + dns_result_totext(result)); + } + return (result); +} + +/*% configure a view */ +static isc_result_t +configure_view(const char *vclass, const char *view, const cfg_obj_t *config, + const cfg_obj_t *vconfig, isc_mem_t *mctx, bool list) { + const cfg_listelt_t *element; + const cfg_obj_t *voptions; + const cfg_obj_t *zonelist; + isc_result_t result = ISC_R_SUCCESS; + isc_result_t tresult; + + voptions = NULL; + if (vconfig != NULL) { + voptions = cfg_tuple_get(vconfig, "options"); + } + + zonelist = NULL; + if (voptions != NULL) { + (void)cfg_map_get(voptions, "zone", &zonelist); + } else { + (void)cfg_map_get(config, "zone", &zonelist); + } + + for (element = cfg_list_first(zonelist); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *zconfig = cfg_listelt_value(element); + tresult = configure_zone(vclass, view, zconfig, vconfig, config, + mctx, list); + if (tresult != ISC_R_SUCCESS) { + result = tresult; + } + } + return (result); +} + +static isc_result_t +config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass, + dns_rdataclass_t *classp) { + isc_textregion_t r; + + if (!cfg_obj_isstring(classobj)) { + *classp = defclass; + return (ISC_R_SUCCESS); + } + DE_CONST(cfg_obj_asstring(classobj), r.base); + r.length = strlen(r.base); + return (dns_rdataclass_fromtext(classp, &r)); +} + +/*% load zones from the configuration */ +static isc_result_t +load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx, + bool list_zones) { + const cfg_listelt_t *element; + const cfg_obj_t *views; + const cfg_obj_t *vconfig; + isc_result_t result = ISC_R_SUCCESS; + isc_result_t tresult; + + views = NULL; + + (void)cfg_map_get(config, "view", &views); + for (element = cfg_list_first(views); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *classobj; + dns_rdataclass_t viewclass; + const char *vname; + char buf[sizeof("CLASS65535")]; + + vconfig = cfg_listelt_value(element); + if (vconfig == NULL) { + continue; + } + + classobj = cfg_tuple_get(vconfig, "class"); + tresult = config_getclass(classobj, dns_rdataclass_in, + &viewclass); + if (tresult != ISC_R_SUCCESS) { + CHECK(tresult); + } + + if (dns_rdataclass_ismeta(viewclass)) { + CHECK(ISC_R_FAILURE); + } + + dns_rdataclass_format(viewclass, buf, sizeof(buf)); + vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); + tresult = configure_view(buf, vname, config, vconfig, mctx, + list_zones); + if (tresult != ISC_R_SUCCESS) { + result = tresult; + } + } + + if (views == NULL) { + tresult = configure_view("IN", "_default", config, NULL, mctx, + list_zones); + if (tresult != ISC_R_SUCCESS) { + result = tresult; + } + } + +cleanup: + return (result); +} + +static void +output(void *closure, const char *text, int textlen) { + UNUSED(closure); + if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) { + perror("fwrite"); + exit(1); + } +} + +/*% The main processing routine */ +int +main(int argc, char **argv) { + int c; + cfg_parser_t *parser = NULL; + cfg_obj_t *config = NULL; + const char *conffile = NULL; + isc_mem_t *mctx = NULL; + isc_result_t result; + int exit_status = 0; + bool load_zones = false; + bool list_zones = false; + bool print = false; + bool nodeprecate = false; + unsigned int flags = 0; + + isc_commandline_errprint = false; + + /* + * Process memory debugging argument first. + */ +#define CMDLINE_FLAGS "cdhijlm:t:pvxz" + while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (c) { + case 'm': + if (strcasecmp(isc_commandline_argument, "record") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + } + if (strcasecmp(isc_commandline_argument, "trace") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGTRACE; + } + if (strcasecmp(isc_commandline_argument, "usage") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; + } + if (strcasecmp(isc_commandline_argument, "size") == 0) { + isc_mem_debugging |= ISC_MEM_DEBUGSIZE; + } + if (strcasecmp(isc_commandline_argument, "mctx") == 0) { + isc_mem_debugging |= ISC_MEM_DEBUGCTX; + } + break; + default: + break; + } + } + isc_commandline_reset = true; + + isc_mem_create(&mctx); + + while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) { + switch (c) { + case 'c': + loadplugins = false; + break; + + case 'd': + debug++; + break; + + case 'i': + nodeprecate = true; + break; + + case 'j': + nomerge = false; + break; + + case 'l': + list_zones = true; + break; + + case 'm': + break; + + case 't': + result = isc_dir_chroot(isc_commandline_argument); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "isc_dir_chroot: %s\n", + isc_result_totext(result)); + exit(1); + } + break; + + case 'p': + print = true; + break; + + case 'v': + printf(VERSION "\n"); + exit(0); + + case 'x': + flags |= CFG_PRINTER_XKEY; + break; + + case 'z': + load_zones = true; + docheckmx = false; + docheckns = false; + dochecksrv = false; + break; + + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + } + FALLTHROUGH; + case 'h': + usage(); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + if (((flags & CFG_PRINTER_XKEY) != 0) && !print) { + fprintf(stderr, "%s: -x cannot be used without -p\n", program); + exit(1); + } + if (print && list_zones) { + fprintf(stderr, "%s: -l cannot be used with -p\n", program); + exit(1); + } + + if (isc_commandline_index + 1 < argc) { + usage(); + } + if (argv[isc_commandline_index] != NULL) { + conffile = argv[isc_commandline_index]; + } + if (conffile == NULL || conffile[0] == '\0') { + conffile = NAMED_CONFFILE; + } + +#ifdef _WIN32 + InitSockets(); +#endif /* ifdef _WIN32 */ + + RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS); + + dns_result_register(); + + RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS); + + if (nodeprecate) { + cfg_parser_setflags(parser, CFG_PCTX_NODEPRECATED, true); + } + cfg_parser_setcallback(parser, directory_callback, NULL); + + if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) != + ISC_R_SUCCESS) + { + exit(1); + } + + result = bind9_check_namedconf(config, loadplugins, logc, mctx); + if (result != ISC_R_SUCCESS) { + exit_status = 1; + } + + if (result == ISC_R_SUCCESS && (load_zones || list_zones)) { + result = load_zones_fromconfig(config, mctx, list_zones); + if (result != ISC_R_SUCCESS) { + exit_status = 1; + } + } + + if (print && exit_status == 0) { + cfg_printx(config, flags, output, NULL); + } + cfg_obj_destroy(parser, &config); + + cfg_parser_destroy(&parser); + + isc_log_destroy(&logc); + + isc_mem_destroy(&mctx); + +#ifdef _WIN32 + DestroySockets(); +#endif /* ifdef _WIN32 */ + + return (exit_status); +} diff --git a/bin/check/named-checkconf.rst b/bin/check/named-checkconf.rst new file mode 100644 index 0000000..3cb7d74 --- /dev/null +++ b/bin/check/named-checkconf.rst @@ -0,0 +1,95 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_named-checkconf: + +named-checkconf - named configuration file syntax checking tool +--------------------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`named-checkconf` [**-chjlvz**] [**-p** [**-x** ]] [**-t** directory] {filename} + +Description +~~~~~~~~~~~ + +``named-checkconf`` checks the syntax, but not the semantics, of a +``named`` configuration file. The file, along with all files included by it, is parsed and checked for syntax +errors. If no file is specified, +``/etc/named.conf`` is read by default. + +Note: files that ``named`` reads in separate parser contexts, such as +``rndc.key`` and ``bind.keys``, are not automatically read by +``named-checkconf``. Configuration errors in these files may cause +``named`` to fail to run, even if ``named-checkconf`` was successful. +However, ``named-checkconf`` can be run on these files explicitly. + +Options +~~~~~~~ + +``-h`` + This option prints the usage summary and exits. + +``-j`` + When loading a zonefile, this option instructs ``named`` to read the journal if it exists. + +``-l`` + This option lists all the configured zones. Each line of output contains the zone + name, class (e.g. IN), view, and type (e.g. primary or secondary). + +``-c`` + This option specifies that only the "core" configuration should be checked. This suppresses the loading of + plugin modules, and causes all parameters to ``plugin`` statements to + be ignored. + +``-i`` + This option ignores warnings on deprecated options. + +``-p`` + This option prints out the ``named.conf`` and included files in canonical form if + no errors were detected. See also the ``-x`` option. + +``-t directory`` + This option instructs ``named`` to chroot to ``directory``, so that ``include`` directives in the + configuration file are processed as if run by a similarly chrooted + ``named``. + +``-v`` + This option prints the version of the ``named-checkconf`` program and exits. + +``-x`` + When printing the configuration files in canonical form, this option obscures + shared secrets by replacing them with strings of question marks + (``?``). This allows the contents of ``named.conf`` and related files + to be shared - for example, when submitting bug reports - + without compromising private data. This option cannot be used without + ``-p``. + +``-z`` + This option performs a test load of all zones of type ``primary`` found in ``named.conf``. + +``filename`` + This indicates the name of the configuration file to be checked. If not specified, + it defaults to ``/etc/named.conf``. + +Return Values +~~~~~~~~~~~~~ + +``named-checkconf`` returns an exit status of 1 if errors were detected +and 0 otherwise. + +See Also +~~~~~~~~ + +:manpage:`named(8)`, :manpage:`named-checkzone(8)`, BIND 9 Administrator Reference Manual. diff --git a/bin/check/named-checkzone.c b/bin/check/named-checkzone.c new file mode 100644 index 0000000..6a63a1f --- /dev/null +++ b/bin/check/named-checkzone.c @@ -0,0 +1,569 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check-tool.h" + +static int quiet = 0; +static isc_mem_t *mctx = NULL; +dns_zone_t *zone = NULL; +dns_zonetype_t zonetype = dns_zone_primary; +static int dumpzone = 0; +static const char *output_filename; +static const char *prog_name = NULL; +static const dns_master_style_t *outputstyle = NULL; +static enum { progmode_check, progmode_compile } progmode; + +#define ERRRET(result, function) \ + do { \ + if (result != ISC_R_SUCCESS) { \ + if (!quiet) \ + fprintf(stderr, "%s() returned %s\n", \ + function, dns_result_totext(result)); \ + return (result); \ + } \ + } while (0) + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, + "usage: %s [-djqvD] [-c class] " + "[-f inputformat] [-F outputformat] [-J filename] " + "[-s (full|relative)] [-t directory] [-w directory] " + "[-k (ignore|warn|fail)] [-m (ignore|warn|fail)] " + "[-n (ignore|warn|fail)] [-r (ignore|warn|fail)] " + "[-i (full|full-sibling|local|local-sibling|none)] " + "[-M (ignore|warn|fail)] [-S (ignore|warn|fail)] " + "[-W (ignore|warn)] " + "%s zonename filename\n", + prog_name, + progmode == progmode_check ? "[-o filename]" : "-o filename"); + exit(1); +} + +static void +destroy(void) { + if (zone != NULL) { + dns_zone_detach(&zone); + } +} + +/*% main processing routine */ +int +main(int argc, char **argv) { + int c; + char *origin = NULL; + char *filename = NULL; + isc_log_t *lctx = NULL; + isc_result_t result; + char classname_in[] = "IN"; + char *classname = classname_in; + const char *workdir = NULL; + const char *inputformatstr = NULL; + const char *outputformatstr = NULL; + dns_masterformat_t inputformat = dns_masterformat_text; + dns_masterformat_t outputformat = dns_masterformat_text; + dns_masterrawheader_t header; + uint32_t rawversion = 1, serialnum = 0; + dns_ttl_t maxttl = 0; + bool snset = false; + bool logdump = false; + FILE *errout = stdout; + char *endp; + + /* + * Uncomment the following line if memory debugging is needed: + * isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + */ + + outputstyle = &dns_master_style_full; + + prog_name = strrchr(argv[0], '/'); + if (prog_name == NULL) { + prog_name = strrchr(argv[0], '\\'); + } + if (prog_name != NULL) { + prog_name++; + } else { + prog_name = argv[0]; + } + /* + * Libtool doesn't preserve the program name prior to final + * installation. Remove the libtool prefix ("lt-"). + */ + if (strncmp(prog_name, "lt-", 3) == 0) { + prog_name += 3; + } + +#define PROGCMP(X) \ + (strcasecmp(prog_name, X) == 0 || strcasecmp(prog_name, X ".exe") == 0) + + if (PROGCMP("named-checkzone")) { + progmode = progmode_check; + } else if (PROGCMP("named-compilezone")) { + progmode = progmode_compile; + } else { + UNREACHABLE(); + } + + /* Compilation specific defaults */ + if (progmode == progmode_compile) { + zone_options |= (DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_FATALNS | + DNS_ZONEOPT_CHECKSPF | DNS_ZONEOPT_CHECKDUPRR | + DNS_ZONEOPT_CHECKNAMES | + DNS_ZONEOPT_CHECKNAMESFAIL | + DNS_ZONEOPT_CHECKWILDCARD); + } else { + zone_options |= (DNS_ZONEOPT_CHECKDUPRR | DNS_ZONEOPT_CHECKSPF); + } + +#define ARGCMP(X) (strcmp(isc_commandline_argument, X) == 0) + + isc_commandline_errprint = false; + + while ((c = isc_commandline_parse(argc, argv, + "c:df:hi:jJ:k:L:l:m:n:qr:s:t:o:vw:DF:" + "M:S:T:W:")) != EOF) + { + switch (c) { + case 'c': + classname = isc_commandline_argument; + break; + + case 'd': + debug++; + break; + + case 'i': + if (ARGCMP("full")) { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY | + DNS_ZONEOPT_CHECKSIBLING; + docheckmx = true; + docheckns = true; + dochecksrv = true; + } else if (ARGCMP("full-sibling")) { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; + docheckmx = true; + docheckns = true; + dochecksrv = true; + } else if (ARGCMP("local")) { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + zone_options |= DNS_ZONEOPT_CHECKSIBLING; + docheckmx = false; + docheckns = false; + dochecksrv = false; + } else if (ARGCMP("local-sibling")) { + zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; + zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; + docheckmx = false; + docheckns = false; + dochecksrv = false; + } else if (ARGCMP("none")) { + zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY; + zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; + docheckmx = false; + docheckns = false; + dochecksrv = false; + } else { + fprintf(stderr, "invalid argument to -i: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'f': + inputformatstr = isc_commandline_argument; + break; + + case 'F': + outputformatstr = isc_commandline_argument; + break; + + case 'j': + nomerge = false; + break; + + case 'J': + journal = isc_commandline_argument; + nomerge = false; + break; + + case 'k': + if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_CHECKNAMES; + zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; + } else if (ARGCMP("fail")) { + zone_options |= DNS_ZONEOPT_CHECKNAMES | + DNS_ZONEOPT_CHECKNAMESFAIL; + } else if (ARGCMP("ignore")) { + zone_options &= ~(DNS_ZONEOPT_CHECKNAMES | + DNS_ZONEOPT_CHECKNAMESFAIL); + } else { + fprintf(stderr, "invalid argument to -k: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'L': + snset = true; + endp = NULL; + serialnum = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fprintf(stderr, "source serial number " + "must be numeric"); + exit(1); + } + break; + + case 'l': + zone_options |= DNS_ZONEOPT_CHECKTTL; + endp = NULL; + maxttl = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fprintf(stderr, "maximum TTL " + "must be numeric"); + exit(1); + } + break; + + case 'n': + if (ARGCMP("ignore")) { + zone_options &= ~(DNS_ZONEOPT_CHECKNS | + DNS_ZONEOPT_FATALNS); + } else if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_CHECKNS; + zone_options &= ~DNS_ZONEOPT_FATALNS; + } else if (ARGCMP("fail")) { + zone_options |= DNS_ZONEOPT_CHECKNS | + DNS_ZONEOPT_FATALNS; + } else { + fprintf(stderr, "invalid argument to -n: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'm': + if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_CHECKMX; + zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; + } else if (ARGCMP("fail")) { + zone_options |= DNS_ZONEOPT_CHECKMX | + DNS_ZONEOPT_CHECKMXFAIL; + } else if (ARGCMP("ignore")) { + zone_options &= ~(DNS_ZONEOPT_CHECKMX | + DNS_ZONEOPT_CHECKMXFAIL); + } else { + fprintf(stderr, "invalid argument to -m: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'o': + output_filename = isc_commandline_argument; + break; + + case 'q': + quiet++; + break; + + case 'r': + if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_CHECKDUPRR; + zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL; + } else if (ARGCMP("fail")) { + zone_options |= DNS_ZONEOPT_CHECKDUPRR | + DNS_ZONEOPT_CHECKDUPRRFAIL; + } else if (ARGCMP("ignore")) { + zone_options &= ~(DNS_ZONEOPT_CHECKDUPRR | + DNS_ZONEOPT_CHECKDUPRRFAIL); + } else { + fprintf(stderr, "invalid argument to -r: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 's': + if (ARGCMP("full")) { + outputstyle = &dns_master_style_full; + } else if (ARGCMP("relative")) { + outputstyle = &dns_master_style_default; + } else { + fprintf(stderr, + "unknown or unsupported style: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 't': + result = isc_dir_chroot(isc_commandline_argument); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "isc_dir_chroot: %s: %s\n", + isc_commandline_argument, + isc_result_totext(result)); + exit(1); + } + break; + + case 'v': + printf(VERSION "\n"); + exit(0); + + case 'w': + workdir = isc_commandline_argument; + break; + + case 'D': + dumpzone++; + break; + + case 'M': + if (ARGCMP("fail")) { + zone_options &= ~DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } else if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; + } else if (ARGCMP("ignore")) { + zone_options |= DNS_ZONEOPT_WARNMXCNAME; + zone_options |= DNS_ZONEOPT_IGNOREMXCNAME; + } else { + fprintf(stderr, "invalid argument to -M: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'S': + if (ARGCMP("fail")) { + zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } else if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; + } else if (ARGCMP("ignore")) { + zone_options |= DNS_ZONEOPT_WARNSRVCNAME; + zone_options |= DNS_ZONEOPT_IGNORESRVCNAME; + } else { + fprintf(stderr, "invalid argument to -S: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'T': + if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_CHECKSPF; + } else if (ARGCMP("ignore")) { + zone_options &= ~DNS_ZONEOPT_CHECKSPF; + } else { + fprintf(stderr, "invalid argument to -T: %s\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'W': + if (ARGCMP("warn")) { + zone_options |= DNS_ZONEOPT_CHECKWILDCARD; + } else if (ARGCMP("ignore")) { + zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD; + } + break; + + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + prog_name, isc_commandline_option); + } + FALLTHROUGH; + case 'h': + usage(); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", prog_name, + isc_commandline_option); + exit(1); + } + } + + if (workdir != NULL) { + result = isc_dir_chdir(workdir); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "isc_dir_chdir: %s: %s\n", workdir, + isc_result_totext(result)); + exit(1); + } + } + + if (inputformatstr != NULL) { + if (strcasecmp(inputformatstr, "text") == 0) { + inputformat = dns_masterformat_text; + } else if (strcasecmp(inputformatstr, "raw") == 0) { + inputformat = dns_masterformat_raw; + } else if (strncasecmp(inputformatstr, "raw=", 4) == 0) { + inputformat = dns_masterformat_raw; + fprintf(stderr, "WARNING: input format raw, version " + "ignored\n"); + } else if (strcasecmp(inputformatstr, "map") == 0) { + inputformat = dns_masterformat_map; + } else { + fprintf(stderr, "unknown file format: %s\n", + inputformatstr); + exit(1); + } + } + + if (outputformatstr != NULL) { + if (strcasecmp(outputformatstr, "text") == 0) { + outputformat = dns_masterformat_text; + } else if (strcasecmp(outputformatstr, "raw") == 0) { + outputformat = dns_masterformat_raw; + } else if (strncasecmp(outputformatstr, "raw=", 4) == 0) { + char *end; + + outputformat = dns_masterformat_raw; + rawversion = strtol(outputformatstr + 4, &end, 10); + if (end == outputformatstr + 4 || *end != '\0' || + rawversion > 1U) + { + fprintf(stderr, "unknown raw format version\n"); + exit(1); + } + } else if (strcasecmp(outputformatstr, "map") == 0) { + outputformat = dns_masterformat_map; + } else { + fprintf(stderr, "unknown file format: %s\n", + outputformatstr); + exit(1); + } + } + + if (progmode == progmode_compile) { + dumpzone = 1; /* always dump */ + logdump = !quiet; + if (output_filename == NULL) { + fprintf(stderr, "output file required, but not " + "specified\n"); + usage(); + } + } + + if (output_filename != NULL) { + dumpzone = 1; + } + + /* + * If we are printing to stdout then send the informational + * output to stderr. + */ + if (dumpzone && + (output_filename == NULL || strcmp(output_filename, "-") == 0 || + strcmp(output_filename, "/dev/fd/1") == 0 || + strcmp(output_filename, "/dev/stdout") == 0)) + { + errout = stderr; + logdump = false; + } + + if (isc_commandline_index + 2 != argc) { + usage(); + } + +#ifdef _WIN32 + InitSockets(); +#endif /* ifdef _WIN32 */ + + isc_mem_create(&mctx); + if (!quiet) { + RUNTIME_CHECK(setup_logging(mctx, errout, &lctx) == + ISC_R_SUCCESS); + } + + dns_result_register(); + + origin = argv[isc_commandline_index++]; + filename = argv[isc_commandline_index++]; + result = load_zone(mctx, origin, filename, inputformat, classname, + maxttl, &zone); + + if (snset) { + dns_master_initrawheader(&header); + header.flags = DNS_MASTERRAW_SOURCESERIALSET; + header.sourceserial = serialnum; + dns_zone_setrawdata(zone, &header); + } + + if (result == ISC_R_SUCCESS && dumpzone) { + if (logdump) { + fprintf(errout, "dump zone to %s...", output_filename); + fflush(errout); + } + result = dump_zone(origin, zone, output_filename, outputformat, + outputstyle, rawversion); + if (logdump) { + fprintf(errout, "done\n"); + } + } + + if (!quiet && result == ISC_R_SUCCESS) { + fprintf(errout, "OK\n"); + } + destroy(); + if (lctx != NULL) { + isc_log_destroy(&lctx); + } + isc_mem_destroy(&mctx); +#ifdef _WIN32 + DestroySockets(); +#endif /* ifdef _WIN32 */ + return ((result == ISC_R_SUCCESS) ? 0 : 1); +} diff --git a/bin/check/named-checkzone.rst b/bin/check/named-checkzone.rst new file mode 100644 index 0000000..dae72dc --- /dev/null +++ b/bin/check/named-checkzone.rst @@ -0,0 +1,193 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. BEWARE: Do not forget to edit also named-compilezone.rst! + +.. _man_named-checkzone: + +named-checkzone - zone file validation tool +------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`named-checkzone` [**-d**] [**-h**] [**-j**] [**-q**] [**-v**] [**-c** class] [**-f** format] [**-F** format] [**-J** filename] [**-i** mode] [**-k** mode] [**-m** mode] [**-M** mode] [**-n** mode] [**-l** ttl] [**-L** serial] [**-o** filename] [**-r** mode] [**-s** style] [**-S** mode] [**-t** directory] [**-T** mode] [**-w** directory] [**-D**] [**-W** mode] {zonename} {filename} + +Description +~~~~~~~~~~~ + +``named-checkzone`` checks the syntax and integrity of a zone file. It +performs the same checks as ``named`` does when loading a zone. This +makes ``named-checkzone`` useful for checking zone files before +configuring them into a name server. + +Options +~~~~~~~ + +``-d`` + This option enables debugging. + +``-h`` + This option prints the usage summary and exits. + +``-q`` + This option sets quiet mode, which only sets an exit code to indicate + successful or failed completion. + +``-v`` + This option prints the version of the ``named-checkzone`` program and exits. + +``-j`` + When loading a zone file, this option tells ``named`` to read the journal if it exists. The journal + file name is assumed to be the zone file name with the + string ``.jnl`` appended. + +``-J filename`` + When loading the zone file, this option tells ``named`` to read the journal from the given file, if + it exists. This implies ``-j``. + +``-c class`` + This option specifies the class of the zone. If not specified, ``IN`` is assumed. + +``-i mode`` + This option performs post-load zone integrity checks. Possible modes are + ``full`` (the default), ``full-sibling``, ``local``, + ``local-sibling``, and ``none``. + + Mode ``full`` checks that MX records refer to A or AAAA records + (both in-zone and out-of-zone hostnames). Mode ``local`` only + checks MX records which refer to in-zone hostnames. + + Mode ``full`` checks that SRV records refer to A or AAAA records + (both in-zone and out-of-zone hostnames). Mode ``local`` only + checks SRV records which refer to in-zone hostnames. + + Mode ``full`` checks that delegation NS records refer to A or AAAA + records (both in-zone and out-of-zone hostnames). It also checks that + glue address records in the zone match those advertised by the child. + Mode ``local`` only checks NS records which refer to in-zone + hostnames or verifies that some required glue exists, i.e., when the + name server is in a child zone. + + Modes ``full-sibling`` and ``local-sibling`` disable sibling glue + checks, but are otherwise the same as ``full`` and ``local``, + respectively. + + Mode ``none`` disables the checks. + +``-f format`` + This option specifies the format of the zone file. Possible formats are + ``text`` (the default), ``raw``, and ``map``. + +``-F format`` + This option specifies the format of the output file specified. For + ``named-checkzone``, this does not have any effect unless it dumps + the zone contents. + + Possible formats are ``text`` (the default), which is the standard + textual representation of the zone, and ``map``, ``raw``, and ``raw=N``, which + store the zone in a binary format for rapid loading by ``named``. + ``raw=N`` specifies the format version of the raw zone file: if ``N`` is + 0, the raw file can be read by any version of ``named``; if N is 1, the + file can only be read by release 9.9.0 or higher. The default is 1. + +``-k mode`` + This option performs ``check-names`` checks with the specified failure mode. + Possible modes are ``fail``, ``warn`` (the default), and ``ignore``. + +``-l ttl`` + This option sets a maximum permissible TTL for the input file. Any record with a + TTL higher than this value causes the zone to be rejected. This + is similar to using the ``max-zone-ttl`` option in ``named.conf``. + +``-L serial`` + When compiling a zone to ``raw`` or ``map`` format, this option sets the "source + serial" value in the header to the specified serial number. This is + expected to be used primarily for testing purposes. + +``-m mode`` + This option specifies whether MX records should be checked to see if they are + addresses. Possible modes are ``fail``, ``warn`` (the default), and + ``ignore``. + +``-M mode`` + This option checks whether a MX record refers to a CNAME. Possible modes are + ``fail``, ``warn`` (the default), and ``ignore``. + +``-n mode`` + This option specifies whether NS records should be checked to see if they are + addresses. Possible modes are ``fail``, ``warn`` (the default), and ``ignore``. + +``-o filename`` + This option writes the zone output to ``filename``. If ``filename`` is ``-``, then + the zone output is written to standard output. + +``-r mode`` + This option checks for records that are treated as different by DNSSEC but are + semantically equal in plain DNS. Possible modes are ``fail``, + ``warn`` (the default), and ``ignore``. + +``-s style`` + This option specifies the style of the dumped zone file. Possible styles are + ``full`` (the default) and ``relative``. The ``full`` format is most + suitable for processing automatically by a separate script. + The relative format is more human-readable and is thus + suitable for editing by hand. This does not have any effect unless it dumps + the zone contents. It also does not have any meaning if the output format + is not text. + +``-S mode`` + This option checks whether an SRV record refers to a CNAME. Possible modes are + ``fail``, ``warn`` (the default), and ``ignore``. + +``-t directory`` + This option tells ``named`` to chroot to ``directory``, so that ``include`` directives in the + configuration file are processed as if run by a similarly chrooted + ``named``. + +``-T mode`` + This option checks whether Sender Policy Framework (SPF) records exist and issues a + warning if an SPF-formatted TXT record is not also present. Possible + modes are ``warn`` (the default) and ``ignore``. + +``-w directory`` + This option instructs ``named`` to chdir to ``directory``, so that relative filenames in master file + ``$INCLUDE`` directives work. This is similar to the directory clause in + ``named.conf``. + +``-D`` + This option dumps the zone file in canonical format. + +``-W mode`` + This option specifies whether to check for non-terminal wildcards. Non-terminal + wildcards are almost always the result of a failure to understand the + wildcard matching algorithm (:rfc:`4592`). Possible modes are ``warn`` + (the default) and ``ignore``. + +``zonename`` + This indicates the domain name of the zone being checked. + +``filename`` + This is the name of the zone file. + +Return Values +~~~~~~~~~~~~~ + +``named-checkzone`` returns an exit status of 1 if errors were detected +and 0 otherwise. + +See Also +~~~~~~~~ + +:manpage:`named(8)`, :manpage:`named-checkconf(8)`, :manpage:`named-compilezone(8)`, +:rfc:`1035`, BIND 9 Administrator Reference Manual. diff --git a/bin/check/named-compilezone.rst b/bin/check/named-compilezone.rst new file mode 100644 index 0000000..e56d264 --- /dev/null +++ b/bin/check/named-compilezone.rst @@ -0,0 +1,195 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. BEWARE: Do not forget to edit also named-checkzone.rst! + +.. _man_named-compilezone: + +named-compilezone - zone file converting tool +--------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`named-compilezone` [**-d**] [**-h**] [**-j**] [**-q**] [**-v**] [**-c** class] [**-f** format] [**-F** format] [**-J** filename] [**-i** mode] [**-k** mode] [**-m** mode] [**-M** mode] [**-n** mode] [**-l** ttl] [**-L** serial] [**-r** mode] [**-s** style] [**-S** mode] [**-t** directory] [**-T** mode] [**-w** directory] [**-D**] [**-W** mode] {**-o** filename} {zonename} {filename} + +Description +~~~~~~~~~~~ + +``named-compilezone`` checks the syntax and integrity of a zone file, +and dumps the zone contents to a specified file in a specified format. +It applies strict check levels by default, since the +dump output is used as an actual zone file loaded by ``named``. +When manually specified otherwise, the check levels must at least be as +strict as those specified in the ``named`` configuration file. + +Options +~~~~~~~ + +``-d`` + This option enables debugging. + +``-h`` + This option prints the usage summary and exits. + +``-q`` + This option sets quiet mode, which only sets an exit code to indicate + successful or failed completion. + +``-v`` + This option prints the version of the ``named-checkzone`` program and exits. + +``-j`` + When loading a zone file, this option tells ``named`` to read the journal if it exists. The journal + file name is assumed to be the zone file name with the + string ``.jnl`` appended. + +``-J filename`` + When loading the zone file, this option tells ``named`` to read the journal from the given file, if + it exists. This implies ``-j``. + +``-c class`` + This option specifies the class of the zone. If not specified, ``IN`` is assumed. + +``-i mode`` + This option performs post-load zone integrity checks. Possible modes are + ``full`` (the default), ``full-sibling``, ``local``, + ``local-sibling``, and ``none``. + + Mode ``full`` checks that MX records refer to A or AAAA records + (both in-zone and out-of-zone hostnames). Mode ``local`` only + checks MX records which refer to in-zone hostnames. + + Mode ``full`` checks that SRV records refer to A or AAAA records + (both in-zone and out-of-zone hostnames). Mode ``local`` only + checks SRV records which refer to in-zone hostnames. + + Mode ``full`` checks that delegation NS records refer to A or AAAA + records (both in-zone and out-of-zone hostnames). It also checks that + glue address records in the zone match those advertised by the child. + Mode ``local`` only checks NS records which refer to in-zone + hostnames or verifies that some required glue exists, i.e., when the + name server is in a child zone. + + Modes ``full-sibling`` and ``local-sibling`` disable sibling glue + checks, but are otherwise the same as ``full`` and ``local``, + respectively. + + Mode ``none`` disables the checks. + +``-f format`` + This option specifies the format of the zone file. Possible formats are + ``text`` (the default), ``raw``, and ``map``. + +``-F format`` + This option specifies the format of the output file specified. For + ``named-checkzone``, this does not have any effect unless it dumps + the zone contents. + + Possible formats are ``text`` (the default), which is the standard + textual representation of the zone, and ``map``, ``raw``, and ``raw=N``, which + store the zone in a binary format for rapid loading by ``named``. + ``raw=N`` specifies the format version of the raw zone file: if ``N`` is + 0, the raw file can be read by any version of ``named``; if N is 1, the + file can only be read by release 9.9.0 or higher. The default is 1. + +``-k mode`` + This option performs ``check-names`` checks with the specified failure mode. + Possible modes are ``fail`` (the default), ``warn``, and ``ignore``. + +``-l ttl`` + This option sets a maximum permissible TTL for the input file. Any record with a + TTL higher than this value causes the zone to be rejected. This + is similar to using the ``max-zone-ttl`` option in ``named.conf``. + +``-L serial`` + When compiling a zone to ``raw`` or ``map`` format, this option sets the "source + serial" value in the header to the specified serial number. This is + expected to be used primarily for testing purposes. + +``-m mode`` + This option specifies whether MX records should be checked to see if they are + addresses. Possible modes are ``fail``, ``warn`` (the default), and + ``ignore``. + +``-M mode`` + This option checks whether a MX record refers to a CNAME. Possible modes are + ``fail``, ``warn`` (the default), and ``ignore``. + +``-n mode`` + This option specifies whether NS records should be checked to see if they are + addresses. Possible modes are ``fail`` (the default), ``warn``, and + ``ignore``. + +``-o filename`` + This option writes the zone output to ``filename``. If ``filename`` is ``-``, then + the zone output is written to standard output. This is mandatory for ``named-compilezone``. + +``-r mode`` + This option checks for records that are treated as different by DNSSEC but are + semantically equal in plain DNS. Possible modes are ``fail``, + ``warn`` (the default), and ``ignore``. + +``-s style`` + This option specifies the style of the dumped zone file. Possible styles are + ``full`` (the default) and ``relative``. The ``full`` format is most + suitable for processing automatically by a separate script. + The relative format is more human-readable and is thus + suitable for editing by hand. + +``-S mode`` + This option checks whether an SRV record refers to a CNAME. Possible modes are + ``fail``, ``warn`` (the default), and ``ignore``. + +``-t directory`` + This option tells ``named`` to chroot to ``directory``, so that ``include`` directives in the + configuration file are processed as if run by a similarly chrooted + ``named``. + +``-T mode`` + This option checks whether Sender Policy Framework (SPF) records exist and issues a + warning if an SPF-formatted TXT record is not also present. Possible + modes are ``warn`` (the default) and ``ignore``. + +``-w directory`` + This option instructs ``named`` to chdir to ``directory``, so that relative filenames in master file + ``$INCLUDE`` directives work. This is similar to the directory clause in + ``named.conf``. + +``-D`` + This option dumps the zone file in canonical format. This is always enabled for + ``named-compilezone``. + +``-W mode`` + This option specifies whether to check for non-terminal wildcards. Non-terminal + wildcards are almost always the result of a failure to understand the + wildcard matching algorithm (:rfc:`4592`). Possible modes are ``warn`` + (the default) and ``ignore``. + +``zonename`` + This indicates the domain name of the zone being checked. + +``filename`` + This is the name of the zone file. + +Return Values +~~~~~~~~~~~~~ + +``named-compilezone`` returns an exit status of 1 if errors were detected +and 0 otherwise. + +See Also +~~~~~~~~ + +:manpage:`named(8)`, :manpage:`named-checkconf(8)`, :manpage:`named-checkzone(8)`, +:rfc:`1035`, BIND 9 Administrator Reference Manual. diff --git a/bin/check/win32/checkconf.vcxproj.filters.in b/bin/check/win32/checkconf.vcxproj.filters.in new file mode 100644 index 0000000..7d0bc52 --- /dev/null +++ b/bin/check/win32/checkconf.vcxproj.filters.in @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/check/win32/checkconf.vcxproj.in b/bin/check/win32/checkconf.vcxproj.in new file mode 100644 index 0000000..1391d5a --- /dev/null +++ b/bin/check/win32/checkconf.vcxproj.in @@ -0,0 +1,124 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {03A96113-CB14-43AA-AEB2-48950E3915C5} + Win32Proj + checkconf + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + named-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + named-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;..\..\..\lib\isccfg\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);..\..\..\lib\ns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@checktool.lib;libisc.lib;libdns.lib;libisccfg.lib;libisccc.lib;libbind9.lib;libns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;..\..\..\lib\isccfg\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);..\..\..\lib\ns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@checktool.lib;libisc.lib;libdns.lib;libisccfg.lib;libisccc.lib;libbind9.lib;libns.lib;ws2_32.lib;%(AdditionalDependencies) + Default + + + + + + + + + + + + diff --git a/bin/check/win32/checkconf.vcxproj.user b/bin/check/win32/checkconf.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/check/win32/checkconf.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/check/win32/checktool.vcxproj.filters.in b/bin/check/win32/checktool.vcxproj.filters.in new file mode 100644 index 0000000..34fc8c6 --- /dev/null +++ b/bin/check/win32/checktool.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/check/win32/checktool.vcxproj.in b/bin/check/win32/checktool.vcxproj.in new file mode 100644 index 0000000..26c8423 --- /dev/null +++ b/bin/check/win32/checktool.vcxproj.in @@ -0,0 +1,110 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + + + + {2C1F7096-C5B5-48D4-846F-A7ACA454335D} + Win32Proj + checktool + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + StaticLibrary + true + MultiByte + @PLATFORM_TOOLSET@ + + + StaticLibrary + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + .\$(Configuration)\ + + + .\$(Configuration)\ + None + + + .\$(Configuration)\ + + + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;..\..\..\lib\ns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + .\$(Configuration)\$(TargetName)$(TargetExt) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;..\..\..\lib\ns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + .\$(Configuration)\$(TargetName)$(TargetExt) + + + + + + diff --git a/bin/check/win32/checktool.vcxproj.user b/bin/check/win32/checktool.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/check/win32/checktool.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/check/win32/checkzone.vcxproj.filters.in b/bin/check/win32/checkzone.vcxproj.filters.in new file mode 100644 index 0000000..4f3396c --- /dev/null +++ b/bin/check/win32/checkzone.vcxproj.filters.in @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/check/win32/checkzone.vcxproj.in b/bin/check/win32/checkzone.vcxproj.in new file mode 100644 index 0000000..063f673 --- /dev/null +++ b/bin/check/win32/checkzone.vcxproj.in @@ -0,0 +1,135 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {66028555-7DD5-4016-B601-9EF9A1EE8BFA} + Win32Proj + checkzone + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + named-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + named-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\ns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@checktool.lib;libisc.lib;libdns.lib;libisccfg.lib;libns.lib;ws2_32.lib;%(AdditionalDependencies) + + + cd ..\..\..\Build\$(Configuration) +copy /Y named-checkzone.exe named-compilezone.exe +copy /Y named-checkzone.ilk named-compilezone.ilk + + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\ns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@checktool.lib;libisc.lib;libdns.lib;libisccfg.lib;libns.lib;ws2_32.lib;%(AdditionalDependencies) + Default + + + cd ..\..\..\Build\$(Configuration) +copy /Y named-checkzone.exe named-compilezone.exe + + + + + + + + + + + + + diff --git a/bin/check/win32/checkzone.vcxproj.user b/bin/check/win32/checkzone.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/check/win32/checkzone.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/confgen/Makefile.in b/bin/confgen/Makefile.in new file mode 100644 index 0000000..daab83a --- /dev/null +++ b/bin/confgen/Makefile.in @@ -0,0 +1,97 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +# Attempt to disable parallel processing. +.NOTPARALLEL: +.NO_PARALLEL: + +VERSION=@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include ${ISC_INCLUDES} ${ISCCC_INCLUDES} \ + ${ISCCFG_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} + +CDEFINES = +CWARNINGS = + +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCLIBS = ../../lib/isccc/libisccc.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +BIND9LIBS = ../../lib/bind9/libbind9.@A@ + +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCDEPLIBS = ../../lib/isccc/libisccc.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ + +RNDCLIBS = ${ISCCFGLIBS} ${ISCCCLIBS} ${BIND9LIBS} ${DNSLIBS} ${ISCLIBS} @LIBS@ +RNDCDEPLIBS = ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${BIND9DEPLIBS} ${DNSDEPLIBS} ${ISCDEPLIBS} + +LIBS = ${DNSLIBS} ${ISCLIBS} @LIBS@ + +NOSYMLIBS = ${DNSLIBS} ${ISCNOSYMLIBS} @LIBS@ + +CONFDEPLIBS = ${DNSDEPLIBS} ${ISCDEPLIBS} + +SRCS= rndc-confgen.c ddns-confgen.c + +SUBDIRS = unix + +TARGETS = rndc-confgen@EXEEXT@ ddns-confgen@EXEEXT@ tsig-keygen@EXEEXT@ + +UOBJS = unix/os.@O@ + +@BIND9_MAKE_RULES@ + +rndc-confgen.@O@: rndc-confgen.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DRNDC_KEYFILE=\"${sysconfdir}/rndc.key\" \ + -c ${srcdir}/rndc-confgen.c + +ddns-confgen.@O@: ddns-confgen.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${srcdir}/ddns-confgen.c + +rndc-confgen@EXEEXT@: rndc-confgen.@O@ util.@O@ keygen.@O@ ${CONFDEPLIBS} + export BASEOBJS="rndc-confgen.@O@ util.@O@ keygen.@O@ ${UOBJS}"; \ + ${FINALBUILDCMD} + +ddns-confgen@EXEEXT@: ddns-confgen.@O@ util.@O@ keygen.@O@ ${CONFDEPLIBS} + export BASEOBJS="ddns-confgen.@O@ util.@O@ keygen.@O@ ${UOBJS}"; \ + ${FINALBUILDCMD} + +# make a link in the build directory to assist with testing +tsig-keygen@EXEEXT@: ddns-confgen@EXEEXT@ + rm -f tsig-keygen@EXEEXT@ + ${LINK_PROGRAM} ddns-confgen@EXEEXT@ tsig-keygen@EXEEXT@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} + +install:: rndc-confgen@EXEEXT@ ddns-confgen@EXEEXT@ installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} rndc-confgen@EXEEXT@ ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} ddns-confgen@EXEEXT@ ${DESTDIR}${sbindir} + (cd ${DESTDIR}${sbindir}; rm -f tsig-keygen@EXEEXT@; ${LINK_PROGRAM} ddns-confgen@EXEEXT@ tsig-keygen@EXEEXT@) + +uninstall:: + rm -f ${DESTDIR}${sbindir}/tsig-keygen@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${sbindir}/ddns-confgen@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${sbindir}/rndc-confgen@EXEEXT@ + +clean distclean maintainer-clean:: + rm -f ${TARGETS} diff --git a/bin/confgen/ddns-confgen.c b/bin/confgen/ddns-confgen.c new file mode 100644 index 0000000..0afe087 --- /dev/null +++ b/bin/confgen/ddns-confgen.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +/** + * ddns-confgen generates configuration files for dynamic DNS. It can + * be used as a convenient alternative to writing the ddns.key file + * and the corresponding key and update-policy statements in named.conf. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include +#include +#include + +#include + +#include + +#include "keygen.h" +#include "util.h" + +#define KEYGEN_DEFAULT "tsig-key" +#define CONFGEN_DEFAULT "ddns-key" + +static char program[256]; +const char *progname; +static enum { progmode_keygen, progmode_confgen } progmode; +bool verbose = false; /* needed by util.c but not used here */ + +ISC_PLATFORM_NORETURN_PRE static void +usage(int status) ISC_PLATFORM_NORETURN_POST; + +static void +usage(int status) { + if (progmode == progmode_confgen) { + fprintf(stderr, "\ +Usage:\n\ + %s [-a alg] [-k keyname] [-q] [-s name | -z zone]\n\ + -a alg: algorithm (default hmac-sha256)\n\ + -k keyname: name of the key as it will be used in named.conf\n\ + -s name: domain name to be updated using the created key\n\ + -z zone: name of the zone as it will be used in named.conf\n\ + -q: quiet mode: print the key, with no explanatory text\n", + progname); + } else { + fprintf(stderr, "\ +Usage:\n\ + %s [-a alg] [keyname]\n\ + -a alg: algorithm (default hmac-sha256)\n\n", + progname); + } + + exit(status); +} + +int +main(int argc, char **argv) { + isc_result_t result = ISC_R_SUCCESS; + bool show_final_mem = false; + bool quiet = false; + isc_buffer_t key_txtbuffer; + char key_txtsecret[256]; + isc_mem_t *mctx = NULL; + const char *keyname = NULL; + const char *zone = NULL; + const char *self_domain = NULL; + char *keybuf = NULL; + dns_secalg_t alg = DST_ALG_HMACSHA256; + const char *algname; + int keysize = 256; + int len = 0; + int ch; + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + result = isc_file_progname(*argv, program, sizeof(program)); + if (result != ISC_R_SUCCESS) { + memmove(program, "tsig-keygen", 11); + } + progname = program; + + /* + * Libtool doesn't preserve the program name prior to final + * installation. Remove the libtool prefix ("lt-"). + */ + if (strncmp(progname, "lt-", 3) == 0) { + progname += 3; + } + +#define PROGCMP(X) \ + (strcasecmp(progname, X) == 0 || strcasecmp(progname, X ".exe") == 0) + + if (PROGCMP("tsig-keygen")) { + progmode = progmode_keygen; + quiet = true; + } else if (PROGCMP("ddns-confgen")) { + progmode = progmode_confgen; + } else { + UNREACHABLE(); + } + + isc_commandline_errprint = false; + + while ((ch = isc_commandline_parse(argc, argv, "a:hk:Mmr:qs:y:z:")) != + -1) + { + switch (ch) { + case 'a': + algname = isc_commandline_argument; + alg = alg_fromtext(algname); + if (alg == DST_ALG_UNKNOWN) { + fatal("Unsupported algorithm '%s'", algname); + } + keysize = alg_bits(alg); + break; + case 'h': + usage(0); + case 'k': + case 'y': + if (progmode == progmode_confgen) { + keyname = isc_commandline_argument; + } else { + usage(1); + } + break; + case 'M': + isc_mem_debugging = ISC_MEM_DEBUGTRACE; + break; + case 'm': + show_final_mem = true; + break; + case 'q': + if (progmode == progmode_confgen) { + quiet = true; + } else { + usage(1); + } + break; + case 'r': + fatal("The -r option has been deprecated."); + break; + case 's': + if (progmode == progmode_confgen) { + self_domain = isc_commandline_argument; + } else { + usage(1); + } + break; + case 'z': + if (progmode == progmode_confgen) { + zone = isc_commandline_argument; + } else { + usage(1); + } + break; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + usage(1); + } else { + usage(0); + } + break; + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + if (progmode == progmode_keygen) { + keyname = argv[isc_commandline_index++]; + } + + POST(argv); + + if (self_domain != NULL && zone != NULL) { + usage(1); /* -s and -z cannot coexist */ + } + + if (argc > isc_commandline_index) { + usage(1); + } + + /* Use canonical algorithm name */ + algname = alg_totext(alg); + + isc_mem_create(&mctx); + + if (keyname == NULL) { + const char *suffix = NULL; + + keyname = ((progmode == progmode_keygen) ? KEYGEN_DEFAULT + : CONFGEN_DEFAULT); + if (self_domain != NULL) { + suffix = self_domain; + } else if (zone != NULL) { + suffix = zone; + } + if (suffix != NULL) { + len = strlen(keyname) + strlen(suffix) + 2; + keybuf = isc_mem_get(mctx, len); + snprintf(keybuf, len, "%s.%s", keyname, suffix); + keyname = (const char *)keybuf; + } + } + + isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); + + generate_key(mctx, alg, keysize, &key_txtbuffer); + + if (!quiet) { + printf("\ +# To activate this key, place the following in named.conf, and\n\ +# in a separate keyfile on the system or systems from which nsupdate\n\ +# will be run:\n"); + } + + printf("\ +key \"%s\" {\n\ + algorithm %s;\n\ + secret \"%.*s\";\n\ +};\n", + keyname, algname, (int)isc_buffer_usedlength(&key_txtbuffer), + (char *)isc_buffer_base(&key_txtbuffer)); + + if (!quiet) { + if (self_domain != NULL) { + printf("\n\ +# Then, in the \"zone\" statement for the zone containing the\n\ +# name \"%s\", place an \"update-policy\" statement\n\ +# like this one, adjusted as needed for your preferred permissions:\n\ +update-policy {\n\ + grant %s name %s ANY;\n\ +};\n", + self_domain, keyname, self_domain); + } else if (zone != NULL) { + printf("\n\ +# Then, in the \"zone\" definition statement for \"%s\",\n\ +# place an \"update-policy\" statement like this one, adjusted as \n\ +# needed for your preferred permissions:\n\ +update-policy {\n\ + grant %s zonesub ANY;\n\ +};\n", + zone, keyname); + } else { + printf("\n\ +# Then, in the \"zone\" statement for each zone you wish to dynamically\n\ +# update, place an \"update-policy\" statement granting update permission\n\ +# to this key. For example, the following statement grants this key\n\ +# permission to update any name within the zone:\n\ +update-policy {\n\ + grant %s zonesub ANY;\n\ +};\n", + keyname); + } + + printf("\n\ +# After the keyfile has been placed, the following command will\n\ +# execute nsupdate using this key:\n\ +nsupdate -k \n"); + } + + if (keybuf != NULL) { + isc_mem_put(mctx, keybuf, len); + } + + if (show_final_mem) { + isc_mem_stats(mctx, stderr); + } + + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/confgen/ddns-confgen.rst b/bin/confgen/ddns-confgen.rst new file mode 100644 index 0000000..52ae412 --- /dev/null +++ b/bin/confgen/ddns-confgen.rst @@ -0,0 +1,88 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. BEWARE: Do not forget to edit also tsig-keygen.rst! + +.. _man_ddns-confgen: + +ddns-confgen - TSIG key generation tool +--------------------------------------- + +Synopsis +~~~~~~~~ +:program:`ddns-confgen` [**-a** algorithm] [**-h**] [**-k** keyname] [**-q**] [**-s** name] [**-z** zone] + +Description +~~~~~~~~~~~ + +``ddns-confgen`` is an utility that generates keys for use in TSIG signing. +The resulting keys can be used, for example, to secure dynamic DNS updates +to a zone, or for the ``rndc`` command channel. + +The key name can specified using ``-k`` parameter and defaults to ``ddns-key``. +The generated key is accompanied by configuration text and instructions that +can be used with ``nsupdate`` and ``named`` when setting up dynamic DNS, +including an example ``update-policy`` statement. +(This usage is similar to the ``rndc-confgen`` command for setting up +command-channel security.) + +Note that ``named`` itself can configure a local DDNS key for use with +``nsupdate -l``; it does this when a zone is configured with +``update-policy local;``. ``ddns-confgen`` is only needed when a more +elaborate configuration is required: for instance, if ``nsupdate`` is to +be used from a remote system. + +Options +~~~~~~~ + +``-a algorithm`` + This option specifies the algorithm to use for the TSIG key. Available + choices are: hmac-md5, hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384, + and hmac-sha512. The default is hmac-sha256. Options are + case-insensitive, and the "hmac-" prefix may be omitted. + +``-h`` + This option prints a short summary of options and arguments. + +``-k keyname`` + This option specifies the key name of the DDNS authentication key. The + default is ``ddns-key`` when neither the ``-s`` nor ``-z`` option is + specified; otherwise, the default is ``ddns-key`` as a separate label + followed by the argument of the option, e.g., ``ddns-key.example.com.`` + The key name must have the format of a valid domain name, consisting of + letters, digits, hyphens, and periods. + +``-q`` + This option enables quiet mode, which prints only the key, with no + explanatory text or usage examples. This is essentially identical to + ``tsig-keygen``. + +``-s name`` + This option generates a configuration example to allow dynamic updates + of a single hostname. The example ``named.conf`` text shows how to set + an update policy for the specified name using the "name" nametype. The + default key name is ``ddns-key.name``. Note that the "self" nametype + cannot be used, since the name to be updated may differ from the key + name. This option cannot be used with the ``-z`` option. + +``-z zone`` + This option generates a configuration example to allow + dynamic updates of a zone. The example ``named.conf`` text shows how + to set an update policy for the specified zone using the "zonesub" + nametype, allowing updates to all subdomain names within that zone. + This option cannot be used with the ``-s`` option. + +See Also +~~~~~~~~ + +:manpage:`nsupdate(1)`, :manpage:`named.conf(5)`, :manpage:`named(8)`, BIND 9 Administrator Reference Manual. diff --git a/bin/confgen/include/.clang-format b/bin/confgen/include/.clang-format new file mode 120000 index 0000000..0e62f72 --- /dev/null +++ b/bin/confgen/include/.clang-format @@ -0,0 +1 @@ +../../../.clang-format.headers \ No newline at end of file diff --git a/bin/confgen/include/confgen/os.h b/bin/confgen/include/confgen/os.h new file mode 100644 index 0000000..9754c17 --- /dev/null +++ b/bin/confgen/include/confgen/os.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#ifndef RNDC_OS_H +#define RNDC_OS_H 1 + +#include + +#include + +ISC_LANG_BEGINDECLS + +int +set_user(FILE *fd, const char *user); +/*%< + * Set the owner of the file referenced by 'fd' to 'user'. + * Returns: + * 0 success + * -1 insufficient permissions, or 'user' does not exist. + */ + +ISC_LANG_ENDDECLS + +#endif /* ifndef RNDC_OS_H */ diff --git a/bin/confgen/keygen.c b/bin/confgen/keygen.c new file mode 100644 index 0000000..73f976c --- /dev/null +++ b/bin/confgen/keygen.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include "keygen.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#include "util.h" + +/*% + * Convert algorithm type to string. + */ +const char * +alg_totext(dns_secalg_t alg) { + switch (alg) { + case DST_ALG_HMACMD5: + return ("hmac-md5"); + case DST_ALG_HMACSHA1: + return ("hmac-sha1"); + case DST_ALG_HMACSHA224: + return ("hmac-sha224"); + case DST_ALG_HMACSHA256: + return ("hmac-sha256"); + case DST_ALG_HMACSHA384: + return ("hmac-sha384"); + case DST_ALG_HMACSHA512: + return ("hmac-sha512"); + default: + return ("(unknown)"); + } +} + +/*% + * Convert string to algorithm type. + */ +dns_secalg_t +alg_fromtext(const char *name) { + const char *p = name; + if (strncasecmp(p, "hmac-", 5) == 0) { + p = &name[5]; + } + + if (strcasecmp(p, "md5") == 0) { + return (DST_ALG_HMACMD5); + } + if (strcasecmp(p, "sha1") == 0) { + return (DST_ALG_HMACSHA1); + } + if (strcasecmp(p, "sha224") == 0) { + return (DST_ALG_HMACSHA224); + } + if (strcasecmp(p, "sha256") == 0) { + return (DST_ALG_HMACSHA256); + } + if (strcasecmp(p, "sha384") == 0) { + return (DST_ALG_HMACSHA384); + } + if (strcasecmp(p, "sha512") == 0) { + return (DST_ALG_HMACSHA512); + } + return (DST_ALG_UNKNOWN); +} + +/*% + * Return default keysize for a given algorithm type. + */ +int +alg_bits(dns_secalg_t alg) { + switch (alg) { + case DST_ALG_HMACMD5: + return (128); + case DST_ALG_HMACSHA1: + return (160); + case DST_ALG_HMACSHA224: + return (224); + case DST_ALG_HMACSHA256: + return (256); + case DST_ALG_HMACSHA384: + return (384); + case DST_ALG_HMACSHA512: + return (512); + default: + return (0); + } +} + +/*% + * Generate a key of size 'keysize' and place it in 'key_txtbuffer' + */ +void +generate_key(isc_mem_t *mctx, dns_secalg_t alg, int keysize, + isc_buffer_t *key_txtbuffer) { + isc_result_t result = ISC_R_SUCCESS; + isc_buffer_t key_rawbuffer; + isc_region_t key_rawregion; + char key_rawsecret[64]; + dst_key_t *key = NULL; + + switch (alg) { + case DST_ALG_HMACMD5: + case DST_ALG_HMACSHA1: + case DST_ALG_HMACSHA224: + case DST_ALG_HMACSHA256: + if (keysize < 1 || keysize > 512) { + fatal("keysize %d out of range (must be 1-512)\n", + keysize); + } + break; + case DST_ALG_HMACSHA384: + case DST_ALG_HMACSHA512: + if (keysize < 1 || keysize > 1024) { + fatal("keysize %d out of range (must be 1-1024)\n", + keysize); + } + break; + default: + fatal("unsupported algorithm %d\n", alg); + } + + DO("initialize dst library", dst_lib_init(mctx, NULL)); + + DO("generate key", + dst_key_generate(dns_rootname, alg, keysize, 0, 0, DNS_KEYPROTO_ANY, + dns_rdataclass_in, mctx, &key, NULL)); + + isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret)); + + DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer)); + + isc_buffer_usedregion(&key_rawbuffer, &key_rawregion); + + DO("bsse64 encode secret", + isc_base64_totext(&key_rawregion, -1, "", key_txtbuffer)); + + if (key != NULL) { + dst_key_free(&key); + } + + dst_lib_destroy(); +} + +/*% + * Write a key file to 'keyfile'. If 'user' is non-NULL, + * make that user the owner of the file. The key will have + * the name 'keyname' and the secret in the buffer 'secret'. + */ +void +write_key_file(const char *keyfile, const char *user, const char *keyname, + isc_buffer_t *secret, dns_secalg_t alg) { + isc_result_t result; + const char *algname = alg_totext(alg); + FILE *fd = NULL; + + DO("create keyfile", isc_file_safecreate(keyfile, &fd)); + + if (user != NULL) { + if (set_user(fd, user) == -1) { + fatal("unable to set file owner\n"); + } + } + + fprintf(fd, + "key \"%s\" {\n\talgorithm %s;\n" + "\tsecret \"%.*s\";\n};\n", + keyname, algname, (int)isc_buffer_usedlength(secret), + (char *)isc_buffer_base(secret)); + fflush(fd); + if (ferror(fd)) { + fatal("write to %s failed\n", keyfile); + } + if (fclose(fd)) { + fatal("fclose(%s) failed\n", keyfile); + } + fprintf(stderr, "wrote key file \"%s\"\n", keyfile); +} diff --git a/bin/confgen/keygen.h b/bin/confgen/keygen.h new file mode 100644 index 0000000..6519b20 --- /dev/null +++ b/bin/confgen/keygen.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef RNDC_KEYGEN_H +#define RNDC_KEYGEN_H 1 + +/*! \file */ + +#include +#include +#include + +#include + +ISC_LANG_BEGINDECLS + +void +generate_key(isc_mem_t *mctx, dns_secalg_t alg, int keysize, + isc_buffer_t *key_txtbuffer); + +void +write_key_file(const char *keyfile, const char *user, const char *keyname, + isc_buffer_t *secret, dns_secalg_t alg); + +const char * +alg_totext(dns_secalg_t alg); +dns_secalg_t +alg_fromtext(const char *name); +int +alg_bits(dns_secalg_t alg); + +ISC_LANG_ENDDECLS + +#endif /* RNDC_KEYGEN_H */ diff --git a/bin/confgen/rndc-confgen.c b/bin/confgen/rndc-confgen.c new file mode 100644 index 0000000..cfbb295 --- /dev/null +++ b/bin/confgen/rndc-confgen.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +/** + * rndc-confgen generates configuration files for rndc. It can be used + * as a convenient alternative to writing the rndc.conf file and the + * corresponding controls and key statements in named.conf by hand. + * Alternatively, it can be run with the -a option to set up a + * rndc.key file and avoid the need for a rndc.conf file and a + * controls statement altogether. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#include "keygen.h" +#include "util.h" + +#define DEFAULT_KEYNAME "rndc-key" +#define DEFAULT_SERVER "127.0.0.1" +#define DEFAULT_PORT 953 + +static char program[256]; +const char *progname; + +bool verbose = false; + +const char *keyfile, *keydef; + +ISC_PLATFORM_NORETURN_PRE static void +usage(int status) ISC_PLATFORM_NORETURN_POST; + +static void +usage(int status) { + fprintf(stderr, "\ +Usage:\n\ + %s [-a] [-b bits] [-c keyfile] [-k keyname] [-p port] \ +[-s addr] [-t chrootdir] [-u user]\n\ + -a: generate just the key clause and write it to keyfile (%s)\n\ + -A alg: algorithm (default hmac-sha256)\n\ + -b bits: from 1 through 512, default 256; total length of the secret\n\ + -c keyfile: specify an alternate key file (requires -a)\n\ + -k keyname: the name as it will be used in named.conf and rndc.conf\n\ + -p port: the port named will listen on and rndc will connect to\n\ + -s addr: the address to which rndc should connect\n\ + -t chrootdir: write a keyfile in chrootdir as well (requires -a)\n\ + -u user: set the keyfile owner to \"user\" (requires -a)\n", + progname, keydef); + + exit(status); +} + +int +main(int argc, char **argv) { + bool show_final_mem = false; + isc_buffer_t key_txtbuffer; + char key_txtsecret[256]; + isc_mem_t *mctx = NULL; + isc_result_t result = ISC_R_SUCCESS; + const char *keyname = NULL; + const char *serveraddr = NULL; + dns_secalg_t alg; + const char *algname; + char *p; + int ch; + int port; + int keysize = -1; + struct in_addr addr4_dummy; + struct in6_addr addr6_dummy; + char *chrootdir = NULL; + char *user = NULL; + bool keyonly = false; + int len; + + keydef = keyfile = RNDC_KEYFILE; + + result = isc_file_progname(*argv, program, sizeof(program)); + if (result != ISC_R_SUCCESS) { + memmove(program, "rndc-confgen", 13); + } + progname = program; + + keyname = DEFAULT_KEYNAME; + alg = DST_ALG_HMACSHA256; + serveraddr = DEFAULT_SERVER; + port = DEFAULT_PORT; + + isc_commandline_errprint = false; + + while ((ch = isc_commandline_parse(argc, argv, + "aA:b:c:hk:Mmp:r:s:t:u:Vy")) != -1) + { + switch (ch) { + case 'a': + keyonly = true; + break; + case 'A': + algname = isc_commandline_argument; + alg = alg_fromtext(algname); + if (alg == DST_ALG_UNKNOWN) { + fatal("Unsupported algorithm '%s'", algname); + } + break; + case 'b': + keysize = strtol(isc_commandline_argument, &p, 10); + if (*p != '\0' || keysize < 0) { + fatal("-b requires a non-negative number"); + } + break; + case 'c': + keyfile = isc_commandline_argument; + break; + case 'h': + usage(0); + case 'k': + case 'y': /* Compatible with rndc -y. */ + keyname = isc_commandline_argument; + break; + case 'M': + isc_mem_debugging = ISC_MEM_DEBUGTRACE; + break; + + case 'm': + show_final_mem = true; + break; + case 'p': + port = strtol(isc_commandline_argument, &p, 10); + if (*p != '\0' || port < 0 || port > 65535) { + fatal("port '%s' out of range", + isc_commandline_argument); + } + break; + case 'r': + fatal("The -r option has been deprecated."); + break; + case 's': + serveraddr = isc_commandline_argument; + if (inet_pton(AF_INET, serveraddr, &addr4_dummy) != 1 && + inet_pton(AF_INET6, serveraddr, &addr6_dummy) != 1) + { + fatal("-s should be an IPv4 or IPv6 address"); + } + break; + case 't': + chrootdir = isc_commandline_argument; + break; + case 'u': + user = isc_commandline_argument; + break; + case 'V': + verbose = true; + break; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + usage(1); + } else { + usage(0); + } + break; + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + POST(argv); + + if (argc > 0) { + usage(1); + } + + if (alg == DST_ALG_HMACMD5) { + fprintf(stderr, "warning: use of hmac-md5 for RNDC keys " + "is deprecated; hmac-sha256 is now " + "recommended.\n"); + } + + if (keysize < 0) { + keysize = alg_bits(alg); + } + algname = alg_totext(alg); + + isc_mem_create(&mctx); + isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); + + generate_key(mctx, alg, keysize, &key_txtbuffer); + + if (keyonly) { + write_key_file(keyfile, chrootdir == NULL ? user : NULL, + keyname, &key_txtbuffer, alg); + + if (chrootdir != NULL) { + char *buf; + len = strlen(chrootdir) + strlen(keyfile) + 2; + buf = isc_mem_get(mctx, len); + snprintf(buf, len, "%s%s%s", chrootdir, + (*keyfile != '/') ? "/" : "", keyfile); + + write_key_file(buf, user, keyname, &key_txtbuffer, alg); + isc_mem_put(mctx, buf, len); + } + } else { + printf("\ +# Start of rndc.conf\n\ +key \"%s\" {\n\ + algorithm %s;\n\ + secret \"%.*s\";\n\ +};\n\ +\n\ +options {\n\ + default-key \"%s\";\n\ + default-server %s;\n\ + default-port %d;\n\ +};\n\ +# End of rndc.conf\n\ +\n\ +# Use with the following in named.conf, adjusting the allow list as needed:\n\ +# key \"%s\" {\n\ +# algorithm %s;\n\ +# secret \"%.*s\";\n\ +# };\n\ +# \n\ +# controls {\n\ +# inet %s port %d\n\ +# allow { %s; } keys { \"%s\"; };\n\ +# };\n\ +# End of named.conf\n", + keyname, algname, + (int)isc_buffer_usedlength(&key_txtbuffer), + (char *)isc_buffer_base(&key_txtbuffer), keyname, + serveraddr, port, keyname, algname, + (int)isc_buffer_usedlength(&key_txtbuffer), + (char *)isc_buffer_base(&key_txtbuffer), serveraddr, + port, serveraddr, keyname); + } + + if (show_final_mem) { + isc_mem_stats(mctx, stderr); + } + + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/confgen/rndc-confgen.rst b/bin/confgen/rndc-confgen.rst new file mode 100644 index 0000000..d90acba --- /dev/null +++ b/bin/confgen/rndc-confgen.rst @@ -0,0 +1,106 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_rndc-confgen: + +rndc-confgen - rndc key generation tool +--------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`rndc-confgen` [**-a**] [**-A** algorithm] [**-b** keysize] [**-c** keyfile] [**-h**] [**-k** keyname] [**-p** port] [**-s** address] [**-t** chrootdir] [**-u** user] + +Description +~~~~~~~~~~~ + +``rndc-confgen`` generates configuration files for ``rndc``. It can be +used as a convenient alternative to writing the ``rndc.conf`` file and +the corresponding ``controls`` and ``key`` statements in ``named.conf`` +by hand. Alternatively, it can be run with the ``-a`` option to set up a +``rndc.key`` file and avoid the need for a ``rndc.conf`` file and a +``controls`` statement altogether. + +Options +~~~~~~~ + +``-a`` + This option sets automatic ``rndc`` configuration, which creates a file ``rndc.key`` + in ``/etc`` (or a different ``sysconfdir`` specified when BIND + was built) that is read by both ``rndc`` and ``named`` on startup. + The ``rndc.key`` file defines a default command channel and + authentication key allowing ``rndc`` to communicate with ``named`` on + the local host with no further configuration. + + If a more elaborate configuration than that generated by + ``rndc-confgen -a`` is required, for example if rndc is to be used + remotely, run ``rndc-confgen`` without the ``-a`` option + and set up ``rndc.conf`` and ``named.conf`` as directed. + +``-A algorithm`` + This option specifies the algorithm to use for the TSIG key. Available choices + are: hmac-md5, hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384, and + hmac-sha512. The default is hmac-sha256. + +``-b keysize`` + This option specifies the size of the authentication key in bits. The size must be between + 1 and 512 bits; the default is the hash size. + +``-c keyfile`` + This option is used with the ``-a`` option to specify an alternate location for + ``rndc.key``. + +``-h`` + This option prints a short summary of the options and arguments to + ``rndc-confgen``. + +``-k keyname`` + This option specifies the key name of the ``rndc`` authentication key. This must be a + valid domain name. The default is ``rndc-key``. + +``-p port`` + This option specifies the command channel port where ``named`` listens for + connections from ``rndc``. The default is 953. + +``-s address`` + This option specifies the IP address where ``named`` listens for command-channel + connections from ``rndc``. The default is the loopback address + 127.0.0.1. + +``-t chrootdir`` + This option is used with the ``-a`` option to specify a directory where ``named`` + runs chrooted. An additional copy of the ``rndc.key`` is + written relative to this directory, so that it is found by the + chrooted ``named``. + +``-u user`` + This option is used with the ``-a`` option to set the owner of the generated ``rndc.key`` file. + If ``-t`` is also specified, only the file in the chroot + area has its owner changed. + +Examples +~~~~~~~~ + +To allow ``rndc`` to be used with no manual configuration, run: + +``rndc-confgen -a`` + +To print a sample ``rndc.conf`` file and the corresponding ``controls`` and +``key`` statements to be manually inserted into ``named.conf``, run: + +``rndc-confgen`` + +See Also +~~~~~~~~ + +:manpage:`rndc(8)`, :manpage:`rndc.conf(5)`, :manpage:`named(8)`, BIND 9 Administrator Reference Manual. diff --git a/bin/confgen/tsig-keygen.rst b/bin/confgen/tsig-keygen.rst new file mode 100644 index 0000000..a127407 --- /dev/null +++ b/bin/confgen/tsig-keygen.rst @@ -0,0 +1,50 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. BEWARE: Do not forget to edit also ddns-confgen.rst! + +.. _man_tsig-keygen: + +tsig-keygen - TSIG key generation tool +-------------------------------------- + +Synopsis +~~~~~~~~ +:program:`tsig-keygen` [**-a** algorithm] [**-h**] [name] + +Description +~~~~~~~~~~~ + +``tsig-keygen`` is an utility that generates keys for use in TSIG signing. +The resulting keys can be used, for example, to secure dynamic DNS updates +to a zone, or for the ``rndc`` command channel. + +A domain name can be specified on the command line to be used as the name +of the generated key. If no name is specified, the default is ``tsig-key``. + +Options +~~~~~~~ + +``-a algorithm`` + This option specifies the algorithm to use for the TSIG key. Available + choices are: hmac-md5, hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384, + and hmac-sha512. The default is hmac-sha256. Options are + case-insensitive, and the "hmac-" prefix may be omitted. + +``-h`` + This option prints a short summary of options and arguments. + +See Also +~~~~~~~~ + +:manpage:`nsupdate(1)`, :manpage:`named.conf(5)`, :manpage:`named(8)`, BIND 9 Administrator Reference Manual. diff --git a/bin/confgen/unix/Makefile.in b/bin/confgen/unix/Makefile.in new file mode 100644 index 0000000..cad563e --- /dev/null +++ b/bin/confgen/unix/Makefile.in @@ -0,0 +1,30 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include -I${srcdir}/../include \ + ${DNS_INCLUDES} ${ISC_INCLUDES} + +CDEFINES = +CWARNINGS = + +OBJS = os.@O@ + +SRCS = os.c + +TARGETS = ${OBJS} + +@BIND9_MAKE_RULES@ diff --git a/bin/confgen/unix/os.c b/bin/confgen/unix/os.c new file mode 100644 index 0000000..445d64b --- /dev/null +++ b/bin/confgen/unix/os.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +int +set_user(FILE *fd, const char *user) { + struct passwd *pw; + + pw = getpwnam(user); + if (pw == NULL) { + errno = EINVAL; + return (-1); + } + return (fchown(fileno(fd), pw->pw_uid, -1)); +} diff --git a/bin/confgen/util.c b/bin/confgen/util.c new file mode 100644 index 0000000..3b3587c --- /dev/null +++ b/bin/confgen/util.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include "util.h" +#include +#include +#include +#include + +#include + +extern bool verbose; +extern const char *progname; + +void +notify(const char *fmt, ...) { + va_list ap; + + if (verbose) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputs("\n", stderr); + } +} + +void +fatal(const char *format, ...) { + va_list args; + + fprintf(stderr, "%s: ", progname); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + exit(1); +} diff --git a/bin/confgen/util.h b/bin/confgen/util.h new file mode 100644 index 0000000..2d3c664 --- /dev/null +++ b/bin/confgen/util.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef RNDC_UTIL_H +#define RNDC_UTIL_H 1 + +/*! \file */ + +#include +#include +#include + +#define NS_CONTROL_PORT 953 + +#undef DO +#define DO(name, function) \ + do { \ + result = function; \ + if (result != ISC_R_SUCCESS) \ + fatal("%s: %s", name, isc_result_totext(result)); \ + else \ + notify("%s", name); \ + } while (0) + +ISC_LANG_BEGINDECLS + +void +notify(const char *fmt, ...) ISC_FORMAT_PRINTF(1, 2); + +ISC_PLATFORM_NORETURN_PRE void +fatal(const char *format, ...) + ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; + +ISC_LANG_ENDDECLS + +#endif /* RNDC_UTIL_H */ diff --git a/bin/confgen/win32/confgentool.vcxproj.filters.in b/bin/confgen/win32/confgentool.vcxproj.filters.in new file mode 100644 index 0000000..231e4e1 --- /dev/null +++ b/bin/confgen/win32/confgentool.vcxproj.filters.in @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/bin/confgen/win32/confgentool.vcxproj.in b/bin/confgen/win32/confgentool.vcxproj.in new file mode 100644 index 0000000..26e4461 --- /dev/null +++ b/bin/confgen/win32/confgentool.vcxproj.in @@ -0,0 +1,120 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {64964B03-4815-41F0-9057-E766A94AF197} + Win32Proj + confgentool + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + StaticLibrary + true + MultiByte + @PLATFORM_TOOLSET@ + + + StaticLibrary + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + .\$(Configuration)\ + .\$(Configuration)\ + None + + + false + .\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + true + true + false + + + + + + + + + + + + + + + + diff --git a/bin/confgen/win32/confgentool.vcxproj.user b/bin/confgen/win32/confgentool.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/confgen/win32/confgentool.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/confgen/win32/ddnsconfgen.vcxproj.filters.in b/bin/confgen/win32/ddnsconfgen.vcxproj.filters.in new file mode 100644 index 0000000..ccdaa81 --- /dev/null +++ b/bin/confgen/win32/ddnsconfgen.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/confgen/win32/ddnsconfgen.vcxproj.in b/bin/confgen/win32/ddnsconfgen.vcxproj.in new file mode 100644 index 0000000..ce37aed --- /dev/null +++ b/bin/confgen/win32/ddnsconfgen.vcxproj.in @@ -0,0 +1,132 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {1EA4FC64-F33B-4A50-970A-EA052BBE9CF1} + Win32Proj + ddnsconfgen + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + ddns-confgen + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + ddns-confgen + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\isccc\include;..\..\..\lib\isccfg\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@confgentool.lib;libisc.lib;libdns.lib;libisccfg.lib;libisccc.lib;ws2_32.lib;%(AdditionalDependencies) + + + cd ..\..\..\Build\$(Configuration) +copy /Y ddns-confgen.exe tsig-keygen.exe +copy /Y ddns-confgen.ilk tsig-keygen.ilk + + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\isccc\include;..\..\..\lib\isccfg\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@confgentool.lib;libisc.lib;libdns.lib;libisccfg.lib;libisccc.lib;ws2_32.lib;%(AdditionalDependencies) + + + cd ..\..\..\Build\$(Configuration) +copy /Y ddns-confgen.exe tsig-keygen.exe + + + + + + + + + + diff --git a/bin/confgen/win32/ddnsconfgen.vcxproj.user b/bin/confgen/win32/ddnsconfgen.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/confgen/win32/ddnsconfgen.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/confgen/win32/os.c b/bin/confgen/win32/os.c new file mode 100644 index 0000000..ee8314e --- /dev/null +++ b/bin/confgen/win32/os.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +int +set_user(FILE *fd, const char *user) { + return (0); +} diff --git a/bin/confgen/win32/rndcconfgen.vcxproj.filters.in b/bin/confgen/win32/rndcconfgen.vcxproj.filters.in new file mode 100644 index 0000000..20f6b5a --- /dev/null +++ b/bin/confgen/win32/rndcconfgen.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/confgen/win32/rndcconfgen.vcxproj.in b/bin/confgen/win32/rndcconfgen.vcxproj.in new file mode 100644 index 0000000..5ddabd1 --- /dev/null +++ b/bin/confgen/win32/rndcconfgen.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {1E2C1635-3093-4D59-80E7-4743AC10F22F} + Win32Proj + rndcconfgen + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + rndc-confgen + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + rndc-confgen + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\isccc\include;..\..\..\lib\isccfg\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@confgentool.lib;libisc.lib;libdns.lib;libisccfg.lib;libisccc.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\isccc\include;..\..\..\lib\isccfg\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@confgentool.lib;libisc.lib;libdns.lib;libisccfg.lib;libisccc.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/confgen/win32/rndcconfgen.vcxproj.user b/bin/confgen/win32/rndcconfgen.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/confgen/win32/rndcconfgen.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/delv/Makefile.in b/bin/delv/Makefile.in new file mode 100644 index 0000000..f02600d --- /dev/null +++ b/bin/delv/Makefile.in @@ -0,0 +1,70 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include ${DNS_INCLUDES} ${ISC_INCLUDES} \ + ${IRS_INCLUDES} ${ISCCFG_INCLUDES} \ + ${OPENSSL_CFLAGS} + +CDEFINES = -DVERSION=\"${VERSION}\" \ + -DSYSCONFDIR=\"${sysconfdir}\" +CWARNINGS = + +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +IRSLIBS = ../../lib/irs/libirs.@A@ + +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +IRSDEPLIBS = ../../lib/irs/libirs.@A@ + +DEPLIBS = ${DNSDEPLIBS} ${IRSDEPLIBS} ${ISCCFGDEPLIBS} ${ISCDEPLIBS} + +LIBS = ${DNSLIBS} ${IRSLIBS} ${ISCCFGLIBS} ${ISCLIBS} @LIBS@ +NOSYMLIBS = ${DNSLIBS} ${IRSLIBS} ${ISCCFGLIBS} ${ISCNOSYMLIBS} @LIBS@ + +SUBDIRS = + +TARGETS = delv@EXEEXT@ + +OBJS = delv.@O@ + +SRCS = delv.c + +@BIND9_MAKE_RULES@ + +delv@EXEEXT@: delv.@O@ ${DEPLIBS} + export BASEOBJS="delv.@O@"; \ + export LIBS0="${DNSLIBS}"; \ + ${FINALBUILDCMD} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${bindir} + +install:: delv@EXEEXT@ installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} \ + delv@EXEEXT@ ${DESTDIR}${bindir} + +uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${bindir}/delv@EXEEXT@ + +clean distclean maintainer-clean:: + rm -f ${TARGETS} diff --git a/bin/delv/delv.c b/bin/delv/delv.c new file mode 100644 index 0000000..daf0239 --- /dev/null +++ b/bin/delv/delv.c @@ -0,0 +1,1889 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include + +#ifndef WIN32 +#include +#include +#include +#include +#include +#include +#endif /* ifndef WIN32 */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#endif /* ifdef WIN32 */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define CHECK(r) \ + do { \ + result = (r); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +#define MAXNAME (DNS_NAME_MAXTEXT + 1) + +/* Variables used internally by delv. */ +char *progname; +static isc_mem_t *mctx = NULL; +static isc_log_t *lctx = NULL; + +/* Configurables */ +static char *server = NULL; +static const char *port = "53"; +static isc_sockaddr_t *srcaddr4 = NULL, *srcaddr6 = NULL; +static isc_sockaddr_t a4, a6; +static char *curqname = NULL, *qname = NULL; +static bool classset = false; +static dns_rdatatype_t qtype = dns_rdatatype_none; +static bool typeset = false; + +static unsigned int styleflags = 0; +static uint32_t splitwidth = 0xffffffff; +static bool showcomments = true, showdnssec = true, showtrust = true, + rrcomments = true, noclass = false, nocrypto = false, nottl = false, + multiline = false, short_form = false, print_unknown_format = false, + yaml = false; + +static bool resolve_trace = false, validator_trace = false, + message_trace = false; + +static bool use_ipv4 = true, use_ipv6 = true; + +static bool cdflag = false, no_sigs = false, root_validation = true; + +static bool use_tcp = false; + +static char *anchorfile = NULL; +static char *trust_anchor = NULL; +static int num_keys = 0; + +static dns_fixedname_t afn; +static dns_name_t *anchor_name = NULL; + +/* Default bind.keys contents */ +static char anchortext[] = TRUST_ANCHORS; + +/* + * Static function prototypes + */ +static isc_result_t +get_reverse(char *reverse, size_t len, char *value, bool strict); + +static isc_result_t +parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc); + +static void +usage(void) { + fputs("Usage: delv [@server] {q-opt} {d-opt} [domain] [q-type] " + "[q-class]\n" + "Where: domain is in the Domain Name System\n" + " q-class is one of (in,hs,ch,...) [default: in]\n" + " q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) " + "[default:a]\n" + " q-opt is one of:\n" + " -4 (use IPv4 query transport " + "only)\n" + " -6 (use IPv6 query transport " + "only)\n" + " -a anchor-file (specify root trust " + "anchor)\n" + " -b address[#port] (bind to source " + "address/port)\n" + " -c class (option included for " + "compatibility;\n" + " -d level (set debugging level)\n" + " -h (print help and exit)\n" + " -i (disable DNSSEC " + "validation)\n" + " -m (enable memory usage " + "debugging)\n" + " -p port (specify port number)\n" + " -q name (specify query name)\n" + " -t type (specify query type)\n" + " only IN is supported)\n" + " -v (print version and exit)\n" + " -x dot-notation (shortcut for reverse " + "lookups)\n" + " d-opt is of the form +keyword[=value], where keyword " + "is:\n" + " +[no]all (Set or clear all display " + "flags)\n" + " +[no]class (Control display of " + "class)\n" + " +[no]comments (Control display of " + "comment lines)\n" + " +[no]crypto (Control display of " + "cryptographic\n" + " fields in records)\n" + " +[no]dlv (Obsolete)\n" + " +[no]dnssec (Display DNSSEC records)\n" + " +[no]mtrace (Trace messages received)\n" + " +[no]multiline (Print records in an " + "expanded format)\n" + " +[no]root (DNSSEC validation trust " + "anchor)\n" + " +[no]rrcomments (Control display of " + "per-record " + "comments)\n" + " +[no]rtrace (Trace resolver fetches)\n" + " +[no]short (Short form answer)\n" + " +[no]split=## (Split hex/base64 fields " + "into chunks)\n" + " +[no]tcp (TCP mode)\n" + " +[no]ttl (Control display of ttls " + "in records)\n" + " +[no]trust (Control display of trust " + "level)\n" + " +[no]unknownformat (Print RDATA in RFC 3597 " + "\"unknown\" format)\n" + " +[no]vtrace (Trace validation " + "process)\n" + " +[no]yaml (Present the results as " + "YAML)\n", + stderr); + exit(1); +} + +ISC_PLATFORM_NORETURN_PRE static void +fatal(const char *format, ...) + ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; + +static void +fatal(const char *format, ...) { + va_list args; + + fflush(stdout); + fprintf(stderr, "%s: ", progname); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + exit(1); +} + +static void +warn(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +static void +warn(const char *format, ...) { + va_list args; + + fflush(stdout); + fprintf(stderr, "%s: warning: ", progname); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); +} + +static isc_logcategory_t categories[] = { { "delv", 0 }, { NULL, 0 } }; +#define LOGCATEGORY_DEFAULT (&categories[0]) +#define LOGMODULE_DEFAULT (&modules[0]) + +static isc_logmodule_t modules[] = { { "delv", 0 }, { NULL, 0 } }; + +static void +delv_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); + +static void +delv_log(int level, const char *fmt, ...) { + va_list ap; + char msgbuf[2048]; + + if (!isc_log_wouldlog(lctx, level)) { + return; + } + + va_start(ap, fmt); + + vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); + isc_log_write(lctx, LOGCATEGORY_DEFAULT, LOGMODULE_DEFAULT, level, "%s", + msgbuf); + va_end(ap); +} + +static int loglevel = 0; + +static void +setup_logging(FILE *errout) { + isc_result_t result; + isc_logdestination_t destination; + isc_logconfig_t *logconfig = NULL; + + isc_log_create(mctx, &lctx, &logconfig); + isc_log_registercategories(lctx, categories); + isc_log_registermodules(lctx, modules); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + cfg_log_init(lctx); + + destination.file.stream = errout; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, + ISC_LOG_PRINTPREFIX); + + isc_log_setdebuglevel(lctx, loglevel); + isc_log_settag(logconfig, ";; "); + + result = isc_log_usechannel(logconfig, "stderr", + ISC_LOGCATEGORY_DEFAULT, NULL); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't attach to log channel 'stderr'"); + } + + if (resolve_trace && loglevel < 1) { + isc_log_createchannel(logconfig, "resolver", ISC_LOG_TOFILEDESC, + ISC_LOG_DEBUG(1), &destination, + ISC_LOG_PRINTPREFIX); + + result = isc_log_usechannel(logconfig, "resolver", + DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't attach to log channel 'resolver'"); + } + } + + if (validator_trace && loglevel < 3) { + isc_log_createchannel(logconfig, "validator", + ISC_LOG_TOFILEDESC, ISC_LOG_DEBUG(3), + &destination, ISC_LOG_PRINTPREFIX); + + result = isc_log_usechannel(logconfig, "validator", + DNS_LOGCATEGORY_DNSSEC, + DNS_LOGMODULE_VALIDATOR); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't attach to log channel 'validator'"); + } + } + + if (message_trace && loglevel < 10) { + isc_log_createchannel(logconfig, "messages", ISC_LOG_TOFILEDESC, + ISC_LOG_DEBUG(10), &destination, + ISC_LOG_PRINTPREFIX); + + result = isc_log_usechannel(logconfig, "messages", + DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_PACKETS); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't attach to log channel 'messagse'"); + } + } +} + +static void +print_status(dns_rdataset_t *rdataset) { + char buf[1024] = { 0 }; + + REQUIRE(rdataset != NULL); + + if (!showtrust || !dns_rdataset_isassociated(rdataset)) { + return; + } + + buf[0] = '\0'; + + if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { + strlcat(buf, "negative response", sizeof(buf)); + strlcat(buf, (yaml ? "_" : ", "), sizeof(buf)); + } + + switch (rdataset->trust) { + case dns_trust_none: + strlcat(buf, "untrusted", sizeof(buf)); + break; + case dns_trust_pending_additional: + strlcat(buf, "signed additional data", sizeof(buf)); + if (!yaml) { + strlcat(buf, ", ", sizeof(buf)); + } + strlcat(buf, "pending validation", sizeof(buf)); + break; + case dns_trust_pending_answer: + strlcat(buf, "signed answer", sizeof(buf)); + if (!yaml) { + strlcat(buf, ", ", sizeof(buf)); + } + strlcat(buf, "pending validation", sizeof(buf)); + break; + case dns_trust_additional: + strlcat(buf, "unsigned additional data", sizeof(buf)); + break; + case dns_trust_glue: + strlcat(buf, "glue data", sizeof(buf)); + break; + case dns_trust_answer: + if (root_validation) { + strlcat(buf, "unsigned answer", sizeof(buf)); + } else { + strlcat(buf, "answer not validated", sizeof(buf)); + } + break; + case dns_trust_authauthority: + strlcat(buf, "authority data", sizeof(buf)); + break; + case dns_trust_authanswer: + strlcat(buf, "authoritative", sizeof(buf)); + break; + case dns_trust_secure: + strlcat(buf, "fully validated", sizeof(buf)); + break; + case dns_trust_ultimate: + strlcat(buf, "ultimate trust", sizeof(buf)); + break; + } + + if (yaml) { + char *p; + + /* Convert spaces to underscores for YAML */ + for (p = buf; p != NULL && *p != '\0'; p++) { + if (*p == ' ') { + *p = '_'; + } + } + + printf(" - %s:\n", buf); + } else { + printf("; %s\n", buf); + } +} + +static isc_result_t +printdata(dns_rdataset_t *rdataset, dns_name_t *owner, + dns_master_style_t *style) { + isc_result_t result = ISC_R_SUCCESS; + static dns_trust_t trust; + static bool first = true; + isc_buffer_t target; + isc_region_t r; + char *t = NULL; + int len = 2048; + + if (!dns_rdataset_isassociated(rdataset)) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(owner, namebuf, sizeof(namebuf)); + delv_log(ISC_LOG_DEBUG(4), "WARN: empty rdataset %s", namebuf); + return (ISC_R_SUCCESS); + } + + if (!showdnssec && rdataset->type == dns_rdatatype_rrsig) { + return (ISC_R_SUCCESS); + } + + if (first || rdataset->trust != trust) { + if (!first && showtrust && !short_form && !yaml) { + putchar('\n'); + } + print_status(rdataset); + trust = rdataset->trust; + first = false; + } + + do { + t = isc_mem_get(mctx, len); + + isc_buffer_init(&target, t, len); + if (short_form) { + dns_rdata_t rdata = DNS_RDATA_INIT; + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) + { + if ((rdataset->attributes & + DNS_RDATASETATTR_NEGATIVE) != 0) + { + continue; + } + + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tofmttext( + &rdata, dns_rootname, styleflags, 0, + splitwidth, " ", &target); + if (result != ISC_R_SUCCESS) { + break; + } + + if (isc_buffer_availablelength(&target) < 1) { + result = ISC_R_NOSPACE; + break; + } + + isc_buffer_putstr(&target, "\n"); + + dns_rdata_reset(&rdata); + } + } else { + dns_indent_t indent = { " ", 2 }; + if (!yaml && (rdataset->attributes & + DNS_RDATASETATTR_NEGATIVE) != 0) + { + isc_buffer_putstr(&target, "; "); + } + result = dns_master_rdatasettotext( + owner, rdataset, style, yaml ? &indent : NULL, + &target); + } + + if (result == ISC_R_NOSPACE) { + isc_mem_put(mctx, t, len); + len += 1024; + } else if (result == ISC_R_NOMORE) { + result = ISC_R_SUCCESS; + } else { + CHECK(result); + } + } while (result == ISC_R_NOSPACE); + + isc_buffer_usedregion(&target, &r); + printf("%.*s", (int)r.length, (char *)r.base); + +cleanup: + if (t != NULL) { + isc_mem_put(mctx, t, len); + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +setup_style(dns_master_style_t **stylep) { + isc_result_t result; + dns_master_style_t *style = NULL; + + REQUIRE(stylep != NULL && *stylep == NULL); + + styleflags |= DNS_STYLEFLAG_REL_OWNER; + if (yaml) { + styleflags |= DNS_STYLEFLAG_YAML; + } else { + if (showcomments) { + styleflags |= DNS_STYLEFLAG_COMMENT; + } + if (print_unknown_format) { + styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT; + } + if (rrcomments) { + styleflags |= DNS_STYLEFLAG_RRCOMMENT; + } + if (nottl) { + styleflags |= DNS_STYLEFLAG_NO_TTL; + } + if (noclass) { + styleflags |= DNS_STYLEFLAG_NO_CLASS; + } + if (nocrypto) { + styleflags |= DNS_STYLEFLAG_NOCRYPTO; + } + if (multiline) { + styleflags |= DNS_STYLEFLAG_MULTILINE; + styleflags |= DNS_STYLEFLAG_COMMENT; + } + } + + if (multiline || (nottl && noclass)) { + result = dns_master_stylecreate(&style, styleflags, 24, 24, 24, + 32, 80, 8, splitwidth, mctx); + } else if (nottl || noclass) { + result = dns_master_stylecreate(&style, styleflags, 24, 24, 32, + 40, 80, 8, splitwidth, mctx); + } else { + result = dns_master_stylecreate(&style, styleflags, 24, 32, 40, + 48, 80, 8, splitwidth, mctx); + } + + if (result == ISC_R_SUCCESS) { + *stylep = style; + } + return (result); +} + +static isc_result_t +convert_name(dns_fixedname_t *fn, dns_name_t **name, const char *text) { + isc_result_t result; + isc_buffer_t b; + dns_name_t *n; + unsigned int len; + + REQUIRE(fn != NULL && name != NULL && text != NULL); + len = strlen(text); + + isc_buffer_constinit(&b, text, len); + isc_buffer_add(&b, len); + n = dns_fixedname_initname(fn); + + result = dns_name_fromtext(n, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + delv_log(ISC_LOG_ERROR, "failed to convert QNAME %s: %s", text, + isc_result_totext(result)); + return (result); + } + + *name = n; + return (ISC_R_SUCCESS); +} + +static isc_result_t +key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { + dns_rdata_dnskey_t dnskey; + dns_rdata_ds_t ds; + uint32_t rdata1, rdata2, rdata3; + const char *datastr = NULL, *keynamestr = NULL, *atstr = NULL; + unsigned char data[4096]; + isc_buffer_t databuf; + unsigned char rrdata[4096]; + isc_buffer_t rrdatabuf; + isc_region_t r; + dns_fixedname_t fkeyname; + dns_name_t *keyname; + isc_result_t result; + bool match_root = false; + enum { + INITIAL_KEY, + STATIC_KEY, + INITIAL_DS, + STATIC_DS, + TRUSTED + } anchortype; + const cfg_obj_t *obj; + + keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); + CHECK(convert_name(&fkeyname, &keyname, keynamestr)); + + if (!root_validation) { + return (ISC_R_SUCCESS); + } + + if (anchor_name) { + match_root = dns_name_equal(keyname, anchor_name); + } + + if (!match_root) { + return (ISC_R_SUCCESS); + } + + if (!root_validation) { + return (ISC_R_SUCCESS); + } + + delv_log(ISC_LOG_DEBUG(3), "adding trust anchor %s", trust_anchor); + + /* if DNSKEY, flags; if DS, key tag */ + rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1")); + + /* if DNSKEY, protocol; if DS, algorithm */ + rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2")); + + /* if DNSKEY, algorithm; if DS, digest type */ + rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3")); + + /* What type of trust anchor is this? */ + obj = cfg_tuple_get(key, "anchortype"); + if (cfg_obj_isvoid(obj)) { + /* + * "anchortype" is not defined, this must be a static-key + * configured with trusted-keys. + */ + anchortype = STATIC_KEY; + } else { + atstr = cfg_obj_asstring(obj); + if (strcasecmp(atstr, "static-key") == 0) { + anchortype = STATIC_KEY; + } else if (strcasecmp(atstr, "static-ds") == 0) { + anchortype = STATIC_DS; + } else if (strcasecmp(atstr, "initial-key") == 0) { + anchortype = INITIAL_KEY; + } else if (strcasecmp(atstr, "initial-ds") == 0) { + anchortype = INITIAL_DS; + } else { + delv_log(ISC_LOG_ERROR, + "key '%s': invalid initialization method '%s'", + keynamestr, atstr); + result = ISC_R_FAILURE; + goto cleanup; + } + } + + isc_buffer_init(&databuf, data, sizeof(data)); + isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); + + if (rdata1 > 0xffff) { + CHECK(ISC_R_RANGE); + } + if (rdata2 > 0xff) { + CHECK(ISC_R_RANGE); + } + if (rdata3 > 0xff) { + CHECK(ISC_R_RANGE); + } + + switch (anchortype) { + case STATIC_KEY: + case INITIAL_KEY: + case TRUSTED: + dnskey.common.rdclass = dns_rdataclass_in; + dnskey.common.rdtype = dns_rdatatype_dnskey; + dnskey.mctx = NULL; + + ISC_LINK_INIT(&dnskey.common, link); + + dnskey.flags = (uint16_t)rdata1; + dnskey.protocol = (uint8_t)rdata2; + dnskey.algorithm = (uint8_t)rdata3; + + datastr = cfg_obj_asstring(cfg_tuple_get(key, "data")); + CHECK(isc_base64_decodestring(datastr, &databuf)); + isc_buffer_usedregion(&databuf, &r); + dnskey.datalen = r.length; + dnskey.data = r.base; + + CHECK(dns_rdata_fromstruct(NULL, dnskey.common.rdclass, + dnskey.common.rdtype, &dnskey, + &rrdatabuf)); + CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, + dns_rdatatype_dnskey, keyname, + &rrdatabuf)); + break; + case INITIAL_DS: + case STATIC_DS: + ds.common.rdclass = dns_rdataclass_in; + ds.common.rdtype = dns_rdatatype_ds; + ds.mctx = NULL; + + ISC_LINK_INIT(&ds.common, link); + + ds.key_tag = (uint16_t)rdata1; + ds.algorithm = (uint8_t)rdata2; + ds.digest_type = (uint8_t)rdata3; + + datastr = cfg_obj_asstring(cfg_tuple_get(key, "data")); + CHECK(isc_hex_decodestring(datastr, &databuf)); + isc_buffer_usedregion(&databuf, &r); + + switch (ds.digest_type) { + case DNS_DSDIGEST_SHA1: + if (r.length != ISC_SHA1_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; + case DNS_DSDIGEST_SHA256: + if (r.length != ISC_SHA256_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; + case DNS_DSDIGEST_SHA384: + if (r.length != ISC_SHA384_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; + } + + ds.length = r.length; + ds.digest = r.base; + + CHECK(dns_rdata_fromstruct(NULL, ds.common.rdclass, + ds.common.rdtype, &ds, &rrdatabuf)); + CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, + dns_rdatatype_ds, keyname, + &rrdatabuf)); + } + + num_keys++; + +cleanup: + if (result == DST_R_NOCRYPTO) { + cfg_obj_log(key, lctx, ISC_LOG_ERROR, "no crypto support"); + } else if (result == DST_R_UNSUPPORTEDALG) { + cfg_obj_log(key, lctx, ISC_LOG_WARNING, + "skipping trusted key '%s': %s", keynamestr, + isc_result_totext(result)); + result = ISC_R_SUCCESS; + } else if (result != ISC_R_SUCCESS) { + cfg_obj_log(key, lctx, ISC_LOG_ERROR, + "failed to add trusted key '%s': %s", keynamestr, + isc_result_totext(result)); + result = ISC_R_FAILURE; + } + + return (result); +} + +static isc_result_t +load_keys(const cfg_obj_t *keys, dns_client_t *client) { + const cfg_listelt_t *elt, *elt2; + const cfg_obj_t *key, *keylist; + isc_result_t result = ISC_R_SUCCESS; + + for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt)) + { + keylist = cfg_listelt_value(elt); + + for (elt2 = cfg_list_first(keylist); elt2 != NULL; + elt2 = cfg_list_next(elt2)) + { + key = cfg_listelt_value(elt2); + CHECK(key_fromconfig(key, client)); + } + } + +cleanup: + if (result == DST_R_NOCRYPTO) { + result = ISC_R_SUCCESS; + } + return (result); +} + +static isc_result_t +setup_dnsseckeys(dns_client_t *client) { + isc_result_t result; + cfg_parser_t *parser = NULL; + const cfg_obj_t *trusted_keys = NULL; + const cfg_obj_t *managed_keys = NULL; + const cfg_obj_t *trust_anchors = NULL; + cfg_obj_t *bindkeys = NULL; + const char *filename = anchorfile; + + if (!root_validation) { + return (ISC_R_SUCCESS); + } + + if (filename == NULL) { +#ifndef WIN32 + filename = SYSCONFDIR "/bind.keys"; +#else /* ifndef WIN32 */ + static char buf[MAX_PATH]; + strlcpy(buf, isc_ntpaths_get(SYS_CONF_DIR), sizeof(buf)); + strlcat(buf, "\\bind.keys", sizeof(buf)); + filename = buf; +#endif /* ifndef WIN32 */ + } + + if (trust_anchor == NULL) { + trust_anchor = isc_mem_strdup(mctx, "."); + } + + if (trust_anchor != NULL) { + CHECK(convert_name(&afn, &anchor_name, trust_anchor)); + } + + CHECK(cfg_parser_create(mctx, dns_lctx, &parser)); + + if (access(filename, R_OK) != 0) { + if (anchorfile != NULL) { + fatal("Unable to read key file '%s'", anchorfile); + } + } else { + result = cfg_parse_file(parser, filename, &cfg_type_bindkeys, + &bindkeys); + if (result != ISC_R_SUCCESS) { + if (anchorfile != NULL) { + fatal("Unable to load keys from '%s'", + anchorfile); + } + } + } + + if (bindkeys == NULL) { + isc_buffer_t b; + + isc_buffer_init(&b, anchortext, sizeof(anchortext) - 1); + isc_buffer_add(&b, sizeof(anchortext) - 1); + cfg_parser_reset(parser); + result = cfg_parse_buffer(parser, &b, NULL, 0, + &cfg_type_bindkeys, 0, &bindkeys); + if (result != ISC_R_SUCCESS) { + fatal("Unable to parse built-in keys"); + } + } + + INSIST(bindkeys != NULL); + cfg_map_get(bindkeys, "trusted-keys", &trusted_keys); + cfg_map_get(bindkeys, "managed-keys", &managed_keys); + cfg_map_get(bindkeys, "trust-anchors", &trust_anchors); + + if (trusted_keys != NULL) { + CHECK(load_keys(trusted_keys, client)); + } + if (managed_keys != NULL) { + CHECK(load_keys(managed_keys, client)); + } + if (trust_anchors != NULL) { + CHECK(load_keys(trust_anchors, client)); + } + result = ISC_R_SUCCESS; + + if (num_keys == 0) { + fatal("No trusted keys were loaded"); + } + +cleanup: + if (bindkeys != NULL) { + cfg_obj_destroy(parser, &bindkeys); + } + if (parser != NULL) { + cfg_parser_destroy(&parser); + } + if (result != ISC_R_SUCCESS) { + delv_log(ISC_LOG_ERROR, "setup_dnsseckeys: %s", + isc_result_totext(result)); + } + return (result); +} + +static isc_result_t +addserver(dns_client_t *client) { + struct addrinfo hints, *res, *cur; + int gaierror; + struct in_addr in4; + struct in6_addr in6; + isc_sockaddr_t *sa; + isc_sockaddrlist_t servers; + uint32_t destport; + isc_result_t result; + dns_name_t *name = NULL; + + result = parse_uint(&destport, port, 0xffff, "port"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse port number"); + } + + ISC_LIST_INIT(servers); + + if (inet_pton(AF_INET, server, &in4) == 1) { + if (!use_ipv4) { + fatal("Use of IPv4 disabled by -6"); + } + sa = isc_mem_get(mctx, sizeof(*sa)); + ISC_LINK_INIT(sa, link); + isc_sockaddr_fromin(sa, &in4, destport); + ISC_LIST_APPEND(servers, sa, link); + } else if (inet_pton(AF_INET6, server, &in6) == 1) { + if (!use_ipv6) { + fatal("Use of IPv6 disabled by -4"); + } + sa = isc_mem_get(mctx, sizeof(*sa)); + ISC_LINK_INIT(sa, link); + isc_sockaddr_fromin6(sa, &in6, destport); + ISC_LIST_APPEND(servers, sa, link); + } else { + memset(&hints, 0, sizeof(hints)); + if (!use_ipv6) { + hints.ai_family = AF_INET; + } else if (!use_ipv4) { + hints.ai_family = AF_INET6; + } else { + hints.ai_family = AF_UNSPEC; + } + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + gaierror = getaddrinfo(server, port, &hints, &res); + if (gaierror != 0) { + delv_log(ISC_LOG_ERROR, "getaddrinfo failed: %s", + gai_strerror(gaierror)); + return (ISC_R_FAILURE); + } + + result = ISC_R_SUCCESS; + for (cur = res; cur != NULL; cur = cur->ai_next) { + if (cur->ai_family != AF_INET && + cur->ai_family != AF_INET6) + { + continue; + } + sa = isc_mem_get(mctx, sizeof(*sa)); + memset(sa, 0, sizeof(*sa)); + ISC_LINK_INIT(sa, link); + memmove(&sa->type, cur->ai_addr, cur->ai_addrlen); + sa->length = (unsigned int)cur->ai_addrlen; + ISC_LIST_APPEND(servers, sa, link); + } + freeaddrinfo(res); + CHECK(result); + } + + CHECK(dns_client_setservers(client, dns_rdataclass_in, name, &servers)); + +cleanup: + while (!ISC_LIST_EMPTY(servers)) { + sa = ISC_LIST_HEAD(servers); + ISC_LIST_UNLINK(servers, sa, link); + isc_mem_put(mctx, sa, sizeof(*sa)); + } + + if (result != ISC_R_SUCCESS) { + delv_log(ISC_LOG_ERROR, "addserver: %s", + isc_result_totext(result)); + } + + return (result); +} + +static isc_result_t +findserver(dns_client_t *client) { + isc_result_t result; + irs_resconf_t *resconf = NULL; + isc_sockaddrlist_t *nameservers; + isc_sockaddr_t *sa, *next; + uint32_t destport; + + result = parse_uint(&destport, port, 0xffff, "port"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse port number"); + } + + result = irs_resconf_load(mctx, "/etc/resolv.conf", &resconf); + if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) { + delv_log(ISC_LOG_ERROR, "irs_resconf_load: %s", + isc_result_totext(result)); + goto cleanup; + } + + /* Get nameservers from resolv.conf */ + nameservers = irs_resconf_getnameservers(resconf); + for (sa = ISC_LIST_HEAD(*nameservers); sa != NULL; sa = next) { + next = ISC_LIST_NEXT(sa, link); + + /* Set destination port */ + if (sa->type.sa.sa_family == AF_INET && use_ipv4) { + sa->type.sin.sin_port = htons(destport); + continue; + } + if (sa->type.sa.sa_family == AF_INET6 && use_ipv6) { + sa->type.sin6.sin6_port = htons(destport); + continue; + } + + /* Incompatible protocol family */ + ISC_LIST_UNLINK(*nameservers, sa, link); + isc_mem_put(mctx, sa, sizeof(*sa)); + } + + /* None found, use localhost */ + if (ISC_LIST_EMPTY(*nameservers)) { + if (use_ipv4) { + struct in_addr localhost; + localhost.s_addr = htonl(INADDR_LOOPBACK); + sa = isc_mem_get(mctx, sizeof(*sa)); + isc_sockaddr_fromin(sa, &localhost, destport); + + ISC_LINK_INIT(sa, link); + ISC_LIST_APPEND(*nameservers, sa, link); + } + + if (use_ipv6) { + sa = isc_mem_get(mctx, sizeof(*sa)); + isc_sockaddr_fromin6(sa, &in6addr_loopback, destport); + + ISC_LINK_INIT(sa, link); + ISC_LIST_APPEND(*nameservers, sa, link); + } + } + + result = dns_client_setservers(client, dns_rdataclass_in, NULL, + nameservers); + if (result != ISC_R_SUCCESS) { + delv_log(ISC_LOG_ERROR, "dns_client_setservers: %s", + isc_result_totext(result)); + } + +cleanup: + if (resconf != NULL) { + irs_resconf_destroy(&resconf); + } + return (result); +} + +static isc_result_t +parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc) { + uint32_t n; + isc_result_t result = isc_parse_uint32(&n, value, 10); + if (result == ISC_R_SUCCESS && n > max) { + result = ISC_R_RANGE; + } + if (result != ISC_R_SUCCESS) { + printf("invalid %s '%s': %s\n", desc, value, + isc_result_totext(result)); + return (result); + } + *uip = n; + return (ISC_R_SUCCESS); +} + +static void +plus_option(char *option) { + isc_result_t result; + char *cmd, *value, *last = NULL; + bool state = true; + + INSIST(option != NULL); + + cmd = strtok_r(option, "=", &last); + if (cmd == NULL) { + printf(";; Invalid option %s\n", option); + return; + } + if (strncasecmp(cmd, "no", 2) == 0) { + cmd += 2; + state = false; + } + + value = strtok_r(NULL, "\0", &last); + +#define FULLCHECK(A) \ + do { \ + size_t _l = strlen(cmd); \ + if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ + goto invalid_option; \ + } while (0) + + switch (cmd[0]) { + case 'a': /* all */ + FULLCHECK("all"); + showcomments = state; + rrcomments = state; + showtrust = state; + break; + case 'c': + switch (cmd[1]) { + case 'd': /* cdflag */ + FULLCHECK("cdflag"); + cdflag = state; + break; + case 'l': /* class */ + FULLCHECK("class"); + noclass = !state; + break; + case 'o': /* comments */ + FULLCHECK("comments"); + showcomments = state; + break; + case 'r': /* crypto */ + FULLCHECK("crypto"); + nocrypto = !state; + break; + default: + goto invalid_option; + } + break; + case 'd': + switch (cmd[1]) { + case 'l': /* dlv */ + FULLCHECK("dlv"); + if (state) { + fprintf(stderr, "Invalid option: " + "+dlv is obsolete\n"); + exit(1); + } + break; + case 'n': /* dnssec */ + FULLCHECK("dnssec"); + showdnssec = state; + break; + default: + goto invalid_option; + } + break; + case 'm': + switch (cmd[1]) { + case 't': /* mtrace */ + message_trace = state; + if (state) { + resolve_trace = state; + } + break; + case 'u': /* multiline */ + FULLCHECK("multiline"); + multiline = state; + break; + default: + goto invalid_option; + } + break; + case 'r': + switch (cmd[1]) { + case 'o': /* root */ + FULLCHECK("root"); + if (state && no_sigs) { + break; + } + root_validation = state; + if (value != NULL) { + trust_anchor = isc_mem_strdup(mctx, value); + } + break; + case 'r': /* rrcomments */ + FULLCHECK("rrcomments"); + rrcomments = state; + break; + case 't': /* rtrace */ + FULLCHECK("rtrace"); + resolve_trace = state; + break; + default: + goto invalid_option; + } + break; + case 's': + switch (cmd[1]) { + case 'h': /* short */ + FULLCHECK("short"); + short_form = state; + if (short_form) { + multiline = false; + showcomments = false; + showtrust = false; + showdnssec = false; + } + break; + case 'p': /* split */ + FULLCHECK("split"); + if (value != NULL && !state) { + goto invalid_option; + } + if (!state) { + splitwidth = 0; + break; + } else if (value == NULL) { + break; + } + + result = parse_uint(&splitwidth, value, 1023, "split"); + if (splitwidth % 4 != 0) { + splitwidth = ((splitwidth + 3) / 4) * 4; + warn("split must be a multiple of 4; " + "adjusting to %d", + splitwidth); + } + /* + * There is an adjustment done in the + * totext_() functions which causes + * splitwidth to shrink. This is okay when we're + * using the default width but incorrect in this + * case, so we correct for it + */ + if (splitwidth) { + splitwidth += 3; + } + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse split"); + } + break; + default: + goto invalid_option; + } + break; + case 'u': + FULLCHECK("unknownformat"); + print_unknown_format = state; + break; + case 't': + switch (cmd[1]) { + case 'c': /* tcp */ + FULLCHECK("tcp"); + use_tcp = state; + break; + case 'r': /* trust */ + FULLCHECK("trust"); + showtrust = state; + break; + case 't': /* ttl */ + FULLCHECK("ttl"); + nottl = !state; + break; + default: + goto invalid_option; + } + break; + case 'v': /* vtrace */ + FULLCHECK("vtrace"); + validator_trace = state; + if (state) { + resolve_trace = state; + } + break; + case 'y': /* yaml */ + FULLCHECK("yaml"); + yaml = state; + if (state) { + rrcomments = false; + } + break; + default: + invalid_option: + /* + * We can also add a "need_value:" case here if we ever + * add a plus-option that requires a specified value + */ + fprintf(stderr, "Invalid option: +%s\n", option); + usage(); + } + return; +} + +/* + * options: "46a:b:c:d:himp:q:t:vx:"; + */ +static const char *single_dash_opts = "46himv"; +static const char *dash_opts = "46abcdhimpqtvx"; + +static bool +dash_option(char *option, char *next, bool *open_type_class) { + char opt, *value; + isc_result_t result; + bool value_from_next; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + char textname[MAXNAME]; + struct in_addr in4; + struct in6_addr in6; + in_port_t srcport; + uint32_t num; + char *hash; + + while (strpbrk(option, single_dash_opts) == &option[0]) { + /* + * Since the -[46himv] options do not take an argument, + * account for them (in any number and/or combination) + * if they appear as the first character(s) of a q-opt. + */ + opt = option[0]; + switch (opt) { + case '4': + if (isc_net_probeipv4() != ISC_R_SUCCESS) { + fatal("IPv4 networking not available"); + } + if (use_ipv6) { + isc_net_disableipv6(); + use_ipv6 = false; + } + break; + case '6': + if (isc_net_probeipv6() != ISC_R_SUCCESS) { + fatal("IPv6 networking not available"); + } + if (use_ipv4) { + isc_net_disableipv4(); + use_ipv4 = false; + } + break; + case 'h': + usage(); + exit(0); + case 'i': + no_sigs = true; + root_validation = false; + break; + case 'm': + /* handled in preparse_args() */ + break; + case 'v': + fputs("delv " VERSION "\n", stderr); + exit(0); + default: + UNREACHABLE(); + } + if (strlen(option) > 1U) { + option = &option[1]; + } else { + return (false); + } + } + opt = option[0]; + if (strlen(option) > 1U) { + value_from_next = false; + value = &option[1]; + } else { + value_from_next = true; + value = next; + } + if (value == NULL) { + goto invalid_option; + } + switch (opt) { + case 'a': + anchorfile = isc_mem_strdup(mctx, value); + return (value_from_next); + case 'b': + hash = strchr(value, '#'); + if (hash != NULL) { + result = parse_uint(&num, hash + 1, 0xffff, "port"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse port number"); + } + srcport = num; + *hash = '\0'; + } else { + srcport = 0; + } + + if (inet_pton(AF_INET, value, &in4) == 1) { + if (srcaddr4 != NULL) { + fatal("Only one local address per family " + "can be specified\n"); + } + isc_sockaddr_fromin(&a4, &in4, srcport); + srcaddr4 = &a4; + } else if (inet_pton(AF_INET6, value, &in6) == 1) { + if (srcaddr6 != NULL) { + fatal("Only one local address per family " + "can be specified\n"); + } + isc_sockaddr_fromin6(&a6, &in6, srcport); + srcaddr6 = &a6; + } else { + if (hash != NULL) { + *hash = '#'; + } + fatal("Invalid address %s", value); + } + if (hash != NULL) { + *hash = '#'; + } + return (value_from_next); + case 'c': + if (classset) { + warn("extra query class"); + } + + *open_type_class = false; + tr.base = value; + tr.length = strlen(value); + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) { + classset = true; + } else if (rdclass != dns_rdataclass_in) { + warn("ignoring non-IN query class"); + } else { + warn("ignoring invalid class"); + } + return (value_from_next); + case 'd': + result = parse_uint(&num, value, 99, "debug level"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse debug level"); + } + loglevel = num; + return (value_from_next); + case 'p': + port = value; + return (value_from_next); + case 'q': + if (curqname != NULL) { + warn("extra query name"); + isc_mem_free(mctx, curqname); + } + curqname = isc_mem_strdup(mctx, value); + return (value_from_next); + case 't': + *open_type_class = false; + tr.base = value; + tr.length = strlen(value); + result = dns_rdatatype_fromtext(&rdtype, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) { + if (typeset) { + warn("extra query type"); + } + if (rdtype == dns_rdatatype_ixfr || + rdtype == dns_rdatatype_axfr) + { + fatal("Transfer not supported"); + } + qtype = rdtype; + typeset = true; + } else { + warn("ignoring invalid type"); + } + return (value_from_next); + case 'x': + result = get_reverse(textname, sizeof(textname), value, false); + if (result == ISC_R_SUCCESS) { + if (curqname != NULL) { + isc_mem_free(mctx, curqname); + warn("extra query name"); + } + curqname = isc_mem_strdup(mctx, textname); + if (typeset) { + warn("extra query type"); + } + qtype = dns_rdatatype_ptr; + typeset = true; + } else { + fprintf(stderr, "Invalid IP address %s\n", value); + exit(1); + } + return (value_from_next); + invalid_option: + default: + fprintf(stderr, "Invalid option: -%s\n", option); + usage(); + } + UNREACHABLE(); + return (false); +} + +/* + * Check for -m first to determine whether to enable + * memory debugging when setting up the memory context. + */ +static void +preparse_args(int argc, char **argv) { + bool ipv4only = false, ipv6only = false; + char *option; + + for (argc--, argv++; argc > 0; argc--, argv++) { + if (argv[0][0] != '-') { + continue; + } + + option = &argv[0][1]; + while (strpbrk(option, single_dash_opts) == &option[0]) { + switch (option[0]) { + case 'm': + isc_mem_debugging = ISC_MEM_DEBUGTRACE | + ISC_MEM_DEBUGRECORD; + break; + case '4': + if (ipv6only) { + fatal("only one of -4 and -6 allowed"); + } + ipv4only = true; + break; + case '6': + if (ipv4only) { + fatal("only one of -4 and -6 allowed"); + } + ipv6only = true; + break; + } + option = &option[1]; + } + + if (strlen(option) == 0U) { + continue; + } + + /* Look for dash value option. */ + if (strpbrk(option, dash_opts) != &option[0] || + strlen(option) > 1U) + { + /* Error or value in option. */ + continue; + } + + /* Dash value is next argument so we need to skip it. */ + argc--; + argv++; + + /* Handle missing argument */ + if (argc == 0) { + break; + } + } +} + +/* + * Argument parsing is based on dig, but simplified: only one + * QNAME/QCLASS/QTYPE tuple can be specified, and options have + * been removed that aren't applicable to delv. The interface + * should be familiar to dig users, however. + */ +static void +parse_args(int argc, char **argv) { + isc_result_t result; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + bool open_type_class = true; + + for (; argc > 0; argc--, argv++) { + if (argv[0][0] == '@') { + server = &argv[0][1]; + } else if (argv[0][0] == '+') { + plus_option(&argv[0][1]); + } else if (argv[0][0] == '-') { + if (argc <= 1) { + if (dash_option(&argv[0][1], NULL, + &open_type_class)) + { + argc--; + argv++; + } + } else { + if (dash_option(&argv[0][1], argv[1], + &open_type_class)) + { + argc--; + argv++; + } + } + } else { + /* + * Anything which isn't an option + */ + if (open_type_class) { + tr.base = argv[0]; + tr.length = strlen(argv[0]); + result = dns_rdatatype_fromtext( + &rdtype, (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) { + if (typeset) { + warn("extra query type"); + } + if (rdtype == dns_rdatatype_ixfr || + rdtype == dns_rdatatype_axfr) + { + fatal("Transfer not supported"); + } + qtype = rdtype; + typeset = true; + continue; + } + result = dns_rdataclass_fromtext( + &rdclass, (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) { + if (classset) { + warn("extra query class"); + } else if (rdclass != dns_rdataclass_in) + { + warn("ignoring non-IN " + "query class"); + } + continue; + } + } + + if (curqname == NULL) { + curqname = isc_mem_strdup(mctx, argv[0]); + } + } + } + + /* + * If no qname or qtype specified, search for root/NS + * If no qtype specified, use A + */ + if (!typeset) { + qtype = dns_rdatatype_a; + } + + if (curqname == NULL) { + qname = isc_mem_strdup(mctx, "."); + + if (!typeset) { + qtype = dns_rdatatype_ns; + } + } else { + qname = curqname; + } +} + +static isc_result_t +append_str(const char *text, int len, char **p, char *end) { + if (len > end - *p) { + return (ISC_R_NOSPACE); + } + memmove(*p, text, len); + *p += len; + return (ISC_R_SUCCESS); +} + +static isc_result_t +reverse_octets(const char *in, char **p, char *end) { + char *dot = strchr(in, '.'); + int len; + if (dot != NULL) { + isc_result_t result; + result = reverse_octets(dot + 1, p, end); + if (result != ISC_R_SUCCESS) { + return (result); + } + result = append_str(".", 1, p, end); + if (result != ISC_R_SUCCESS) { + return (result); + } + len = (int)(dot - in); + } else { + len = strlen(in); + } + return (append_str(in, len, p, end)); +} + +static isc_result_t +get_reverse(char *reverse, size_t len, char *value, bool strict) { + int r; + isc_result_t result; + isc_netaddr_t addr; + + addr.family = AF_INET6; + r = inet_pton(AF_INET6, value, &addr.type.in6); + if (r > 0) { + /* This is a valid IPv6 address. */ + dns_fixedname_t fname; + dns_name_t *name; + unsigned int options = 0; + + name = dns_fixedname_initname(&fname); + result = dns_byaddr_createptrname(&addr, options, name); + if (result != ISC_R_SUCCESS) { + return (result); + } + dns_name_format(name, reverse, (unsigned int)len); + return (ISC_R_SUCCESS); + } else { + /* + * Not a valid IPv6 address. Assume IPv4. + * If 'strict' is not set, construct the + * in-addr.arpa name by blindly reversing + * octets whether or not they look like integers, + * so that this can be used for RFC2317 names + * and such. + */ + char *p = reverse; + char *end = reverse + len; + if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1) { + return (DNS_R_BADDOTTEDQUAD); + } + result = reverse_octets(value, &p, end); + if (result != ISC_R_SUCCESS) { + return (result); + } + result = append_str(".in-addr.arpa.", 15, &p, end); + if (result != ISC_R_SUCCESS) { + return (result); + } + return (ISC_R_SUCCESS); + } +} + +int +main(int argc, char *argv[]) { + dns_client_t *client = NULL; + isc_result_t result; + dns_fixedname_t qfn; + dns_name_t *query_name, *response_name; + char namestr[DNS_NAME_FORMATSIZE]; + dns_rdataset_t *rdataset; + dns_namelist_t namelist; + unsigned int resopt, clopt; + isc_appctx_t *actx = NULL; + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_timermgr_t *timermgr = NULL; + dns_master_style_t *style = NULL; +#ifndef WIN32 + struct sigaction sa; +#endif /* ifndef WIN32 */ + + progname = argv[0]; + preparse_args(argc, argv); + + argc--; + argv++; + + isc_lib_register(); + result = dns_lib_init(); + if (result != ISC_R_SUCCESS) { + fatal("dns_lib_init failed: %d", result); + } + + isc_mem_create(&mctx); + + CHECK(isc_appctx_create(mctx, &actx)); + CHECK(isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr)); + CHECK(isc_socketmgr_create(mctx, &socketmgr)); + CHECK(isc_timermgr_create(mctx, &timermgr)); + + parse_args(argc, argv); + + CHECK(setup_style(&style)); + + setup_logging(stderr); + + CHECK(isc_app_ctxstart(actx)); + +#ifndef WIN32 + /* Unblock SIGINT if it's been blocked by isc_app_ctxstart() */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + if (sigfillset(&sa.sa_mask) != 0 || sigaction(SIGINT, &sa, NULL) < 0) { + fatal("Couldn't set up signal handler"); + } +#endif /* ifndef WIN32 */ + + /* Create client */ + clopt = DNS_CLIENTCREATEOPT_USECACHE; + result = dns_client_create(mctx, actx, taskmgr, socketmgr, timermgr, + clopt, &client, srcaddr4, srcaddr6); + if (result != ISC_R_SUCCESS) { + delv_log(ISC_LOG_ERROR, "dns_client_create: %s", + isc_result_totext(result)); + goto cleanup; + } + + /* Set the nameserver */ + if (server != NULL) { + addserver(client); + } else { + findserver(client); + } + + CHECK(setup_dnsseckeys(client)); + + /* Construct QNAME */ + CHECK(convert_name(&qfn, &query_name, qname)); + + /* Set up resolution options */ + resopt = DNS_CLIENTRESOPT_NOCDFLAG; + if (no_sigs) { + resopt |= DNS_CLIENTRESOPT_NODNSSEC; + } + if (!root_validation) { + resopt |= DNS_CLIENTRESOPT_NOVALIDATE; + } + if (cdflag) { + resopt &= ~DNS_CLIENTRESOPT_NOCDFLAG; + } + if (use_tcp) { + resopt |= DNS_CLIENTRESOPT_TCP; + } + + /* Perform resolution */ + ISC_LIST_INIT(namelist); + result = dns_client_resolve(client, query_name, dns_rdataclass_in, + qtype, resopt, &namelist); + if (result != ISC_R_SUCCESS && !yaml) { + delv_log(ISC_LOG_ERROR, "resolution failed: %s", + isc_result_totext(result)); + } + + if (yaml) { + printf("type: DELV_RESULT\n"); + dns_name_format(query_name, namestr, sizeof(namestr)); + printf("query_name: %s\n", namestr); + printf("status: %s\n", isc_result_totext(result)); + printf("records:\n"); + } + + for (response_name = ISC_LIST_HEAD(namelist); response_name != NULL; + response_name = ISC_LIST_NEXT(response_name, link)) + { + for (rdataset = ISC_LIST_HEAD(response_name->list); + rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) + { + result = printdata(rdataset, response_name, style); + if (result != ISC_R_SUCCESS) { + delv_log(ISC_LOG_ERROR, "print data failed"); + } + } + } + + dns_client_freeresanswer(client, &namelist); + +cleanup: + if (trust_anchor != NULL) { + isc_mem_free(mctx, trust_anchor); + } + if (anchorfile != NULL) { + isc_mem_free(mctx, anchorfile); + } + if (qname != NULL) { + isc_mem_free(mctx, qname); + } + if (style != NULL) { + dns_master_styledestroy(&style, mctx); + } + if (client != NULL) { + dns_client_destroy(&client); + } + if (taskmgr != NULL) { + isc_managers_destroy(&netmgr, &taskmgr); + } + if (timermgr != NULL) { + isc_timermgr_destroy(&timermgr); + } + if (socketmgr != NULL) { + isc_socketmgr_destroy(&socketmgr); + } + if (actx != NULL) { + isc_appctx_destroy(&actx); + } + if (lctx != NULL) { + isc_log_destroy(&lctx); + } + isc_mem_detach(&mctx); + + dns_lib_shutdown(); + + return (0); +} diff --git a/bin/delv/delv.rst b/bin/delv/delv.rst new file mode 100644 index 0000000..0936236 --- /dev/null +++ b/bin/delv/delv.rst @@ -0,0 +1,326 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_delv: + +delv - DNS lookup and validation utility +---------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`delv` [@server] [ [**-4**] | [**-6**] ] [**-a** anchor-file] [**-b** address] [**-c** class] [**-d** level] [**-i**] [**-m**] [**-p** port#] [**-q** name] [**-t** type] [**-x** addr] [name] [type] [class] [queryopt...] + +:program:`delv` [**-h**] + +:program:`delv` [**-v**] + +:program:`delv` [queryopt...] [query...] + +Description +~~~~~~~~~~~ + +``delv`` is a tool for sending DNS queries and validating the results, +using the same internal resolver and validator logic as ``named``. + +``delv`` sends to a specified name server all queries needed to +fetch and validate the requested data; this includes the original +requested query, subsequent queries to follow CNAME or DNAME chains, +queries for DNSKEY, and DS records to establish a chain of trust for +DNSSEC validation. It does not perform iterative resolution, but +simulates the behavior of a name server configured for DNSSEC validating +and forwarding. + +By default, responses are validated using the built-in DNSSEC trust anchor +for the root zone ("."). Records returned by ``delv`` are either fully +validated or were not signed. If validation fails, an explanation of the +failure is included in the output; the validation process can be traced +in detail. Because ``delv`` does not rely on an external server to carry +out validation, it can be used to check the validity of DNS responses in +environments where local name servers may not be trustworthy. + +Unless it is told to query a specific name server, ``delv`` tries +each of the servers listed in ``/etc/resolv.conf``. If no usable server +addresses are found, ``delv`` sends queries to the localhost +addresses (127.0.0.1 for IPv4, ::1 for IPv6). + +When no command-line arguments or options are given, ``delv`` +performs an NS query for "." (the root zone). + +Simple Usage +~~~~~~~~~~~~ + +A typical invocation of ``delv`` looks like: + +:: + + delv @server name type + +where: + +``server`` + is the name or IP address of the name server to query. This can be an + IPv4 address in dotted-decimal notation or an IPv6 address in + colon-delimited notation. When the supplied ``server`` argument is a + hostname, ``delv`` resolves that name before querying that name + server (note, however, that this initial lookup is *not* validated by + DNSSEC). + + If no ``server`` argument is provided, ``delv`` consults + ``/etc/resolv.conf``; if an address is found there, it queries the + name server at that address. If either of the ``-4`` or ``-6`` + options is in use, then only addresses for the corresponding + transport are tried. If no usable addresses are found, ``delv`` + sends queries to the localhost addresses (127.0.0.1 for IPv4, ::1 + for IPv6). + +``name`` + is the domain name to be looked up. + +``type`` + indicates what type of query is required - ANY, A, MX, etc. + ``type`` can be any valid query type. If no ``type`` argument is + supplied, ``delv`` performs a lookup for an A record. + +Options +~~~~~~~ + +``-a anchor-file`` + This option specifies a file from which to read DNSSEC trust anchors. The default + is ``/etc/bind.keys``, which is included with BIND 9 and contains one + or more trust anchors for the root zone ("."). + + Keys that do not match the root zone name are ignored. An alternate + key name can be specified using the ``+root=NAME`` options. + + Note: When reading the trust anchor file, ``delv`` treats ``trust-anchors``, + ``initial-key``, and ``static-key`` identically. That is, for a managed key, + it is the *initial* key that is trusted; :rfc:`5011` key management is not + supported. ``delv`` does not consult the managed-keys database maintained by + ``named``, which means that if either of the keys in ``/etc/bind.keys`` is + revoked and rolled over, ``/etc/bind.keys`` must be updated to + use DNSSEC validation in ``delv``. + +``-b address`` + This option sets the source IP address of the query to ``address``. This must be + a valid address on one of the host's network interfaces, or ``0.0.0.0``, + or ``::``. An optional source port may be specified by appending + ``#`` + +``-c class`` + This option sets the query class for the requested data. Currently, only class + "IN" is supported in ``delv`` and any other value is ignored. + +``-d level`` + This option sets the systemwide debug level to ``level``. The allowed range is + from 0 to 99. The default is 0 (no debugging). Debugging traces from + ``delv`` become more verbose as the debug level increases. See the + ``+mtrace``, ``+rtrace``, and ``+vtrace`` options below for + additional debugging details. + +``-h`` + This option displays the ``delv`` help usage output and exits. + +``-i`` + This option sets insecure mode, which disables internal DNSSEC validation. (Note, + however, that this does not set the CD bit on upstream queries. If the + server being queried is performing DNSSEC validation, then it does + not return invalid data; this can cause ``delv`` to time out. When it + is necessary to examine invalid data to debug a DNSSEC problem, use + ``dig +cd``.) + +``-m`` + This option enables memory usage debugging. + +``-p port#`` + This option specifies a destination port to use for queries, instead of the + standard DNS port number 53. This option is used with a name + server that has been configured to listen for queries on a + non-standard port number. + +``-q name`` + This option sets the query name to ``name``. While the query name can be + specified without using the ``-q`` option, it is sometimes necessary to + disambiguate names from types or classes (for example, when looking + up the name "ns", which could be misinterpreted as the type NS, or + "ch", which could be misinterpreted as class CH). + +``-t type`` + This option sets the query type to ``type``, which can be any valid query type + supported in BIND 9 except for zone transfer types AXFR and IXFR. As + with ``-q``, this is useful to distinguish query-name types or classes + when they are ambiguous. It is sometimes necessary to disambiguate + names from types. + + The default query type is "A", unless the ``-x`` option is supplied + to indicate a reverse lookup, in which case it is "PTR". + +``-v`` + This option prints the ``delv`` version and exits. + +``-x addr`` + This option performs a reverse lookup, mapping an address to a name. ``addr`` + is an IPv4 address in dotted-decimal notation, or a colon-delimited + IPv6 address. When ``-x`` is used, there is no need to provide the + ``name`` or ``type`` arguments; ``delv`` automatically performs a + lookup for a name like ``11.12.13.10.in-addr.arpa`` and sets the + query type to PTR. IPv6 addresses are looked up using nibble format + under the IP6.ARPA domain. + +``-4`` + This option forces ``delv`` to only use IPv4. + +``-6`` + This option forces ``delv`` to only use IPv6. + +Query Options +~~~~~~~~~~~~~ + +``delv`` provides a number of query options which affect the way results +are displayed, and in some cases the way lookups are performed. + +Each query option is identified by a keyword preceded by a plus sign +(``+``). Some keywords set or reset an option. These may be preceded by +the string ``no`` to negate the meaning of that keyword. Other keywords +assign values to options like the timeout interval. They have the form +``+keyword=value``. The query options are: + +``+[no]cdflag`` + This option controls whether to set the CD (checking disabled) bit in queries + sent by ``delv``. This may be useful when troubleshooting DNSSEC + problems from behind a validating resolver. A validating resolver + blocks invalid responses, making it difficult to retrieve them + for analysis. Setting the CD flag on queries causes the resolver + to return invalid responses, which ``delv`` can then validate + internally and report the errors in detail. + +``+[no]class`` + This option controls whether to display the CLASS when printing a record. The + default is to display the CLASS. + +``+[no]ttl`` + This option controls whether to display the TTL when printing a record. The + default is to display the TTL. + +``+[no]rtrace`` + This option toggles resolver fetch logging. This reports the name and type of each + query sent by ``delv`` in the process of carrying out the resolution + and validation process, including the original query + and all subsequent queries to follow CNAMEs and to establish a chain + of trust for DNSSEC validation. + + This is equivalent to setting the debug level to 1 in the "resolver" + logging category. Setting the systemwide debug level to 1 using the + ``-d`` option produces the same output, but affects other + logging categories as well. + +``+[no]mtrace`` + This option toggles message logging. This produces a detailed dump of the + responses received by ``delv`` in the process of carrying out the + resolution and validation process. + + This is equivalent to setting the debug level to 10 for the "packets" + module of the "resolver" logging category. Setting the systemwide + debug level to 10 using the ``-d`` option produces the same + output, but affects other logging categories as well. + +``+[no]vtrace`` + This option toggles validation logging. This shows the internal process of the + validator as it determines whether an answer is validly signed, + unsigned, or invalid. + + This is equivalent to setting the debug level to 3 for the + "validator" module of the "dnssec" logging category. Setting the + systemwide debug level to 3 using the ``-d`` option produces the + same output, but affects other logging categories as well. + +``+[no]short`` + This option toggles between verbose and terse answers. The default is to print the answer in a + verbose form. + +``+[no]comments`` + This option toggles the display of comment lines in the output. The default is to + print comments. + +``+[no]rrcomments`` + This option toggles the display of per-record comments in the output (for example, + human-readable key information about DNSKEY records). The default is + to print per-record comments. + +``+[no]crypto`` + This option toggles the display of cryptographic fields in DNSSEC records. The + contents of these fields are unnecessary to debug most DNSSEC + validation failures and removing them makes it easier to see the + common failures. The default is to display the fields. When omitted, + they are replaced by the string ``[omitted]`` or, in the DNSKEY case, the + key ID is displayed as the replacement, e.g. ``[ key id = value ]``. + +``+[no]trust`` + This option controls whether to display the trust level when printing a record. + The default is to display the trust level. + +``+[no]split[=W]`` + This option splits long hex- or base64-formatted fields in resource records into + chunks of ``W`` characters (where ``W`` is rounded up to the nearest + multiple of 4). ``+nosplit`` or ``+split=0`` causes fields not to be + split at all. The default is 56 characters, or 44 characters when + multiline mode is active. + +``+[no]all`` + This option sets or clears the display options ``+[no]comments``, + ``+[no]rrcomments``, and ``+[no]trust`` as a group. + +``+[no]multiline`` + This option prints long records (such as RRSIG, DNSKEY, and SOA records) in a + verbose multi-line format with human-readable comments. The default + is to print each record on a single line, to facilitate machine + parsing of the ``delv`` output. + +``+[no]dnssec`` + This option indicates whether to display RRSIG records in the ``delv`` output. + The default is to do so. Note that (unlike in ``dig``) this does + *not* control whether to request DNSSEC records or to + validate them. DNSSEC records are always requested, and validation + always occurs unless suppressed by the use of ``-i`` or + ``+noroot``. + +``+[no]root[=ROOT]`` + This option indicates whether to perform conventional DNSSEC validation, and if so, + specifies the name of a trust anchor. The default is to validate using a + trust anchor of "." (the root zone), for which there is a built-in key. If + specifying a different trust anchor, then ``-a`` must be used to specify a + file containing the key. + +``+[no]tcp`` + This option controls whether to use TCP when sending queries. The default is to + use UDP unless a truncated response has been received. + +``+[no]unknownformat`` + This option prints all RDATA in unknown RR-type presentation format (:rfc:`3597`). + The default is to print RDATA for known types in the type's + presentation format. + +``+[no]yaml`` + This option prints response data in YAML format. + +Files +~~~~~ + +``/etc/bind.keys`` + +``/etc/resolv.conf`` + +See Also +~~~~~~~~ + +:manpage:`dig(1)`, :manpage:`named(8)`, :rfc:`4034`, :rfc:`4035`, :rfc:`4431`, :rfc:`5074`, :rfc:`5155`. diff --git a/bin/delv/win32/delv.vcxproj.filters.in b/bin/delv/win32/delv.vcxproj.filters.in new file mode 100644 index 0000000..c1af2f3 --- /dev/null +++ b/bin/delv/win32/delv.vcxproj.filters.in @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + diff --git a/bin/delv/win32/delv.vcxproj.in b/bin/delv/win32/delv.vcxproj.in new file mode 100644 index 0000000..a1f84fb --- /dev/null +++ b/bin/delv/win32/delv.vcxproj.in @@ -0,0 +1,119 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {BE172EFE-C1DC-4812-BFB9-8C5F8ADB7E9F} + Win32Proj + delv + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@GEOIP_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\win32\include;..\..\..\lib\dns\include;..\..\..\lib\irs\win32\include;..\..\..\lib\irs\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;libisccfg.lib;libirs.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@GEOIP_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\win32\include;..\..\..\lib\dns\include;..\..\..\lib\irs\win32\include;..\..\..\lib\irs\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;libisccfg.lib;libirs.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/delv/win32/delv.vcxproj.user b/bin/delv/win32/delv.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/delv/win32/delv.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in new file mode 100644 index 0000000..c329502 --- /dev/null +++ b/bin/dig/Makefile.in @@ -0,0 +1,98 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +READLINE_LIB = @READLINE_LIB@ + +CINCLUDES = -I${srcdir}/include ${DNS_INCLUDES} \ + ${BIND9_INCLUDES} ${ISC_INCLUDES} \ + ${IRS_INCLUDES} ${ISCCFG_INCLUDES} @LIBIDN2_CFLAGS@ \ + ${OPENSSL_CFLAGS} + +CDEFINES = -DVERSION=\"${VERSION}\" +CWARNINGS = + +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +BIND9LIBS = ../../lib/bind9/libbind9.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +IRSLIBS = ../../lib/irs/libirs.@A@ + +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +IRSDEPLIBS = ../../lib/irs/libirs.@A@ + +DEPLIBS = ${DNSDEPLIBS} ${IRSDEPLIBS} ${BIND9DEPLIBS} \ + ${ISCDEPLIBS} ${ISCCFGDEPLIBS} + +LIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ + ${ISCLIBS} @LIBIDN2_LIBS@ @LIBS@ + +NOSYMLIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ + ${ISCNOSYMLIBS} @LIBIDN2_LIBS@ @LIBS@ + +SUBDIRS = + +TARGETS = dig@EXEEXT@ host@EXEEXT@ nslookup@EXEEXT@ + +OBJS = dig.@O@ dighost.@O@ host.@O@ nslookup.@O@ + +UOBJS = + +SRCS = dig.c dighost.c host.c nslookup.c + +@BIND9_MAKE_RULES@ + +LDFLAGS = @LDFLAGS@ @LIBIDN2_LDFLAGS@ + +dig@EXEEXT@: dig.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS} + export BASEOBJS="dig.@O@ dighost.@O@ ${UOBJS}"; \ + export LIBS0="${DNSLIBS} ${IRSLIBS}"; \ + ${FINALBUILDCMD} + +host@EXEEXT@: host.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS} + export BASEOBJS="host.@O@ dighost.@O@ ${UOBJS}"; \ + export LIBS0="${DNSLIBS} ${IRSLIBS}"; \ + ${FINALBUILDCMD} + +nslookup@EXEEXT@: nslookup.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS} + export BASEOBJS="nslookup.@O@ dighost.@O@ ${READLINE_LIB} ${UOBJS}"; \ + export LIBS0="${DNSLIBS} ${IRSLIBS}"; \ + ${FINALBUILDCMD} + +clean distclean maintainer-clean:: + rm -f ${TARGETS} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${bindir} + +install:: dig@EXEEXT@ host@EXEEXT@ nslookup@EXEEXT@ installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} \ + dig@EXEEXT@ ${DESTDIR}${bindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} \ + host@EXEEXT@ ${DESTDIR}${bindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} \ + nslookup@EXEEXT@ ${DESTDIR}${bindir} + +uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${bindir}/nslookup@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${bindir}/host@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${bindir}/dig@EXEEXT@ diff --git a/bin/dig/dig.c b/bin/dig/dig.c new file mode 100644 index 0000000..423bf7d --- /dev/null +++ b/bin/dig/dig.c @@ -0,0 +1,2728 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ADD_STRING(b, s) \ + { \ + if (strlen(s) >= isc_buffer_availablelength(b)) { \ + return (ISC_R_NOSPACE); \ + } else { \ + isc_buffer_putstr(b, s); \ + } \ + } + +#define DIG_MAX_ADDRESSES 20 + +dig_lookup_t *default_lookup = NULL; + +static atomic_uintptr_t batchname = 0; +static FILE *batchfp = NULL; +static char *argv0; +static int addresscount = 0; + +static char domainopt[DNS_NAME_MAXTEXT]; +static char hexcookie[81]; + +static bool short_form = false, printcmd = true, plusquest = false, + pluscomm = false, ipv4only = false, ipv6only = false, digrc = true; +static uint32_t splitwidth = 0xffffffff; + +/*% opcode text */ +static const char *const opcodetext[] = { + "QUERY", "IQUERY", "STATUS", "RESERVED3", + "NOTIFY", "UPDATE", "RESERVED6", "RESERVED7", + "RESERVED8", "RESERVED9", "RESERVED10", "RESERVED11", + "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15" +}; + +static const char * +rcode_totext(dns_rcode_t rcode) { + static char buf[64]; + isc_buffer_t b; + isc_result_t result; + + memset(buf, 0, sizeof(buf)); + isc_buffer_init(&b, buf + 1, sizeof(buf) - 2); + result = dns_rcode_totext(rcode, &b); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (strspn(buf + 1, "0123456789") == strlen(buf + 1)) { + buf[0] = '?'; + return (buf); + } + return (buf + 1); +} + +/*% print usage */ +static void +print_usage(FILE *fp) { + fputs("Usage: dig [@global-server] [domain] [q-type] [q-class] " + "{q-opt}\n" + " {global-d-opt} host [@local-server] {local-d-opt}\n" + " [ host [@local-server] {local-d-opt} [...]]\n", + fp); +} + +#if TARGET_OS_IPHONE +static void +usage(void) { + fprintf(stderr, "Press for complete list of options\n"); +} +#else /* if TARGET_OS_IPHONE */ +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + print_usage(stderr); + fputs("\nUse \"dig -h\" (or \"dig -h | more\") " + "for complete list of options\n", + stderr); + exit(1); +} +#endif /* if TARGET_OS_IPHONE */ + +/*% version */ +static void +version(void) { + fputs("DiG " VERSION "\n", stderr); +} + +/*% help */ +static void +help(void) { + print_usage(stdout); + fputs("Where: domain is in the Domain Name System\n" + " q-class is one of (in,hs,ch,...) [default: in]\n" + " q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) " + "[default:a]\n" + " (Use ixfr=version for type ixfr)\n" + " q-opt is one of:\n" + " -4 (use IPv4 query transport " + "only)\n" + " -6 (use IPv6 query transport " + "only)\n" + " -b address[#port] (bind to source " + "address/port)\n" + " -c class (specify query class)\n" + " -f filename (batch mode)\n" + " -k keyfile (specify tsig key file)\n" + " -m (enable memory usage " + "debugging)\n" + " -p port (specify port number)\n" + " -q name (specify query name)\n" + " -r (do not read ~/.digrc)\n" + " -t type (specify query type)\n" + " -u (display times in usec " + "instead of msec)\n" + " -x dot-notation (shortcut for reverse " + "lookups)\n" + " -y [hmac:]name:key (specify named base64 tsig " + "key)\n" + " d-opt is of the form +keyword[=value], where keyword " + "is:\n" + " +[no]aaflag (Set AA flag in query " + "(+[no]aaflag))\n" + " +[no]aaonly (Set AA flag in query " + "(+[no]aaflag))\n" + " +[no]additional (Control display of " + "additional section)\n" + " +[no]adflag (Set AD flag in query " + "(default on))\n" + " +[no]all (Set or clear all display " + "flags)\n" + " +[no]answer (Control display of answer " + "section)\n" + " +[no]authority (Control display of " + "authority section)\n" + " +[no]badcookie (Retry BADCOOKIE " + "responses)\n" + " +[no]besteffort (Try to parse even illegal " + "messages)\n" + " +bufsize[=###] (Set EDNS0 Max UDP packet " + "size)\n" + " +[no]cdflag (Set checking disabled " + "flag in query)\n" + " +[no]class (Control display of class " + "in records)\n" + " +[no]cmd (Control display of " + "command line -\n" + " global option)\n" + " +[no]comments (Control display of packet " + "header\n" + " and section name " + "comments)\n" + " +[no]cookie (Add a COOKIE option to " + "the request)\n" + " +[no]crypto (Control display of " + "cryptographic\n" + " fields in records)\n" + " +[no]defname (Use search list " + "(+[no]search))\n" + " +[no]dnssec (Request DNSSEC records)\n" + " +domain=### (Set default domainname)\n" + " +[no]dscp[=###] (Set the DSCP value to ### " + "[0..63])\n" + " +[no]edns[=###] (Set EDNS version) [0]\n" + " +ednsflags=### (Set EDNS flag bits)\n" + " +[no]ednsnegotiation (Set EDNS version " + "negotiation)\n" + " +ednsopt=###[:value] (Send specified EDNS " + "option)\n" + " +noednsopt (Clear list of +ednsopt " + "options)\n" + " +[no]expandaaaa (Expand AAAA records)\n" + " +[no]expire (Request time to expire)\n" + " +[no]fail (Don't try next server on " + "SERVFAIL)\n" + " +[no]header-only (Send query without a " + "question section)\n" + " +[no]identify (ID responders in short " + "answers)\n" +#ifdef HAVE_LIBIDN2 + " +[no]idnin (Parse IDN names " + "[default=on on tty])\n" + " +[no]idnout (Convert IDN response " + "[default=on on tty])\n" +#endif /* ifdef HAVE_LIBIDN2 */ + " +[no]ignore (Don't revert to TCP for " + "TC responses.)\n" + " +[no]keepalive (Request EDNS TCP " + "keepalive)\n" + " +[no]keepopen (Keep the TCP socket open " + "between " + "queries)\n" + " +[no]mapped (Allow mapped IPv4 over " + "IPv6)\n" + " +[no]multiline (Print records in an " + "expanded format)\n" + " +ndots=### (Set search NDOTS value)\n" + " +[no]nsid (Request Name Server ID)\n" + " +[no]nssearch (Search all authoritative " + "nameservers)\n" + " +[no]onesoa (AXFR prints only one soa " + "record)\n" + " +[no]opcode=### (Set the opcode of the " + "request)\n" + " +padding=### (Set padding block size " + "[0])\n" + " +[no]qr (Print question before " + "sending)\n" + " +[no]question (Control display of " + "question section)\n" + " +[no]raflag (Set RA flag in query " + "(+[no]raflag))\n" + " +[no]rdflag (Recursive mode " + "(+[no]recurse))\n" + " +[no]recurse (Recursive mode " + "(+[no]rdflag))\n" + " +retry=### (Set number of UDP " + "retries) [2]\n" + " +[no]rrcomments (Control display of " + "per-record " + "comments)\n" + " +[no]search (Set whether to use " + "searchlist)\n" + " +[no]short (Display nothing except " + "short\n" + " form of answers - global " + "option)\n" + " +[no]showsearch (Search with intermediate " + "results)\n" + " +[no]split=## (Split hex/base64 fields " + "into chunks)\n" + " +[no]stats (Control display of " + "statistics)\n" + " +subnet=addr (Set edns-client-subnet " + "option)\n" + " +[no]tcflag (Set TC flag in query " + "(+[no]tcflag))\n" + " +[no]tcp (TCP mode (+[no]vc))\n" + " +timeout=### (Set query timeout) [5]\n" + " +[no]trace (Trace delegation down " + "from root " + "[+dnssec])\n" + " +tries=### (Set number of UDP " + "attempts) [3]\n" + " +[no]ttlid (Control display of ttls " + "in records)\n" + " +[no]ttlunits (Display TTLs in " + "human-readable units)\n" + " +[no]unexpected (Print replies from " + "unexpected sources\n" + " default=off)\n" + " +[no]unknownformat (Print RDATA in RFC 3597 " + "\"unknown\" " + "format)\n" + " +[no]vc (TCP mode (+[no]tcp))\n" + " +[no]yaml (Present the results as " + "YAML)\n" + " +[no]zflag (Set Z flag in query)\n" + " global d-opts and servers (before host name) affect all " + "queries.\n" + " local d-opts and servers (after host name) affect only " + "that lookup.\n" + " -h (print help and exit)\n" + " -v (print version and exit)\n", + stdout); +} + +/*% + * Callback from dighost.c to print the received message. + */ +static void +received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) { + uint64_t diff; + time_t tnow; + struct tm tmnow; +#ifdef WIN32 + wchar_t time_str[100]; +#else /* ifdef WIN32 */ + char time_str[100]; +#endif /* ifdef WIN32 */ + char fromtext[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(from, fromtext, sizeof(fromtext)); + + if (short_form || yaml) { + return; + } + + if (query->lookup->stats) { + diff = isc_time_microdiff(&query->time_recv, &query->time_sent); + if (query->lookup->use_usec) { + printf(";; Query time: %ld usec\n", (long)diff); + } else { + printf(";; Query time: %ld msec\n", (long)diff / 1000); + } + printf(";; SERVER: %s(%s)\n", fromtext, query->servname); + time(&tnow); + (void)localtime_r(&tnow, &tmnow); + +#ifdef WIN32 + /* + * On Windows, time zone name ("%Z") may be a localized + * wide-character string, which strftime() handles incorrectly. + */ + if (wcsftime(time_str, sizeof(time_str) / sizeof(time_str[0]), + L"%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U) + { + printf(";; WHEN: %ls\n", time_str); + } +#else /* ifdef WIN32 */ + if (strftime(time_str, sizeof(time_str), + "%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U) + { + printf(";; WHEN: %s\n", time_str); + } +#endif /* ifdef WIN32 */ + if (query->lookup->doing_xfr) { + printf(";; XFR size: %u records (messages %u, " + "bytes %" PRIu64 ")\n", + query->rr_count, query->msg_count, + query->byte_count); + } else { + printf(";; MSG SIZE rcvd: %u\n", bytes); + } + if (tsigkey != NULL) { + if (!validated) { + puts(";; WARNING -- Some TSIG could not " + "be validated"); + } + } + if ((tsigkey == NULL) && (keysecret[0] != 0)) { + puts(";; WARNING -- TSIG key was not used."); + } + puts(""); + } else if (query->lookup->identify) { + diff = isc_time_microdiff(&query->time_recv, &query->time_sent); + if (query->lookup->use_usec) { + printf(";; Received %" PRIu64 " bytes " + "from %s(%s) in %ld us\n\n", + query->lookup->doing_xfr ? query->byte_count + : (uint64_t)bytes, + fromtext, query->userarg, (long)diff); + } else { + printf(";; Received %" PRIu64 " bytes " + "from %s(%s) in %ld ms\n\n", + query->lookup->doing_xfr ? query->byte_count + : (uint64_t)bytes, + fromtext, query->userarg, (long)diff / 1000); + } + } +} + +/* + * Callback from dighost.c to print that it is trying a server. + * Not used in dig. + * XXX print_trying + */ +static void +trying(char *frm, dig_lookup_t *lookup) { + UNUSED(frm); + UNUSED(lookup); +} + +/*% + * Internal print routine used to print short form replies. + */ +static isc_result_t +say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) { + isc_result_t result; + uint64_t diff; + char store[sizeof(" in 18446744073709551616 us.")]; + unsigned int styleflags = 0; + + if (query->lookup->trace || query->lookup->ns_search_only) { + result = dns_rdatatype_totext(rdata->type, buf); + if (result != ISC_R_SUCCESS) { + return (result); + } + ADD_STRING(buf, " "); + } + + /* Turn on rrcomments if explicitly enabled */ + if (query->lookup->rrcomments > 0) { + styleflags |= DNS_STYLEFLAG_RRCOMMENT; + } + if (query->lookup->nocrypto) { + styleflags |= DNS_STYLEFLAG_NOCRYPTO; + } + if (query->lookup->print_unknown_format) { + styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT; + } + if (query->lookup->expandaaaa) { + styleflags |= DNS_STYLEFLAG_EXPANDAAAA; + } + result = dns_rdata_tofmttext(rdata, NULL, styleflags, 0, splitwidth, + " ", buf); + if (result == ISC_R_NOSPACE) { + return (result); + } + check_result(result, "dns_rdata_totext"); + if (query->lookup->identify) { + diff = isc_time_microdiff(&query->time_recv, &query->time_sent); + ADD_STRING(buf, " from server "); + ADD_STRING(buf, query->servname); + if (query->lookup->use_usec) { + snprintf(store, sizeof(store), " in %" PRIu64 " us.", + diff); + } else { + snprintf(store, sizeof(store), " in %" PRIu64 " ms.", + diff / 1000); + } + ADD_STRING(buf, store); + } + ADD_STRING(buf, "\n"); + return (ISC_R_SUCCESS); +} + +/*% + * short_form message print handler. Calls above say_message() + */ +static isc_result_t +short_answer(dns_message_t *msg, dns_messagetextflag_t flags, isc_buffer_t *buf, + dig_query_t *query) { + dns_name_t *name; + dns_rdataset_t *rdataset; + isc_result_t result, loopresult; + dns_name_t empty_name; + dns_rdata_t rdata = DNS_RDATA_INIT; + + UNUSED(flags); + + dns_name_init(&empty_name, NULL); + result = dns_message_firstname(msg, DNS_SECTION_ANSWER); + if (result == ISC_R_NOMORE) { + return (ISC_R_SUCCESS); + } else if (result != ISC_R_SUCCESS) { + return (result); + } + + for (;;) { + name = NULL; + dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); + + for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + loopresult = dns_rdataset_first(rdataset); + while (loopresult == ISC_R_SUCCESS) { + dns_rdataset_current(rdataset, &rdata); + result = say_message(&rdata, query, buf); + if (result == ISC_R_NOSPACE) { + return (result); + } + check_result(result, "say_message"); + loopresult = dns_rdataset_next(rdataset); + dns_rdata_reset(&rdata); + } + } + result = dns_message_nextname(msg, DNS_SECTION_ANSWER); + if (result == ISC_R_NOMORE) { + break; + } else if (result != ISC_R_SUCCESS) { + return (result); + } + } + + return (ISC_R_SUCCESS); +} + +static bool +isdotlocal(dns_message_t *msg) { + isc_result_t result; + static unsigned char local_ndata[] = { "\005local" }; + static unsigned char local_offsets[] = { 0, 6 }; + static dns_name_t local = DNS_NAME_INITABSOLUTE(local_ndata, + local_offsets); + + for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION); + result == ISC_R_SUCCESS; + result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) + { + dns_name_t *name = NULL; + dns_message_currentname(msg, DNS_SECTION_QUESTION, &name); + if (dns_name_issubdomain(name, &local)) { + return (true); + } + } + return (false); +} + +/* + * Callback from dighost.c to print the reply from a server + */ +static isc_result_t +printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg, + bool headers) { + isc_result_t result; + dns_messagetextflag_t flags; + isc_buffer_t *buf = NULL; + unsigned int len = OUTPUTBUF; + dns_master_style_t *style = NULL; + unsigned int styleflags = 0; + bool isquery = (msg == query->lookup->sendmsg); + + UNUSED(msgbuf); + + styleflags |= DNS_STYLEFLAG_REL_OWNER; + if (yaml) { + msg->indent.string = " "; + msg->indent.count = 3; + styleflags |= DNS_STYLEFLAG_YAML; + } else { + if (query->lookup->comments) { + styleflags |= DNS_STYLEFLAG_COMMENT; + } + if (query->lookup->print_unknown_format) { + styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT; + } + /* Turn on rrcomments if explicitly enabled */ + if (query->lookup->rrcomments > 0) { + styleflags |= DNS_STYLEFLAG_RRCOMMENT; + } + if (query->lookup->ttlunits) { + styleflags |= DNS_STYLEFLAG_TTL_UNITS; + } + if (query->lookup->nottl) { + styleflags |= DNS_STYLEFLAG_NO_TTL; + } + if (query->lookup->noclass) { + styleflags |= DNS_STYLEFLAG_NO_CLASS; + } + if (query->lookup->nocrypto) { + styleflags |= DNS_STYLEFLAG_NOCRYPTO; + } + if (query->lookup->expandaaaa) { + styleflags |= DNS_STYLEFLAG_EXPANDAAAA; + } + if (query->lookup->multiline) { + styleflags |= DNS_STYLEFLAG_OMIT_OWNER; + styleflags |= DNS_STYLEFLAG_OMIT_CLASS; + styleflags |= DNS_STYLEFLAG_REL_DATA; + styleflags |= DNS_STYLEFLAG_OMIT_TTL; + styleflags |= DNS_STYLEFLAG_TTL; + styleflags |= DNS_STYLEFLAG_MULTILINE; + /* Turn on rrcomments unless explicitly disabled */ + if (query->lookup->rrcomments >= 0) { + styleflags |= DNS_STYLEFLAG_RRCOMMENT; + } + } + } + if (query->lookup->multiline || + (query->lookup->nottl && query->lookup->noclass)) + { + result = dns_master_stylecreate(&style, styleflags, 24, 24, 24, + 32, 80, 8, splitwidth, mctx); + } else if (query->lookup->nottl || query->lookup->noclass) { + result = dns_master_stylecreate(&style, styleflags, 24, 24, 32, + 40, 80, 8, splitwidth, mctx); + } else { + result = dns_master_stylecreate(&style, styleflags, 24, 32, 40, + 48, 80, 8, splitwidth, mctx); + } + check_result(result, "dns_master_stylecreate"); + + if (query->lookup->cmdline[0] != 0) { + if (!short_form && printcmd) { + fputs(query->lookup->cmdline, stdout); + } + query->lookup->cmdline[0] = '\0'; + } + debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders", + query->lookup->comments ? "comments" : "nocomments", + short_form ? "short_form" : "long_form"); + + flags = 0; + if (!headers) { + flags |= DNS_MESSAGETEXTFLAG_NOHEADERS; + flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; + } + if (query->lookup->onesoa && + query->lookup->rdtype == dns_rdatatype_axfr) + { + flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA + : DNS_MESSAGETEXTFLAG_OMITSOA; + } + if (!query->lookup->comments) { + flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; + } + + isc_buffer_allocate(mctx, &buf, len); + + if (yaml) { + enum { Q = 0x1, R = 0x2 }; /* Q:query; R:ecursive */ + unsigned int tflag = 0; + isc_sockaddr_t saddr; + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + uint16_t sport; + char *hash; + int pf; + + printf("-\n"); + printf(" type: MESSAGE\n"); + printf(" message:\n"); + + if (isquery) { + tflag |= Q; + if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { + tflag |= R; + } + } else if (((msg->flags & DNS_MESSAGEFLAG_RD) != 0) && + ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)) + { + tflag |= R; + } + + if (tflag == (Q | R)) { + printf(" type: RECURSIVE_QUERY\n"); + } else if (tflag == Q) { + printf(" type: AUTH_QUERY\n"); + } else if (tflag == R) { + printf(" type: RECURSIVE_RESPONSE\n"); + } else { + printf(" type: AUTH_RESPONSE\n"); + } + + if (!isc_time_isepoch(&query->time_sent)) { + char tbuf[100]; + if (query->lookup->use_usec) { + isc_time_formatISO8601us(&query->time_sent, + tbuf, sizeof(tbuf)); + } else { + isc_time_formatISO8601ms(&query->time_sent, + tbuf, sizeof(tbuf)); + } + printf(" query_time: !!timestamp %s\n", tbuf); + } + + if (!isquery && !isc_time_isepoch(&query->time_recv)) { + char tbuf[100]; + if (query->lookup->use_usec) { + isc_time_formatISO8601us(&query->time_recv, + tbuf, sizeof(tbuf)); + } else { + isc_time_formatISO8601ms(&query->time_recv, + tbuf, sizeof(tbuf)); + } + printf(" response_time: !!timestamp %s\n", tbuf); + } + + printf(" message_size: %ub\n", + isc_buffer_usedlength(msgbuf)); + + pf = isc_sockaddr_pf(&query->sockaddr); + if (pf == PF_INET || pf == PF_INET6) { + printf(" socket_family: %s\n", + pf == PF_INET ? "INET" : "INET6"); + + printf(" socket_protocol: %s\n", + query->lookup->tcp_mode ? "TCP" : "UDP"); + + sport = isc_sockaddr_getport(&query->sockaddr); + isc_sockaddr_format(&query->sockaddr, sockstr, + sizeof(sockstr)); + hash = strchr(sockstr, '#'); + if (hash != NULL) { + *hash = '\0'; + } + if (strcmp(sockstr, "::") == 0) { + strlcat(sockstr, "0", sizeof(sockstr)); + } + + printf(" response_address: \"%s\"\n", sockstr); + printf(" response_port: %u\n", sport); + } + + if (query->sock != NULL && + isc_socket_getsockname(query->sock, &saddr) == + ISC_R_SUCCESS) + { + sport = isc_sockaddr_getport(&saddr); + isc_sockaddr_format(&saddr, sockstr, sizeof(sockstr)); + hash = strchr(sockstr, '#'); + if (hash != NULL) { + *hash = '\0'; + } + if (strcmp(sockstr, "::") == 0) { + strlcat(sockstr, "0", sizeof(sockstr)); + } + + printf(" query_address: \"%s\"\n", sockstr); + printf(" query_port: %u\n", sport); + } + + printf(" %s:\n", isquery ? "query_message_data" + : "response_message_data"); + result = dns_message_headertotext(msg, style, flags, buf); + } else if (query->lookup->comments && !short_form) { + if (query->lookup->cmdline[0] != '\0' && printcmd) { + printf("; %s\n", query->lookup->cmdline); + } + if (msg == query->lookup->sendmsg) { + printf(";; Sending:\n"); + } else { + printf(";; Got answer:\n"); + } + + if (headers) { + if (isdotlocal(msg)) { + printf(";; WARNING: .local is reserved for " + "Multicast DNS\n;; You are currently " + "testing what happens when an mDNS " + "query is leaked to DNS\n"); + } + printf(";; ->>HEADER<<- opcode: %s, status: %s, " + "id: %u\n", + opcodetext[msg->opcode], + rcode_totext(msg->rcode), msg->id); + printf(";; flags:"); + if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { + printf(" qr"); + } + if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { + printf(" aa"); + } + if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { + printf(" tc"); + } + if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { + printf(" rd"); + } + if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { + printf(" ra"); + } + if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { + printf(" ad"); + } + if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { + printf(" cd"); + } + if ((msg->flags & 0x0040U) != 0) { + printf("; MBZ: 0x4"); + } + + printf("; QUERY: %u, ANSWER: %u, " + "AUTHORITY: %u, ADDITIONAL: %u\n", + msg->counts[DNS_SECTION_QUESTION], + msg->counts[DNS_SECTION_ANSWER], + msg->counts[DNS_SECTION_AUTHORITY], + msg->counts[DNS_SECTION_ADDITIONAL]); + + if (msg != query->lookup->sendmsg && + (msg->flags & DNS_MESSAGEFLAG_RD) != 0 && + (msg->flags & DNS_MESSAGEFLAG_RA) == 0) + { + printf(";; WARNING: recursion requested " + "but not available\n"); + } + } + if (msg != query->lookup->sendmsg && + query->lookup->edns != -1 && msg->opt == NULL && + (msg->rcode == dns_rcode_formerr || + msg->rcode == dns_rcode_notimp)) + { + printf("\n;; WARNING: EDNS query returned status " + "%s - retry with '%s+noedns'\n", + rcode_totext(msg->rcode), + query->lookup->dnssec ? "+nodnssec " : ""); + } + if (msg != query->lookup->sendmsg && extrabytes != 0U) { + printf(";; WARNING: Message has %u extra byte%s at " + "end\n", + extrabytes, extrabytes != 0 ? "s" : ""); + } + } + +repopulate_buffer: + + if (query->lookup->comments && headers && !short_form) { + result = dns_message_pseudosectiontotext( + msg, DNS_PSEUDOSECTION_OPT, style, flags, buf); + if (result == ISC_R_NOSPACE) { + buftoosmall: + len += OUTPUTBUF; + isc_buffer_free(&buf); + isc_buffer_allocate(mctx, &buf, len); + goto repopulate_buffer; + } + check_result(result, "dns_message_pseudosectiontotext"); + } + + if (query->lookup->section_question && headers) { + if (!short_form) { + result = dns_message_sectiontotext( + msg, DNS_SECTION_QUESTION, style, flags, buf); + if (result == ISC_R_NOSPACE) { + goto buftoosmall; + } + check_result(result, "dns_message_sectiontotext"); + } + } + if (query->lookup->section_answer) { + if (!short_form) { + result = dns_message_sectiontotext( + msg, DNS_SECTION_ANSWER, style, flags, buf); + if (result == ISC_R_NOSPACE) { + goto buftoosmall; + } + check_result(result, "dns_message_sectiontotext"); + } else { + result = short_answer(msg, flags, buf, query); + if (result == ISC_R_NOSPACE) { + goto buftoosmall; + } + check_result(result, "short_answer"); + } + } + if (query->lookup->section_authority) { + if (!short_form) { + result = dns_message_sectiontotext( + msg, DNS_SECTION_AUTHORITY, style, flags, buf); + if (result == ISC_R_NOSPACE) { + goto buftoosmall; + } + check_result(result, "dns_message_sectiontotext"); + } + } + if (query->lookup->section_additional) { + if (!short_form) { + result = dns_message_sectiontotext( + msg, DNS_SECTION_ADDITIONAL, style, flags, buf); + if (result == ISC_R_NOSPACE) { + goto buftoosmall; + } + check_result(result, "dns_message_sectiontotext"); + /* + * Only print the signature on the first record. + */ + if (headers) { + result = dns_message_pseudosectiontotext( + msg, DNS_PSEUDOSECTION_TSIG, style, + flags, buf); + if (result == ISC_R_NOSPACE) { + goto buftoosmall; + } + check_result(result, "dns_message_" + "pseudosectiontotext"); + result = dns_message_pseudosectiontotext( + msg, DNS_PSEUDOSECTION_SIG0, style, + flags, buf); + if (result == ISC_R_NOSPACE) { + goto buftoosmall; + } + check_result(result, "dns_message_" + "pseudosectiontotext"); + } + } + } + + if (headers && query->lookup->comments && !short_form && !yaml) { + printf("\n"); + } + + printf("%.*s", (int)isc_buffer_usedlength(buf), + (char *)isc_buffer_base(buf)); + isc_buffer_free(&buf); + + if (style != NULL) { + dns_master_styledestroy(&style, mctx); + } + return (result); +} + +/*% + * print the greeting message when the program first starts up. + */ +static void +printgreeting(int argc, char **argv, dig_lookup_t *lookup) { + int i; + static bool first = true; + char append[MXNAME]; + + if (printcmd) { + snprintf(lookup->cmdline, sizeof(lookup->cmdline), + "%s; <<>> DiG " VERSION " <<>>", first ? "\n" : ""); + i = 1; + while (i < argc) { + snprintf(append, sizeof(append), " %s", argv[i++]); + strlcat(lookup->cmdline, append, + sizeof(lookup->cmdline)); + } + strlcat(lookup->cmdline, "\n", sizeof(lookup->cmdline)); + if (first && addresscount != 0) { + snprintf(append, sizeof(append), + "; (%d server%s found)\n", addresscount, + addresscount > 1 ? "s" : ""); + strlcat(lookup->cmdline, append, + sizeof(lookup->cmdline)); + } + if (first) { + snprintf(append, sizeof(append), + ";; global options:%s%s\n", + short_form ? " +short" : "", + printcmd ? " +cmd" : ""); + first = false; + strlcat(lookup->cmdline, append, + sizeof(lookup->cmdline)); + } + } +} + +/*% + * We're not using isc_commandline_parse() here since the command line + * syntax of dig is quite a bit different from that which can be described + * by that routine. + * XXX doc options + */ + +static void +plus_option(char *option, bool is_batchfile, dig_lookup_t *lookup) { + isc_result_t result; + char *cmd, *value, *last = NULL, *code, *extra; + uint32_t num; + bool state = true; + size_t n; + + INSIST(option != NULL); + + if ((cmd = strtok_r(option, "=", &last)) == NULL) { + printf(";; Invalid option %s\n", option); + return; + } + if (strncasecmp(cmd, "no", 2) == 0) { + cmd += 2; + state = false; + } + /* parse the rest of the string */ + value = strtok_r(NULL, "", &last); + +#define FULLCHECK(A) \ + do { \ + size_t _l = strlen(cmd); \ + if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ + goto invalid_option; \ + } while (0) +#define FULLCHECK2(A, B) \ + do { \ + size_t _l = strlen(cmd); \ + if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \ + (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \ + goto invalid_option; \ + } while (0) + + switch (cmd[0]) { + case 'a': + switch (cmd[1]) { + case 'a': /* aaonly / aaflag */ + FULLCHECK2("aaonly", "aaflag"); + lookup->aaonly = state; + break; + case 'd': + switch (cmd[2]) { + case 'd': /* additional */ + FULLCHECK("additional"); + lookup->section_additional = state; + break; + case 'f': /* adflag */ + case '\0': /* +ad is a synonym for +adflag */ + FULLCHECK("adflag"); + lookup->adflag = state; + break; + default: + goto invalid_option; + } + break; + case 'l': /* all */ + FULLCHECK("all"); + lookup->section_question = state; + lookup->section_authority = state; + lookup->section_answer = state; + lookup->section_additional = state; + lookup->comments = state; + lookup->stats = state; + printcmd = state; + break; + case 'n': /* answer */ + FULLCHECK("answer"); + lookup->section_answer = state; + break; + case 'u': /* authority */ + FULLCHECK("authority"); + lookup->section_authority = state; + break; + default: + goto invalid_option; + } + break; + case 'b': + switch (cmd[1]) { + case 'a': /* badcookie */ + FULLCHECK("badcookie"); + lookup->badcookie = state; + break; + case 'e': /* besteffort */ + FULLCHECK("besteffort"); + lookup->besteffort = state; + break; + case 'u': /* bufsize */ + FULLCHECK("bufsize"); + if (!state) { + goto invalid_option; + } + if (value == NULL) { + lookup->udpsize = DEFAULT_EDNS_BUFSIZE; + break; + } + result = parse_uint(&num, value, COMMSIZE, + "buffer size"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse buffer size"); + goto exit_or_usage; + } + lookup->udpsize = num; + if (lookup->udpsize == 0) { + lookup->edns = -1; + } + break; + default: + goto invalid_option; + } + break; + case 'c': + switch (cmd[1]) { + case 'd': /* cdflag */ + switch (cmd[2]) { + case 'f': /* cdflag */ + case '\0': /* +cd is a synonym for +cdflag */ + FULLCHECK("cdflag"); + lookup->cdflag = state; + break; + default: + goto invalid_option; + } + break; + case 'l': /* class */ + /* keep +cl for backwards compatibility */ + FULLCHECK2("cl", "class"); + lookup->noclass = !state; + break; + case 'm': /* cmd */ + FULLCHECK("cmd"); + printcmd = state; + break; + case 'o': /* comments */ + switch (cmd[2]) { + case 'm': + FULLCHECK("comments"); + lookup->comments = state; + if (lookup == default_lookup) { + pluscomm = state; + } + break; + case 'o': /* cookie */ + FULLCHECK("cookie"); + if (state && lookup->edns == -1) { + lookup->edns = DEFAULT_EDNS_VERSION; + } + lookup->sendcookie = state; + if (value != NULL) { + n = strlcpy(hexcookie, value, + sizeof(hexcookie)); + if (n >= sizeof(hexcookie)) { + warn("COOKIE data too large"); + goto exit_or_usage; + } + lookup->cookie = hexcookie; + } else { + lookup->cookie = NULL; + } + break; + default: + goto invalid_option; + } + break; + case 'r': + FULLCHECK("crypto"); + lookup->nocrypto = !state; + break; + default: + goto invalid_option; + } + break; + case 'd': + switch (cmd[1]) { + case 'e': /* defname */ + FULLCHECK("defname"); + if (!lookup->trace) { + usesearch = state; + } + break; + case 'n': /* dnssec */ + FULLCHECK("dnssec"); + dnssec: + if (state && lookup->edns == -1) { + lookup->edns = DEFAULT_EDNS_VERSION; + } + lookup->dnssec = state; + break; + case 'o': /* domain ... but treat "do" as synonym for dnssec */ + if (cmd[2] == '\0') { + goto dnssec; + } + FULLCHECK("domain"); + if (value == NULL) { + goto need_value; + } + if (!state) { + goto invalid_option; + } + strlcpy(domainopt, value, sizeof(domainopt)); + break; + case 's': /* dscp */ + FULLCHECK("dscp"); + if (!state) { + lookup->dscp = -1; + break; + } + if (value == NULL) { + goto need_value; + } + result = parse_uint(&num, value, 0x3f, "DSCP"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse DSCP value"); + goto exit_or_usage; + } + lookup->dscp = num; + break; + default: + goto invalid_option; + } + break; + case 'e': + switch (cmd[1]) { + case 'd': + switch (cmd[2]) { + case 'n': + switch (cmd[3]) { + case 's': + switch (cmd[4]) { + case 0: + FULLCHECK("edns"); + if (!state) { + lookup->edns = -1; + break; + } + if (value == NULL) { + lookup->edns = + DEFAULT_EDNS_VERSION; + break; + } + result = parse_uint(&num, value, + 255, + "edns"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse " + "edns"); + goto exit_or_usage; + } + lookup->edns = num; + break; + case 'f': + FULLCHECK("ednsflags"); + if (!state) { + lookup->ednsflags = 0; + break; + } + if (value == NULL) { + lookup->ednsflags = 0; + break; + } + result = parse_xint( + &num, value, 0xffff, + "ednsflags"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse " + "ednsflags"); + goto exit_or_usage; + } + lookup->ednsflags = num; + break; + case 'n': + FULLCHECK("ednsnegotiation"); + lookup->ednsneg = state; + break; + case 'o': + FULLCHECK("ednsopt"); + if (!state) { + lookup->ednsoptscnt = 0; + break; + } + code = NULL; + if (value != NULL) { + code = strtok_r(value, + ":", + &last); + } + if (code == NULL) { + warn("ednsopt no " + "code point " + "specified"); + goto exit_or_usage; + } + extra = strtok_r(NULL, "\0", + &last); + save_opt(lookup, code, extra); + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + case 'x': + switch (cmd[2]) { + case 'p': + switch (cmd[3]) { + case 'a': + FULLCHECK("expandaaaa"); + lookup->expandaaaa = state; + break; + case 'i': + FULLCHECK("expire"); + lookup->expire = state; + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + case 'f': /* fail */ + FULLCHECK("fail"); + lookup->servfail_stops = state; + break; + case 'h': + FULLCHECK("header-only"); + lookup->header_only = state; + break; + case 'i': + switch (cmd[1]) { + case 'd': /* identify */ + switch (cmd[2]) { + case 'e': + FULLCHECK("identify"); + lookup->identify = state; + break; + case 'n': + switch (cmd[3]) { + case 'i': + FULLCHECK("idnin"); +#ifndef HAVE_LIBIDN2 + fprintf(stderr, ";; IDN input support" + " not enabled\n"); +#else /* ifndef HAVE_LIBIDN2 */ + lookup->idnin = state; +#endif /* ifndef HAVE_LIBIDN2 */ + break; + case 'o': + FULLCHECK("idnout"); +#ifndef HAVE_LIBIDN2 + fprintf(stderr, ";; IDN output support" + " not enabled\n"); +#else /* ifndef HAVE_LIBIDN2 */ + lookup->idnout = state; +#endif /* ifndef HAVE_LIBIDN2 */ + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + case 'g': /* ignore */ + default: /* + * Inherits default for compatibility (+[no]i*). + */ + FULLCHECK("ignore"); + lookup->ignore = state; + } + break; + case 'k': + switch (cmd[1]) { + case 'e': + switch (cmd[2]) { + case 'e': + switch (cmd[3]) { + case 'p': + switch (cmd[4]) { + case 'a': + FULLCHECK("keepalive"); + lookup->tcp_keepalive = state; + break; + case 'o': + FULLCHECK("keepopen"); + keep_open = state; + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + case 'm': /* multiline */ + switch (cmd[1]) { + case 'a': + FULLCHECK("mapped"); + lookup->mapped = state; + break; + case 'u': + FULLCHECK("multiline"); + lookup->multiline = state; + break; + default: + goto invalid_option; + } + break; + case 'n': + switch (cmd[1]) { + case 'd': /* ndots */ + FULLCHECK("ndots"); + if (value == NULL) { + goto need_value; + } + if (!state) { + goto invalid_option; + } + result = parse_uint(&num, value, MAXNDOTS, "ndots"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse ndots"); + goto exit_or_usage; + } + ndots = num; + break; + case 's': + switch (cmd[2]) { + case 'i': /* nsid */ + FULLCHECK("nsid"); + if (state && lookup->edns == -1) { + lookup->edns = DEFAULT_EDNS_VERSION; + } + lookup->nsid = state; + break; + case 's': /* nssearch */ + FULLCHECK("nssearch"); + lookup->ns_search_only = state; + if (state) { + lookup->trace_root = true; + lookup->recurse = true; + lookup->identify = true; + lookup->stats = false; + lookup->comments = false; + lookup->section_additional = false; + lookup->section_authority = false; + lookup->section_question = false; + lookup->rdtype = dns_rdatatype_ns; + lookup->rdtypeset = true; + short_form = true; + lookup->rrcomments = 0; + } + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + case 'o': + switch (cmd[1]) { + case 'n': + FULLCHECK("onesoa"); + lookup->onesoa = state; + break; + case 'p': + FULLCHECK("opcode"); + if (!state) { + lookup->opcode = 0; /* default - query */ + break; + } + if (value == NULL) { + goto need_value; + } + for (num = 0; + num < sizeof(opcodetext) / sizeof(opcodetext[0]); + num++) + { + if (strcasecmp(opcodetext[num], value) == 0) { + break; + } + } + if (num < 16) { + lookup->opcode = (dns_opcode_t)num; + break; + } + result = parse_uint(&num, value, 15, "opcode"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse opcode"); + goto exit_or_usage; + } + lookup->opcode = (dns_opcode_t)num; + break; + default: + goto invalid_option; + } + break; + case 'p': + FULLCHECK("padding"); + if (state && lookup->edns == -1) { + lookup->edns = DEFAULT_EDNS_VERSION; + } + if (value == NULL) { + goto need_value; + } + result = parse_uint(&num, value, 512, "padding"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse padding"); + goto exit_or_usage; + } + lookup->padding = (uint16_t)num; + break; + case 'q': + switch (cmd[1]) { + case 'r': /* qr */ + FULLCHECK("qr"); + lookup->qr = state; + break; + case 'u': /* question */ + FULLCHECK("question"); + lookup->section_question = state; + if (lookup == default_lookup) { + plusquest = state; + } + break; + default: + goto invalid_option; + } + break; + case 'r': + switch (cmd[1]) { + case 'a': /* raflag */ + FULLCHECK("raflag"); + lookup->raflag = state; + break; + case 'd': /* rdflag */ + FULLCHECK("rdflag"); + lookup->recurse = state; + break; + case 'e': + switch (cmd[2]) { + case 'c': /* recurse */ + FULLCHECK("recurse"); + lookup->recurse = state; + break; + case 't': /* retry / retries */ + FULLCHECK2("retry", "retries"); + if (value == NULL) { + goto need_value; + } + if (!state) { + goto invalid_option; + } + result = parse_uint(&lookup->retries, value, + MAXTRIES - 1, "retries"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse retries"); + goto exit_or_usage; + } + lookup->retries++; + break; + default: + goto invalid_option; + } + break; + case 'r': /* rrcomments */ + FULLCHECK("rrcomments"); + lookup->rrcomments = state ? 1 : -1; + break; + default: + goto invalid_option; + } + break; + case 's': + switch (cmd[1]) { + case 'e': /* search */ + FULLCHECK("search"); + if (!lookup->trace) { + usesearch = state; + } + break; + case 'h': + if (cmd[2] != 'o') { + goto invalid_option; + } + switch (cmd[3]) { + case 'r': /* short */ + FULLCHECK("short"); + short_form = state; + if (state) { + printcmd = false; + lookup->section_additional = false; + lookup->section_answer = true; + lookup->section_authority = false; + lookup->section_question = false; + lookup->comments = false; + lookup->stats = false; + lookup->rrcomments = -1; + } + break; + case 'w': /* showsearch */ + FULLCHECK("showsearch"); + if (!lookup->trace) { + showsearch = state; + usesearch = state; + } + break; + default: + goto invalid_option; + } + break; + case 'i': /* sigchase */ + FULLCHECK("sigchase"); + fprintf(stderr, ";; +sigchase option is deprecated"); + break; + case 'p': /* split */ + FULLCHECK("split"); + if (value != NULL && !state) { + goto invalid_option; + } + if (!state) { + splitwidth = 0; + break; + } else if (value == NULL) { + break; + } + + result = parse_uint(&splitwidth, value, 1023, "split"); + if ((splitwidth % 4) != 0U) { + splitwidth = ((splitwidth + 3) / 4) * 4; + fprintf(stderr, + ";; Warning, split must be " + "a multiple of 4; adjusting " + "to %u\n", + splitwidth); + } + /* + * There is an adjustment done in the + * totext_() functions which causes + * splitwidth to shrink. This is okay when we're + * using the default width but incorrect in this + * case, so we correct for it + */ + if (splitwidth) { + splitwidth += 3; + } + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse split"); + goto exit_or_usage; + } + break; + case 't': /* stats */ + FULLCHECK("stats"); + lookup->stats = state; + break; + case 'u': /* subnet */ + FULLCHECK("subnet"); + if (state && value == NULL) { + goto need_value; + } + if (!state) { + if (lookup->ecs_addr != NULL) { + isc_mem_free(mctx, lookup->ecs_addr); + lookup->ecs_addr = NULL; + } + break; + } + if (lookup->edns == -1) { + lookup->edns = DEFAULT_EDNS_VERSION; + } + if (lookup->ecs_addr != NULL) { + isc_mem_free(mctx, lookup->ecs_addr); + lookup->ecs_addr = NULL; + } + result = parse_netprefix(&lookup->ecs_addr, value); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse client"); + goto exit_or_usage; + } + break; + default: + goto invalid_option; + } + break; + case 't': + switch (cmd[1]) { + case 'c': /* tcp */ + switch (cmd[2]) { + case 'f': + FULLCHECK("tcflag"); + lookup->tcflag = state; + break; + case 'p': + FULLCHECK("tcp"); + if (!is_batchfile) { + lookup->tcp_mode = state; + lookup->tcp_mode_set = true; + } + break; + default: + goto invalid_option; + } + break; + case 'i': /* timeout */ + FULLCHECK("timeout"); + if (value == NULL) { + goto need_value; + } + if (!state) { + goto invalid_option; + } + result = parse_uint(&timeout, value, MAXTIMEOUT, + "timeout"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse timeout"); + goto exit_or_usage; + } + if (timeout == 0) { + timeout = 1; + } + break; + case 'o': + FULLCHECK("topdown"); + fprintf(stderr, ";; +topdown option is deprecated"); + break; + case 'r': + switch (cmd[2]) { + case 'a': /* trace */ + FULLCHECK("trace"); + lookup->trace = state; + lookup->trace_root = state; + if (state) { + lookup->recurse = true; + lookup->identify = true; + lookup->comments = false; + lookup->rrcomments = 0; + lookup->stats = false; + lookup->section_additional = false; + lookup->section_authority = true; + lookup->section_question = false; + lookup->dnssec = true; + lookup->sendcookie = true; + usesearch = false; + } + break; + case 'i': /* tries */ + FULLCHECK("tries"); + if (value == NULL) { + goto need_value; + } + if (!state) { + goto invalid_option; + } + result = parse_uint(&lookup->retries, value, + MAXTRIES, "tries"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse tries"); + goto exit_or_usage; + } + if (lookup->retries == 0) { + lookup->retries = 1; + } + break; + case 'u': /* trusted-key */ + FULLCHECK("trusted-key"); + fprintf(stderr, ";; +trusted-key option is " + "deprecated"); + break; + default: + goto invalid_option; + } + break; + case 't': + switch (cmd[2]) { + case 'l': + switch (cmd[3]) { + case 0: + case 'i': /* ttlid */ + FULLCHECK2("ttl", "ttlid"); + lookup->nottl = !state; + break; + case 'u': /* ttlunits */ + FULLCHECK("ttlunits"); + lookup->nottl = false; + lookup->ttlunits = state; + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + break; + case 'u': + switch (cmd[1]) { + case 'n': + switch (cmd[2]) { + case 'e': + FULLCHECK("unexpected"); + lookup->accept_reply_unexpected_src = state; + break; + case 'k': + FULLCHECK("unknownformat"); + lookup->print_unknown_format = state; + break; + default: + goto invalid_option; + } + break; + default: + goto invalid_option; + } + + break; + case 'v': + FULLCHECK("vc"); + if (!is_batchfile) { + lookup->tcp_mode = state; + lookup->tcp_mode_set = true; + } + break; + case 'y': /* yaml */ + FULLCHECK("yaml"); + yaml = state; + if (state) { + printcmd = false; + lookup->stats = false; + lookup->rrcomments = -1; + } + break; + case 'z': /* zflag */ + FULLCHECK("zflag"); + lookup->zflag = state; + break; + default: + invalid_option: + need_value: +#if TARGET_OS_IPHONE + exit_or_usage: +#endif /* if TARGET_OS_IPHONE */ + fprintf(stderr, "Invalid option: +%s\n", option); + usage(); + } + return; + +#if !TARGET_OS_IPHONE +exit_or_usage: + digexit(); +#endif /* if !TARGET_OS_IPHONE */ +} + +/*% + * #true returned if value was used + */ +static const char *single_dash_opts = "46dhimnruv"; +static const char *dash_opts = "46bcdfhikmnpqrtvyx"; +static bool +dash_option(char *option, char *next, dig_lookup_t **lookup, + bool *open_type_class, bool *need_clone, bool config_only, int argc, + char **argv, bool *firstarg) { + char opt, *value, *ptr, *ptr2, *ptr3, *last; + isc_result_t result; + bool value_from_next; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + char textname[MXNAME]; + struct in_addr in4; + struct in6_addr in6; + in_port_t srcport; + char *hash, *cmd; + uint32_t num; + + while (strpbrk(option, single_dash_opts) == &option[0]) { + /* + * Since the -[46dhimnuv] options do not take an argument, + * account for them (in any number and/or combination) + * if they appear as the first character(s) of a q-opt. + */ + opt = option[0]; + switch (opt) { + case '4': + if (have_ipv4) { + isc_net_disableipv6(); + have_ipv6 = false; + } else { + fatal("can't find IPv4 networking"); + UNREACHABLE(); + return (false); + } + break; + case '6': + if (have_ipv6) { + isc_net_disableipv4(); + have_ipv4 = false; + } else { + fatal("can't find IPv6 networking"); + UNREACHABLE(); + return (false); + } + break; + case 'd': + ptr = strpbrk(&option[1], dash_opts); + if (ptr != &option[1]) { + cmd = option; + FULLCHECK("debug"); + debugging = true; + return (false); + } else { + debugging = true; + } + break; + case 'h': + help(); + exit(0); + break; + case 'i': + /* deprecated */ + break; + case 'm': /* memdebug */ + /* memdebug is handled in preparse_args() */ + break; + case 'n': + /* deprecated */ + break; + case 'r': + debug("digrc (late)"); + digrc = false; + break; + case 'u': + (*lookup)->use_usec = true; + break; + case 'v': + version(); + exit(0); + break; + } + if (strlen(option) > 1U) { + option = &option[1]; + } else { + return (false); + } + } + opt = option[0]; + if (strlen(option) > 1U) { + value_from_next = false; + value = &option[1]; + } else { + value_from_next = true; + value = next; + } + if (value == NULL) { + goto invalid_option; + } + switch (opt) { + case 'b': + hash = strchr(value, '#'); + if (hash != NULL) { + result = parse_uint(&num, hash + 1, MAXPORT, + "port number"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse port number"); + } + srcport = num; + *hash = '\0'; + } else { + srcport = 0; + } + if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) { + isc_sockaddr_fromin6(&bind_address, &in6, srcport); + isc_net_disableipv4(); + } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) { + isc_sockaddr_fromin(&bind_address, &in4, srcport); + isc_net_disableipv6(); + } else { + if (hash != NULL) { + *hash = '#'; + } + fatal("invalid address %s", value); + } + if (hash != NULL) { + *hash = '#'; + } + specified_source = true; + return (value_from_next); + case 'c': + if ((*lookup)->rdclassset) { + fprintf(stderr, ";; Warning, extra class option\n"); + } + *open_type_class = false; + tr.base = value; + tr.length = (unsigned int)strlen(value); + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) { + (*lookup)->rdclass = rdclass; + (*lookup)->rdclassset = true; + } else { + fprintf(stderr, + ";; Warning, ignoring " + "invalid class %s\n", + value); + } + return (value_from_next); + case 'f': + atomic_store(&batchname, (uintptr_t)value); + return (value_from_next); + case 'k': + strlcpy(keyfile, value, sizeof(keyfile)); + return (value_from_next); + case 'p': + result = parse_uint(&num, value, MAXPORT, "port number"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse port number"); + } + port = num; + return (value_from_next); + case 'q': + if (!config_only) { + if (*need_clone) { + (*lookup) = clone_lookup(default_lookup, true); + } + *need_clone = true; + strlcpy((*lookup)->textname, value, + sizeof((*lookup)->textname)); + (*lookup)->trace_root = ((*lookup)->trace || + (*lookup)->ns_search_only); + (*lookup)->new_search = true; + if (*firstarg) { + printgreeting(argc, argv, *lookup); + *firstarg = false; + } + ISC_LIST_APPEND(lookup_list, (*lookup), link); + debug("looking up %s", (*lookup)->textname); + } + return (value_from_next); + case 't': + *open_type_class = false; + if (strncasecmp(value, "ixfr=", 5) == 0) { + rdtype = dns_rdatatype_ixfr; + result = ISC_R_SUCCESS; + } else { + tr.base = value; + tr.length = (unsigned int)strlen(value); + result = dns_rdatatype_fromtext( + &rdtype, (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS && + rdtype == dns_rdatatype_ixfr) + { + result = DNS_R_UNKNOWN; + } + } + if (result == ISC_R_SUCCESS) { + if ((*lookup)->rdtypeset) { + fprintf(stderr, ";; Warning, " + "extra type option\n"); + } + if (rdtype == dns_rdatatype_ixfr) { + uint32_t serial; + (*lookup)->rdtype = dns_rdatatype_ixfr; + (*lookup)->rdtypeset = true; + result = parse_uint(&serial, &value[5], + MAXSERIAL, "serial number"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse serial number"); + } + (*lookup)->ixfr_serial = serial; + (*lookup)->section_question = plusquest; + (*lookup)->comments = pluscomm; + if (!(*lookup)->tcp_mode_set) { + (*lookup)->tcp_mode = true; + } + } else { + (*lookup)->rdtype = rdtype; + if (!config_only) { + (*lookup)->rdtypeset = true; + } + if (rdtype == dns_rdatatype_axfr) { + (*lookup)->section_question = plusquest; + (*lookup)->comments = pluscomm; + } else if (rdtype == dns_rdatatype_any) { + if (!(*lookup)->tcp_mode_set) { + (*lookup)->tcp_mode = true; + } + } + (*lookup)->ixfr_serial = false; + } + } else { + fprintf(stderr, + ";; Warning, ignoring " + "invalid type %s\n", + value); + } + return (value_from_next); + case 'y': + if ((ptr = strtok_r(value, ":", &last)) == NULL) { + usage(); + } + if ((ptr2 = strtok_r(NULL, ":", &last)) == NULL) { /* name or + * secret */ + usage(); + } + if ((ptr3 = strtok_r(NULL, ":", &last)) != NULL) { /* secret or + * NULL */ + parse_hmac(ptr); + ptr = ptr2; + ptr2 = ptr3; + } else { + hmacname = DNS_TSIG_HMACMD5_NAME; + digestbits = 0; + } + /* XXXONDREJ: FIXME */ + strlcpy(keynametext, ptr, sizeof(keynametext)); + strlcpy(keysecret, ptr2, sizeof(keysecret)); + return (value_from_next); + case 'x': + if (*need_clone) { + *lookup = clone_lookup(default_lookup, true); + } + *need_clone = true; + if (get_reverse(textname, sizeof(textname), value, false) == + ISC_R_SUCCESS) + { + strlcpy((*lookup)->textname, textname, + sizeof((*lookup)->textname)); + debug("looking up %s", (*lookup)->textname); + (*lookup)->trace_root = ((*lookup)->trace || + (*lookup)->ns_search_only); + if (!(*lookup)->rdtypeset) { + (*lookup)->rdtype = dns_rdatatype_ptr; + } + if (!(*lookup)->rdclassset) { + (*lookup)->rdclass = dns_rdataclass_in; + } + (*lookup)->new_search = true; + if (*firstarg) { + printgreeting(argc, argv, *lookup); + *firstarg = false; + } + ISC_LIST_APPEND(lookup_list, *lookup, link); + } else { + fprintf(stderr, "Invalid IP address %s\n", value); + exit(1); + } + return (value_from_next); + invalid_option: + default: + fprintf(stderr, "Invalid option: -%s\n", option); + usage(); + } + UNREACHABLE(); + return (false); +} + +/*% + * Because we may be trying to do memory allocation recording, we're going + * to need to parse the arguments for the -m *before* we start the main + * argument parsing routine. + * + * I'd prefer not to have to do this, but I am not quite sure how else to + * fix the problem. Argument parsing in dig involves memory allocation + * by its nature, so it can't be done in the main argument parser. + */ +static void +preparse_args(int argc, char **argv) { + int rc; + char **rv; + char *option; + + rc = argc; + rv = argv; + for (rc--, rv++; rc > 0; rc--, rv++) { + if (rv[0][0] != '-') { + continue; + } + option = &rv[0][1]; + while (strpbrk(option, single_dash_opts) == &option[0]) { + switch (option[0]) { + case 'd': + /* For debugging early startup */ + debugging = true; + break; + case 'm': + memdebugging = true; + isc_mem_debugging = ISC_MEM_DEBUGTRACE | + ISC_MEM_DEBUGRECORD; + break; + case 'r': + /* + * Must be done early, because ~/.digrc + * is read before command line parsing + */ + debug("digrc (early)"); + digrc = false; + break; + case '4': + if (ipv6only) { + fatal("only one of -4 and -6 allowed"); + } + ipv4only = true; + break; + case '6': + if (ipv4only) { + fatal("only one of -4 and -6 allowed"); + } + ipv6only = true; + break; + } + option = &option[1]; + } + if (strlen(option) == 0U) { + continue; + } + /* Look for dash value option. */ + if (strpbrk(option, dash_opts) != &option[0]) { + goto invalid_option; + } + if (strlen(option) > 1U) { + /* value in option. */ + continue; + } + /* Dash value is next argument so we need to skip it. */ + rc--, rv++; + /* Handle missing argument */ + if (rc == 0) { + invalid_option: + fprintf(stderr, "Invalid option: -%s\n", option); + usage(); + } + } +} + +static int +split_batchline(char *batchline, char **bargv, int len, const char *msg) { + int bargc; + char *last = NULL; + + REQUIRE(batchline != NULL); + + for (bargc = 1, bargv[bargc] = strtok_r(batchline, " \t\r\n", &last); + bargc < len && bargv[bargc]; + bargv[++bargc] = strtok_r(NULL, " \t\r\n", &last)) + { + debug("%s %d: %s", msg, bargc, bargv[bargc]); + } + return (bargc); +} + +static void +parse_args(bool is_batchfile, bool config_only, int argc, char **argv) { + isc_result_t result; + isc_textregion_t tr; + bool firstarg = true; + dig_lookup_t *lookup = NULL; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + bool open_type_class = true; + char batchline[MXNAME]; + int bargc; + char *bargv[64]; + int rc; + char **rv; +#ifndef NOPOSIX + char *homedir; + char rcfile[PATH_MAX]; +#endif /* ifndef NOPOSIX */ + bool need_clone = true; + + /* + * The semantics for parsing the args is a bit complex; if + * we don't have a host yet, make the arg apply globally, + * otherwise make it apply to the latest host. This is + * a bit different than the previous versions, but should + * form a consistent user interface. + * + * First, create a "default lookup" which won't actually be used + * anywhere, except for cloning into new lookups + */ + + debug("parse_args()"); + if (!is_batchfile) { + debug("making new lookup"); + default_lookup = make_empty_lookup(); + default_lookup->adflag = true; + default_lookup->edns = DEFAULT_EDNS_VERSION; + default_lookup->sendcookie = true; + +#ifndef NOPOSIX + /* + * Treat ${HOME}/.digrc as a special batchfile + */ + INSIST(batchfp == NULL); + homedir = getenv("HOME"); + if (homedir != NULL && digrc) { + unsigned int n; + debug("digrc (open)"); + n = snprintf(rcfile, sizeof(rcfile), "%s/.digrc", + homedir); + if (n < sizeof(rcfile)) { + batchfp = fopen(rcfile, "r"); + } + } + if (batchfp != NULL) { + while (fgets(batchline, sizeof(batchline), batchfp) != + 0) + { + debug("config line %s", batchline); + bargc = split_batchline(batchline, bargv, 62, + ".digrc argv"); + bargv[0] = argv[0]; + argv0 = argv[0]; + parse_args(true, true, bargc, (char **)bargv); + } + fclose(batchfp); + } +#endif /* ifndef NOPOSIX */ + } + + if (is_batchfile && !config_only) { + /* Processing '-f batchfile'. */ + lookup = clone_lookup(default_lookup, true); + need_clone = false; + } else { + lookup = default_lookup; + } + + rc = argc; + rv = argv; + for (rc--, rv++; rc > 0; rc--, rv++) { + debug("main parsing %s", rv[0]); + if (strncmp(rv[0], "%", 1) == 0) { + break; + } + if (rv[0][0] == '@') { + if (is_batchfile && !config_only) { + addresscount = getaddresses(lookup, &rv[0][1], + &result); + if (addresscount == 0) { + fprintf(stderr, + "couldn't get address " + "for '%s': %s: skipping " + "lookup\n", + &rv[0][1], + isc_result_totext(result)); + if (ISC_LINK_LINKED(lookup, link)) { + ISC_LIST_DEQUEUE(lookup_list, + lookup, link); + } + destroy_lookup(lookup); + return; + } + } else { + addresscount = getaddresses(lookup, &rv[0][1], + NULL); + if (addresscount == 0) { + fatal("no valid addresses for '%s'\n", + &rv[0][1]); + } + } + } else if (rv[0][0] == '+') { + plus_option(&rv[0][1], is_batchfile, lookup); + } else if (rv[0][0] == '-') { + if (rc <= 1) { + if (dash_option(&rv[0][1], NULL, &lookup, + &open_type_class, &need_clone, + config_only, argc, argv, + &firstarg)) + { + rc--; + rv++; + } + } else { + if (dash_option(&rv[0][1], rv[1], &lookup, + &open_type_class, &need_clone, + config_only, argc, argv, + &firstarg)) + { + rc--; + rv++; + } + } + } else { + /* + * Anything which isn't an option + */ + if (open_type_class) { + if (strncasecmp(rv[0], "ixfr=", 5) == 0) { + rdtype = dns_rdatatype_ixfr; + result = ISC_R_SUCCESS; + } else { + tr.base = rv[0]; + tr.length = (unsigned int)strlen(rv[0]); + result = dns_rdatatype_fromtext( + &rdtype, + (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS && + rdtype == dns_rdatatype_ixfr) + { + fprintf(stderr, ";; Warning, " + "ixfr requires " + "a " + "serial " + "number\n"); + continue; + } + } + if (result == ISC_R_SUCCESS) { + if (lookup->rdtypeset) { + fprintf(stderr, ";; Warning, " + "extra type " + "option\n"); + } + if (rdtype == dns_rdatatype_ixfr) { + uint32_t serial; + lookup->rdtype = + dns_rdatatype_ixfr; + lookup->rdtypeset = true; + result = parse_uint(&serial, + &rv[0][5], + MAXSERIAL, + "serial " + "number"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse " + "serial number"); + } + lookup->ixfr_serial = serial; + lookup->section_question = + plusquest; + lookup->comments = pluscomm; + if (!lookup->tcp_mode_set) { + lookup->tcp_mode = true; + } + } else { + lookup->rdtype = rdtype; + lookup->rdtypeset = true; + if (rdtype == + dns_rdatatype_axfr) + { + lookup->section_question = + plusquest; + lookup->comments = + pluscomm; + } + if (rdtype == + dns_rdatatype_any && + !lookup->tcp_mode_set) + { + lookup->tcp_mode = true; + } + lookup->ixfr_serial = false; + } + continue; + } + result = dns_rdataclass_fromtext( + &rdclass, (isc_textregion_t *)&tr); + if (result == ISC_R_SUCCESS) { + if (lookup->rdclassset) { + fprintf(stderr, ";; Warning, " + "extra class " + "option\n"); + } + lookup->rdclass = rdclass; + lookup->rdclassset = true; + continue; + } + } + + if (!config_only) { + if (need_clone) { + lookup = clone_lookup(default_lookup, + true); + } + need_clone = true; + strlcpy(lookup->textname, rv[0], + sizeof(lookup->textname)); + lookup->trace_root = (lookup->trace || + lookup->ns_search_only); + lookup->new_search = true; + if (firstarg) { + printgreeting(argc, argv, lookup); + firstarg = false; + } + ISC_LIST_APPEND(lookup_list, lookup, link); + debug("looking up %s", lookup->textname); + } + /* XXX Error message */ + } + } + + /* + * If we have a batchfile, seed the lookup list with the + * first entry, then trust the callback in dighost_shutdown + * to get the rest + */ + char *filename = (char *)atomic_load(&batchname); + if ((filename != NULL) && !(is_batchfile)) { + if (strcmp(filename, "-") == 0) { + batchfp = stdin; + } else { + batchfp = fopen(filename, "r"); + } + if (batchfp == NULL) { + perror(filename); + if (exitcode < 8) { + exitcode = 8; + } + fatal("couldn't open specified batch file"); + } + /* XXX Remove code dup from shutdown code */ + next_line: + if (fgets(batchline, sizeof(batchline), batchfp) != 0) { + debug("batch line %s", batchline); + if (batchline[0] == '\r' || batchline[0] == '\n' || + batchline[0] == '#' || batchline[0] == ';') + { + goto next_line; + } + bargc = split_batchline(batchline, bargv, 14, + "batch argv"); + bargv[0] = argv[0]; + argv0 = argv[0]; + parse_args(true, false, bargc, (char **)bargv); + return; + } + return; + } + /* + * If no lookup specified, search for root + */ + if ((lookup_list.head == NULL) && !config_only) { + if (need_clone) { + lookup = clone_lookup(default_lookup, true); + } + need_clone = true; + lookup->trace_root = (lookup->trace || lookup->ns_search_only); + lookup->new_search = true; + strlcpy(lookup->textname, ".", sizeof(lookup->textname)); + lookup->rdtype = dns_rdatatype_ns; + lookup->rdtypeset = true; + if (firstarg) { + printgreeting(argc, argv, lookup); + firstarg = false; + } + ISC_LIST_APPEND(lookup_list, lookup, link); + } + if (!need_clone) { + destroy_lookup(lookup); + } +} + +/* + * Callback from dighost.c to allow program-specific shutdown code. + * Here, we're possibly reading from a batch file, then shutting down + * for real if there's nothing in the batch file to read. + */ +static void +query_finished(void) { + char batchline[MXNAME]; + int bargc; + char *bargv[16]; + + if (atomic_load(&batchname) == 0) { + isc_app_shutdown(); + return; + } + + fflush(stdout); + if (feof(batchfp)) { + atomic_store(&batchname, 0); + isc_app_shutdown(); + if (batchfp != stdin) { + fclose(batchfp); + } + return; + } + + if (fgets(batchline, sizeof(batchline), batchfp) != 0) { + debug("batch line %s", batchline); + bargc = split_batchline(batchline, bargv, 14, "batch argv"); + bargv[0] = argv0; + parse_args(true, false, bargc, (char **)bargv); + start_lookup(); + } else { + atomic_store(&batchname, 0); + if (batchfp != stdin) { + fclose(batchfp); + } + isc_app_shutdown(); + return; + } +} + +static void +dig_error(const char *format, ...) { + va_list args; + + if (yaml) { + printf("-\n"); + printf(" type: DIG_ERROR\n"); + + /* + * Print an indent before a literal block quote. + * Note: this will break if used to print more than + * one line of text as only the first line would be + * indented. + */ + printf(" message: |\n"); + printf(" "); + } else { + printf(";; "); + } + + va_start(args, format); + vprintf(format, args); + va_end(args); + + if (!yaml) { + printf("\n"); + } +} + +static void +dig_warning(const char *format, ...) { + va_list args; + + if (!yaml) { + printf(";; "); + + va_start(args, format); + vprintf(format, args); + va_end(args); + + printf("\n"); + } +} + +static void +dig_comments(dig_lookup_t *lookup, const char *format, ...) { + va_list args; + + if (lookup->comments && !yaml) { + printf(";; "); + + va_start(args, format); + vprintf(format, args); + va_end(args); + + printf("\n"); + } +} + +void +dig_setup(int argc, char **argv) { + isc_result_t result; + + ISC_LIST_INIT(lookup_list); + ISC_LIST_INIT(server_list); + ISC_LIST_INIT(search_list); + + debug("dig_setup()"); + + /* setup dighost callbacks */ + dighost_printmessage = printmessage; + dighost_received = received; + dighost_trying = trying; + dighost_shutdown = query_finished; + dighost_error = dig_error; + dighost_warning = dig_warning; + dighost_comments = dig_comments; + + progname = argv[0]; + preparse_args(argc, argv); + + result = isc_app_start(); + check_result(result, "isc_app_start"); + + setup_libs(); + setup_system(ipv4only, ipv6only); +} + +void +dig_query_setup(bool is_batchfile, bool config_only, int argc, char **argv) { + debug("dig_query_setup"); + + parse_args(is_batchfile, config_only, argc, argv); + if (keyfile[0] != 0) { + setup_file_key(); + } else if (keysecret[0] != 0) { + setup_text_key(); + } + if (domainopt[0] != '\0') { + set_search_domain(domainopt); + usesearch = true; + } +} + +void +dig_startup() { + isc_result_t result; + + debug("dig_startup()"); + + result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); + check_result(result, "isc_app_onrun"); + isc_app_run(); +} + +void +dig_query_start() { + start_lookup(); +} + +void +dig_shutdown() { + destroy_lookup(default_lookup); + if (atomic_load(&batchname) != 0) { + if (batchfp != stdin) { + fclose(batchfp); + } + atomic_store(&batchname, 0); + } + cancel_all(); + destroy_libs(); + isc_app_finish(); +} + +/*% Main processing routine for dig */ +int +main(int argc, char **argv) { + dig_setup(argc, argv); + dig_query_setup(false, false, argc, argv); + dig_startup(); + dig_shutdown(); + + return (exitcode); +} diff --git a/bin/dig/dig.rst b/bin/dig/dig.rst new file mode 100644 index 0000000..d27b1fd --- /dev/null +++ b/bin/dig/dig.rst @@ -0,0 +1,645 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dig: + +dig - DNS lookup utility +------------------------ + +Synopsis +~~~~~~~~ +:program:`dig` [@server] [**-b** address] [**-c** class] [**-f** filename] [**-k** filename] [**-m**] [**-p** port#] [**-q** name] [**-t** type] [**-v**] [**-x** addr] [**-y** [hmac:]name:key] [ [**-4**] | [**-6**] ] [name] [type] [class] [queryopt...] + +:program:`dig` [**-h**] + +:program:`dig` [global-queryopt...] [query...] + +Description +~~~~~~~~~~~ + +``dig`` is a flexible tool for interrogating DNS name servers. It +performs DNS lookups and displays the answers that are returned from the +name server(s) that were queried. Most DNS administrators use ``dig`` to +troubleshoot DNS problems because of its flexibility, ease of use, and +clarity of output. Other lookup tools tend to have less functionality +than ``dig``. + +Although ``dig`` is normally used with command-line arguments, it also +has a batch mode of operation for reading lookup requests from a file. A +brief summary of its command-line arguments and options is printed when +the ``-h`` option is given. The BIND 9 +implementation of ``dig`` allows multiple lookups to be issued from the +command line. + +Unless it is told to query a specific name server, ``dig`` tries each +of the servers listed in ``/etc/resolv.conf``. If no usable server +addresses are found, ``dig`` sends the query to the local host. + +When no command-line arguments or options are given, ``dig`` +performs an NS query for "." (the root). + +It is possible to set per-user defaults for ``dig`` via +``${HOME}/.digrc``. This file is read and any options in it are applied +before the command-line arguments. The ``-r`` option disables this +feature, for scripts that need predictable behavior. + +The IN and CH class names overlap with the IN and CH top-level domain +names. Either use the ``-t`` and ``-c`` options to specify the type and +class, use the ``-q`` to specify the domain name, or use "IN." and +"CH." when looking up these top-level domains. + +Simple Usage +~~~~~~~~~~~~ + +A typical invocation of ``dig`` looks like: + +:: + + dig @server name type + +where: + +``server`` + is the name or IP address of the name server to query. This can be an + IPv4 address in dotted-decimal notation or an IPv6 address in + colon-delimited notation. When the supplied ``server`` argument is a + hostname, ``dig`` resolves that name before querying that name + server. + + If no ``server`` argument is provided, ``dig`` consults + ``/etc/resolv.conf``; if an address is found there, it queries the + name server at that address. If either of the ``-4`` or ``-6`` + options are in use, then only addresses for the corresponding + transport are tried. If no usable addresses are found, ``dig`` + sends the query to the local host. The reply from the name server + that responds is displayed. + +``name`` + is the name of the resource record that is to be looked up. + +``type`` + indicates what type of query is required - ANY, A, MX, SIG, etc. + ``type`` can be any valid query type. If no ``type`` argument is + supplied, ``dig`` performs a lookup for an A record. + +Options +~~~~~~~ + +``-4`` + This option indicates that only IPv4 should be used. + +``-6`` + This option indicates that only IPv6 should be used. + +``-b address[#port]`` + This option sets the source IP address of the query. The ``address`` must be a + valid address on one of the host's network interfaces, or "0.0.0.0" + or "::". An optional port may be specified by appending ``#port``. + +``-c class`` + This option sets the query class. The default ``class`` is IN; other classes are + HS for Hesiod records or CH for Chaosnet records. + +``-f file`` + This option sets batch mode, in which ``dig`` reads a list of lookup requests to process from + the given ``file``. Each line in the file should be organized in the + same way it would be presented as a query to ``dig`` using the + command-line interface. + +``-k keyfile`` + This option tells ``named`` to sign queries using TSIG using a key read from the given file. Key + files can be generated using ``tsig-keygen``. When using TSIG + authentication with ``dig``, the name server that is queried needs to + know the key and algorithm that is being used. In BIND, this is done + by providing appropriate ``key`` and ``server`` statements in + ``named.conf``. + +``-m`` + This option enables memory usage debugging. + +``-p port`` + This option sends the query to a non-standard port on the server, instead of the + default port 53. This option is used to test a name server that + has been configured to listen for queries on a non-standard port + number. + +``-q name`` + This option specifies the domain name to query. This is useful to distinguish the ``name`` + from other arguments. + +``-r`` + This option indicates that options from ``${HOME}/.digrc`` should not be read. This is useful for + scripts that need predictable behavior. + +``-t type`` + This option indicates the resource record type to query, which can be any valid query type. If + it is a resource record type supported in BIND 9, it can be given by + the type mnemonic (such as ``NS`` or ``AAAA``). The default query type is + ``A``, unless the ``-x`` option is supplied to indicate a reverse + lookup. A zone transfer can be requested by specifying a type of + AXFR. When an incremental zone transfer (IXFR) is required, set the + ``type`` to ``ixfr=N``. The incremental zone transfer contains + all changes made to the zone since the serial number in the zone's + SOA record was ``N``. + + All resource record types can be expressed as ``TYPEnn``, where ``nn`` is + the number of the type. If the resource record type is not supported + in BIND 9, the result is displayed as described in :rfc:`3597`. + +``-u`` + This option indicates that print query times should be provided in microseconds instead of milliseconds. + +``-v`` + This option prints the version number and exits. + +``-x addr`` + This option sets simplified reverse lookups, for mapping addresses to names. The + ``addr`` is an IPv4 address in dotted-decimal notation, or a + colon-delimited IPv6 address. When the ``-x`` option is used, there is no + need to provide the ``name``, ``class``, and ``type`` arguments. + ``dig`` automatically performs a lookup for a name like + ``94.2.0.192.in-addr.arpa`` and sets the query type and class to PTR + and IN respectively. IPv6 addresses are looked up using nibble format + under the IP6.ARPA domain. + +``-y [hmac:]keyname:secret`` + This option signs queries using TSIG with the given authentication key. + ``keyname`` is the name of the key, and ``secret`` is the + base64-encoded shared secret. ``hmac`` is the name of the key algorithm; + valid choices are ``hmac-md5``, ``hmac-sha1``, ``hmac-sha224``, + ``hmac-sha256``, ``hmac-sha384``, or ``hmac-sha512``. If ``hmac`` is + not specified, the default is ``hmac-md5``; if MD5 was disabled, the default is + ``hmac-sha256``. + +.. note:: Only the ``-k`` option should be used, rather than the ``-y`` option, + because with ``-y`` the shared secret is supplied as a command-line + argument in clear text. This may be visible in the output from ``ps1`` or + in a history file maintained by the user's shell. + +Query Options +~~~~~~~~~~~~~ + +``dig`` provides a number of query options which affect the way in which +lookups are made and the results displayed. Some of these set or reset +flag bits in the query header, some determine which sections of the +answer get printed, and others determine the timeout and retry +strategies. + +Each query option is identified by a keyword preceded by a plus sign +(``+``). Some keywords set or reset an option; these may be preceded by +the string ``no`` to negate the meaning of that keyword. Other keywords +assign values to options, like the timeout interval. They have the form +``+keyword=value``. Keywords may be abbreviated, provided the +abbreviation is unambiguous; for example, ``+cd`` is equivalent to +``+cdflag``. The query options are: + +``+[no]aaflag`` + This option is a synonym for ``+[no]aaonly``. + +``+[no]aaonly`` + This option sets the ``aa`` flag in the query. + +``+[no]additional`` + This option displays [or does not display] the additional section of a reply. The + default is to display it. + +``+[no]adflag`` + This option sets [or does not set] the AD (authentic data) bit in the query. This + requests the server to return whether all of the answer and authority + sections have been validated as secure, according to the security + policy of the server. ``AD=1`` indicates that all records have been + validated as secure and the answer is not from a OPT-OUT range. ``AD=0`` + indicates that some part of the answer was insecure or not validated. + This bit is set by default. + +``+[no]all`` + This option sets or clears all display flags. + +``+[no]answer`` + This option displays [or does not display] the answer section of a reply. The default + is to display it. + +``+[no]authority`` + This option displays [or does not display] the authority section of a reply. The + default is to display it. + +``+[no]badcookie`` + This option retries the lookup with a new server cookie if a BADCOOKIE response is + received. + +``+[no]besteffort`` + This option attempts to display the contents of messages which are malformed. The + default is to not display malformed answers. + +``+bufsize[=B]`` + This option sets the UDP message buffer size advertised using EDNS0 + to ``B`` bytes. The maximum and minimum sizes of this buffer are + 65535 and 0, respectively. ``+bufsize=0`` disables EDNS (use + ``+bufsize=0 +edns`` to send an EDNS message with an advertised size + of 0 bytes). ``+bufsize`` restores the default buffer size. + +``+[no]cdflag`` + This option sets [or does not set] the CD (checking disabled) bit in the query. This + requests the server to not perform DNSSEC validation of responses. + +``+[no]class`` + This option displays [or does not display] the CLASS when printing the record. + +``+[no]cmd`` + This option toggles the printing of the initial comment in the output, identifying the + version of ``dig`` and the query options that have been applied. This option + always has a global effect; it cannot be set globally and then overridden on a + per-lookup basis. The default is to print this comment. + +``+[no]comments`` + This option toggles the display of some comment lines in the output, with + information about the packet header and OPT pseudosection, and the names of + the response section. The default is to print these comments. + + Other types of comments in the output are not affected by this option, but + can be controlled using other command-line switches. These include + ``+[no]cmd``, ``+[no]question``, ``+[no]stats``, and ``+[no]rrcomments``. + +``+[no]cookie=####`` + This option sends [or does not send] a COOKIE EDNS option, with an optional value. Replaying a COOKIE + from a previous response allows the server to identify a previous + client. The default is ``+cookie``. + + ``+cookie`` is also set when ``+trace`` is set to better emulate the + default queries from a nameserver. + +``+[no]crypto`` + This option toggles the display of cryptographic fields in DNSSEC records. The + contents of these fields are unnecessary for debugging most DNSSEC + validation failures and removing them makes it easier to see the + common failures. The default is to display the fields. When omitted, + they are replaced by the string ``[omitted]`` or, in the DNSKEY case, the + key ID is displayed as the replacement, e.g. ``[ key id = value ]``. + +``+[no]defname`` + This option, which is deprecated, is treated as a synonym for ``+[no]search``. + +``+[no]dnssec`` + This option requests that DNSSEC records be sent by setting the DNSSEC OK (DO) bit in + the OPT record in the additional section of the query. + +``+domain=somename`` + This option sets the search list to contain the single domain ``somename``, as if + specified in a ``domain`` directive in ``/etc/resolv.conf``, and + enables search list processing as if the ``+search`` option were + given. + +``+dscp=value`` + This option sets the DSCP code point to be used when sending the query. Valid DSCP + code points are in the range [0...63]. By default no code point is + explicitly set. + +``+[no]edns[=#]`` + This option specifies the EDNS version to query with. Valid values are 0 to 255. + Setting the EDNS version causes an EDNS query to be sent. + ``+noedns`` clears the remembered EDNS version. EDNS is set to 0 by + default. + +``+[no]ednsflags[=#]`` + This option sets the must-be-zero EDNS flags bits (Z bits) to the specified value. + Decimal, hex, and octal encodings are accepted. Setting a named flag + (e.g., DO) is silently ignored. By default, no Z bits are set. + +``+[no]ednsnegotiation`` + This option enables/disables EDNS version negotiation. By default, EDNS version + negotiation is enabled. + +``+[no]ednsopt[=code[:value]]`` + This option specifies the EDNS option with code point ``code`` and an optional payload + of ``value`` as a hexadecimal string. ``code`` can be either an EDNS + option name (for example, ``NSID`` or ``ECS``) or an arbitrary + numeric value. ``+noednsopt`` clears the EDNS options to be sent. + +``+[no]expire`` + This option sends an EDNS Expire option. + +``+[no]fail`` + This option indicates that ``named`` should try [or not try] the next server if a SERVFAIL is received. The default is + to not try the next server, which is the reverse of normal stub + resolver behavior. + +``+[no]header-only`` + This option sends a query with a DNS header without a question section. The + default is to add a question section. The query type and query name + are ignored when this is set. + +``+[no]identify`` + This option shows [or does not show] the IP address and port number that supplied + the answer, when the ``+short`` option is enabled. If short form + answers are requested, the default is not to show the source address + and port number of the server that provided the answer. + +``+[no]idnin`` + This option processes [or does not process] IDN domain names on input. This requires + ``IDN SUPPORT`` to have been enabled at compile time. + + The default is to process IDN input when standard output is a tty. + The IDN processing on input is disabled when ``dig`` output is redirected + to files, pipes, and other non-tty file descriptors. + +``+[no]idnout`` + This option converts [or does not convert] puny code on output. This requires + ``IDN SUPPORT`` to have been enabled at compile time. + + The default is to process puny code on output when standard output is + a tty. The puny code processing on output is disabled when ``dig`` output + is redirected to files, pipes, and other non-tty file descriptors. + +``+[no]ignore`` + This option ignores [or does not ignore] truncation in UDP responses instead of retrying with TCP. By + default, TCP retries are performed. + +``+[no]keepalive`` + This option sends [or does not send] an EDNS Keepalive option. + +``+[no]keepopen`` + This option keeps [or does not keep] the TCP socket open between queries, and reuses it rather than + creating a new TCP socket for each lookup. The default is + ``+nokeepopen``. + +``+[no]mapped`` + This option allows [or does not allow] mapped IPv4-over-IPv6 addresses to be used. The default is + ``+mapped``. + +``+[no]multiline`` + This option prints [or does not print] records, like the SOA records, in a verbose multi-line format + with human-readable comments. The default is to print each record on + a single line to facilitate machine parsing of the ``dig`` output. + +``+ndots=D`` + This option sets the number of dots (``D``) that must appear in ``name`` for + it to be considered absolute. The default value is that defined using + the ``ndots`` statement in ``/etc/resolv.conf``, or 1 if no ``ndots`` + statement is present. Names with fewer dots are interpreted as + relative names, and are searched for in the domains listed in the + ``search`` or ``domain`` directive in ``/etc/resolv.conf`` if + ``+search`` is set. + +``+[no]nsid`` + When enabled, this option includes an EDNS name server ID request when sending a query. + +``+[no]nssearch`` + When this option is set, ``dig`` attempts to find the authoritative + name servers for the zone containing the name being looked up, and + display the SOA record that each name server has for the zone. + Addresses of servers that did not respond are also printed. + +``+[no]onesoa`` + When enabled, this option prints only one (starting) SOA record when performing an AXFR. The + default is to print both the starting and ending SOA records. + +``+[no]opcode=value`` + When enabled, this option sets (restores) the DNS message opcode to the specified value. The + default value is QUERY (0). + +``+padding=value`` + This option pads the size of the query packet using the EDNS Padding option to + blocks of ``value`` bytes. For example, ``+padding=32`` causes a + 48-byte query to be padded to 64 bytes. The default block size is 0, + which disables padding; the maximum is 512. Values are ordinarily + expected to be powers of two, such as 128; however, this is not + mandatory. Responses to padded queries may also be padded, but only + if the query uses TCP or DNS COOKIE. + +``+[no]qr`` + This option toggles the display of the query message as it is sent. By default, the query + is not printed. + +``+[no]question`` + This option toggles the display of the question section of a query when an answer is + returned. The default is to print the question section as a comment. + +``+[no]raflag`` + This option sets [or does not set] the RA (Recursion Available) bit in the query. The + default is ``+noraflag``. This bit is ignored by the server for + QUERY. + +``+[no]rdflag`` + This option is a synonym for ``+[no]recurse``. + +``+[no]recurse`` + This option toggles the setting of the RD (recursion desired) bit in the query. + This bit is set by default, which means ``dig`` normally sends + recursive queries. Recursion is automatically disabled when the + ``+nssearch`` or ``+trace`` query option is used. + +``+retry=T`` + This option sets the number of times to retry UDP and TCP queries to server to ``T`` + instead of the default, 2. Unlike ``+tries``, this does not include + the initial query. + +``+[no]rrcomments`` + This option toggles the display of per-record comments in the output (for example, + human-readable key information about DNSKEY records). The default is + not to print record comments unless multiline mode is active. + +``+[no]search`` + This option uses [or does not use] the search list defined by the searchlist or domain + directive in ``resolv.conf``, if any. The search list is not used by + default. + + ``ndots`` from ``resolv.conf`` (default 1), which may be overridden by + ``+ndots``, determines whether the name is treated as relative + and hence whether a search is eventually performed. + +``+[no]short`` + This option toggles whether a terse answer is provided. The default is to print the answer in a verbose + form. This option always has a global effect; it cannot be set globally and + then overridden on a per-lookup basis. + +``+[no]showsearch`` + This option performs [or does not perform] a search showing intermediate results. + +``+[no]sigchase`` + This feature is now obsolete and has been removed; use ``delv`` + instead. + +``+split=W`` + This option splits long hex- or base64-formatted fields in resource records into + chunks of ``W`` characters (where ``W`` is rounded up to the nearest + multiple of 4). ``+nosplit`` or ``+split=0`` causes fields not to be + split at all. The default is 56 characters, or 44 characters when + multiline mode is active. + +``+[no]stats`` + This option toggles the printing of statistics: when the query was made, the size of the + reply, etc. The default behavior is to print the query statistics as a + comment after each lookup. + +``+[no]subnet=addr[/prefix-length]`` + This option sends [or does not send] an EDNS CLIENT-SUBNET option with the specified IP + address or network prefix. + + ``dig +subnet=0.0.0.0/0``, or simply ``dig +subnet=0`` for short, + sends an EDNS CLIENT-SUBNET option with an empty address and a source + prefix-length of zero, which signals a resolver that the client's + address information must *not* be used when resolving this query. + +``+[no]tcflag`` + This option sets [or does not set] the TC (TrunCation) bit in the query. The default is + ``+notcflag``. This bit is ignored by the server for QUERY. + +``+[no]tcp`` + This option uses [or does not use] TCP when querying name servers. + The default behavior is to use UDP unless a type ``any`` or + ``ixfr=N`` query is requested, in which case the default is TCP. + AXFR queries always use TCP. To prevent retry over TCP when TC=1 + is returned from a UDP query, use ``+ignore``. + +``+timeout=T`` + This option sets the timeout for a query to ``T`` seconds. The default timeout is + 5 seconds. An attempt to set ``T`` to less than 1 is silently set to 1. + +``+[no]topdown`` + This feature is related to ``dig +sigchase``, which is obsolete and + has been removed. Use ``delv`` instead. + +``+[no]trace`` + This option toggles tracing of the delegation path from the root name servers for + the name being looked up. Tracing is disabled by default. When + tracing is enabled, ``dig`` makes iterative queries to resolve the + name being looked up. It follows referrals from the root servers, + showing the answer from each server that was used to resolve the + lookup. + + If ``@server`` is also specified, it affects only the initial query for + the root zone name servers. + + ``+dnssec`` is also set when ``+trace`` is set, to better emulate the + default queries from a name server. + +``+tries=T`` + This option sets the number of times to try UDP and TCP queries to server to ``T`` + instead of the default, 3. If ``T`` is less than or equal to zero, + the number of tries is silently rounded up to 1. + +``+trusted-key=####`` + This option formerly specified trusted keys for use with ``dig +sigchase``. This + feature is now obsolete and has been removed; use ``delv`` instead. + +``+[no]ttlid`` + This option displays [or does not display] the TTL when printing the record. + +``+[no]ttlunits`` + This option displays [or does not display] the TTL in friendly human-readable time + units of ``s``, ``m``, ``h``, ``d``, and ``w``, representing seconds, minutes, + hours, days, and weeks. This implies ``+ttlid``. + +``+[no]unexpected`` + This option accepts [or does not accept] answers from unexpected sources. By default, ``dig`` + will not accept a reply from a source other than the one to which it sent the + query. + +``+[no]unknownformat`` + This option prints all RDATA in unknown RR type presentation format (:rfc:`3597`). + The default is to print RDATA for known types in the type's + presentation format. + +``+[no]vc`` + This option uses [or does not use] TCP when querying name servers. This alternate + syntax to ``+[no]tcp`` is provided for backwards compatibility. The + ``vc`` stands for "virtual circuit." + +``+[no]yaml`` + When enabled, this option prints the responses (and, if ``+qr`` is in use, also the + outgoing queries) in a detailed YAML format. + +``+[no]zflag`` + This option sets [or does not set] the last unassigned DNS header flag in a DNS query. + This flag is off by default. + +Multiple Queries +~~~~~~~~~~~~~~~~ + +The BIND 9 implementation of ``dig`` supports specifying multiple +queries on the command line (in addition to supporting the ``-f`` batch +file option). Each of those queries can be supplied with its own set of +flags, options, and query options. + +In this case, each ``query`` argument represents an individual query in +the command-line syntax described above. Each consists of any of the +standard options and flags, the name to be looked up, an optional query +type and class, and any query options that should be applied to that +query. + +A global set of query options, which should be applied to all queries, +can also be supplied. These global query options must precede the first +tuple of name, class, type, options, flags, and query options supplied +on the command line. Any global query options (except ``+[no]cmd`` and +``+[no]short`` options) can be overridden by a query-specific set of +query options. For example: + +:: + + dig +qr www.isc.org any -x 127.0.0.1 isc.org ns +noqr + +shows how ``dig`` can be used from the command line to make three +lookups: an ANY query for ``www.isc.org``, a reverse lookup of 127.0.0.1, +and a query for the NS records of ``isc.org``. A global query option of +``+qr`` is applied, so that ``dig`` shows the initial query it made for +each lookup. The final query has a local query option of ``+noqr`` which +means that ``dig`` does not print the initial query when it looks up the +NS records for ``isc.org``. + +IDN Support +~~~~~~~~~~~ + +If ``dig`` has been built with IDN (internationalized domain name) +support, it can accept and display non-ASCII domain names. ``dig`` +appropriately converts character encoding of a domain name before sending +a request to a DNS server or displaying a reply from the server. +To turn off IDN support, use the parameters +``+noidnin`` and ``+noidnout``, or define the ``IDN_DISABLE`` environment +variable. + +Return Codes +~~~~~~~~~~~~ + +``dig`` return codes are: + +``0`` + DNS response received, including NXDOMAIN status + +``1`` + Usage error + +``8`` + Couldn't open batch file + +``9`` + No reply from server + +``10`` + Internal error + +Files +~~~~~ + +``/etc/resolv.conf`` + +``${HOME}/.digrc`` + +See Also +~~~~~~~~ + +:manpage:`delv(1)`, :manpage:`host(1)`, :manpage:`named(8)`, :manpage:`dnssec-keygen(8)`, :rfc:`1035`. + +Bugs +~~~~ + +There are probably too many query options. diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c new file mode 100644 index 0000000..ac7e1fb --- /dev/null +++ b/bin/dig/dighost.c @@ -0,0 +1,4604 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file + * \note + * Notice to programmers: Do not use this code as an example of how to + * use the ISC library to perform DNS lookups. Dig and Host both operate + * on the request level, since they allow fine-tuning of output and are + * intended as debugging tools. As a result, they perform many of the + * functions which could be better handled using the dns_resolver + * functions in most applications. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LOCALE_H +#include +#endif /* ifdef HAVE_LOCALE_H */ + +#ifdef HAVE_LIBIDN2 +#include +#endif /* HAVE_LIBIDN2 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#if !defined(NS_INADDRSZ) +#define NS_INADDRSZ 4 +#endif /* if !defined(NS_INADDRSZ) */ + +#if !defined(NS_IN6ADDRSZ) +#define NS_IN6ADDRSZ 16 +#endif /* if !defined(NS_IN6ADDRSZ) */ + +#if HAVE_SETLOCALE +#define systemlocale(l) (void)setlocale(l, "") +#define resetlocale(l) (void)setlocale(l, "C") +#else +#define systemlocale(l) +#define resetlocale(l) +#endif /* HAVE_SETLOCALE */ + +dig_lookuplist_t lookup_list; +dig_serverlist_t server_list; +dig_searchlistlist_t search_list; + +bool check_ra = false, have_ipv4 = false, have_ipv6 = false, + specified_source = false, free_now = false, cancel_now = false, + usesearch = false, showsearch = false, is_dst_up = false, + keep_open = false, verbose = false, yaml = false; +in_port_t port = 53; +unsigned int timeout = 0; +unsigned int extrabytes; +isc_mem_t *mctx = NULL; +isc_log_t *lctx = NULL; +isc_nm_t *netmgr = NULL; +isc_taskmgr_t *taskmgr = NULL; +isc_task_t *global_task = NULL; +isc_timermgr_t *timermgr = NULL; +isc_socketmgr_t *socketmgr = NULL; +isc_sockaddr_t bind_address; +isc_sockaddr_t bind_any; +int sendcount = 0; +int recvcount = 0; +int sockcount = 0; +int ndots = -1; +int tries = 3; +int lookup_counter = 0; + +static char servercookie[256]; + +#ifdef HAVE_LIBIDN2 +static void +idn_locale_to_ace(const char *src, char *dst, size_t dstlen); +static void +idn_ace_to_locale(const char *src, char **dst); +static isc_result_t +idn_output_filter(isc_buffer_t *buffer, unsigned int used_org); +#endif /* HAVE_LIBIDN2 */ + +isc_socket_t *keep = NULL; +isc_sockaddr_t keepaddr; + +/*% + * Exit Codes: + * + *\li 0 Everything went well, including things like NXDOMAIN + *\li 1 Usage error + *\li 7 Got too many RR's or Names + *\li 8 Couldn't open batch file + *\li 9 No reply from server + *\li 10 Internal error + */ +int exitcode = 0; +int fatalexit = 0; +char keynametext[MXNAME]; +char keyfile[MXNAME] = ""; +char keysecret[MXNAME] = ""; +unsigned char cookie_secret[33]; +unsigned char cookie[8]; +const dns_name_t *hmacname = NULL; +unsigned int digestbits = 0; +isc_buffer_t *namebuf = NULL; +dns_tsigkey_t *tsigkey = NULL; +bool validated = true; +bool debugging = false; +bool debugtiming = false; +bool memdebugging = false; +char *progname = NULL; +isc_mutex_t lookup_lock; +dig_lookup_t *current_lookup = NULL; + +#define DIG_MAX_ADDRESSES 20 + +/*% + * Apply and clear locks at the event level in global task. + * Can I get rid of these using shutdown events? XXX + */ +#define LOCK_LOOKUP \ + { \ + debug("lock_lookup %s:%d", __FILE__, __LINE__); \ + check_result(isc_mutex_lock((&lookup_lock)), "isc_mutex_" \ + "lock"); \ + debug("success"); \ + } +#define UNLOCK_LOOKUP \ + { \ + debug("unlock_lookup %s:%d", __FILE__, __LINE__); \ + check_result(isc_mutex_unlock((&lookup_lock)), "isc_mutex_" \ + "unlock"); \ + } + +static void +default_warnerr(const char *format, ...) { + va_list args; + + printf(";; "); + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); +} + +static void +default_comments(dig_lookup_t *lookup, const char *format, ...) { + va_list args; + + if (lookup->comments) { + printf(";; "); + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); + } +} + +/* dynamic callbacks */ + +isc_result_t (*dighost_printmessage)(dig_query_t *query, + const isc_buffer_t *msgbuf, + dns_message_t *msg, bool headers); + +void (*dighost_error)(const char *format, ...) = default_warnerr; + +void (*dighost_warning)(const char *format, ...) = default_warnerr; + +void (*dighost_comments)(dig_lookup_t *lookup, const char *format, + ...) = default_comments; + +void (*dighost_received)(unsigned int bytes, isc_sockaddr_t *from, + dig_query_t *query); + +void (*dighost_trying)(char *frm, dig_lookup_t *lookup); + +void (*dighost_shutdown)(void); + +/* forward declarations */ + +static void +cancel_lookup(dig_lookup_t *lookup); + +static void +recv_done(isc_task_t *task, isc_event_t *event); + +static void +send_udp(dig_query_t *query); + +static void +connect_timeout(isc_task_t *task, isc_event_t *event); + +static void +launch_next_query(dig_query_t *query, bool include_question); + +static void +check_next_lookup(dig_lookup_t *lookup); + +static bool +next_origin(dig_lookup_t *oldlookup); + +static int +count_dots(char *string) { + char *s; + int i = 0; + + s = string; + while (*s != '\0') { + if (*s == '.') { + i++; + } + s++; + } + return (i); +} + +static void +hex_dump(isc_buffer_t *b) { + unsigned int len, i; + isc_region_t r; + + isc_buffer_usedregion(b, &r); + + printf("%u bytes\n", r.length); + for (len = 0; len < r.length; len++) { + printf("%02x ", r.base[len]); + if (len % 16 == 15) { + fputs(" ", stdout); + for (i = len - 15; i <= len; i++) { + if (r.base[i] >= '!' && r.base[i] <= '}') { + putchar(r.base[i]); + } else { + putchar('.'); + } + } + printf("\n"); + } + } + if (len % 16 != 0) { + for (i = len; (i % 16) != 0; i++) { + fputs(" ", stdout); + } + fputs(" ", stdout); + for (i = ((len >> 4) << 4); i < len; i++) { + if (r.base[i] >= '!' && r.base[i] <= '}') { + putchar(r.base[i]); + } else { + putchar('.'); + } + } + printf("\n"); + } +} + +/*% + * Append 'len' bytes of 'text' at '*p', failing with + * ISC_R_NOSPACE if that would advance p past 'end'. + */ +static isc_result_t +append(const char *text, size_t len, char **p, char *end) { + if (*p + len > end) { + return (ISC_R_NOSPACE); + } + memmove(*p, text, len); + *p += len; + return (ISC_R_SUCCESS); +} + +static isc_result_t +reverse_octets(const char *in, char **p, char *end) { + const char *dot = strchr(in, '.'); + size_t len; + if (dot != NULL) { + isc_result_t result; + result = reverse_octets(dot + 1, p, end); + if (result != ISC_R_SUCCESS) { + return (result); + } + result = append(".", 1, p, end); + if (result != ISC_R_SUCCESS) { + return (result); + } + len = (int)(dot - in); + } else { + len = (int)strlen(in); + } + return (append(in, len, p, end)); +} + +isc_result_t +get_reverse(char *reverse, size_t len, char *value, bool strict) { + int r; + isc_result_t result; + isc_netaddr_t addr; + + addr.family = AF_INET6; + r = inet_pton(AF_INET6, value, &addr.type.in6); + if (r > 0) { + /* This is a valid IPv6 address. */ + dns_fixedname_t fname; + dns_name_t *name; + unsigned int options = 0; + + name = dns_fixedname_initname(&fname); + result = dns_byaddr_createptrname(&addr, options, name); + if (result != ISC_R_SUCCESS) { + return (result); + } + dns_name_format(name, reverse, (unsigned int)len); + return (ISC_R_SUCCESS); + } else { + /* + * Not a valid IPv6 address. Assume IPv4. + * If 'strict' is not set, construct the + * in-addr.arpa name by blindly reversing + * octets whether or not they look like integers, + * so that this can be used for RFC2317 names + * and such. + */ + char *p = reverse; + char *end = reverse + len; + if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1) { + return (DNS_R_BADDOTTEDQUAD); + } + result = reverse_octets(value, &p, end); + if (result != ISC_R_SUCCESS) { + return (result); + } + /* Append .in-addr.arpa. and a terminating NUL. */ + result = append(".in-addr.arpa.", 15, &p, end); + if (result != ISC_R_SUCCESS) { + return (result); + } + return (ISC_R_SUCCESS); + } +} + +void (*dighost_pre_exit_hook)(void) = NULL; + +#if TARGET_OS_IPHONE +void +warn(const char *format, ...) { + va_list args; + + fflush(stdout); + fprintf(stderr, ";; Warning: "); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); +} +#else /* if TARGET_OS_IPHONE */ +void +warn(const char *format, ...) { + va_list args; + + fflush(stdout); + fprintf(stderr, "%s: ", progname); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); +} +#endif /* if TARGET_OS_IPHONE */ + +void +digexit(void) { + if (exitcode < 10) { + exitcode = 10; + } + if (fatalexit != 0) { + exitcode = fatalexit; + } + if (dighost_pre_exit_hook != NULL) { + dighost_pre_exit_hook(); + } + exit(exitcode); +} + +void +fatal(const char *format, ...) { + va_list args; + + fflush(stdout); + fprintf(stderr, "%s: ", progname); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + digexit(); +} + +void +debug(const char *format, ...) { + va_list args; + isc_time_t t; + + if (debugging) { + fflush(stdout); + if (debugtiming) { + TIME_NOW(&t); + fprintf(stderr, "%u.%06u: ", isc_time_seconds(&t), + isc_time_nanoseconds(&t) / 1000); + } + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + } +} + +void +check_result(isc_result_t result, const char *msg) { + if (result != ISC_R_SUCCESS) { + fatal("%s: %s", msg, isc_result_totext(result)); + } +} + +/*% + * Create a server structure, which is part of the lookup structure. + * This is little more than a linked list of servers to query in hopes + * of finding the answer the user is looking for + */ +dig_server_t * +make_server(const char *servname, const char *userarg) { + dig_server_t *srv; + + REQUIRE(servname != NULL); + + debug("make_server(%s)", servname); + srv = isc_mem_allocate(mctx, sizeof(struct dig_server)); + strlcpy(srv->servername, servname, MXNAME); + strlcpy(srv->userarg, userarg, MXNAME); + ISC_LINK_INIT(srv, link); + return (srv); +} + +/*% + * Create a copy of the server list from the resolver configuration structure. + * The dest list must have already had ISC_LIST_INIT applied. + */ +static void +get_server_list(irs_resconf_t *resconf) { + isc_sockaddrlist_t *servers; + isc_sockaddr_t *sa; + dig_server_t *newsrv; + char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") + + sizeof("%4000000000")]; + debug("get_server_list()"); + servers = irs_resconf_getnameservers(resconf); + for (sa = ISC_LIST_HEAD(*servers); sa != NULL; + sa = ISC_LIST_NEXT(sa, link)) + { + int pf = isc_sockaddr_pf(sa); + isc_netaddr_t na; + isc_result_t result; + isc_buffer_t b; + + if (pf == AF_INET && !have_ipv4) { + continue; + } + if (pf == AF_INET6 && !have_ipv6) { + continue; + } + + isc_buffer_init(&b, tmp, sizeof(tmp)); + isc_netaddr_fromsockaddr(&na, sa); + result = isc_netaddr_totext(&na, &b); + if (result != ISC_R_SUCCESS) { + continue; + } + isc_buffer_putuint8(&b, 0); + if (pf == AF_INET6 && na.zone != 0) { + char buf[sizeof("%4000000000")]; + snprintf(buf, sizeof(buf), "%%%u", na.zone); + strlcat(tmp, buf, sizeof(tmp)); + } + newsrv = make_server(tmp, tmp); + ISC_LINK_INIT(newsrv, link); + ISC_LIST_APPEND(server_list, newsrv, link); + } +} + +void +flush_server_list(void) { + dig_server_t *s, *ps; + + debug("flush_server_list()"); + s = ISC_LIST_HEAD(server_list); + while (s != NULL) { + ps = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(server_list, ps, link); + isc_mem_free(mctx, ps); + } +} + +void +set_nameserver(char *opt) { + isc_result_t result; + isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES]; + isc_netaddr_t netaddr; + int count, i; + dig_server_t *srv; + char tmp[ISC_NETADDR_FORMATSIZE]; + + if (opt == NULL) { + return; + } + + result = bind9_getaddresses(opt, 0, sockaddrs, DIG_MAX_ADDRESSES, + &count); + if (result != ISC_R_SUCCESS) { + fatal("couldn't get address for '%s': %s", opt, + isc_result_totext(result)); + } + + flush_server_list(); + + for (i = 0; i < count; i++) { + isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]); + isc_netaddr_format(&netaddr, tmp, sizeof(tmp)); + srv = make_server(tmp, opt); + if (srv == NULL) { + fatal("memory allocation failure"); + } + ISC_LIST_APPEND(server_list, srv, link); + } +} + +/*% + * Produce a cloned server list. The dest list must have already had + * ISC_LIST_INIT applied. + */ +void +clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) { + dig_server_t *srv, *newsrv; + + debug("clone_server_list()"); + srv = ISC_LIST_HEAD(src); + while (srv != NULL) { + newsrv = make_server(srv->servername, srv->userarg); + ISC_LINK_INIT(newsrv, link); + ISC_LIST_ENQUEUE(*dest, newsrv, link); + srv = ISC_LIST_NEXT(srv, link); + } +} + +/*% + * Create an empty lookup structure, which holds all the information needed + * to get an answer to a user's question. This structure contains two + * linked lists: the server list (servers to query) and the query list + * (outstanding queries which have been made to the listed servers). + */ +dig_lookup_t * +make_empty_lookup(void) { + dig_lookup_t *looknew; + + debug("make_empty_lookup()"); + + INSIST(!free_now); + + looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup)); + looknew->pending = true; + looknew->textname[0] = 0; + looknew->cmdline[0] = 0; + looknew->rdtype = dns_rdatatype_a; + looknew->qrdtype = dns_rdatatype_a; + looknew->rdclass = dns_rdataclass_in; + looknew->rdtypeset = false; + looknew->rdclassset = false; + looknew->sendspace = NULL; + looknew->sendmsg = NULL; + looknew->name = NULL; + looknew->oname = NULL; + looknew->xfr_q = NULL; + looknew->current_query = NULL; + looknew->doing_xfr = false; + looknew->ixfr_serial = 0; + looknew->trace = false; + looknew->trace_root = false; + looknew->identify = false; + looknew->identify_previous_line = false; + looknew->ignore = false; + looknew->servfail_stops = true; + looknew->besteffort = true; + looknew->dnssec = false; + looknew->ednsflags = 0; + looknew->opcode = dns_opcode_query; + looknew->expire = false; + looknew->nsid = false; + looknew->tcp_keepalive = false; + looknew->padding = 0; + looknew->header_only = false; + looknew->sendcookie = false; + looknew->seenbadcookie = false; + looknew->badcookie = true; + looknew->multiline = false; + looknew->nottl = false; + looknew->noclass = false; + looknew->onesoa = false; + looknew->use_usec = false; + looknew->nocrypto = false; + looknew->ttlunits = false; + looknew->expandaaaa = false; + looknew->qr = false; + looknew->accept_reply_unexpected_src = false; +#ifdef HAVE_LIBIDN2 + looknew->idnin = isatty(1) ? (getenv("IDN_DISABLE") == NULL) : false; + looknew->idnout = looknew->idnin; +#else /* ifdef HAVE_LIBIDN2 */ + looknew->idnin = false; + looknew->idnout = false; +#endif /* HAVE_LIBIDN2 */ + looknew->udpsize = -1; + looknew->edns = -1; + looknew->recurse = true; + looknew->aaonly = false; + looknew->adflag = false; + looknew->cdflag = false; + looknew->raflag = false; + looknew->tcflag = false; + looknew->print_unknown_format = false; + looknew->zflag = false; + looknew->ns_search_only = false; + looknew->origin = NULL; + looknew->tsigctx = NULL; + looknew->querysig = NULL; + looknew->retries = tries; + looknew->nsfound = 0; + looknew->tcp_mode = false; + looknew->tcp_mode_set = false; + looknew->comments = true; + looknew->stats = true; + looknew->section_question = true; + looknew->section_answer = true; + looknew->section_authority = true; + looknew->section_additional = true; + looknew->new_search = false; + looknew->done_as_is = false; + looknew->need_search = false; + looknew->ecs_addr = NULL; + looknew->cookie = NULL; + looknew->ednsopts = NULL; + looknew->ednsoptscnt = 0; + looknew->ednsneg = true; + looknew->mapped = true; + looknew->dscp = -1; + looknew->rrcomments = 0; + looknew->eoferr = 0; + dns_fixedname_init(&looknew->fdomain); + ISC_LINK_INIT(looknew, link); + ISC_LIST_INIT(looknew->q); + ISC_LIST_INIT(looknew->connecting); + ISC_LIST_INIT(looknew->my_server_list); + return (looknew); +} + +#define EDNSOPT_OPTIONS 100U + +static void +cloneopts(dig_lookup_t *looknew, dig_lookup_t *lookold) { + size_t len = sizeof(looknew->ednsopts[0]) * EDNSOPT_OPTIONS; + size_t i; + looknew->ednsopts = isc_mem_allocate(mctx, len); + for (i = 0; i < EDNSOPT_OPTIONS; i++) { + looknew->ednsopts[i].code = 0; + looknew->ednsopts[i].length = 0; + looknew->ednsopts[i].value = NULL; + } + looknew->ednsoptscnt = 0; + if (lookold == NULL || lookold->ednsopts == NULL) { + return; + } + + for (i = 0; i < lookold->ednsoptscnt; i++) { + len = lookold->ednsopts[i].length; + if (len != 0) { + INSIST(lookold->ednsopts[i].value != NULL); + looknew->ednsopts[i].value = isc_mem_allocate(mctx, + len); + memmove(looknew->ednsopts[i].value, + lookold->ednsopts[i].value, len); + } + looknew->ednsopts[i].code = lookold->ednsopts[i].code; + looknew->ednsopts[i].length = len; + } + looknew->ednsoptscnt = lookold->ednsoptscnt; +} + +/*% + * Clone a lookup, perhaps copying the server list. This does not clone + * the query list, since it will be regenerated by the setup_lookup() + * function, nor does it queue up the new lookup for processing. + * Caution: If you don't clone the servers, you MUST clone the server + * list separately from somewhere else, or construct it by hand. + */ +dig_lookup_t * +clone_lookup(dig_lookup_t *lookold, bool servers) { + dig_lookup_t *looknew; + + debug("clone_lookup(%p)", lookold); + + INSIST(!free_now); + + looknew = make_empty_lookup(); + INSIST(looknew != NULL); + strlcpy(looknew->textname, lookold->textname, MXNAME); + strlcpy(looknew->cmdline, lookold->cmdline, MXNAME); + looknew->textname[MXNAME - 1] = 0; + looknew->rdtype = lookold->rdtype; + looknew->qrdtype = lookold->qrdtype; + looknew->rdclass = lookold->rdclass; + looknew->rdtypeset = lookold->rdtypeset; + looknew->rdclassset = lookold->rdclassset; + looknew->doing_xfr = lookold->doing_xfr; + looknew->ixfr_serial = lookold->ixfr_serial; + looknew->trace = lookold->trace; + looknew->trace_root = lookold->trace_root; + looknew->identify = lookold->identify; + looknew->identify_previous_line = lookold->identify_previous_line; + looknew->ignore = lookold->ignore; + looknew->servfail_stops = lookold->servfail_stops; + looknew->besteffort = lookold->besteffort; + looknew->dnssec = lookold->dnssec; + looknew->ednsflags = lookold->ednsflags; + looknew->opcode = lookold->opcode; + looknew->expire = lookold->expire; + looknew->nsid = lookold->nsid; + looknew->tcp_keepalive = lookold->tcp_keepalive; + looknew->header_only = lookold->header_only; + looknew->sendcookie = lookold->sendcookie; + looknew->seenbadcookie = lookold->seenbadcookie; + looknew->badcookie = lookold->badcookie; + looknew->cookie = lookold->cookie; + if (lookold->ednsopts != NULL) { + cloneopts(looknew, lookold); + } else { + looknew->ednsopts = NULL; + looknew->ednsoptscnt = 0; + } + looknew->ednsneg = lookold->ednsneg; + looknew->padding = lookold->padding; + looknew->mapped = lookold->mapped; + looknew->multiline = lookold->multiline; + looknew->nottl = lookold->nottl; + looknew->noclass = lookold->noclass; + looknew->onesoa = lookold->onesoa; + looknew->use_usec = lookold->use_usec; + looknew->nocrypto = lookold->nocrypto; + looknew->ttlunits = lookold->ttlunits; + looknew->expandaaaa = lookold->expandaaaa; + looknew->qr = lookold->qr; + looknew->accept_reply_unexpected_src = + lookold->accept_reply_unexpected_src; + looknew->idnin = lookold->idnin; + looknew->idnout = lookold->idnout; + looknew->udpsize = lookold->udpsize; + looknew->edns = lookold->edns; + looknew->recurse = lookold->recurse; + looknew->aaonly = lookold->aaonly; + looknew->adflag = lookold->adflag; + looknew->cdflag = lookold->cdflag; + looknew->raflag = lookold->raflag; + looknew->tcflag = lookold->tcflag; + looknew->print_unknown_format = lookold->print_unknown_format; + looknew->zflag = lookold->zflag; + looknew->ns_search_only = lookold->ns_search_only; + looknew->tcp_mode = lookold->tcp_mode; + looknew->tcp_mode_set = lookold->tcp_mode_set; + looknew->comments = lookold->comments; + looknew->stats = lookold->stats; + looknew->section_question = lookold->section_question; + looknew->section_answer = lookold->section_answer; + looknew->section_authority = lookold->section_authority; + looknew->section_additional = lookold->section_additional; + looknew->origin = lookold->origin; + looknew->retries = lookold->retries; + looknew->tsigctx = NULL; + looknew->need_search = lookold->need_search; + looknew->done_as_is = lookold->done_as_is; + looknew->dscp = lookold->dscp; + looknew->rrcomments = lookold->rrcomments; + looknew->eoferr = lookold->eoferr; + + if (lookold->ecs_addr != NULL) { + size_t len = sizeof(isc_sockaddr_t); + looknew->ecs_addr = isc_mem_allocate(mctx, len); + memmove(looknew->ecs_addr, lookold->ecs_addr, len); + } + + dns_name_copynf(dns_fixedname_name(&lookold->fdomain), + dns_fixedname_name(&looknew->fdomain)); + + if (servers) { + clone_server_list(lookold->my_server_list, + &looknew->my_server_list); + } + return (looknew); +} + +/*% + * Requeue a lookup for further processing, perhaps copying the server + * list. The new lookup structure is returned to the caller, and is + * queued for processing. If servers are not cloned in the requeue, they + * must be added before allowing the current event to complete, since the + * completion of the event may result in the next entry on the lookup + * queue getting run. + */ +dig_lookup_t * +requeue_lookup(dig_lookup_t *lookold, bool servers) { + dig_lookup_t *looknew; + + debug("requeue_lookup(%p)", lookold); + + lookup_counter++; + if (lookup_counter > LOOKUP_LIMIT) { + fatal("too many lookups"); + } + + looknew = clone_lookup(lookold, servers); + INSIST(looknew != NULL); + + debug("before insertion, init@%p -> %p, new@%p -> %p", lookold, + lookold->link.next, looknew, looknew->link.next); + ISC_LIST_PREPEND(lookup_list, looknew, link); + debug("after insertion, init -> %p, new = %p, new -> %p", lookold, + looknew, looknew->link.next); + return (looknew); +} + +void +setup_text_key(void) { + isc_result_t result; + dns_name_t keyname; + isc_buffer_t secretbuf; + unsigned int secretsize; + unsigned char *secretstore; + + debug("setup_text_key()"); + isc_buffer_allocate(mctx, &namebuf, MXNAME); + dns_name_init(&keyname, NULL); + isc_buffer_putstr(namebuf, keynametext); + secretsize = (unsigned int)strlen(keysecret) * 3 / 4; + secretstore = isc_mem_allocate(mctx, secretsize); + isc_buffer_init(&secretbuf, secretstore, secretsize); + result = isc_base64_decodestring(keysecret, &secretbuf); + if (result != ISC_R_SUCCESS) { + goto failure; + } + + secretsize = isc_buffer_usedlength(&secretbuf); + + if (hmacname == NULL) { + result = DST_R_UNSUPPORTEDALG; + goto failure; + } + + result = dns_name_fromtext(&keyname, namebuf, dns_rootname, 0, namebuf); + if (result != ISC_R_SUCCESS) { + goto failure; + } + + result = dns_tsigkey_create(&keyname, hmacname, secretstore, + (int)secretsize, false, NULL, 0, 0, mctx, + NULL, &tsigkey); +failure: + if (result != ISC_R_SUCCESS) { + printf(";; Couldn't create key %s: %s\n", keynametext, + isc_result_totext(result)); + } else { + dst_key_setbits(tsigkey->key, digestbits); + } + + isc_mem_free(mctx, secretstore); + dns_name_invalidate(&keyname); + isc_buffer_free(&namebuf); +} + +static isc_result_t +parse_uint_helper(uint32_t *uip, const char *value, uint32_t max, + const char *desc, int base) { + uint32_t n; + isc_result_t result = isc_parse_uint32(&n, value, base); + if (result == ISC_R_SUCCESS && n > max) { + result = ISC_R_RANGE; + } + if (result != ISC_R_SUCCESS) { + printf("invalid %s '%s': %s\n", desc, value, + isc_result_totext(result)); + return (result); + } + *uip = n; + return (ISC_R_SUCCESS); +} + +isc_result_t +parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc) { + return (parse_uint_helper(uip, value, max, desc, 10)); +} + +isc_result_t +parse_xint(uint32_t *uip, const char *value, uint32_t max, const char *desc) { + return (parse_uint_helper(uip, value, max, desc, 0)); +} + +static uint32_t +parse_bits(char *arg, const char *desc, uint32_t max) { + isc_result_t result; + uint32_t tmp; + + result = parse_uint(&tmp, arg, max, desc); + if (result != ISC_R_SUCCESS) { + fatal("couldn't parse digest bits"); + } + tmp = (tmp + 7) & ~0x7U; + return (tmp); +} + +isc_result_t +parse_netprefix(isc_sockaddr_t **sap, const char *value) { + isc_result_t result = ISC_R_SUCCESS; + isc_sockaddr_t *sa = NULL; + struct in_addr in4; + struct in6_addr in6; + uint32_t prefix_length = 0xffffffff; + char *slash = NULL; + bool parsed = false; + bool prefix_parsed = false; + char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")]; + + REQUIRE(sap != NULL && *sap == NULL); + + if (strlcpy(buf, value, sizeof(buf)) >= sizeof(buf)) { + fatal("invalid prefix '%s'\n", value); + } + + sa = isc_mem_allocate(mctx, sizeof(*sa)); + memset(sa, 0, sizeof(*sa)); + + if (strcmp(buf, "0") == 0) { + sa->type.sa.sa_family = AF_UNSPEC; + prefix_length = 0; + goto done; + } + + slash = strchr(buf, '/'); + if (slash != NULL) { + *slash = '\0'; + result = isc_parse_uint32(&prefix_length, slash + 1, 10); + if (result != ISC_R_SUCCESS) { + fatal("invalid prefix length in '%s': %s\n", value, + isc_result_totext(result)); + } + prefix_parsed = true; + } + + if (inet_pton(AF_INET6, buf, &in6) == 1) { + parsed = true; + isc_sockaddr_fromin6(sa, &in6, 0); + if (prefix_length > 128) { + prefix_length = 128; + } + } else if (inet_pton(AF_INET, buf, &in4) == 1) { + parsed = true; + isc_sockaddr_fromin(sa, &in4, 0); + if (prefix_length > 32) { + prefix_length = 32; + } + } else if (prefix_parsed) { + int i; + + for (i = 0; i < 3 && strlen(buf) < sizeof(buf) - 2; i++) { + strlcat(buf, ".0", sizeof(buf)); + if (inet_pton(AF_INET, buf, &in4) == 1) { + parsed = true; + isc_sockaddr_fromin(sa, &in4, 0); + break; + } + } + + if (prefix_length > 32) { + prefix_length = 32; + } + } + + if (!parsed) { + fatal("invalid address '%s'", value); + } + +done: + sa->length = prefix_length; + *sap = sa; + + return (ISC_R_SUCCESS); +} + +/* + * Parse HMAC algorithm specification + */ +void +parse_hmac(const char *hmac) { + char buf[20]; + size_t len; + + REQUIRE(hmac != NULL); + + len = strlen(hmac); + if (len >= sizeof(buf)) { + fatal("unknown key type '%.*s'", (int)len, hmac); + } + strlcpy(buf, hmac, sizeof(buf)); + + digestbits = 0; + + if (strcasecmp(buf, "hmac-md5") == 0) { + hmacname = DNS_TSIG_HMACMD5_NAME; + } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) { + hmacname = DNS_TSIG_HMACMD5_NAME; + digestbits = parse_bits(&buf[9], "digest-bits [0..128]", 128); + } else if (strcasecmp(buf, "hmac-sha1") == 0) { + hmacname = DNS_TSIG_HMACSHA1_NAME; + digestbits = 0; + } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) { + hmacname = DNS_TSIG_HMACSHA1_NAME; + digestbits = parse_bits(&buf[10], "digest-bits [0..160]", 160); + } else if (strcasecmp(buf, "hmac-sha224") == 0) { + hmacname = DNS_TSIG_HMACSHA224_NAME; + } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA224_NAME; + digestbits = parse_bits(&buf[12], "digest-bits [0..224]", 224); + } else if (strcasecmp(buf, "hmac-sha256") == 0) { + hmacname = DNS_TSIG_HMACSHA256_NAME; + } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA256_NAME; + digestbits = parse_bits(&buf[12], "digest-bits [0..256]", 256); + } else if (strcasecmp(buf, "hmac-sha384") == 0) { + hmacname = DNS_TSIG_HMACSHA384_NAME; + } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA384_NAME; + digestbits = parse_bits(&buf[12], "digest-bits [0..384]", 384); + } else if (strcasecmp(buf, "hmac-sha512") == 0) { + hmacname = DNS_TSIG_HMACSHA512_NAME; + } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) { + hmacname = DNS_TSIG_HMACSHA512_NAME; + digestbits = parse_bits(&buf[12], "digest-bits [0..512]", 512); + } else { + fprintf(stderr, + ";; Warning, ignoring " + "invalid TSIG algorithm %s\n", + buf); + } +} + +/* + * Get a key from a named.conf format keyfile + */ +static isc_result_t +read_confkey(void) { + cfg_parser_t *pctx = NULL; + cfg_obj_t *file = NULL; + const cfg_obj_t *keyobj = NULL; + const cfg_obj_t *secretobj = NULL; + const cfg_obj_t *algorithmobj = NULL; + const char *keyname; + const char *secretstr; + const char *algorithm; + isc_result_t result; + + if (!isc_file_exists(keyfile)) { + return (ISC_R_FILENOTFOUND); + } + + result = cfg_parser_create(mctx, NULL, &pctx); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey, &file); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = cfg_map_get(file, "key", &keyobj); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + (void)cfg_map_get(keyobj, "secret", &secretobj); + (void)cfg_map_get(keyobj, "algorithm", &algorithmobj); + if (secretobj == NULL || algorithmobj == NULL) { + fatal("key must have algorithm and secret"); + } + + keyname = cfg_obj_asstring(cfg_map_getname(keyobj)); + secretstr = cfg_obj_asstring(secretobj); + algorithm = cfg_obj_asstring(algorithmobj); + + strlcpy(keynametext, keyname, sizeof(keynametext)); + strlcpy(keysecret, secretstr, sizeof(keysecret)); + parse_hmac(algorithm); + setup_text_key(); + +cleanup: + if (pctx != NULL) { + if (file != NULL) { + cfg_obj_destroy(pctx, &file); + } + cfg_parser_destroy(&pctx); + } + + return (result); +} + +void +setup_file_key(void) { + isc_result_t result; + dst_key_t *dstkey = NULL; + + debug("setup_file_key()"); + + /* Try reading the key from a K* pair */ + result = dst_key_fromnamedfile( + keyfile, NULL, DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, &dstkey); + + /* If that didn't work, try reading it as a session.key keyfile */ + if (result != ISC_R_SUCCESS) { + result = read_confkey(); + if (result == ISC_R_SUCCESS) { + return; + } + } + + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "Couldn't read key from %s: %s\n", keyfile, + isc_result_totext(result)); + goto failure; + } + + switch (dst_key_alg(dstkey)) { + case DST_ALG_HMACMD5: + hmacname = DNS_TSIG_HMACMD5_NAME; + break; + case DST_ALG_HMACSHA1: + hmacname = DNS_TSIG_HMACSHA1_NAME; + break; + case DST_ALG_HMACSHA224: + hmacname = DNS_TSIG_HMACSHA224_NAME; + break; + case DST_ALG_HMACSHA256: + hmacname = DNS_TSIG_HMACSHA256_NAME; + break; + case DST_ALG_HMACSHA384: + hmacname = DNS_TSIG_HMACSHA384_NAME; + break; + case DST_ALG_HMACSHA512: + hmacname = DNS_TSIG_HMACSHA512_NAME; + break; + default: + printf(";; Couldn't create key %s: bad algorithm\n", + keynametext); + goto failure; + } + result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmacname, + dstkey, false, NULL, 0, 0, mctx, + NULL, &tsigkey); + if (result != ISC_R_SUCCESS) { + printf(";; Couldn't create key %s: %s\n", keynametext, + isc_result_totext(result)); + goto failure; + } +failure: + if (dstkey != NULL) { + dst_key_free(&dstkey); + } +} + +static dig_searchlist_t * +make_searchlist_entry(char *domain) { + dig_searchlist_t *search; + search = isc_mem_allocate(mctx, sizeof(*search)); + strlcpy(search->origin, domain, MXNAME); + search->origin[MXNAME - 1] = 0; + ISC_LINK_INIT(search, link); + return (search); +} + +static void +clear_searchlist(void) { + dig_searchlist_t *search; + while ((search = ISC_LIST_HEAD(search_list)) != NULL) { + ISC_LIST_UNLINK(search_list, search, link); + isc_mem_free(mctx, search); + } +} + +static void +create_search_list(irs_resconf_t *resconf) { + irs_resconf_searchlist_t *list; + irs_resconf_search_t *entry; + dig_searchlist_t *search; + + debug("create_search_list()"); + clear_searchlist(); + + list = irs_resconf_getsearchlist(resconf); + for (entry = ISC_LIST_HEAD(*list); entry != NULL; + entry = ISC_LIST_NEXT(entry, link)) + { + search = make_searchlist_entry(entry->domain); + ISC_LIST_APPEND(search_list, search, link); + } +} + +/*% + * Append 'addr' to the list of servers to be queried. This function is only + * called when no server addresses are explicitly specified and either libirs + * returns an empty list of servers to use or none of the addresses returned by + * libirs are usable due to the specified address family restrictions. + */ +static void +add_fallback_nameserver(const char *addr) { + dig_server_t *server = make_server(addr, addr); + ISC_LINK_INIT(server, link); + ISC_LIST_APPEND(server_list, server, link); +} + +/*% + * Setup the system as a whole, reading key information and resolv.conf + * settings. + */ +void +setup_system(bool ipv4only, bool ipv6only) { + irs_resconf_t *resconf = NULL; + isc_result_t result; + + debug("setup_system()"); + + if (ipv4only) { + if (have_ipv4) { + isc_net_disableipv6(); + have_ipv6 = false; + } else { + fatal("can't find IPv4 networking"); + } + } + + if (ipv6only) { + if (have_ipv6) { + isc_net_disableipv4(); + have_ipv4 = false; + } else { + fatal("can't find IPv6 networking"); + } + } + + result = irs_resconf_load(mctx, RESOLV_CONF, &resconf); + if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) { + fatal("parse of %s failed", RESOLV_CONF); + } + + create_search_list(resconf); + if (ndots == -1) { + ndots = irs_resconf_getndots(resconf); + debug("ndots is %d.", ndots); + } + + /* If user doesn't specify server use nameservers from resolv.conf. */ + if (ISC_LIST_EMPTY(server_list)) { + get_server_list(resconf); + } + + /* If we don't find a nameserver fall back to localhost */ + if (ISC_LIST_EMPTY(server_list)) { + if (have_ipv6) { + add_fallback_nameserver("::1"); + } + if (have_ipv4) { + add_fallback_nameserver("127.0.0.1"); + } + } + + irs_resconf_destroy(&resconf); + + if (keyfile[0] != 0) { + setup_file_key(); + } else if (keysecret[0] != 0) { + setup_text_key(); + } + + isc_nonce_buf(cookie_secret, sizeof(cookie_secret)); +} + +/*% + * Override the search list derived from resolv.conf by 'domain'. + */ +void +set_search_domain(char *domain) { + dig_searchlist_t *search; + + clear_searchlist(); + search = make_searchlist_entry(domain); + ISC_LIST_APPEND(search_list, search, link); +} + +/*% + * Setup the ISC and DNS libraries for use by the system. + */ +void +setup_libs(void) { + isc_result_t result; + isc_logconfig_t *logconfig = NULL; + + debug("setup_libs()"); + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + result = isc_net_probeipv4(); + if (result == ISC_R_SUCCESS) { + have_ipv4 = true; + } + + result = isc_net_probeipv6(); + if (result == ISC_R_SUCCESS) { + have_ipv6 = true; + } + if (!have_ipv6 && !have_ipv4) { + fatal("can't find either v4 or v6 networking"); + } + + isc_mem_create(&mctx); + isc_mem_setname(mctx, "dig", NULL); + + isc_log_create(mctx, &lctx, &logconfig); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL); + check_result(result, "isc_log_usechannel"); + + isc_log_setdebuglevel(lctx, 0); + + result = isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr); + check_result(result, "isc_managers_create"); + + result = isc_task_create(taskmgr, 0, &global_task); + check_result(result, "isc_task_create"); + isc_task_setname(global_task, "dig", NULL); + + result = isc_timermgr_create(mctx, &timermgr); + check_result(result, "isc_timermgr_create"); + + result = isc_socketmgr_create(mctx, &socketmgr); + check_result(result, "isc_socketmgr_create"); + + result = dst_lib_init(mctx, NULL); + check_result(result, "dst_lib_init"); + is_dst_up = true; + + isc_mutex_init(&lookup_lock); +} + +typedef struct dig_ednsoptname { + uint32_t code; + const char *name; +} dig_ednsoptname_t; + +dig_ednsoptname_t optnames[] = { + { 1, "LLQ" }, /* draft-sekar-dns-llq */ + { 3, "NSID" }, /* RFC 5001 */ + { 5, "DAU" }, /* RFC 6975 */ + { 6, "DHU" }, /* RFC 6975 */ + { 7, "N3U" }, /* RFC 6975 */ + { 8, "ECS" }, /* RFC 7871 */ + { 9, "EXPIRE" }, /* RFC 7314 */ + { 10, "COOKIE" }, /* RFC 7873 */ + { 11, "KEEPALIVE" }, /* RFC 7828 */ + { 12, "PADDING" }, /* RFC 7830 */ + { 12, "PAD" }, /* shorthand */ + { 13, "CHAIN" }, /* RFC 7901 */ + { 14, "KEY-TAG" }, /* RFC 8145 */ + { 15, "EDE" }, /* ietf-dnsop-extended-error-16 */ + { 16, "CLIENT-TAG" }, /* draft-bellis-dnsop-edns-tags */ + { 17, "SERVER-TAG" }, /* draft-bellis-dnsop-edns-tags */ + { 26946, "DEVICEID" }, /* Brian Hartvigsen */ +}; + +#define N_EDNS_OPTNAMES (sizeof(optnames) / sizeof(optnames[0])) + +void +save_opt(dig_lookup_t *lookup, char *code, char *value) { + isc_result_t result; + uint32_t num = 0; + isc_buffer_t b; + bool found = false; + unsigned int i; + + if (lookup->ednsoptscnt >= EDNSOPT_OPTIONS) { + fatal("too many ednsopts"); + } + + for (i = 0; i < N_EDNS_OPTNAMES; i++) { + if (strcasecmp(code, optnames[i].name) == 0) { + num = optnames[i].code; + found = true; + break; + } + } + + if (!found) { + result = parse_uint(&num, code, 65535, "ednsopt"); + if (result != ISC_R_SUCCESS) { + fatal("bad edns code point: %s", code); + } + } + + if (lookup->ednsopts == NULL) { + cloneopts(lookup, NULL); + } + + if (lookup->ednsopts[lookup->ednsoptscnt].value != NULL) { + isc_mem_free(mctx, lookup->ednsopts[lookup->ednsoptscnt].value); + } + + lookup->ednsopts[lookup->ednsoptscnt].code = num; + lookup->ednsopts[lookup->ednsoptscnt].length = 0; + lookup->ednsopts[lookup->ednsoptscnt].value = NULL; + + if (value != NULL) { + char *buf; + buf = isc_mem_allocate(mctx, strlen(value) / 2 + 1); + isc_buffer_init(&b, buf, (unsigned int)strlen(value) / 2 + 1); + result = isc_hex_decodestring(value, &b); + check_result(result, "isc_hex_decodestring"); + lookup->ednsopts[lookup->ednsoptscnt].value = + isc_buffer_base(&b); + lookup->ednsopts[lookup->ednsoptscnt].length = + isc_buffer_usedlength(&b); + } + + lookup->ednsoptscnt++; +} + +/*% + * Add EDNS0 option record to a message. Currently, the only supported + * options are UDP buffer size, the DO bit, and EDNS options + * (e.g., NSID, COOKIE, client-subnet) + */ +static void +add_opt(dns_message_t *msg, uint16_t udpsize, uint16_t edns, unsigned int flags, + dns_ednsopt_t *opts, size_t count) { + dns_rdataset_t *rdataset = NULL; + isc_result_t result; + + debug("add_opt()"); + result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags, + opts, count); + check_result(result, "dns_message_buildopt"); + result = dns_message_setopt(msg, rdataset); + check_result(result, "dns_message_setopt"); +} + +/*% + * Add a question section to a message, asking for the specified name, + * type, and class. + */ +static void +add_question(dns_message_t *message, dns_name_t *name, dns_rdataclass_t rdclass, + dns_rdatatype_t rdtype) { + dns_rdataset_t *rdataset; + isc_result_t result; + + debug("add_question()"); + rdataset = NULL; + result = dns_message_gettemprdataset(message, &rdataset); + check_result(result, "dns_message_gettemprdataset()"); + dns_rdataset_makequestion(rdataset, rdclass, rdtype); + ISC_LIST_APPEND(name->list, rdataset, link); +} + +/*% + * Check if we're done with all the queued lookups, which is true iff + * all sockets, sends, and recvs are accounted for (counters == 0), + * and the lookup list is empty. + * If we are done, pass control back out to dighost_shutdown() (which is + * part of dig.c, host.c, or nslookup.c) to either shutdown the system as + * a whole or reseed the lookup list. + */ +static void +check_if_done(void) { + debug("check_if_done()"); + debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full"); + if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL && + sendcount == 0) + { + INSIST(sockcount == 0); + INSIST(recvcount == 0); + debug("shutting down"); + dighost_shutdown(); + } +} + +/*% + * Clear out a query when we're done with it. WARNING: This routine + * WILL invalidate the query pointer. + */ +static void +clear_query(dig_query_t *query) { + dig_lookup_t *lookup; + + REQUIRE(query != NULL); + + debug("clear_query(%p)", query); + + if (query->timer != NULL) { + isc_timer_destroy(&query->timer); + } + lookup = query->lookup; + + if (lookup->current_query == query) { + lookup->current_query = NULL; + } + + if (ISC_LINK_LINKED(query, link)) { + query->saved_next = ISC_LIST_NEXT(query, link); + ISC_LIST_UNLINK(lookup->q, query, link); + } + if (ISC_LINK_LINKED(query, clink)) { + ISC_LIST_UNLINK(lookup->connecting, query, clink); + } + INSIST(query->recvspace != NULL); + + if (query->sock != NULL) { + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + } + isc_mem_put(mctx, query->recvspace, COMMSIZE); + isc_mem_put(mctx, query->tmpsendspace, COMMSIZE); + isc_buffer_invalidate(&query->recvbuf); + isc_buffer_invalidate(&query->lengthbuf); + + if (query->waiting_senddone) { + debug("waiting senddone, delay freeing query"); + query->pending_free = true; + } else { + query->magic = 0; + isc_mem_free(mctx, query); + } +} + +/*% + * Try and clear out a lookup if we're done with it. Return true if + * the lookup was successfully cleared. If true is returned, the + * lookup pointer has been invalidated. + */ +static bool +try_clear_lookup(dig_lookup_t *lookup) { + dig_query_t *q; + + REQUIRE(lookup != NULL); + + debug("try_clear_lookup(%p)", lookup); + + if (ISC_LIST_HEAD(lookup->q) != NULL || + ISC_LIST_HEAD(lookup->connecting) != NULL) + { + if (debugging) { + q = ISC_LIST_HEAD(lookup->q); + while (q != NULL) { + debug("query to %s still pending", q->servname); + q = ISC_LIST_NEXT(q, link); + } + + q = ISC_LIST_HEAD(lookup->connecting); + while (q != NULL) { + debug("query to %s still connecting", + q->servname); + q = ISC_LIST_NEXT(q, clink); + } + } + return (false); + } + + /* + * At this point, we know there are no queries on the lookup, + * so can make it go away also. + */ + destroy_lookup(lookup); + return (true); +} + +void +destroy_lookup(dig_lookup_t *lookup) { + dig_server_t *s; + void *ptr; + + debug("destroy"); + s = ISC_LIST_HEAD(lookup->my_server_list); + while (s != NULL) { + debug("freeing server %p belonging to %p", s, lookup); + ptr = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(lookup->my_server_list, (dig_server_t *)ptr, + link); + isc_mem_free(mctx, ptr); + } + if (lookup->sendmsg != NULL) { + dns_message_detach(&lookup->sendmsg); + } + if (lookup->querysig != NULL) { + debug("freeing buffer %p", lookup->querysig); + isc_buffer_free(&lookup->querysig); + } + if (lookup->sendspace != NULL) { + isc_mem_put(mctx, lookup->sendspace, COMMSIZE); + } + + if (lookup->tsigctx != NULL) { + dst_context_destroy(&lookup->tsigctx); + } + + if (lookup->ecs_addr != NULL) { + isc_mem_free(mctx, lookup->ecs_addr); + } + + if (lookup->ednsopts != NULL) { + size_t i; + for (i = 0; i < EDNSOPT_OPTIONS; i++) { + if (lookup->ednsopts[i].value != NULL) { + isc_mem_free(mctx, lookup->ednsopts[i].value); + } + } + isc_mem_free(mctx, lookup->ednsopts); + } + + isc_mem_free(mctx, lookup); +} + +/*% + * If we can, start the next lookup in the queue running. + * This assumes that the lookup on the head of the queue hasn't been + * started yet. It also removes the lookup from the head of the queue, + * setting the current_lookup pointer pointing to it. + */ +void +start_lookup(void) { + debug("start_lookup()"); + if (cancel_now) { + return; + } + + /* + * If there's a current lookup running, we really shouldn't get + * here. + */ + INSIST(current_lookup == NULL); + + current_lookup = ISC_LIST_HEAD(lookup_list); + /* + * Put the current lookup somewhere so cancel_all can find it + */ + if (current_lookup != NULL) { + ISC_LIST_DEQUEUE(lookup_list, current_lookup, link); + if (setup_lookup(current_lookup)) { + do_lookup(current_lookup); + } else if (next_origin(current_lookup)) { + check_next_lookup(current_lookup); + } + } else { + check_if_done(); + } +} + +/*% + * If we can, clear the current lookup and start the next one running. + * This calls try_clear_lookup, so may invalidate the lookup pointer. + */ +static void +check_next_lookup(dig_lookup_t *lookup) { + INSIST(!free_now); + + debug("check_next_lookup(%p)", lookup); + + if (ISC_LIST_HEAD(lookup->q) != NULL) { + debug("still have a worker"); + return; + } + if (try_clear_lookup(lookup)) { + current_lookup = NULL; + start_lookup(); + } +} + +/*% + * Create and queue a new lookup as a followup to the current lookup, + * based on the supplied message and section. This is used in trace and + * name server search modes to start a new lookup using servers from + * NS records in a reply. Returns the number of followup lookups made. + */ +static int +followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section) { + dig_lookup_t *lookup = NULL; + dig_server_t *srv = NULL; + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_name_t *name = NULL; + isc_result_t result; + bool success = false; + int numLookups = 0; + int num; + isc_result_t lresult, addresses_result; + char bad_namestr[DNS_NAME_FORMATSIZE]; + dns_name_t *domain; + bool horizontal = false, bad = false; + + INSIST(!free_now); + + debug("following up %s", query->lookup->textname); + + addresses_result = ISC_R_SUCCESS; + bad_namestr[0] = '\0'; + for (result = dns_message_firstname(msg, section); + result == ISC_R_SUCCESS; + result = dns_message_nextname(msg, section)) + { + name = NULL; + dns_message_currentname(msg, section, &name); + + if (section == DNS_SECTION_AUTHORITY) { + rdataset = NULL; + result = dns_message_findtype(name, dns_rdatatype_soa, + 0, &rdataset); + if (result == ISC_R_SUCCESS) { + return (0); + } + } + rdataset = NULL; + result = dns_message_findtype(name, dns_rdatatype_ns, 0, + &rdataset); + if (result != ISC_R_SUCCESS) { + continue; + } + + debug("found NS set"); + + if (query->lookup->trace && !query->lookup->trace_root) { + dns_namereln_t namereln; + unsigned int nlabels; + int order; + + domain = dns_fixedname_name(&query->lookup->fdomain); + namereln = dns_name_fullcompare(name, domain, &order, + &nlabels); + if (namereln == dns_namereln_equal) { + if (!horizontal) { + dighost_warning("BAD (HORIZONTAL) " + "REFERRAL"); + } + horizontal = true; + } else if (namereln != dns_namereln_subdomain) { + if (!bad) { + dighost_warning("BAD REFERRAL"); + } + bad = true; + continue; + } + } + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) + { + char namestr[DNS_NAME_FORMATSIZE]; + dns_rdata_ns_t ns; + + if (query->lookup->trace_root && + query->lookup->nsfound >= MXSERV) + { + break; + } + + dns_rdataset_current(rdataset, &rdata); + + query->lookup->nsfound++; + result = dns_rdata_tostruct(&rdata, &ns, NULL); + check_result(result, "dns_rdata_tostruct"); + dns_name_format(&ns.name, namestr, sizeof(namestr)); + dns_rdata_freestruct(&ns); + + /* Initialize lookup if we've not yet */ + debug("found NS %s", namestr); + if (!success) { + success = true; + lookup_counter++; + lookup = requeue_lookup(query->lookup, false); + cancel_lookup(query->lookup); + lookup->doing_xfr = false; + if (!lookup->trace_root && + section == DNS_SECTION_ANSWER) + { + lookup->trace = false; + } else { + lookup->trace = query->lookup->trace; + } + lookup->ns_search_only = + query->lookup->ns_search_only; + lookup->trace_root = false; + if (lookup->ns_search_only) { + lookup->recurse = false; + } + domain = dns_fixedname_name(&lookup->fdomain); + dns_name_copynf(name, domain); + } + debug("adding server %s", namestr); + num = getaddresses(lookup, namestr, &lresult); + if (lresult != ISC_R_SUCCESS) { + printf("couldn't get address for '%s': %s\n", + namestr, isc_result_totext(lresult)); + if (addresses_result == ISC_R_SUCCESS) { + addresses_result = lresult; + strlcpy(bad_namestr, namestr, + sizeof(bad_namestr)); + } + } + numLookups += num; + dns_rdata_reset(&rdata); + } + } + if (numLookups == 0 && addresses_result != ISC_R_SUCCESS) { + fatal("couldn't get address for '%s': %s", bad_namestr, + isc_result_totext(result)); + } + + if (lookup == NULL && section == DNS_SECTION_ANSWER && + (query->lookup->trace || query->lookup->ns_search_only)) + { + return (followup_lookup(msg, query, DNS_SECTION_AUTHORITY)); + } + + /* + * Randomize the order the nameserver will be tried. + */ + if (numLookups > 1) { + uint32_t i, j; + dig_serverlist_t my_server_list; + dig_server_t *next; + + ISC_LIST_INIT(my_server_list); + + i = numLookups; + for (srv = ISC_LIST_HEAD(lookup->my_server_list); srv != NULL; + srv = ISC_LIST_HEAD(lookup->my_server_list)) + { + INSIST(i > 0); + j = isc_random_uniform(i); + next = ISC_LIST_NEXT(srv, link); + while (j-- > 0 && next != NULL) { + srv = next; + next = ISC_LIST_NEXT(srv, link); + } + ISC_LIST_DEQUEUE(lookup->my_server_list, srv, link); + ISC_LIST_APPEND(my_server_list, srv, link); + i--; + } + ISC_LIST_APPENDLIST(lookup->my_server_list, my_server_list, + link); + } + + return (numLookups); +} + +/*% + * Create and queue a new lookup using the next origin from the search + * list, read in setup_system(). + * + * Return true iff there was another searchlist entry. + */ +static bool +next_origin(dig_lookup_t *oldlookup) { + dig_lookup_t *newlookup; + dig_searchlist_t *search; + dns_fixedname_t fixed; + dns_name_t *name; + isc_result_t result; + + INSIST(!free_now); + + debug("next_origin(%p)", oldlookup); + debug("following up %s", oldlookup->textname); + + if (!usesearch) { + /* + * We're not using a search list, so don't even think + * about finding the next entry. + */ + return (false); + } + + /* + * Check for a absolute name or ndots being met. + */ + name = dns_fixedname_initname(&fixed); + result = dns_name_fromstring2(name, oldlookup->textname, NULL, 0, NULL); + if (result == ISC_R_SUCCESS && + (dns_name_isabsolute(name) || + (int)dns_name_countlabels(name) > ndots)) + { + return (false); + } + + if (oldlookup->origin == NULL && !oldlookup->need_search) { + /* + * Then we just did rootorg; there's nothing left. + */ + return (false); + } + if (oldlookup->origin == NULL && oldlookup->need_search) { + newlookup = requeue_lookup(oldlookup, true); + newlookup->origin = ISC_LIST_HEAD(search_list); + newlookup->need_search = false; + } else { + search = ISC_LIST_NEXT(oldlookup->origin, link); + if (search == NULL && oldlookup->done_as_is) { + return (false); + } + newlookup = requeue_lookup(oldlookup, true); + newlookup->origin = search; + } + cancel_lookup(oldlookup); + return (true); +} + +/*% + * Insert an SOA record into the sendmessage in a lookup. Used for + * creating IXFR queries. + */ +static void +insert_soa(dig_lookup_t *lookup) { + isc_result_t result; + dns_rdata_soa_t soa; + dns_rdata_t *rdata = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdataset_t *rdataset = NULL; + dns_name_t *soaname = NULL; + + debug("insert_soa(%p)", lookup); + soa.mctx = mctx; + soa.serial = lookup->ixfr_serial; + soa.refresh = 0; + soa.retry = 0; + soa.expire = 0; + soa.minimum = 0; + soa.common.rdclass = lookup->rdclass; + soa.common.rdtype = dns_rdatatype_soa; + + dns_name_init(&soa.origin, NULL); + dns_name_init(&soa.contact, NULL); + + dns_name_clone(dns_rootname, &soa.origin); + dns_name_clone(dns_rootname, &soa.contact); + + isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore, + sizeof(lookup->rdatastore)); + + result = dns_message_gettemprdata(lookup->sendmsg, &rdata); + check_result(result, "dns_message_gettemprdata"); + + result = dns_rdata_fromstruct(rdata, lookup->rdclass, dns_rdatatype_soa, + &soa, &lookup->rdatabuf); + check_result(result, "isc_rdata_fromstruct"); + + result = dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist); + check_result(result, "dns_message_gettemprdatalist"); + + result = dns_message_gettemprdataset(lookup->sendmsg, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + + dns_rdatalist_init(rdatalist); + rdatalist->type = dns_rdatatype_soa; + rdatalist->rdclass = lookup->rdclass; + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + + dns_rdatalist_tordataset(rdatalist, rdataset); + + result = dns_message_gettempname(lookup->sendmsg, &soaname); + check_result(result, "dns_message_gettempname"); + dns_name_clone(lookup->name, soaname); + ISC_LIST_INIT(soaname->list); + ISC_LIST_APPEND(soaname->list, rdataset, link); + dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY); +} + +static void +compute_cookie(unsigned char *clientcookie, size_t len) { + /* XXXMPA need to fix, should be per server. */ + INSIST(len >= 8U); + memmove(clientcookie, cookie_secret, 8); +} + +/*% + * Setup the supplied lookup structure, making it ready to start sending + * queries to servers. Create and initialize the message to be sent as + * well as the query structures and buffer space for the replies. If the + * server list is empty, clone it from the system default list. + */ +bool +setup_lookup(dig_lookup_t *lookup) { + isc_result_t result; + unsigned int len; + dig_server_t *serv; + dig_query_t *query; + isc_buffer_t b; + dns_compress_t cctx; + char store[MXNAME]; + char ecsbuf[20]; + char cookiebuf[256]; + char *origin = NULL; + char *textname = NULL; + + REQUIRE(lookup != NULL); + +#ifdef HAVE_LIBIDN2 + char idn_origin[MXNAME], idn_textname[MXNAME]; + + result = dns_name_settotextfilter(lookup->idnout ? idn_output_filter + : NULL); + check_result(result, "dns_name_settotextfilter"); +#endif /* HAVE_LIBIDN2 */ + + INSIST(!free_now); + + debug("setup_lookup(%p)", lookup); + + dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &lookup->sendmsg); + + if (lookup->new_search) { + debug("resetting lookup counter."); + lookup_counter = 0; + } + + if (ISC_LIST_EMPTY(lookup->my_server_list)) { + debug("cloning server list"); + clone_server_list(server_list, &lookup->my_server_list); + } + result = dns_message_gettempname(lookup->sendmsg, &lookup->name); + check_result(result, "dns_message_gettempname"); + + isc_buffer_init(&lookup->namebuf, lookup->name_space, + sizeof(lookup->name_space)); + isc_buffer_init(&lookup->onamebuf, lookup->oname_space, + sizeof(lookup->oname_space)); + + /* + * We cannot convert `textname' and `origin' separately. + * `textname' doesn't contain TLD, but local mapping needs + * TLD. + */ + textname = lookup->textname; +#ifdef HAVE_LIBIDN2 + if (lookup->idnin) { + idn_locale_to_ace(textname, idn_textname, sizeof(idn_textname)); + debug("idn_textname: %s", idn_textname); + textname = idn_textname; + } +#endif /* HAVE_LIBIDN2 */ + + /* + * If the name has too many dots, force the origin to be NULL + * (which produces an absolute lookup). Otherwise, take the origin + * we have if there's one in the struct already. If it's NULL, + * take the first entry in the searchlist iff either usesearch + * is TRUE or we got a domain line in the resolv.conf file. + */ + if (lookup->new_search) { + if ((count_dots(textname) >= ndots) || !usesearch) { + lookup->origin = NULL; /* Force abs lookup */ + lookup->done_as_is = true; + lookup->need_search = usesearch; + } else if (lookup->origin == NULL && usesearch) { + lookup->origin = ISC_LIST_HEAD(search_list); + lookup->need_search = false; + } + } + + if (lookup->origin != NULL) { + debug("trying origin %s", lookup->origin->origin); + result = dns_message_gettempname(lookup->sendmsg, + &lookup->oname); + check_result(result, "dns_message_gettempname"); + /* XXX Helper funct to conv char* to name? */ + origin = lookup->origin->origin; +#ifdef HAVE_LIBIDN2 + if (lookup->idnin) { + idn_locale_to_ace(origin, idn_origin, + sizeof(idn_origin)); + debug("trying idn origin %s", idn_origin); + origin = idn_origin; + } +#endif /* HAVE_LIBIDN2 */ + len = (unsigned int)strlen(origin); + isc_buffer_init(&b, origin, len); + isc_buffer_add(&b, len); + result = dns_name_fromtext(lookup->oname, &b, dns_rootname, 0, + &lookup->onamebuf); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(lookup->sendmsg, &lookup->name); + dns_message_puttempname(lookup->sendmsg, + &lookup->oname); + fatal("'%s' is not in legal name syntax (%s)", origin, + isc_result_totext(result)); + } + if (lookup->trace && lookup->trace_root) { + dns_name_clone(dns_rootname, lookup->name); + } else { + dns_fixedname_t fixed; + dns_name_t *name; + + name = dns_fixedname_initname(&fixed); + len = (unsigned int)strlen(textname); + isc_buffer_init(&b, textname, len); + isc_buffer_add(&b, len); + result = dns_name_fromtext(name, &b, NULL, 0, NULL); + if (result == ISC_R_SUCCESS) { + if (!dns_name_isabsolute(name)) { + result = dns_name_concatenate( + name, lookup->oname, + lookup->name, &lookup->namebuf); + } else { + result = dns_name_copy( + name, lookup->name, + &lookup->namebuf); + } + } + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(lookup->sendmsg, + &lookup->name); + dns_message_puttempname(lookup->sendmsg, + &lookup->oname); + if (result == DNS_R_NAMETOOLONG) { + return (false); + } + fatal("'%s' is not in legal name syntax (%s)", + lookup->textname, + isc_result_totext(result)); + } + } + dns_message_puttempname(lookup->sendmsg, &lookup->oname); + } else { + debug("using root origin"); + if (lookup->trace && lookup->trace_root) { + dns_name_clone(dns_rootname, lookup->name); + } else { + len = (unsigned int)strlen(textname); + isc_buffer_init(&b, textname, len); + isc_buffer_add(&b, len); + result = dns_name_fromtext(lookup->name, &b, + dns_rootname, 0, + &lookup->namebuf); + } + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(lookup->sendmsg, &lookup->name); + warn("'%s' is not a legal name " + "(%s)", + lookup->textname, isc_result_totext(result)); +#if TARGET_OS_IPHONE + check_next_lookup(current_lookup); + return (false); +#else /* if TARGET_OS_IPHONE */ + digexit(); +#endif /* if TARGET_OS_IPHONE */ + } + } + dns_name_format(lookup->name, store, sizeof(store)); + dighost_trying(store, lookup); + INSIST(dns_name_isabsolute(lookup->name)); + + lookup->sendmsg->id = (dns_messageid_t)isc_random16(); + lookup->sendmsg->opcode = lookup->opcode; + lookup->msgcounter = 0; + + /* + * If this is a trace request, completely disallow recursion after + * looking up the root name servers, since it's meaningless for traces. + */ + if ((lookup->trace || lookup->ns_search_only) && !lookup->trace_root) { + lookup->recurse = false; + } + + if (lookup->recurse && lookup->rdtype != dns_rdatatype_axfr && + lookup->rdtype != dns_rdatatype_ixfr) + { + debug("recursive query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD; + } + + /* XXX aaflag */ + if (lookup->aaonly) { + debug("AA query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA; + } + + if (lookup->adflag) { + debug("AD query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD; + } + + if (lookup->cdflag) { + debug("CD query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD; + } + + if (lookup->raflag) { + debug("RA query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RA; + } + + if (lookup->tcflag) { + debug("TC query"); + lookup->sendmsg->flags |= DNS_MESSAGEFLAG_TC; + } + + if (lookup->zflag) { + debug("Z query"); + lookup->sendmsg->flags |= 0x0040U; + } + + dns_message_addname(lookup->sendmsg, lookup->name, + DNS_SECTION_QUESTION); + + if (lookup->trace && lookup->trace_root) { + lookup->qrdtype = lookup->rdtype; + lookup->rdtype = dns_rdatatype_ns; + } + + if ((lookup->rdtype == dns_rdatatype_axfr) || + (lookup->rdtype == dns_rdatatype_ixfr)) + { + /* + * Force TCP mode if we're doing an axfr. + */ + if (lookup->rdtype == dns_rdatatype_axfr) { + lookup->doing_xfr = true; + lookup->tcp_mode = true; + } else if (lookup->tcp_mode) { + lookup->doing_xfr = true; + } + } + + if (!lookup->header_only) { + add_question(lookup->sendmsg, lookup->name, lookup->rdclass, + lookup->rdtype); + } + + /* add_soa */ + if (lookup->rdtype == dns_rdatatype_ixfr) { + insert_soa(lookup); + } + + /* XXX Insist this? */ + lookup->tsigctx = NULL; + lookup->querysig = NULL; + if (tsigkey != NULL) { + debug("initializing keys"); + result = dns_message_settsigkey(lookup->sendmsg, tsigkey); + check_result(result, "dns_message_settsigkey"); + } + + lookup->sendspace = isc_mem_get(mctx, COMMSIZE); + + result = dns_compress_init(&cctx, -1, mctx); + check_result(result, "dns_compress_init"); + + debug("starting to render the message"); + isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE); + result = dns_message_renderbegin(lookup->sendmsg, &cctx, + &lookup->renderbuf); + check_result(result, "dns_message_renderbegin"); + if (lookup->udpsize > 0 || lookup->dnssec || lookup->edns > -1 || + lookup->ecs_addr != NULL) + { +#define MAXOPTS (EDNSOPT_OPTIONS + DNS_EDNSOPTIONS) + dns_ednsopt_t opts[MAXOPTS]; + unsigned int flags; + unsigned int i = 0; + + /* + * There can't be more than MAXOPTS options to send: + * a maximum of EDNSOPT_OPTIONS set by +ednsopt + * and DNS_EDNSOPTIONS set by other arguments + * (+nsid, +cookie, etc). + */ + if (lookup->udpsize < 0) { + lookup->udpsize = DEFAULT_EDNS_BUFSIZE; + } + if (lookup->edns < 0) { + lookup->edns = DEFAULT_EDNS_VERSION; + } + + if (lookup->nsid) { + INSIST(i < MAXOPTS); + opts[i].code = DNS_OPT_NSID; + opts[i].length = 0; + opts[i].value = NULL; + i++; + } + + if (lookup->ecs_addr != NULL) { + uint8_t addr[16]; + uint16_t family = 0; + uint32_t plen; + struct sockaddr *sa; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + size_t addrl; + + sa = &lookup->ecs_addr->type.sa; + plen = lookup->ecs_addr->length; + + /* Round up prefix len to a multiple of 8 */ + addrl = (plen + 7) / 8; + + INSIST(i < MAXOPTS); + opts[i].code = DNS_OPT_CLIENT_SUBNET; + opts[i].length = (uint16_t)addrl + 4; + check_result(result, "isc_buffer_allocate"); + + /* + * XXXMUKS: According to RFC7871, "If there is + * no ADDRESS set, i.e., SOURCE PREFIX-LENGTH is + * set to 0, then FAMILY SHOULD be set to the + * transport over which the query is sent." + * + * However, at this point we don't know what + * transport(s) we'll be using, so we can't + * set the value now. For now, we're using + * IPv4 as the default the +subnet option + * used an IPv4 prefix, or for +subnet=0, + * and IPv6 if the +subnet option used an + * IPv6 prefix. + * + * (For future work: preserve the offset into + * the buffer where the family field is; + * that way we can update it in send_udp() + * or send_tcp_connect() once we know + * what it outght to be.) + */ + switch (sa->sa_family) { + case AF_UNSPEC: + INSIST(plen == 0); + family = 1; + break; + case AF_INET: + INSIST(plen <= 32); + family = 1; + sin = (struct sockaddr_in *)sa; + memmove(addr, &sin->sin_addr, addrl); + break; + case AF_INET6: + INSIST(plen <= 128); + family = 2; + sin6 = (struct sockaddr_in6 *)sa; + memmove(addr, &sin6->sin6_addr, addrl); + break; + default: + UNREACHABLE(); + } + + isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf)); + /* family */ + isc_buffer_putuint16(&b, family); + /* source prefix-length */ + isc_buffer_putuint8(&b, plen); + /* scope prefix-length */ + isc_buffer_putuint8(&b, 0); + + /* address */ + if (addrl > 0) { + /* Mask off last address byte */ + if ((plen % 8) != 0) { + addr[addrl - 1] &= ~0U + << (8 - (plen % 8)); + } + isc_buffer_putmem(&b, addr, (unsigned)addrl); + } + + opts[i].value = (uint8_t *)ecsbuf; + i++; + } + + if (lookup->sendcookie) { + INSIST(i < MAXOPTS); + opts[i].code = DNS_OPT_COOKIE; + if (lookup->cookie != NULL) { + isc_buffer_init(&b, cookiebuf, + sizeof(cookiebuf)); + result = isc_hex_decodestring(lookup->cookie, + &b); + check_result(result, "isc_hex_decodestring"); + opts[i].value = isc_buffer_base(&b); + opts[i].length = isc_buffer_usedlength(&b); + } else { + compute_cookie(cookie, sizeof(cookie)); + opts[i].length = 8; + opts[i].value = cookie; + } + i++; + } + + if (lookup->expire) { + INSIST(i < MAXOPTS); + opts[i].code = DNS_OPT_EXPIRE; + opts[i].length = 0; + opts[i].value = NULL; + i++; + } + + if (lookup->tcp_keepalive) { + INSIST(i < MAXOPTS); + opts[i].code = DNS_OPT_TCP_KEEPALIVE; + opts[i].length = 0; + opts[i].value = NULL; + i++; + } + + if (lookup->ednsoptscnt != 0) { + INSIST(i + lookup->ednsoptscnt <= MAXOPTS); + memmove(&opts[i], lookup->ednsopts, + sizeof(dns_ednsopt_t) * lookup->ednsoptscnt); + i += lookup->ednsoptscnt; + } + + if (lookup->padding != 0 && (i >= MAXOPTS)) { + debug("turned off padding because of EDNS overflow"); + lookup->padding = 0; + } + + if (lookup->padding != 0) { + INSIST(i < MAXOPTS); + opts[i].code = DNS_OPT_PAD; + opts[i].length = 0; + opts[i].value = NULL; + i++; + dns_message_setpadding(lookup->sendmsg, + lookup->padding); + } + + flags = lookup->ednsflags; + flags &= ~DNS_MESSAGEEXTFLAG_DO; + if (lookup->dnssec) { + flags |= DNS_MESSAGEEXTFLAG_DO; + } + add_opt(lookup->sendmsg, lookup->udpsize, lookup->edns, flags, + opts, i); + } + + result = dns_message_rendersection(lookup->sendmsg, + DNS_SECTION_QUESTION, 0); + check_result(result, "dns_message_rendersection"); + result = dns_message_rendersection(lookup->sendmsg, + DNS_SECTION_AUTHORITY, 0); + check_result(result, "dns_message_rendersection"); + result = dns_message_renderend(lookup->sendmsg); + check_result(result, "dns_message_renderend"); + debug("done rendering"); + + dns_compress_invalidate(&cctx); + + /* + * Force TCP mode if the request is larger than 512 bytes. + */ + if (isc_buffer_usedlength(&lookup->renderbuf) > 512) { + lookup->tcp_mode = true; + } + + lookup->pending = false; + + for (serv = ISC_LIST_HEAD(lookup->my_server_list); serv != NULL; + serv = ISC_LIST_NEXT(serv, link)) + { + query = isc_mem_allocate(mctx, sizeof(dig_query_t)); + debug("create query %p linked to lookup %p", query, lookup); + query->lookup = lookup; + query->timer = NULL; + query->waiting_connect = false; + query->waiting_senddone = false; + query->pending_free = false; + query->recv_made = false; + query->first_pass = true; + query->first_soa_rcvd = false; + query->second_rr_rcvd = false; + query->first_repeat_rcvd = false; + query->warn_id = true; + query->timedout = false; + query->first_rr_serial = 0; + query->second_rr_serial = 0; + query->servname = serv->servername; + query->userarg = serv->userarg; + query->rr_count = 0; + query->msg_count = 0; + query->byte_count = 0; + query->ixfr_axfr = false; + query->sock = NULL; + query->recvspace = isc_mem_get(mctx, COMMSIZE); + query->tmpsendspace = isc_mem_get(mctx, COMMSIZE); + if (query->recvspace == NULL) { + fatal("memory allocation failure"); + } + + isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE); + isc_buffer_init(&query->lengthbuf, query->lengthspace, 2); + isc_buffer_init(&query->tmpsendbuf, query->tmpsendspace, + COMMSIZE); + query->sendbuf = lookup->renderbuf; + + isc_time_settoepoch(&query->time_sent); + isc_time_settoepoch(&query->time_recv); + + ISC_LINK_INIT(query, clink); + ISC_LINK_INIT(query, link); + query->saved_next = NULL; + + query->magic = DIG_QUERY_MAGIC; + + ISC_LIST_ENQUEUE(lookup->q, query, link); + } + + return (true); +} + +/*% + * Event handler for send completion. Track send counter, and clear out + * the query if the send was canceled. + */ +static void +send_done(isc_task_t *_task, isc_event_t *event) { + dig_query_t *query, *next; + dig_lookup_t *l; + + REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); + + UNUSED(_task); + + LOCK_LOOKUP; + + debug("send_done(%p)", event->ev_arg); + sendcount--; + debug("sendcount=%d", sendcount); + INSIST(sendcount >= 0); + + query = event->ev_arg; + REQUIRE(DIG_VALID_QUERY(query)); + query->waiting_senddone = false; + l = query->lookup; + + if (l == current_lookup && l->ns_search_only && !l->trace_root && + !l->tcp_mode) + { + debug("sending next, since searching"); + next = query->pending_free ? query->saved_next + : ISC_LIST_NEXT(query, link); + if (next != NULL) { + send_udp(next); + } + } + + isc_event_free(&event); + + if (query->pending_free) { + query->magic = 0; + isc_mem_free(mctx, query); + } + + check_if_done(); + UNLOCK_LOOKUP; +} + +/*% + * Cancel a lookup, sending isc_socket_cancel() requests to all outstanding + * IO sockets. The cancel handlers should take care of cleaning up the + * query and lookup structures + */ +static void +cancel_lookup(dig_lookup_t *lookup) { + dig_query_t *query, *next; + + debug("cancel_lookup(%p)", lookup); + query = ISC_LIST_HEAD(lookup->q); + while (query != NULL) { + REQUIRE(DIG_VALID_QUERY(query)); + next = ISC_LIST_NEXT(query, link); + if (query->sock != NULL) { + isc_socket_cancel(query->sock, global_task, + ISC_SOCKCANCEL_ALL); + check_if_done(); + } else { + clear_query(query); + } + query = next; + } + lookup->pending = false; + lookup->retries = 0; +} + +static void +bringup_timer(dig_query_t *query, unsigned int default_timeout) { + dig_lookup_t *l; + unsigned int local_timeout; + isc_result_t result; + REQUIRE(DIG_VALID_QUERY(query)); + + debug("bringup_timer(%p)", query); + /* + * If the timer already exists, that means we're calling this + * a second time (for a retry). Don't need to recreate it, + * just reset it. + */ + l = query->lookup; + if (ISC_LINK_LINKED(query, link) && ISC_LIST_NEXT(query, link) != NULL) + { + local_timeout = SERVER_TIMEOUT; + } else { + if (timeout == 0) { + local_timeout = default_timeout; + } else { + local_timeout = timeout; + } + } + debug("have local timeout of %d", local_timeout); + isc_interval_set(&l->interval, local_timeout, 0); + if (query->timer != NULL) { + isc_timer_destroy(&query->timer); + } + result = isc_timer_create(timermgr, isc_timertype_once, NULL, + &l->interval, global_task, connect_timeout, + query, &query->timer); + check_result(result, "isc_timer_create"); +} + +static void +force_timeout(dig_query_t *query) { + isc_event_t *event; + + debug("force_timeout(%p)", query); + event = isc_event_allocate(mctx, query, ISC_TIMEREVENT_IDLE, + connect_timeout, query, sizeof(isc_event_t)); + isc_task_send(global_task, &event); + + /* + * The timer may have expired if, for example, get_address() takes + * long time and the timer was running on a different thread. + * We need to cancel the possible timeout event not to confuse + * ourselves due to the duplicate events. + */ + if (query->timer != NULL) { + isc_timer_destroy(&query->timer); + } +} + +static void +connect_done(isc_task_t *task, isc_event_t *event); + +/*% + * Unlike send_udp, this can't be called multiple times with the same + * query. When we retry TCP, we requeue the whole lookup, which should + * start anew. + */ +static void +send_tcp_connect(dig_query_t *query) { + isc_result_t result; + dig_query_t *next; + dig_lookup_t *l; + REQUIRE(DIG_VALID_QUERY(query)); + + debug("send_tcp_connect(%p)", query); + + l = query->lookup; + query->waiting_connect = true; + query->lookup->current_query = query; + result = get_address(query->servname, port, &query->sockaddr); + if (result != ISC_R_SUCCESS) { + /* + * This servname doesn't have an address. Try the next server + * by triggering an immediate 'timeout' (we lie, but the effect + * is the same). + */ + force_timeout(query); + return; + } + + if (!l->mapped && isc_sockaddr_pf(&query->sockaddr) == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&query->sockaddr.type.sin6.sin6_addr)) + { + isc_netaddr_t netaddr; + char buf[ISC_NETADDR_FORMATSIZE]; + + isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr); + isc_netaddr_format(&netaddr, buf, sizeof(buf)); + dighost_warning("Skipping mapped address '%s'", buf); + + query->waiting_connect = false; + if (ISC_LINK_LINKED(query, link)) { + next = ISC_LIST_NEXT(query, link); + } else { + next = NULL; + } + l = query->lookup; + clear_query(query); + if (next == NULL) { + dighost_warning("No acceptable nameservers"); + check_next_lookup(l); + return; + } + send_tcp_connect(next); + return; + } + + INSIST(query->sock == NULL); + + if (keep != NULL && isc_sockaddr_equal(&keepaddr, &query->sockaddr)) { + sockcount++; + isc_socket_attach(keep, &query->sock); + query->waiting_connect = false; + launch_next_query(query, true); + goto search; + } + + result = isc_socket_create(socketmgr, isc_sockaddr_pf(&query->sockaddr), + isc_sockettype_tcp, &query->sock); + check_result(result, "isc_socket_create"); + sockcount++; + debug("sockcount=%d", sockcount); + if (query->lookup->dscp != -1) { + isc_socket_dscp(query->sock, query->lookup->dscp); + } + isc_socket_ipv6only(query->sock, !query->lookup->mapped); + if (specified_source) { + result = isc_socket_bind(query->sock, &bind_address, + ISC_SOCKET_REUSEADDRESS); + } else { + if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) && have_ipv4) + { + isc_sockaddr_any(&bind_any); + } else { + isc_sockaddr_any6(&bind_any); + } + result = isc_socket_bind(query->sock, &bind_any, 0); + } + check_result(result, "isc_socket_bind"); + bringup_timer(query, TCP_TIMEOUT); + result = isc_socket_connect(query->sock, &query->sockaddr, global_task, + connect_done, query); + check_result(result, "isc_socket_connect"); +search: + /* + * If we're at the endgame of a nameserver search, we need to + * immediately bring up all the queries. Do it here. + */ + if (l->ns_search_only && !l->trace_root) { + debug("sending next, since searching"); + if (ISC_LINK_LINKED(query, link)) { + next = ISC_LIST_NEXT(query, link); + ISC_LIST_DEQUEUE(l->q, query, link); + } else { + next = NULL; + } + ISC_LIST_ENQUEUE(l->connecting, query, clink); + if (next != NULL) { + send_tcp_connect(next); + } + } +} + +static void +print_query_size(dig_query_t *query) { + if (!yaml) { + printf(";; QUERY SIZE: %u\n\n", + isc_buffer_usedlength(&query->lookup->renderbuf)); + } +} + +/*% + * Send a UDP packet to the remote nameserver, possible starting the + * recv action as well. Also make sure that the timer is running and + * is properly reset. + */ +static void +send_udp(dig_query_t *query) { + dig_lookup_t *l = NULL; + isc_result_t result; + dig_query_t *next; + isc_region_t r; + isc_socketevent_t *sevent; + REQUIRE(DIG_VALID_QUERY(query)); + + debug("send_udp(%p)", query); + + l = query->lookup; + bringup_timer(query, UDP_TIMEOUT); + l->current_query = query; + debug("working on lookup %p, query %p", query->lookup, query); + if (!query->recv_made) { + /* XXX Check the sense of this, need assertion? */ + query->waiting_connect = false; + result = get_address(query->servname, port, &query->sockaddr); + if (result != ISC_R_SUCCESS) { + /* This servname doesn't have an address. */ + force_timeout(query); + return; + } + + if (!l->mapped && + isc_sockaddr_pf(&query->sockaddr) == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&query->sockaddr.type.sin6.sin6_addr)) + { + isc_netaddr_t netaddr; + char buf[ISC_NETADDR_FORMATSIZE]; + + isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr); + isc_netaddr_format(&netaddr, buf, sizeof(buf)); + dighost_warning("Skipping mapped address '%s'", buf); + next = ISC_LIST_NEXT(query, link); + l = query->lookup; + clear_query(query); + if (next == NULL) { + dighost_warning("No acceptable nameservers"); + check_next_lookup(l); + } else { + send_udp(next); + } + return; + } + + result = isc_socket_create(socketmgr, + isc_sockaddr_pf(&query->sockaddr), + isc_sockettype_udp, &query->sock); + check_result(result, "isc_socket_create"); + sockcount++; + debug("sockcount=%d", sockcount); + if (query->lookup->dscp != -1) { + isc_socket_dscp(query->sock, query->lookup->dscp); + } + isc_socket_ipv6only(query->sock, !query->lookup->mapped); + if (specified_source) { + result = isc_socket_bind(query->sock, &bind_address, + ISC_SOCKET_REUSEADDRESS); + } else { + isc_sockaddr_anyofpf(&bind_any, + isc_sockaddr_pf(&query->sockaddr)); + result = isc_socket_bind(query->sock, &bind_any, 0); + } + check_result(result, "isc_socket_bind"); + + query->recv_made = true; + isc_buffer_availableregion(&query->recvbuf, &r); + debug("recving with lookup=%p, query=%p, sock=%p", + query->lookup, query, query->sock); + result = isc_socket_recv(query->sock, &r, 1, global_task, + recv_done, query); + check_result(result, "isc_socket_recv"); + recvcount++; + debug("recvcount=%d", recvcount); + } + isc_buffer_usedregion(&query->sendbuf, &r); + debug("sending a request"); + if (query->lookup->use_usec) { + TIME_NOW_HIRES(&query->time_sent); + } else { + TIME_NOW(&query->time_sent); + } + INSIST(query->sock != NULL); + query->waiting_senddone = true; + sevent = isc_socket_socketevent( + mctx, query->sock, ISC_SOCKEVENT_SENDDONE, send_done, query); + result = isc_socket_sendto2(query->sock, &r, global_task, + &query->sockaddr, NULL, sevent, + ISC_SOCKFLAG_NORETRY); + check_result(result, "isc_socket_sendto2"); + sendcount++; + + /* XXX qrflag, print_query, etc... */ + if (!ISC_LIST_EMPTY(query->lookup->q) && query->lookup->qr) { + extrabytes = 0; + dighost_printmessage(ISC_LIST_HEAD(query->lookup->q), + &query->lookup->renderbuf, + query->lookup->sendmsg, true); + if (query->lookup->stats) { + print_query_size(query); + } + } +} + +/*% + * If there are more servers available for querying within 'lookup', initiate a + * TCP or UDP query to the next available server and return true; otherwise, + * return false. + */ +static bool +try_next_server(dig_lookup_t *lookup) { + dig_query_t *current_query, *next_query; + + current_query = lookup->current_query; + if (current_query == NULL || !ISC_LINK_LINKED(current_query, link)) { + return (false); + } + + next_query = ISC_LIST_NEXT(current_query, link); + if (next_query == NULL) { + return (false); + } + + debug("trying next server..."); + + if (lookup->tcp_mode) { + send_tcp_connect(next_query); + } else { + send_udp(next_query); + } + + return (true); +} + +/*% + * IO timeout handler, used for both connect and recv timeouts. If + * retries are still allowed, either resend the UDP packet or queue a + * new TCP lookup. Otherwise, cancel the lookup. + */ +static void +connect_timeout(isc_task_t *task, isc_event_t *event) { + dig_lookup_t *l = NULL; + dig_query_t *query = NULL; + + UNUSED(task); + REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE); + + debug("connect_timeout(%p)", event->ev_arg); + + LOCK_LOOKUP; + query = event->ev_arg; + REQUIRE(DIG_VALID_QUERY(query)); + l = query->lookup; + isc_event_free(&event); + + INSIST(!free_now); + + if (cancel_now) { + UNLOCK_LOOKUP; + return; + } + + if (try_next_server(l)) { + if (l->tcp_mode) { + if (query->sock != NULL) { + isc_socket_cancel(query->sock, NULL, + ISC_SOCKCANCEL_ALL); + } else { + clear_query(query); + } + } + UNLOCK_LOOKUP; + return; + } + + if (l->tcp_mode && query->sock != NULL) { + query->timedout = true; + isc_socket_cancel(query->sock, NULL, ISC_SOCKCANCEL_ALL); + } + + if (l->retries > 1) { + if (!l->tcp_mode) { + l->retries--; + debug("resending UDP request to first server"); + send_udp(ISC_LIST_HEAD(l->q)); + } else { + debug("making new TCP request, %d tries left", + l->retries); + l->retries--; + requeue_lookup(l, true); + cancel_lookup(l); + check_next_lookup(l); + } + } else { + if (l->ns_search_only) { + isc_netaddr_t netaddr; + char buf[ISC_NETADDR_FORMATSIZE]; + + isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr); + isc_netaddr_format(&netaddr, buf, sizeof(buf)); + + dighost_error("no response from %s\n", buf); + } else { + fputs(l->cmdline, stdout); + dighost_error("connection timed out; " + "no servers could be reached\n"); + } + cancel_lookup(l); + check_next_lookup(l); + if (exitcode < 9) { + exitcode = 9; + } + } + UNLOCK_LOOKUP; +} + +/*% + * Called when a peer closes a TCP socket prematurely. + */ +static void +requeue_or_update_exitcode(dig_lookup_t *lookup) { + if (lookup->eoferr == 0U && lookup->retries > 1) { + --lookup->retries; + /* + * Peer closed the connection prematurely for the first time + * for this lookup. Try again, keeping track of this failure. + */ + dig_lookup_t *requeued_lookup = requeue_lookup(lookup, true); + requeued_lookup->eoferr++; + } else { + /* + * Peer closed the connection prematurely and it happened + * previously for this lookup. Indicate an error. + */ + exitcode = 9; + } +} + +/*% + * Event handler for the TCP recv which gets the length header of TCP + * packets. Start the next recv of length bytes. + */ +static void +tcp_length_done(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent; + isc_buffer_t b; + isc_region_t r; + isc_result_t result; + dig_query_t *query = NULL; + dig_lookup_t *l; + uint16_t length; + + REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); + INSIST(!free_now); + + UNUSED(task); + + debug("tcp_length_done(%p)", event->ev_arg); + + LOCK_LOOKUP; + sevent = (isc_socketevent_t *)event; + query = event->ev_arg; + REQUIRE(DIG_VALID_QUERY(query)); + + recvcount--; + INSIST(recvcount >= 0); + + if (sevent->result == ISC_R_CANCELED) { + isc_event_free(&event); + l = query->lookup; + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if (sevent->result != ISC_R_SUCCESS) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr)); + dighost_error("communications error to %s: %s\n", sockstr, + isc_result_totext(sevent->result)); + if (keep != NULL) { + isc_socket_detach(&keep); + } + l = query->lookup; + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + INSIST(sockcount >= 0); + if (sevent->result == ISC_R_EOF) { + requeue_or_update_exitcode(l); + } + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + isc_buffer_init(&b, sevent->region.base, sevent->n); + isc_buffer_add(&b, sevent->n); + length = isc_buffer_getuint16(&b); + + if (length == 0) { + isc_event_free(&event); + launch_next_query(query, false); + UNLOCK_LOOKUP; + return; + } + + /* + * Even though the buffer was already init'ed, we need + * to redo it now, to force the length we want. + */ + isc_buffer_invalidate(&query->recvbuf); + isc_buffer_init(&query->recvbuf, query->recvspace, length); + isc_buffer_availableregion(&query->recvbuf, &r); + debug("recving with lookup=%p, query=%p", query->lookup, query); + result = isc_socket_recv(query->sock, &r, length, task, recv_done, + query); + check_result(result, "isc_socket_recv"); + recvcount++; + debug("resubmitted recv request with length %d, recvcount=%d", length, + recvcount); + isc_event_free(&event); + UNLOCK_LOOKUP; +} + +/*% + * For transfers that involve multiple recvs (XFR's in particular), + * launch the next recv. + */ +static void +launch_next_query(dig_query_t *query, bool include_question) { + isc_result_t result; + dig_lookup_t *l; + isc_region_t r; + REQUIRE(DIG_VALID_QUERY(query)); + + INSIST(!free_now); + + debug("launch_next_query(%p)", query); + + if (!query->lookup->pending) { + debug("ignoring launch_next_query because !pending"); + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + INSIST(sockcount >= 0); + query->waiting_connect = false; + l = query->lookup; + clear_query(query); + check_next_lookup(l); + return; + } + + isc_buffer_clear(&query->lengthbuf); + isc_buffer_availableregion(&query->lengthbuf, &r); + result = isc_socket_recv(query->sock, &r, 0, global_task, + tcp_length_done, query); + check_result(result, "isc_socket_recv"); + recvcount++; + debug("recvcount=%d", recvcount); + if (!query->first_soa_rcvd) { + debug("sending a request in launch_next_query"); + if (query->lookup->use_usec) { + TIME_NOW_HIRES(&query->time_sent); + } else { + TIME_NOW(&query->time_sent); + } + query->waiting_senddone = true; + isc_buffer_clear(&query->tmpsendbuf); + isc_buffer_putuint16(&query->tmpsendbuf, + isc_buffer_usedlength(&query->sendbuf)); + if (include_question) { + isc_buffer_usedregion(&query->sendbuf, &r); + isc_buffer_copyregion(&query->tmpsendbuf, &r); + } + isc_buffer_usedregion(&query->tmpsendbuf, &r); + result = isc_socket_send(query->sock, &r, global_task, + send_done, query); + check_result(result, "isc_socket_send"); + sendcount++; + debug("sendcount=%d", sendcount); + + /* XXX qrflag, print_query, etc... */ + if (!ISC_LIST_EMPTY(query->lookup->q) && query->lookup->qr) { + extrabytes = 0; + dighost_printmessage(ISC_LIST_HEAD(query->lookup->q), + &query->lookup->renderbuf, + query->lookup->sendmsg, true); + if (query->lookup->stats) { + print_query_size(query); + } + } + } + query->waiting_connect = false; +#if 0 + check_next_lookup(query->lookup); +#endif /* if 0 */ + return; +} + +/*% + * Event handler for TCP connect complete. Make sure the connection was + * successful, then pass into launch_next_query to actually send the + * question. + */ +static void +connect_done(isc_task_t *task, isc_event_t *event) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + isc_socketevent_t *sevent = NULL; + dig_query_t *query = NULL, *next; + dig_lookup_t *l; + + UNUSED(task); + + REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); + INSIST(!free_now); + + debug("connect_done(%p)", event->ev_arg); + + LOCK_LOOKUP; + sevent = (isc_socketevent_t *)event; + query = sevent->ev_arg; + REQUIRE(DIG_VALID_QUERY(query)); + + INSIST(query->waiting_connect); + + query->waiting_connect = false; + + if (sevent->result == ISC_R_CANCELED) { + debug("in cancel handler"); + isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr)); + if (query->timedout) { + dighost_warning("Connection to %s(%s) for %s failed: " + "%s.", + sockstr, query->servname, + query->lookup->textname, + isc_result_totext(ISC_R_TIMEDOUT)); + } + isc_socket_detach(&query->sock); + INSIST(sockcount > 0); + sockcount--; + debug("sockcount=%d", sockcount); + query->waiting_connect = false; + isc_event_free(&event); + l = query->lookup; + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if (sevent->result != ISC_R_SUCCESS) { + debug("unsuccessful connection: %s", + isc_result_totext(sevent->result)); + isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr)); + if (sevent->result != ISC_R_CANCELED) { + dighost_warning("Connection to %s(%s) for %s failed: " + "%s.", + sockstr, query->servname, + query->lookup->textname, + isc_result_totext(sevent->result)); + } + isc_socket_detach(&query->sock); + INSIST(sockcount > 0); + sockcount--; + /* XXX Clean up exitcodes */ + if (exitcode < 9) { + exitcode = 9; + } + debug("sockcount=%d", sockcount); + query->waiting_connect = false; + isc_event_free(&event); + l = query->lookup; + if ((l->current_query != NULL) && + (ISC_LINK_LINKED(l->current_query, link))) + { + next = ISC_LIST_NEXT(l->current_query, link); + } else { + next = NULL; + } + clear_query(query); + if (next != NULL) { + bringup_timer(next, TCP_TIMEOUT); + send_tcp_connect(next); + } else { + check_next_lookup(l); + } + UNLOCK_LOOKUP; + return; + } + exitcode = 0; + if (keep_open) { + if (keep != NULL) { + isc_socket_detach(&keep); + } + isc_socket_attach(query->sock, &keep); + keepaddr = query->sockaddr; + } + launch_next_query(query, true); + isc_event_free(&event); + UNLOCK_LOOKUP; +} + +/*% + * Check if the ongoing XFR needs more data before it's complete, using + * the semantics of IXFR and AXFR protocols. Much of the complexity of + * this routine comes from determining when an IXFR is complete. + * false means more data is on the way, and the recv has been issued. + */ +static bool +check_for_more_data(dig_query_t *query, dns_message_t *msg, + isc_socketevent_t *sevent) { + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_soa_t soa; + uint32_t ixfr_serial = query->lookup->ixfr_serial, serial; + isc_result_t result; + bool ixfr = query->lookup->rdtype == dns_rdatatype_ixfr; + bool axfr = query->lookup->rdtype == dns_rdatatype_axfr; + + if (ixfr) { + axfr = query->ixfr_axfr; + } + + debug("check_for_more_data(%p)", query); + + /* + * By the time we're in this routine, we know we're doing + * either an AXFR or IXFR. If there's no second_rr_type, + * then we don't yet know which kind of answer we got back + * from the server. Here, we're going to walk through the + * rr's in the message, acting as necessary whenever we hit + * an SOA rr. + */ + + query->msg_count++; + query->byte_count += sevent->n; + result = dns_message_firstname(msg, DNS_SECTION_ANSWER); + if (result != ISC_R_SUCCESS) { + puts("; Transfer failed."); + return (true); + } + do { + dns_name_t *name; + name = NULL; + dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); + for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + result = dns_rdataset_first(rdataset); + if (result != ISC_R_SUCCESS) { + continue; + } + do { + query->rr_count++; + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + /* + * If this is the first rr, make sure + * it's an SOA + */ + if ((!query->first_soa_rcvd) && + (rdata.type != dns_rdatatype_soa)) + { + puts("; Transfer failed. " + "Didn't start with SOA answer."); + return (true); + } + if ((!query->second_rr_rcvd) && + (rdata.type != dns_rdatatype_soa)) + { + query->second_rr_rcvd = true; + query->second_rr_serial = 0; + debug("got the second rr as nonsoa"); + axfr = query->ixfr_axfr = true; + goto next_rdata; + } + + /* + * If the record is anything except an SOA + * now, just continue on... + */ + if (rdata.type != dns_rdatatype_soa) { + goto next_rdata; + } + + /* Now we have an SOA. Work with it. */ + debug("got an SOA"); + result = dns_rdata_tostruct(&rdata, &soa, NULL); + check_result(result, "dns_rdata_tostruct"); + serial = soa.serial; + dns_rdata_freestruct(&soa); + if (!query->first_soa_rcvd) { + query->first_soa_rcvd = true; + query->first_rr_serial = serial; + debug("this is the first serial %u", + serial); + if (ixfr && + isc_serial_ge(ixfr_serial, serial)) + { + debug("got up to date " + "response"); + goto doexit; + } + goto next_rdata; + } + if (axfr) { + debug("doing axfr, got second SOA"); + goto doexit; + } + if (!query->second_rr_rcvd) { + if (query->first_rr_serial == serial) { + debug("doing ixfr, got " + "empty zone"); + goto doexit; + } + debug("this is the second serial %u", + serial); + query->second_rr_rcvd = true; + query->second_rr_serial = serial; + goto next_rdata; + } + /* + * If we get to this point, we're doing an + * IXFR and have to start really looking + * at serial numbers. + */ + if (query->first_rr_serial == serial) { + debug("got a match for ixfr"); + if (!query->first_repeat_rcvd) { + query->first_repeat_rcvd = true; + goto next_rdata; + } + debug("done with ixfr"); + goto doexit; + } + debug("meaningless soa %u", serial); + next_rdata: + result = dns_rdataset_next(rdataset); + } while (result == ISC_R_SUCCESS); + } + result = dns_message_nextname(msg, DNS_SECTION_ANSWER); + } while (result == ISC_R_SUCCESS); + launch_next_query(query, false); + return (false); +doexit: + dighost_received(sevent->n, &sevent->address, query); + return (true); +} + +static void +process_cookie(dig_lookup_t *l, dns_message_t *msg, isc_buffer_t *optbuf, + size_t optlen) { + char bb[256]; + isc_buffer_t hexbuf; + size_t len; + const unsigned char *sent; + bool copy = true; + isc_result_t result; + + if (l->cookie != NULL) { + isc_buffer_init(&hexbuf, bb, sizeof(bb)); + result = isc_hex_decodestring(l->cookie, &hexbuf); + check_result(result, "isc_hex_decodestring"); + sent = isc_buffer_base(&hexbuf); + len = isc_buffer_usedlength(&hexbuf); + } else { + sent = cookie; + len = sizeof(cookie); + } + + INSIST(msg->cc_ok == 0 && msg->cc_bad == 0); + if (len >= 8 && optlen >= 8U) { + if (isc_safe_memequal(isc_buffer_current(optbuf), sent, 8)) { + msg->cc_ok = 1; + } else { + dighost_warning("Warning: Client COOKIE mismatch"); + msg->cc_bad = 1; + copy = false; + } + } else { + dighost_warning("Warning: COOKIE bad token (too short)"); + msg->cc_bad = 1; + copy = false; + } + if (copy) { + isc_region_t r; + + r.base = isc_buffer_current(optbuf); + r.length = (unsigned int)optlen; + isc_buffer_init(&hexbuf, servercookie, sizeof(servercookie)); + result = isc_hex_totext(&r, 2, "", &hexbuf); + check_result(result, "isc_hex_totext"); + if (isc_buffer_availablelength(&hexbuf) > 0) { + isc_buffer_putuint8(&hexbuf, 0); + l->cookie = servercookie; + } + } + isc_buffer_forward(optbuf, (unsigned int)optlen); +} + +static void +process_opt(dig_lookup_t *l, dns_message_t *msg) { + dns_rdata_t rdata; + isc_result_t result; + isc_buffer_t optbuf; + uint16_t optcode, optlen; + dns_rdataset_t *opt = msg->opt; + bool seen_cookie = false; + + result = dns_rdataset_first(opt); + if (result == ISC_R_SUCCESS) { + dns_rdata_init(&rdata); + dns_rdataset_current(opt, &rdata); + isc_buffer_init(&optbuf, rdata.data, rdata.length); + isc_buffer_add(&optbuf, rdata.length); + while (isc_buffer_remaininglength(&optbuf) >= 4) { + optcode = isc_buffer_getuint16(&optbuf); + optlen = isc_buffer_getuint16(&optbuf); + switch (optcode) { + case DNS_OPT_COOKIE: + /* + * Only process the first cookie option. + */ + if (seen_cookie) { + isc_buffer_forward(&optbuf, optlen); + break; + } + process_cookie(l, msg, &optbuf, optlen); + seen_cookie = true; + break; + default: + isc_buffer_forward(&optbuf, optlen); + break; + } + } + } +} + +static int +ednsvers(dns_rdataset_t *opt) { + return ((opt->ttl >> 16) & 0xff); +} + +/*% + * Event handler for recv complete. Perform whatever actions are necessary, + * based on the specifics of the user's request. + */ +static void +recv_done(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = NULL; + isc_region_t r; + dig_query_t *query = NULL; + isc_buffer_t b; + dns_message_t *msg = NULL; + isc_result_t result; + dig_lookup_t *n, *l; + bool docancel = false; + bool match = true; + bool done_process_opt = false; + unsigned int parseflags; + dns_messageid_t id; + unsigned int msgflags; + int newedns; + + UNUSED(task); + INSIST(!free_now); + + debug("recv_done(%p)", event->ev_arg); + + LOCK_LOOKUP; + recvcount--; + debug("recvcount=%d", recvcount); + INSIST(recvcount >= 0); + + query = event->ev_arg; + if (query->lookup->use_usec) { + TIME_NOW_HIRES(&query->time_recv); + } else { + TIME_NOW(&query->time_recv); + } + + l = query->lookup; + + REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); + sevent = (isc_socketevent_t *)event; + + isc_buffer_init(&b, sevent->region.base, sevent->n); + isc_buffer_add(&b, sevent->n); + + if ((l->tcp_mode) && (query->timer != NULL)) { + isc_timer_touch(query->timer); + } + if ((!l->pending && !l->ns_search_only) || cancel_now) { + debug("no longer pending. Got %s", + isc_result_totext(sevent->result)); + query->waiting_connect = false; + + isc_event_free(&event); + clear_query(query); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + + if (sevent->result != ISC_R_SUCCESS) { + if (sevent->result == ISC_R_CANCELED) { + debug("in recv cancel handler"); + query->waiting_connect = false; + } else { + dighost_error("communications error: %s\n", + isc_result_totext(sevent->result)); + if (keep != NULL) { + isc_socket_detach(&keep); + } + isc_socket_detach(&query->sock); + sockcount--; + debug("sockcount=%d", sockcount); + INSIST(sockcount >= 0); + } + if (sevent->result == ISC_R_EOF) { + requeue_or_update_exitcode(l); + } + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + + if (!l->tcp_mode && + !isc_sockaddr_compare(&sevent->address, &query->sockaddr, + ISC_SOCKADDR_CMPADDR | ISC_SOCKADDR_CMPPORT | + ISC_SOCKADDR_CMPSCOPE | + ISC_SOCKADDR_CMPSCOPEZERO)) + { + char buf1[ISC_SOCKADDR_FORMATSIZE]; + char buf2[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t any; + + if (isc_sockaddr_pf(&query->sockaddr) == AF_INET) { + isc_sockaddr_any(&any); + } else { + isc_sockaddr_any6(&any); + } + + /* + * We don't expect a match when the packet is + * sent to 0.0.0.0, :: or to a multicast addresses. + * XXXMPA broadcast needs to be handled here as well. + */ + if ((!isc_sockaddr_eqaddr(&query->sockaddr, &any) && + !isc_sockaddr_ismulticast(&query->sockaddr)) || + isc_sockaddr_getport(&query->sockaddr) != + isc_sockaddr_getport(&sevent->address)) + { + isc_sockaddr_format(&sevent->address, buf1, + sizeof(buf1)); + isc_sockaddr_format(&query->sockaddr, buf2, + sizeof(buf2)); + dighost_warning("reply from unexpected source: %s," + " expected %s\n", + buf1, buf2); + if (!l->accept_reply_unexpected_src) { + match = false; + } + } + } + + result = dns_message_peekheader(&b, &id, &msgflags); + if (result != ISC_R_SUCCESS || l->sendmsg->id != id) { + match = false; + if (l->tcp_mode) { + bool fail = true; + if (result == ISC_R_SUCCESS) { + if ((!query->first_soa_rcvd || query->warn_id)) + { + dighost_warning("%s: ID mismatch: " + "expected ID %u, got " + "%u", + query->first_soa_rcvd + ? "WARNING" + : "ERROR", + l->sendmsg->id, id); + } + if (query->first_soa_rcvd) { + fail = false; + } + query->warn_id = false; + } else { + dighost_warning("ERROR: short (< header size) " + "message"); + } + if (fail) { + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + match = true; + } else if (result == ISC_R_SUCCESS) { + dighost_warning("Warning: ID mismatch: expected ID %u," + " got %u", + l->sendmsg->id, id); + } else { + dighost_warning("Warning: short (< header size) " + "message received"); + } + } + + if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0) { + dighost_warning("Warning: query response not set"); + } + + if (!match) { + goto udp_mismatch; + } + + dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg); + + if (tsigkey != NULL) { + if (l->querysig == NULL) { + debug("getting initial querysig"); + result = dns_message_getquerytsig(l->sendmsg, mctx, + &l->querysig); + check_result(result, "dns_message_getquerytsig"); + } + result = dns_message_setquerytsig(msg, l->querysig); + check_result(result, "dns_message_setquerytsig"); + result = dns_message_settsigkey(msg, tsigkey); + check_result(result, "dns_message_settsigkey"); + msg->tsigctx = l->tsigctx; + l->tsigctx = NULL; + if (l->msgcounter != 0) { + msg->tcp_continuation = 1; + } + l->msgcounter++; + } + + debug("before parse starts"); + parseflags = DNS_MESSAGEPARSE_PRESERVEORDER; + if (l->besteffort) { + parseflags |= DNS_MESSAGEPARSE_BESTEFFORT; + parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION; + } + result = dns_message_parse(msg, &b, parseflags); + if (result == DNS_R_RECOVERABLE) { + dighost_warning("Warning: Message parser reports malformed " + "message packet."); + result = ISC_R_SUCCESS; + } + if (result != ISC_R_SUCCESS) { + if (!yaml) { + printf(";; Got bad packet: %s\n", + isc_result_totext(result)); + hex_dump(&b); + } + query->waiting_connect = false; + dns_message_detach(&msg); + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if (msg->opcode != l->opcode) { + char expect[20] = { 0 }, got[20] = { 0 }; + + isc_buffer_init(&b, &expect, sizeof(expect)); + result = dns_opcode_totext(l->opcode, &b); + check_result(result, "dns_opcode_totext"); + + isc_buffer_init(&b, &got, sizeof(got)); + result = dns_opcode_totext(msg->opcode, &b); + check_result(result, "dns_opcode_totext"); + + dighost_warning("Warning: Opcode mismatch: expected %s, got %s", + expect, got); + + dns_message_detach(&msg); + if (l->tcp_mode) { + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } else { + goto udp_mismatch; + } + } + if (msg->counts[DNS_SECTION_QUESTION] != 0) { + match = true; + for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION); + result == ISC_R_SUCCESS && match; + result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) + { + dns_name_t *name = NULL; + dns_rdataset_t *rdataset; + + dns_message_currentname(msg, DNS_SECTION_QUESTION, + &name); + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + if (l->rdtype != rdataset->type || + l->rdclass != rdataset->rdclass || + !dns_name_equal(l->name, name)) + { + char namestr[DNS_NAME_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; + dns_name_format(name, namestr, + sizeof(namestr)); + dns_rdatatype_format(rdataset->type, + typebuf, + sizeof(typebuf)); + dns_rdataclass_format(rdataset->rdclass, + classbuf, + sizeof(classbuf)); + dighost_warning(";; Question section " + "mismatch: got " + "%s/%s/%s", + namestr, typebuf, + classbuf); + match = false; + } + } + } + if (!match) { + dns_message_detach(&msg); + if (l->tcp_mode) { + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } else { + goto udp_mismatch; + } + } + } + if (msg->rcode == dns_rcode_badvers && msg->opt != NULL && + (newedns = ednsvers(msg->opt)) < l->edns && l->ednsneg) + { + /* + * Add minimum EDNS version required checks here if needed. + */ + dighost_comments(l, "BADVERS, retrying with EDNS version %u.", + (unsigned int)newedns); + l->edns = newedns; + n = requeue_lookup(l, true); + if (l->trace && l->trace_root) { + n->rdtype = l->qrdtype; + } + dns_message_detach(&msg); + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 && !l->ignore && + !l->tcp_mode) + { + if (l->cookie == NULL && l->sendcookie && msg->opt != NULL) { + process_opt(l, msg); + } + dighost_comments(l, "Truncated, retrying in TCP mode."); + n = requeue_lookup(l, true); + n->tcp_mode = true; + if (l->trace && l->trace_root) { + n->rdtype = l->qrdtype; + } + dns_message_detach(&msg); + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + if (msg->rcode == dns_rcode_badcookie && !l->tcp_mode && + l->sendcookie && l->badcookie) + { + process_opt(l, msg); + if (msg->cc_ok) { + dighost_comments(l, "BADCOOKIE, retrying%s.", + l->seenbadcookie ? " in TCP mode" + : ""); + n = requeue_lookup(l, true); + if (l->seenbadcookie) { + n->tcp_mode = true; + } + n->seenbadcookie = true; + if (l->trace && l->trace_root) { + n->rdtype = l->qrdtype; + } + dns_message_detach(&msg); + isc_event_free(&event); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + UNLOCK_LOOKUP; + return; + } + done_process_opt = true; + } + if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) || + (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse)) + { + dig_query_t *next = ISC_LIST_NEXT(query, link); + if (l->current_query == query) { + l->current_query = NULL; + } + if (next != NULL) { + debug("sending query %p\n", next); + if (l->tcp_mode) { + send_tcp_connect(next); + } else { + send_udp(next); + } + } + /* + * If our query is at the head of the list and there + * is no next, we're the only one left, so fall + * through to print the message. + */ + if ((ISC_LIST_HEAD(l->q) != query) || + (ISC_LIST_NEXT(query, link) != NULL)) + { + dighost_comments(l, + "Got %s from %s, trying next " + "server", + msg->rcode == dns_rcode_servfail + ? "SERVFAIL reply" + : "recursion not available", + query->servname); + clear_query(query); + check_next_lookup(l); + dns_message_detach(&msg); + isc_event_free(&event); + UNLOCK_LOOKUP; + return; + } + } + + if (tsigkey != NULL) { + result = dns_tsig_verify(&b, msg, NULL, NULL); + if (result != ISC_R_SUCCESS) { + dighost_warning("Couldn't verify signature: %s", + isc_result_totext(result)); + validated = false; + } + l->tsigctx = msg->tsigctx; + msg->tsigctx = NULL; + if (l->querysig != NULL) { + debug("freeing querysig buffer %p", l->querysig); + isc_buffer_free(&l->querysig); + } + result = dns_message_getquerytsig(msg, mctx, &l->querysig); + check_result(result, "dns_message_getquerytsig"); + } + + extrabytes = isc_buffer_remaininglength(&b); + + debug("after parse"); + if (l->doing_xfr && l->xfr_q == NULL) { + l->xfr_q = query; + /* + * Once we are in the XFR message, increase + * the timeout to much longer, so brief network + * outages won't cause the XFR to abort + */ + if (timeout != INT_MAX && query->timer != NULL) { + unsigned int local_timeout; + + if (timeout == 0) { + if (l->tcp_mode) { + local_timeout = TCP_TIMEOUT * 4; + } else { + local_timeout = UDP_TIMEOUT * 4; + } + } else { + if (timeout < (INT_MAX / 4)) { + local_timeout = timeout * 4; + } else { + local_timeout = INT_MAX; + } + } + debug("have local timeout of %d", local_timeout); + isc_interval_set(&l->interval, local_timeout, 0); + result = isc_timer_reset(query->timer, + isc_timertype_once, NULL, + &l->interval, false); + check_result(result, "isc_timer_reset"); + } + } + + if (!done_process_opt) { + if (l->cookie != NULL) { + if (msg->opt == NULL) { + dighost_warning("expected opt record in " + "response"); + } else { + process_opt(l, msg); + } + } else if (l->sendcookie && msg->opt != NULL) { + process_opt(l, msg); + } + } + if (!l->doing_xfr || l->xfr_q == query) { + if (msg->rcode == dns_rcode_nxdomain && + (l->origin != NULL || l->need_search)) + { + if (!next_origin(query->lookup) || showsearch) { + dighost_printmessage(query, &b, msg, true); + dighost_received(isc_buffer_usedlength(&b), + &sevent->address, query); + } + } else if (!l->trace && !l->ns_search_only) { + dighost_printmessage(query, &b, msg, true); + } else if (l->trace) { + int nl = 0; + int count = msg->counts[DNS_SECTION_ANSWER]; + + debug("in TRACE code"); + if (!l->ns_search_only) { + dighost_printmessage(query, &b, msg, true); + } + + l->rdtype = l->qrdtype; + if (l->trace_root || (l->ns_search_only && count > 0)) { + if (!l->trace_root) { + l->rdtype = dns_rdatatype_soa; + } + nl = followup_lookup(msg, query, + DNS_SECTION_ANSWER); + l->trace_root = false; + } else if (count == 0) { + nl = followup_lookup(msg, query, + DNS_SECTION_AUTHORITY); + } + if (nl == 0) { + docancel = true; + } + } else { + debug("in NSSEARCH code"); + + if (l->trace_root) { + /* + * This is the initial NS query. + */ + int nl; + + l->rdtype = dns_rdatatype_soa; + nl = followup_lookup(msg, query, + DNS_SECTION_ANSWER); + if (nl == 0) { + docancel = true; + } + l->trace_root = false; + usesearch = false; + } else { + dighost_printmessage(query, &b, msg, true); + } + } + } + + if (l->pending) { + debug("still pending."); + } + if (l->doing_xfr) { + if (query != l->xfr_q) { + dns_message_detach(&msg); + isc_event_free(&event); + query->waiting_connect = false; + UNLOCK_LOOKUP; + return; + } + if (!docancel) { + docancel = check_for_more_data(query, msg, sevent); + } + if (docancel) { + dns_message_detach(&msg); + clear_query(query); + cancel_lookup(l); + check_next_lookup(l); + } + } else { + if (msg->rcode == dns_rcode_noerror || l->origin == NULL) { + dighost_received(isc_buffer_usedlength(&b), + &sevent->address, query); + } + + if (!query->lookup->ns_search_only) { + query->lookup->pending = false; + } + if (!query->lookup->ns_search_only || + query->lookup->trace_root || docancel) + { + dns_message_detach(&msg); + cancel_lookup(l); + } + clear_query(query); + check_next_lookup(l); + } + if (msg != NULL) { + dns_message_detach(&msg); + } + isc_event_free(&event); + UNLOCK_LOOKUP; + return; + +udp_mismatch: + isc_buffer_invalidate(&query->recvbuf); + isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE); + isc_buffer_availableregion(&query->recvbuf, &r); + result = isc_socket_recv(query->sock, &r, 1, global_task, recv_done, + query); + check_result(result, "isc_socket_recv"); + recvcount++; + isc_event_free(&event); + UNLOCK_LOOKUP; + return; +} + +/*% + * Turn a name into an address, using system-supplied routines. This is + * used in looking up server names, etc... and needs to use system-supplied + * routines, since they may be using a non-DNS system for these lookups. + */ +isc_result_t +get_address(char *host, in_port_t myport, isc_sockaddr_t *sockaddr) { + int count; + isc_result_t result; + bool is_running; + + is_running = isc_app_isrunning(); + if (is_running) { + isc_app_block(); + } + result = bind9_getaddresses(host, myport, sockaddr, 1, &count); + if (is_running) { + isc_app_unblock(); + } + if (result != ISC_R_SUCCESS) { + return (result); + } + + INSIST(count == 1); + + return (ISC_R_SUCCESS); +} + +int +getaddresses(dig_lookup_t *lookup, const char *host, isc_result_t *resultp) { + isc_result_t result; + isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES]; + isc_netaddr_t netaddr; + int count, i; + dig_server_t *srv; + char tmp[ISC_NETADDR_FORMATSIZE]; + + result = bind9_getaddresses(host, 0, sockaddrs, DIG_MAX_ADDRESSES, + &count); + if (resultp != NULL) { + *resultp = result; + } + if (result != ISC_R_SUCCESS) { + if (resultp == NULL) { + fatal("couldn't get address for '%s': %s", host, + isc_result_totext(result)); + } + return (0); + } + + for (i = 0; i < count; i++) { + isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]); + isc_netaddr_format(&netaddr, tmp, sizeof(tmp)); + srv = make_server(tmp, host); + ISC_LIST_APPEND(lookup->my_server_list, srv, link); + } + + return (count); +} + +/*% + * Initiate either a TCP or UDP lookup + */ +void +do_lookup(dig_lookup_t *lookup) { + dig_query_t *query; + + REQUIRE(lookup != NULL); + + debug("do_lookup(%p)", lookup); + lookup->pending = true; + query = ISC_LIST_HEAD(lookup->q); + if (query != NULL) { + REQUIRE(DIG_VALID_QUERY(query)); + if (lookup->tcp_mode) { + send_tcp_connect(query); + } else { + send_udp(query); + } + } +} + +/*% + * Start everything in action upon task startup. + */ +void +onrun_callback(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + + isc_event_free(&event); + LOCK_LOOKUP; + start_lookup(); + UNLOCK_LOOKUP; +} + +/*% + * Make everything on the lookup queue go away. Mainly used by the + * SIGINT handler. + */ +void +cancel_all(void) { + dig_lookup_t *l, *n; + dig_query_t *q, *nq; + + debug("cancel_all()"); + + LOCK_LOOKUP; + if (free_now) { + UNLOCK_LOOKUP; + return; + } + cancel_now = true; + if (current_lookup != NULL) { + for (q = ISC_LIST_HEAD(current_lookup->q); q != NULL; q = nq) { + nq = ISC_LIST_NEXT(q, link); + debug("canceling pending query %p, belonging to %p", q, + current_lookup); + if (q->sock != NULL) { + isc_socket_cancel(q->sock, NULL, + ISC_SOCKCANCEL_ALL); + } else { + clear_query(q); + } + } + for (q = ISC_LIST_HEAD(current_lookup->connecting); q != NULL; + q = nq) + { + nq = ISC_LIST_NEXT(q, clink); + debug("canceling connecting query %p, belonging to %p", + q, current_lookup); + if (q->sock != NULL) { + isc_socket_cancel(q->sock, NULL, + ISC_SOCKCANCEL_ALL); + } else { + clear_query(q); + } + } + } + l = ISC_LIST_HEAD(lookup_list); + while (l != NULL) { + n = ISC_LIST_NEXT(l, link); + ISC_LIST_DEQUEUE(lookup_list, l, link); + try_clear_lookup(l); + l = n; + } + UNLOCK_LOOKUP; +} + +/*% + * Destroy all of the libs we are using, and get everything ready for a + * clean shutdown. + */ +void +destroy_libs(void) { +#ifdef HAVE_LIBIDN2 + isc_result_t result; +#endif /* HAVE_LIBIDN2 */ + + if (keep != NULL) { + isc_socket_detach(&keep); + } + debug("destroy_libs()"); + if (global_task != NULL) { + debug("freeing task"); + isc_task_detach(&global_task); + } + + if (taskmgr != NULL) { + debug("freeing taskmgr"); + isc_managers_destroy(&netmgr, &taskmgr); + } + LOCK_LOOKUP; + REQUIRE(sockcount == 0); + REQUIRE(recvcount == 0); + REQUIRE(sendcount == 0); + + INSIST(ISC_LIST_HEAD(lookup_list) == NULL); + INSIST(current_lookup == NULL); + INSIST(!free_now); + + free_now = true; + + flush_server_list(); + + clear_searchlist(); + +#ifdef HAVE_LIBIDN2 + result = dns_name_settotextfilter(NULL); + check_result(result, "dns_name_settotextfilter"); +#endif /* HAVE_LIBIDN2 */ + + if (socketmgr != NULL) { + debug("freeing socketmgr"); + isc_socketmgr_destroy(&socketmgr); + } + if (timermgr != NULL) { + debug("freeing timermgr"); + isc_timermgr_destroy(&timermgr); + } + if (tsigkey != NULL) { + debug("freeing key %p", tsigkey); + dns_tsigkey_detach(&tsigkey); + } + if (namebuf != NULL) { + isc_buffer_free(&namebuf); + } + + if (is_dst_up) { + debug("destroy DST lib"); + dst_lib_destroy(); + is_dst_up = false; + } + + UNLOCK_LOOKUP; + isc_mutex_destroy(&lookup_lock); + debug("Removing log context"); + isc_log_destroy(&lctx); + + debug("Destroy memory"); + if (memdebugging != 0) { + isc_mem_stats(mctx, stderr); + } + if (mctx != NULL) { + isc_mem_destroy(&mctx); + } +} + +#ifdef HAVE_LIBIDN2 +static isc_result_t +idn_output_filter(isc_buffer_t *buffer, unsigned int used_org) { + char src[MXNAME], *dst = NULL; + size_t srclen, dstlen; + isc_result_t result = ISC_R_SUCCESS; + + /* + * Copy name from 'buffer' to 'src' and terminate it with NULL. + */ + srclen = isc_buffer_usedlength(buffer) - used_org; + if (srclen >= sizeof(src)) { + warn("Input name too long to perform IDN conversion"); + goto cleanup; + } + memmove(src, (char *)isc_buffer_base(buffer) + used_org, srclen); + src[srclen] = '\0'; + + systemlocale(LC_ALL); + + /* + * Convert 'src' to the current locale's character encoding. + */ + idn_ace_to_locale(src, &dst); + + resetlocale(LC_ALL); + + /* + * Check whether the converted name will fit back into 'buffer'. + */ + dstlen = strlen(dst); + if (isc_buffer_length(buffer) < used_org + dstlen) { + result = ISC_R_NOSPACE; + goto cleanup; + } + + /* + * Put the converted name back into 'buffer'. + */ + isc_buffer_subtract(buffer, srclen); + memmove(isc_buffer_used(buffer), dst, dstlen); + isc_buffer_add(buffer, dstlen); + + /* + * Clean up. + */ +cleanup: + if (dst != NULL) { + idn2_free(dst); + } + + return (result); +} + +/*% + * Convert 'src', which is a string using the current locale's character + * encoding, into an ACE string suitable for use in the DNS, storing the + * conversion result in 'dst', which is 'dstlen' bytes large. + * + * 'dst' MUST be large enough to hold any valid domain name. + */ +static void +idn_locale_to_ace(const char *src, char *dst, size_t dstlen) { + const char *final_src; + char *ascii_src; + int res; + + systemlocale(LC_ALL); + + /* + * We trust libidn2 to return an error if 'src' is too large to be a + * valid domain name. + */ + res = idn2_to_ascii_lz(src, &ascii_src, IDN2_NONTRANSITIONAL); + if (res == IDN2_DISALLOWED) { + res = idn2_to_ascii_lz(src, &ascii_src, IDN2_TRANSITIONAL); + } + if (res != IDN2_OK) { + fatal("'%s' is not a legal IDNA2008 name (%s), use +noidnin", + src, idn2_strerror(res)); + } + + /* + * idn2_to_ascii_lz() normalizes all strings to lower case, but we + * generally don't want to lowercase all input strings; make sure to + * return the original case if the two strings differ only in case. + */ + final_src = (strcasecmp(src, ascii_src) == 0 ? src : ascii_src); + + (void)strlcpy(dst, final_src, dstlen); + + idn2_free(ascii_src); + + resetlocale(LC_ALL); +} + +/*% + * Convert 'src', which is an ACE string suitable for use in the DNS, into a + * string using the current locale's character encoding, storing the conversion + * result in 'dst'. + * + * The caller MUST subsequently release 'dst' using idn2_free(). + */ +static void +idn_ace_to_locale(const char *src, char **dst) { + char *local_src, *utf8_src; + int res; + + systemlocale(LC_ALL); + + /* + * We need to: + * + * 1) check whether 'src' is a valid IDNA2008 name, + * 2) if it is, output it in the current locale's character encoding. + * + * Unlike idn2_to_ascii_*(), idn2_to_unicode_*() functions are unable + * to perform IDNA2008 validity checks. Thus, we need to decode any + * Punycode in 'src', check if the resulting name is a valid IDNA2008 + * name, and only once we ensure it is, output that name in the current + * locale's character encoding. + * + * We could just use idn2_to_unicode_8zlz() + idn2_to_ascii_lz(), but + * then we would not be able to universally tell invalid names and + * character encoding errors apart (if the current locale uses ASCII + * for character encoding, the former function would fail even for a + * valid IDNA2008 name, as long as it contained any non-ASCII + * character). Thus, we need to take a longer route. + * + * First, convert 'src' to UTF-8, ignoring the current locale. + */ + res = idn2_to_unicode_8z8z(src, &utf8_src, 0); + if (res != IDN2_OK) { + fatal("Bad ACE string '%s' (%s), use +noidnout", src, + idn2_strerror(res)); + } + + /* + * Then, check whether decoded 'src' is a valid IDNA2008 name + * and if disallowed character is found, fallback to IDNA2003. + */ + res = idn2_to_ascii_8z(utf8_src, NULL, IDN2_NONTRANSITIONAL); + if (res == IDN2_DISALLOWED) { + res = idn2_to_ascii_8z(utf8_src, NULL, IDN2_TRANSITIONAL); + } + if (res != IDN2_OK) { + fatal("'%s' is not a legal IDNA2008 name (%s), use +noidnout", + src, idn2_strerror(res)); + } + + /* + * Finally, try converting the decoded 'src' into the current locale's + * character encoding. + */ + res = idn2_to_unicode_8zlz(utf8_src, &local_src, 0); + if (res != IDN2_OK) { + static bool warned = false; + + res = idn2_to_ascii_8z(utf8_src, &local_src, 0); + if (res != IDN2_OK) { + fatal("Cannot represent '%s' " + "in the current locale nor ascii (%s), " + "use +noidnout or a different locale", + src, idn2_strerror(res)); + } else if (!warned) { + fprintf(stderr, + ";; Warning: cannot represent '%s' " + "in the current locale", + local_src); + warned = true; + } + } + + /* + * Free the interim conversion result. + */ + idn2_free(utf8_src); + + *dst = local_src; + + resetlocale(LC_ALL); +} +#endif /* HAVE_LIBIDN2 */ diff --git a/bin/dig/host.c b/bin/dig/host.c new file mode 100644 index 0000000..db2e8d4 --- /dev/null +++ b/bin/dig/host.c @@ -0,0 +1,927 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static bool short_form = true, listed_server = false; +static bool default_lookups = true; +static int seen_error = -1; +static bool list_addresses = true; +static bool list_almost_all = false; +static dns_rdatatype_t list_type = dns_rdatatype_a; +static bool printed_server = false; +static bool ipv4only = false, ipv6only = false; + +static const char *opcodetext[] = { "QUERY", "IQUERY", "STATUS", + "RESERVED3", "NOTIFY", "UPDATE", + "RESERVED6", "RESERVED7", "RESERVED8", + "RESERVED9", "RESERVED10", "RESERVED11", + "RESERVED12", "RESERVED13", "RESERVED14", + "RESERVED15" }; + +static const char *rcodetext[] = { "NOERROR", "FORMERR", "SERVFAIL", + "NXDOMAIN", "NOTIMP", "REFUSED", + "YXDOMAIN", "YXRRSET", "NXRRSET", + "NOTAUTH", "NOTZONE", "RESERVED11", + "RESERVED12", "RESERVED13", "RESERVED14", + "RESERVED15", "BADVERS" }; + +struct rtype { + unsigned int type; + const char *text; +}; + +struct rtype rtypes[] = { { 1, "has address" }, + { 2, "name server" }, + { 5, "is an alias for" }, + { 11, "has well known services" }, + { 12, "domain name pointer" }, + { 13, "host information" }, + { 15, "mail is handled by" }, + { 16, "descriptive text" }, + { 19, "x25 address" }, + { 20, "ISDN address" }, + { 24, "has signature" }, + { 25, "has key" }, + { 28, "has IPv6 address" }, + { 29, "location" }, + { 0, NULL } }; + +static char * +rcode_totext(dns_rcode_t rcode) { + static char buf[sizeof("?65535")]; + union { + const char *consttext; + char *deconsttext; + } totext; + + if (rcode >= (sizeof(rcodetext) / sizeof(rcodetext[0]))) { + snprintf(buf, sizeof(buf), "?%u", rcode); + totext.deconsttext = buf; + } else { + totext.consttext = rcodetext[rcode]; + } + return (totext.deconsttext); +} + +ISC_PLATFORM_NORETURN_PRE static void +show_usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +show_usage(void) { + fputs("Usage: host [-aCdilrTvVw] [-c class] [-N ndots] [-t type] [-W " + "time]\n" + " [-R number] [-m flag] [-p port] hostname [server]\n" + " -a is equivalent to -v -t ANY\n" + " -A is like -a but omits RRSIG, NSEC, NSEC3\n" + " -c specifies query class for non-IN data\n" + " -C compares SOA records on authoritative nameservers\n" + " -d is equivalent to -v\n" + " -l lists all hosts in a domain, using AXFR\n" + " -m set memory debugging flag (trace|record|usage)\n" + " -N changes the number of dots allowed before root lookup " + "is done\n" + " -p specifies the port on the server to query\n" + " -r disables recursive processing\n" + " -R specifies number of retries for UDP packets\n" + " -s a SERVFAIL response should stop query\n" + " -t specifies the query type\n" + " -T enables TCP/IP mode\n" + " -U enables UDP mode\n" + " -v enables verbose output\n" + " -V print version number and exit\n" + " -w specifies to wait forever for a reply\n" + " -W specifies how long to wait for a reply\n" + " -4 use IPv4 query transport only\n" + " -6 use IPv6 query transport only\n", + stderr); + exit(1); +} + +static void +host_shutdown(void) { + (void)isc_app_shutdown(); +} + +static void +received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) { + isc_time_t now; + int diff; + + if (!short_form) { + char fromtext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(from, fromtext, sizeof(fromtext)); + if (query->lookup->use_usec) { + TIME_NOW_HIRES(&now); + } else { + TIME_NOW(&now); + } + diff = (int)isc_time_microdiff(&now, &query->time_sent); + printf("Received %u bytes from %s in %d ms\n", bytes, fromtext, + diff / 1000); + } +} + +static void +trying(char *frm, dig_lookup_t *lookup) { + UNUSED(lookup); + + if (!short_form) { + printf("Trying \"%s\"\n", frm); + } +} + +static void +say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata, + dig_query_t *query) { + isc_buffer_t *b = NULL; + char namestr[DNS_NAME_FORMATSIZE]; + isc_region_t r; + isc_result_t result; + unsigned int bufsize = BUFSIZ; + + dns_name_format(name, namestr, sizeof(namestr)); +retry: + isc_buffer_allocate(mctx, &b, bufsize); + result = dns_rdata_totext(rdata, NULL, b); + if (result == ISC_R_NOSPACE) { + isc_buffer_free(&b); + bufsize *= 2; + goto retry; + } + check_result(result, "dns_rdata_totext"); + isc_buffer_usedregion(b, &r); + if (query->lookup->identify_previous_line) { + printf("Nameserver %s:\n\t", query->servname); + } + printf("%s %s %.*s", namestr, msg, (int)r.length, (char *)r.base); + if (query->lookup->identify) { + printf(" on server %s", query->servname); + } + printf("\n"); + isc_buffer_free(&b); +} + +static isc_result_t +printsection(dns_message_t *msg, dns_section_t sectionid, + const char *section_name, bool headers, dig_query_t *query) { + dns_name_t *name, *print_name; + dns_rdataset_t *rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_buffer_t target; + isc_result_t result, loopresult; + isc_region_t r; + dns_name_t empty_name; + char tbuf[4096] = { 0 }; + bool first; + bool no_rdata = (sectionid == DNS_SECTION_QUESTION); + + if (headers) { + printf(";; %s SECTION:\n", section_name); + } + + dns_name_init(&empty_name, NULL); + + result = dns_message_firstname(msg, sectionid); + if (result == ISC_R_NOMORE) { + return (ISC_R_SUCCESS); + } else if (result != ISC_R_SUCCESS) { + return (result); + } + + for (;;) { + name = NULL; + dns_message_currentname(msg, sectionid, &name); + + isc_buffer_init(&target, tbuf, sizeof(tbuf)); + first = true; + print_name = name; + + for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + if (query->lookup->rdtype == dns_rdatatype_axfr && + !((!list_addresses && + (list_type == dns_rdatatype_any || + rdataset->type == list_type)) || + (list_addresses && + (rdataset->type == dns_rdatatype_a || + rdataset->type == dns_rdatatype_aaaa || + rdataset->type == dns_rdatatype_ns || + rdataset->type == dns_rdatatype_ptr)))) + { + continue; + } + if (list_almost_all && + (rdataset->type == dns_rdatatype_rrsig || + rdataset->type == dns_rdatatype_nsec || + rdataset->type == dns_rdatatype_nsec3)) + { + continue; + } + if (!short_form) { + result = dns_rdataset_totext(rdataset, + print_name, false, + no_rdata, &target); + if (result != ISC_R_SUCCESS) { + return (result); + } +#ifdef USEINITALWS + if (first) { + print_name = &empty_name; + first = false; + } +#else /* ifdef USEINITALWS */ + UNUSED(first); /* Shut up compiler. */ +#endif /* ifdef USEINITALWS */ + } else { + loopresult = dns_rdataset_first(rdataset); + while (loopresult == ISC_R_SUCCESS) { + struct rtype *t; + const char *rtt; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + char typebuf2[DNS_RDATATYPE_FORMATSIZE + + 20]; + dns_rdataset_current(rdataset, &rdata); + + for (t = rtypes; t->text != NULL; t++) { + if (t->type == rdata.type) { + rtt = t->text; + goto found; + } + } + + dns_rdatatype_format(rdata.type, + typebuf, + sizeof(typebuf)); + snprintf(typebuf2, sizeof(typebuf2), + "has %s record", typebuf); + rtt = typebuf2; + found: + say_message(print_name, rtt, &rdata, + query); + dns_rdata_reset(&rdata); + loopresult = + dns_rdataset_next(rdataset); + } + } + } + if (!short_form) { + isc_buffer_usedregion(&target, &r); + if (no_rdata) { + printf(";%.*s", (int)r.length, (char *)r.base); + } else { + printf("%.*s", (int)r.length, (char *)r.base); + } + } + + result = dns_message_nextname(msg, sectionid); + if (result == ISC_R_NOMORE) { + break; + } else if (result != ISC_R_SUCCESS) { + return (result); + } + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, + const dns_name_t *owner, const char *set_name, bool headers) { + isc_buffer_t target; + isc_result_t result; + isc_region_t r; + char tbuf[4096]; + + UNUSED(msg); + if (headers) { + printf(";; %s SECTION:\n", set_name); + } + + isc_buffer_init(&target, tbuf, sizeof(tbuf)); + + result = dns_rdataset_totext(rdataset, owner, false, false, &target); + if (result != ISC_R_SUCCESS) { + return (result); + } + isc_buffer_usedregion(&target, &r); + printf("%.*s", (int)r.length, (char *)r.base); + + return (ISC_R_SUCCESS); +} + +static void +chase_cnamechain(dns_message_t *msg, dns_name_t *qname) { + isc_result_t result; + dns_rdataset_t *rdataset; + dns_rdata_cname_t cname; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned int i = msg->counts[DNS_SECTION_ANSWER]; + + while (i-- > 0) { + rdataset = NULL; + result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, + dns_rdatatype_cname, 0, NULL, + &rdataset); + if (result != ISC_R_SUCCESS) { + return; + } + result = dns_rdataset_first(rdataset); + check_result(result, "dns_rdataset_first"); + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &cname, NULL); + check_result(result, "dns_rdata_tostruct"); + dns_name_copynf(&cname.cname, qname); + dns_rdata_freestruct(&cname); + } +} + +static isc_result_t +printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg, + bool headers) { + bool did_flag = false; + dns_rdataset_t *opt, *tsig = NULL; + const dns_name_t *tsigname; + isc_result_t result = ISC_R_SUCCESS; + int force_error; + + UNUSED(msgbuf); + UNUSED(headers); + + /* + * We get called multiple times. + * Preserve any existing error status. + */ + force_error = (seen_error == 1) ? 1 : 0; + seen_error = 1; + if (listed_server && !printed_server) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + + printf("Using domain server:\n"); + printf("Name: %s\n", query->userarg); + isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr)); + printf("Address: %s\n", sockstr); + printf("Aliases: \n\n"); + printed_server = true; + } + + if (msg->rcode != 0) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(query->lookup->name, namestr, sizeof(namestr)); + + if (query->lookup->identify_previous_line) { + printf("Nameserver %s:\n\t%s not found: %d(%s)\n", + query->servname, + (msg->rcode != dns_rcode_nxdomain) + ? namestr + : query->lookup->textname, + msg->rcode, rcode_totext(msg->rcode)); + } else { + printf("Host %s not found: %d(%s)\n", + (msg->rcode != dns_rcode_nxdomain) + ? namestr + : query->lookup->textname, + msg->rcode, rcode_totext(msg->rcode)); + } + return (ISC_R_SUCCESS); + } + + if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) { + char namestr[DNS_NAME_FORMATSIZE]; + dig_lookup_t *lookup; + dns_fixedname_t fixed; + dns_name_t *name; + + /* Add AAAA and MX lookups. */ + name = dns_fixedname_initname(&fixed); + dns_name_copynf(query->lookup->name, name); + chase_cnamechain(msg, name); + dns_name_format(name, namestr, sizeof(namestr)); + lookup = clone_lookup(query->lookup, false); + if (lookup != NULL) { + strlcpy(lookup->textname, namestr, + sizeof(lookup->textname)); + lookup->rdtype = dns_rdatatype_aaaa; + lookup->rdtypeset = true; + lookup->origin = NULL; + lookup->retries = tries; + ISC_LIST_APPEND(lookup_list, lookup, link); + } + lookup = clone_lookup(query->lookup, false); + if (lookup != NULL) { + strlcpy(lookup->textname, namestr, + sizeof(lookup->textname)); + lookup->rdtype = dns_rdatatype_mx; + lookup->rdtypeset = true; + lookup->origin = NULL; + lookup->retries = tries; + ISC_LIST_APPEND(lookup_list, lookup, link); + } + } + + if (!short_form) { + printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", + opcodetext[msg->opcode], rcode_totext(msg->rcode), + msg->id); + printf(";; flags: "); + if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { + printf("qr"); + did_flag = true; + } + if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { + printf("%saa", did_flag ? " " : ""); + did_flag = true; + } + if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { + printf("%stc", did_flag ? " " : ""); + did_flag = true; + } + if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { + printf("%srd", did_flag ? " " : ""); + did_flag = true; + } + if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { + printf("%sra", did_flag ? " " : ""); + did_flag = true; + } + if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { + printf("%sad", did_flag ? " " : ""); + did_flag = true; + } + if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { + printf("%scd", did_flag ? " " : ""); + did_flag = true; + POST(did_flag); + } + printf("; QUERY: %u, ANSWER: %u, " + "AUTHORITY: %u, ADDITIONAL: %u\n", + msg->counts[DNS_SECTION_QUESTION], + msg->counts[DNS_SECTION_ANSWER], + msg->counts[DNS_SECTION_AUTHORITY], + msg->counts[DNS_SECTION_ADDITIONAL]); + opt = dns_message_getopt(msg); + if (opt != NULL) { + printf(";; EDNS: version: %u, udp=%u\n", + (unsigned int)((opt->ttl & 0x00ff0000) >> 16), + (unsigned int)opt->rdclass); + } + tsigname = NULL; + tsig = dns_message_gettsig(msg, &tsigname); + if (tsig != NULL) { + printf(";; PSEUDOSECTIONS: TSIG\n"); + } + } + if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) && !short_form) + { + printf("\n"); + result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION", + true, query); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { + if (!short_form) { + printf("\n"); + } + result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER", + !short_form, query); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + + if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) && + !short_form) + { + printf("\n"); + result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY", + true, query); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) && + !short_form) + { + printf("\n"); + result = printsection(msg, DNS_SECTION_ADDITIONAL, "ADDITIONAL", + true, query); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + if ((tsig != NULL) && !short_form) { + printf("\n"); + result = printrdata(msg, tsig, tsigname, "PSEUDOSECTION TSIG", + true); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + if (!short_form) { + printf("\n"); + } + + if (short_form && !default_lookups && + ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) + { + char namestr[DNS_NAME_FORMATSIZE]; + char typestr[DNS_RDATATYPE_FORMATSIZE]; + dns_name_format(query->lookup->name, namestr, sizeof(namestr)); + dns_rdatatype_format(query->lookup->rdtype, typestr, + sizeof(typestr)); + printf("%s has no %s record\n", namestr, typestr); + } + seen_error = force_error; + return (result); +} + +static const char *optstring = "46aAc:dilnm:p:rst:vVwCDN:R:TUW:"; + +/*% version */ +static void +version(void) { + fputs("host " VERSION "\n", stderr); +} + +static void +pre_parse_args(int argc, char **argv) { + int c; + + while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { + switch (c) { + case 'm': + memdebugging = true; + if (strcasecmp("trace", isc_commandline_argument) == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGTRACE; + } else if (strcasecmp("record", + isc_commandline_argument) == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + } else if (strcasecmp("usage", + isc_commandline_argument) == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; + } + break; + + case '4': + if (ipv6only) { + fatal("only one of -4 and -6 allowed"); + } + ipv4only = true; + break; + case '6': + if (ipv4only) { + fatal("only one of -4 and -6 allowed"); + } + ipv6only = true; + break; + case 'a': + break; + case 'A': + break; + case 'c': + break; + case 'C': + break; + case 'd': + break; + case 'D': + if (debugging) { + debugtiming = true; + } + debugging = true; + break; + case 'i': + break; + case 'l': + break; + case 'n': + break; + case 'N': + break; + case 'p': + break; + case 'r': + break; + case 'R': + break; + case 's': + break; + case 't': + break; + case 'T': + break; + case 'U': + break; + case 'v': + break; + case 'V': + version(); + exit(0); + break; + case 'w': + break; + case 'W': + break; + default: + show_usage(); + } + } + isc_commandline_reset = true; + isc_commandline_index = 1; +} + +static void +parse_args(bool is_batchfile, int argc, char **argv) { + char hostname[MXNAME]; + dig_lookup_t *lookup; + int c; + char store[MXNAME]; + isc_textregion_t tr; + isc_result_t result = ISC_R_SUCCESS; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + uint32_t serial = 0; + + UNUSED(is_batchfile); + + lookup = make_empty_lookup(); + + lookup->servfail_stops = false; + lookup->besteffort = false; + lookup->comments = false; + short_form = !verbose; + + while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { + switch (c) { + case 'l': + lookup->tcp_mode = true; + lookup->rdtype = dns_rdatatype_axfr; + lookup->rdtypeset = true; + fatalexit = 3; + break; + case 'v': + case 'd': + short_form = false; + break; + case 'r': + lookup->recurse = false; + break; + case 't': + if (strncasecmp(isc_commandline_argument, "ixfr=", 5) == + 0) + { + rdtype = dns_rdatatype_ixfr; + /* XXXMPA add error checking */ + serial = strtoul(isc_commandline_argument + 5, + NULL, 10); + result = ISC_R_SUCCESS; + } else { + tr.base = isc_commandline_argument; + tr.length = strlen(isc_commandline_argument); + result = dns_rdatatype_fromtext( + &rdtype, (isc_textregion_t *)&tr); + } + + if (result != ISC_R_SUCCESS) { + fatalexit = 2; + fatal("invalid type: %s\n", + isc_commandline_argument); + } + if (!lookup->rdtypeset || + lookup->rdtype != dns_rdatatype_axfr) + { + lookup->rdtype = rdtype; + } + lookup->rdtypeset = true; + if (rdtype == dns_rdatatype_axfr) { + /* -l -t any -v */ + list_type = dns_rdatatype_any; + short_form = false; + lookup->tcp_mode = true; + } else if (rdtype == dns_rdatatype_ixfr) { + lookup->ixfr_serial = serial; + lookup->tcp_mode = true; + list_type = rdtype; + } else if (rdtype == dns_rdatatype_any) { + if (!lookup->tcp_mode_set) { + lookup->tcp_mode = true; + } + } else { + list_type = rdtype; + } + list_addresses = false; + default_lookups = false; + break; + case 'c': + tr.base = isc_commandline_argument; + tr.length = strlen(isc_commandline_argument); + result = dns_rdataclass_fromtext( + &rdclass, (isc_textregion_t *)&tr); + + if (result != ISC_R_SUCCESS) { + fatalexit = 2; + fatal("invalid class: %s\n", + isc_commandline_argument); + } else { + lookup->rdclass = rdclass; + lookup->rdclassset = true; + } + default_lookups = false; + break; + case 'A': + list_almost_all = true; + FALLTHROUGH; + case 'a': + if (!lookup->rdtypeset || + lookup->rdtype != dns_rdatatype_axfr) + { + lookup->rdtype = dns_rdatatype_any; + } + list_type = dns_rdatatype_any; + list_addresses = false; + lookup->rdtypeset = true; + short_form = false; + default_lookups = false; + break; + case 'i': + /* deprecated */ + break; + case 'n': + /* deprecated */ + break; + case 'm': + /* Handled by pre_parse_args(). */ + break; + case 'w': + /* + * The timer routines are coded such that + * timeout==MAXINT doesn't enable the timer + */ + timeout = INT_MAX; + break; + case 'W': + timeout = atoi(isc_commandline_argument); + if (timeout < 1) { + timeout = 1; + } + break; + case 'R': + tries = atoi(isc_commandline_argument) + 1; + if (tries < 2) { + tries = 2; + } + break; + case 'T': + lookup->tcp_mode = true; + lookup->tcp_mode_set = true; + break; + case 'U': + lookup->tcp_mode = false; + lookup->tcp_mode_set = true; + break; + case 'C': + debug("showing all SOAs"); + lookup->rdtype = dns_rdatatype_ns; + lookup->rdtypeset = true; + lookup->rdclass = dns_rdataclass_in; + lookup->rdclassset = true; + lookup->ns_search_only = true; + lookup->trace_root = true; + lookup->identify_previous_line = true; + default_lookups = false; + break; + case 'N': + debug("setting NDOTS to %s", isc_commandline_argument); + ndots = atoi(isc_commandline_argument); + break; + case 'D': + /* Handled by pre_parse_args(). */ + break; + case '4': + /* Handled by pre_parse_args(). */ + break; + case '6': + /* Handled by pre_parse_args(). */ + break; + case 's': + lookup->servfail_stops = true; + break; + case 'p': + port = atoi(isc_commandline_argument); + break; + } + } + + lookup->retries = tries; + + if (isc_commandline_index >= argc) { + show_usage(); + } + + strlcpy(hostname, argv[isc_commandline_index], sizeof(hostname)); + + if (argc > isc_commandline_index + 1) { + set_nameserver(argv[isc_commandline_index + 1]); + debug("server is %s", argv[isc_commandline_index + 1]); + listed_server = true; + } else { + check_ra = true; + } + + lookup->pending = false; + if (get_reverse(store, sizeof(store), hostname, true) == ISC_R_SUCCESS) + { + strlcpy(lookup->textname, store, sizeof(lookup->textname)); + lookup->rdtype = dns_rdatatype_ptr; + lookup->rdtypeset = true; + default_lookups = false; + } else { + strlcpy(lookup->textname, hostname, sizeof(lookup->textname)); + usesearch = true; + } + lookup->new_search = true; + ISC_LIST_APPEND(lookup_list, lookup, link); +} + +int +main(int argc, char **argv) { + isc_result_t result; + + tries = 2; + + ISC_LIST_INIT(lookup_list); + ISC_LIST_INIT(server_list); + ISC_LIST_INIT(search_list); + + fatalexit = 1; + + /* setup dighost callbacks */ + dighost_printmessage = printmessage; + dighost_received = received; + dighost_trying = trying; + dighost_shutdown = host_shutdown; + + debug("main()"); + progname = argv[0]; + pre_parse_args(argc, argv); + result = isc_app_start(); + check_result(result, "isc_app_start"); + setup_libs(); + setup_system(ipv4only, ipv6only); + parse_args(false, argc, argv); + if (keyfile[0] != 0) { + setup_file_key(); + } else if (keysecret[0] != 0) { + setup_text_key(); + } + result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); + check_result(result, "isc_app_onrun"); + isc_app_run(); + cancel_all(); + destroy_libs(); + isc_app_finish(); + return ((seen_error == 0) ? 0 : 1); +} diff --git a/bin/dig/host.rst b/bin/dig/host.rst new file mode 100644 index 0000000..8e855c3 --- /dev/null +++ b/bin/dig/host.rst @@ -0,0 +1,171 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_host: + +host - DNS lookup utility +------------------------- + +Synopsis +~~~~~~~~ + +:program:`host` [**-aACdlnrsTUwv**] [**-c** class] [**-N** ndots] [**-p** port] [**-R** number] [**-t** type] [**-W** wait] [**-m** flag] [ [**-4**] | [**-6**] ] [**-v**] [**-V**] {name} [server] + +Description +~~~~~~~~~~~ + +``host`` is a simple utility for performing DNS lookups. It is normally +used to convert names to IP addresses and vice versa. When no arguments +or options are given, ``host`` prints a short summary of its +command-line arguments and options. + +``name`` is the domain name that is to be looked up. It can also be a +dotted-decimal IPv4 address or a colon-delimited IPv6 address, in which +case ``host`` by default performs a reverse lookup for that address. +``server`` is an optional argument which is either the name or IP +address of the name server that ``host`` should query instead of the +server or servers listed in ``/etc/resolv.conf``. + +Options +~~~~~~~ + +``-4`` + This option specifies that only IPv4 should be used for query transport. See also the ``-6`` option. + +``-6`` + This option specifies that only IPv6 should be used for query transport. See also the ``-4`` option. + +``-a`` + The ``-a`` ("all") option is normally equivalent to ``-v -t ANY``. It + also affects the behavior of the ``-l`` list zone option. + +``-A`` + The ``-A`` ("almost all") option is equivalent to ``-a``, except that RRSIG, + NSEC, and NSEC3 records are omitted from the output. + +``-c class`` + This option specifies the query class, which can be used to lookup HS (Hesiod) or CH (Chaosnet) + class resource records. The default class is IN (Internet). + +``-C`` + This option indicates that ``named`` should check consistency, meaning that ``host`` queries the SOA records for zone + ``name`` from all the listed authoritative name servers for that + zone. The list of name servers is defined by the NS records that are + found for the zone. + +``-d`` + This option prints debugging traces, and is equivalent to the ``-v`` verbose option. + +``-l`` + This option tells ``named`` to list the zone, meaning the ``host`` command performs a zone transfer of zone + ``name`` and prints out the NS, PTR, and address records (A/AAAA). + + Together, the ``-l -a`` options print all records in the zone. + +``-N ndots`` + This option specifies the number of dots (``ndots``) that have to be in ``name`` for it to be + considered absolute. The default value is that defined using the + ``ndots`` statement in ``/etc/resolv.conf``, or 1 if no ``ndots`` statement + is present. Names with fewer dots are interpreted as relative names, + and are searched for in the domains listed in the ``search`` or + ``domain`` directive in ``/etc/resolv.conf``. + +``-p port`` + This option specifies the port to query on the server. The default is 53. + +``-r`` + This option specifies a non-recursive query; setting this option clears the RD (recursion + desired) bit in the query. This means that the name server + receiving the query does not attempt to resolve ``name``. The ``-r`` + option enables ``host`` to mimic the behavior of a name server by + making non-recursive queries, and expecting to receive answers to + those queries that can be referrals to other name servers. + +``-R number`` + This option specifies the number of retries for UDP queries. If ``number`` is negative or zero, + the number of retries is silently set to 1. The default value is 1, or + the value of the ``attempts`` option in ``/etc/resolv.conf``, if set. + +``-s`` + This option tells ``named`` *not* to send the query to the next nameserver if any server responds + with a SERVFAIL response, which is the reverse of normal stub + resolver behavior. + +``-t type`` + This option specifies the query type. The ``type`` argument can be any recognized query type: + CNAME, NS, SOA, TXT, DNSKEY, AXFR, etc. + + When no query type is specified, ``host`` automatically selects an + appropriate query type. By default, it looks for A, AAAA, and MX + records. If the ``-C`` option is given, queries are made for SOA + records. If ``name`` is a dotted-decimal IPv4 address or + colon-delimited IPv6 address, ``host`` queries for PTR records. + + If a query type of IXFR is chosen, the starting serial number can be + specified by appending an equals sign (=), followed by the starting serial + number, e.g., ``-t IXFR=12345678``. + +``-T``; ``-U`` + This option specifies TCP or UDP. By default, ``host`` uses UDP when making queries; the + ``-T`` option makes it use a TCP connection when querying the name + server. TCP is automatically selected for queries that require + it, such as zone transfer (AXFR) requests. Type ``ANY`` queries default + to TCP, but can be forced to use UDP initially via ``-U``. + +``-m flag`` + This option sets memory usage debugging: the flag can be ``record``, ``usage``, or + ``trace``. The ``-m`` option can be specified more than once to set + multiple flags. + +``-v`` + This option sets verbose output, and is equivalent to the ``-d`` debug option. Verbose output + can also be enabled by setting the ``debug`` option in + ``/etc/resolv.conf``. + +``-V`` + This option prints the version number and exits. + +``-w`` + This option sets "wait forever": the query timeout is set to the maximum possible. See + also the ``-W`` option. + +``-W wait`` + This options sets the length of the wait timeout, indicating that ``named`` should wait for up to ``wait`` seconds for a reply. If ``wait`` is + less than 1, the wait interval is set to 1 second. + + By default, ``host`` waits for 5 seconds for UDP responses and 10 + seconds for TCP connections. These defaults can be overridden by the + ``timeout`` option in ``/etc/resolv.conf``. + + See also the ``-w`` option. + +IDN Support +~~~~~~~~~~~ + +If ``host`` has been built with IDN (internationalized domain name) +support, it can accept and display non-ASCII domain names. ``host`` +appropriately converts character encoding of a domain name before sending +a request to a DNS server or displaying a reply from the server. +To turn off IDN support, define the ``IDN_DISABLE`` +environment variable. IDN support is disabled if the variable is set +when ``host`` runs. + +Files +~~~~~ + +``/etc/resolv.conf`` + +See Also +~~~~~~~~ + +:manpage:`dig(1)`, :manpage:`named(8)`. diff --git a/bin/dig/include/.clang-format b/bin/dig/include/.clang-format new file mode 120000 index 0000000..0e62f72 --- /dev/null +++ b/bin/dig/include/.clang-format @@ -0,0 +1 @@ +../../../.clang-format.headers \ No newline at end of file diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h new file mode 100644 index 0000000..8bf9613 --- /dev/null +++ b/bin/dig/include/dig/dig.h @@ -0,0 +1,425 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef DIG_H +#define DIG_H + +/*! \file */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef __APPLE__ +#include +#endif /* ifdef __APPLE__ */ + +#define MXSERV 20 +#define MXNAME (DNS_NAME_MAXTEXT + 1) +#define MXRD 32 +/*% Buffer Size */ +#define BUFSIZE 512 +#define COMMSIZE 0xffff +#ifndef RESOLV_CONF +/*% location of resolve.conf */ +#define RESOLV_CONF "/etc/resolv.conf" +#endif /* ifndef RESOLV_CONF */ +/*% output buffer */ +#define OUTPUTBUF 32767 +/*% Max RR Limit */ +#define MAXRRLIMIT 0xffffffff +#define MAXTIMEOUT 0xffff +/*% Max number of tries */ +#define MAXTRIES 0xffffffff +/*% Max number of dots */ +#define MAXNDOTS 0xffff +/*% Max number of ports */ +#define MAXPORT 0xffff +/*% Max serial number */ +#define MAXSERIAL 0xffffffff + +/*% Default TCP Timeout */ +#define TCP_TIMEOUT 10 +/*% Default UDP Timeout */ +#define UDP_TIMEOUT 5 + +#define SERVER_TIMEOUT 1 + +#define LOOKUP_LIMIT 64 + +#define DEFAULT_EDNS_VERSION 0 +#define DEFAULT_EDNS_BUFSIZE 4096 + +/*% + * Lookup_limit is just a limiter, keeping too many lookups from being + * created. It's job is mainly to prevent the program from running away + * in a tight loop of constant lookups. It's value is arbitrary. + */ + +ISC_LANG_BEGINDECLS + +typedef struct dig_lookup dig_lookup_t; +typedef struct dig_query dig_query_t; +typedef struct dig_server dig_server_t; +typedef ISC_LIST(dig_server_t) dig_serverlist_t; +typedef struct dig_searchlist dig_searchlist_t; + +#define DIG_QUERY_MAGIC ISC_MAGIC('D', 'i', 'g', 'q') + +#define DIG_VALID_QUERY(x) ISC_MAGIC_VALID((x), DIG_QUERY_MAGIC) + +/*% The dig_lookup structure */ +struct dig_lookup { + bool pending, /*%< Pending a successful answer */ + waiting_connect, doing_xfr, ns_search_only, /*%< dig + * +nssearch, + * host -C */ + identify, /*%< Append an "on server " message */ + identify_previous_line, /*% Prepend a "Nameserver :" + * message, with newline and tab */ + ignore, recurse, aaonly, adflag, cdflag, raflag, tcflag, zflag, + trace, /*% dig +trace */ + trace_root, /*% initial query for either +trace or +nssearch + * */ + tcp_mode, tcp_mode_set, comments, stats, section_question, + section_answer, section_authority, section_additional, + servfail_stops, new_search, need_search, done_as_is, besteffort, + dnssec, expire, sendcookie, seenbadcookie, badcookie, + nsid, /*% Name Server ID (RFC 5001) */ + tcp_keepalive, header_only, ednsneg, mapped, + print_unknown_format, multiline, nottl, noclass, onesoa, + use_usec, nocrypto, ttlunits, idnin, idnout, expandaaaa, qr, + accept_reply_unexpected_src; /*% print replies from + * unexpected + * sources. */ + char textname[MXNAME]; /*% Name we're going to be + * looking up */ + char cmdline[MXNAME]; + dns_rdatatype_t rdtype; + dns_rdatatype_t qrdtype; + dns_rdataclass_t rdclass; + bool rdtypeset; + bool rdclassset; + char name_space[BUFSIZE]; + char oname_space[BUFSIZE]; + isc_buffer_t namebuf; + isc_buffer_t onamebuf; + isc_buffer_t renderbuf; + char *sendspace; + dns_name_t *name; + isc_interval_t interval; + dns_message_t *sendmsg; + dns_name_t *oname; + ISC_LINK(dig_lookup_t) link; + ISC_LIST(dig_query_t) q; + ISC_LIST(dig_query_t) connecting; + dig_query_t *current_query; + dig_serverlist_t my_server_list; + dig_searchlist_t *origin; + dig_query_t *xfr_q; + uint32_t retries; + int nsfound; + int16_t udpsize; + int16_t edns; + int16_t padding; + uint32_t ixfr_serial; + isc_buffer_t rdatabuf; + char rdatastore[MXNAME]; + dst_context_t *tsigctx; + isc_buffer_t *querysig; + uint32_t msgcounter; + dns_fixedname_t fdomain; + isc_sockaddr_t *ecs_addr; + char *cookie; + dns_ednsopt_t *ednsopts; + unsigned int ednsoptscnt; + isc_dscp_t dscp; + unsigned int ednsflags; + dns_opcode_t opcode; + int rrcomments; + unsigned int eoferr; +}; + +/*% The dig_query structure */ +struct dig_query { + unsigned int magic; + dig_lookup_t *lookup; + bool waiting_connect, pending_free, waiting_senddone, first_pass, + first_soa_rcvd, second_rr_rcvd, first_repeat_rcvd, recv_made, + warn_id, timedout; + uint32_t first_rr_serial; + uint32_t second_rr_serial; + uint32_t msg_count; + uint32_t rr_count; + bool ixfr_axfr; + char *servname; + char *userarg; + isc_buffer_t recvbuf, lengthbuf, tmpsendbuf, sendbuf; + char *recvspace, *tmpsendspace, lengthspace[4]; + isc_socket_t *sock; + ISC_LINK(dig_query_t) link; + ISC_LINK(dig_query_t) clink; + dig_query_t *saved_next; + isc_sockaddr_t sockaddr; + isc_time_t time_sent; + isc_time_t time_recv; + uint64_t byte_count; + isc_timer_t *timer; +}; + +struct dig_server { + char servername[MXNAME]; + char userarg[MXNAME]; + ISC_LINK(dig_server_t) link; +}; + +struct dig_searchlist { + char origin[MXNAME]; + ISC_LINK(dig_searchlist_t) link; +}; + +typedef ISC_LIST(dig_searchlist_t) dig_searchlistlist_t; +typedef ISC_LIST(dig_lookup_t) dig_lookuplist_t; + +/* + * Externals from dighost.c + */ + +extern dig_lookuplist_t lookup_list; +extern dig_serverlist_t server_list; +extern dig_searchlistlist_t search_list; +extern unsigned int extrabytes; + +extern bool check_ra, have_ipv4, have_ipv6, specified_source, usesearch, + showsearch, yaml; +extern in_port_t port; +extern unsigned int timeout; +extern isc_mem_t *mctx; +extern int sendcount; +extern int ndots; +extern int lookup_counter; +extern int exitcode; +extern isc_sockaddr_t bind_address; +extern char keynametext[MXNAME]; +extern char keyfile[MXNAME]; +extern char keysecret[MXNAME]; +extern const dns_name_t *hmacname; +extern unsigned int digestbits; +extern dns_tsigkey_t *tsigkey; +extern bool validated; +extern isc_taskmgr_t *taskmgr; +extern isc_task_t *global_task; +extern bool free_now; +extern bool debugging, debugtiming, memdebugging; +extern bool keep_open; + +extern char *progname; +extern int tries; +extern int fatalexit; +extern bool verbose; + +/* + * Routines in dighost.c. + */ +isc_result_t +get_address(char *host, in_port_t myport, isc_sockaddr_t *sockaddr); + +int +getaddresses(dig_lookup_t *lookup, const char *host, isc_result_t *resultp); + +isc_result_t +get_reverse(char *reverse, size_t len, char *value, bool strict); + +ISC_PLATFORM_NORETURN_PRE void +fatal(const char *format, ...) + ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; + +void +warn(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +ISC_PLATFORM_NORETURN_PRE void +digexit(void) ISC_PLATFORM_NORETURN_POST; + +void +debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +void +check_result(isc_result_t result, const char *msg); + +bool +setup_lookup(dig_lookup_t *lookup); + +void +destroy_lookup(dig_lookup_t *lookup); + +void +do_lookup(dig_lookup_t *lookup); + +void +start_lookup(void); + +void +onrun_callback(isc_task_t *task, isc_event_t *event); + +int +dhmain(int argc, char **argv); + +void +setup_libs(void); + +void +setup_system(bool ipv4only, bool ipv6only); + +isc_result_t +parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc); + +isc_result_t +parse_xint(uint32_t *uip, const char *value, uint32_t max, const char *desc); + +isc_result_t +parse_netprefix(isc_sockaddr_t **sap, const char *value); + +void +parse_hmac(const char *hmacstr); + +dig_lookup_t * +requeue_lookup(dig_lookup_t *lookold, bool servers); + +dig_lookup_t * +make_empty_lookup(void); + +dig_lookup_t * +clone_lookup(dig_lookup_t *lookold, bool servers); + +dig_server_t * +make_server(const char *servname, const char *userarg); + +void +flush_server_list(void); + +void +set_nameserver(char *opt); + +void +clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest); + +void +cancel_all(void); + +void +destroy_libs(void); + +void +set_search_domain(char *domain); + +/* + * Routines to be defined in dig.c, host.c, and nslookup.c. and + * then assigned to the appropriate function pointer + */ +extern isc_result_t (*dighost_printmessage)(dig_query_t *query, + const isc_buffer_t *msgbuf, + dns_message_t *msg, bool headers); + +/* + * Print an error message in the appropriate format. + */ +extern void (*dighost_error)(const char *format, ...); + +/* + * Print a warning message in the appropriate format. + */ +extern void (*dighost_warning)(const char *format, ...); + +/* + * Print a comment in the appropriate format. + */ +extern void (*dighost_comments)(dig_lookup_t *lookup, const char *format, ...); + +/*%< + * Print the final result of the lookup. + */ + +extern void (*dighost_received)(unsigned int bytes, isc_sockaddr_t *from, + dig_query_t *query); +/*%< + * Print a message about where and when the response + * was received from, like the final comment in the + * output of "dig". + */ + +extern void (*dighost_trying)(char *frm, dig_lookup_t *lookup); + +extern void (*dighost_shutdown)(void); + +extern void (*dighost_pre_exit_hook)(void); + +void +save_opt(dig_lookup_t *lookup, char *code, char *value); + +void +setup_file_key(void); +void +setup_text_key(void); + +/* + * Routines exported from dig.c for use by dig for iOS + */ + +/*%< + * Call once only to set up libraries, parse global + * parameters and initial command line query parameters + */ +void +dig_setup(int argc, char **argv); + +/*%< + * Call to supply new parameters for the next lookup + */ +void +dig_query_setup(bool, bool, int argc, char **argv); + +/*%< + * set the main application event cycle running + */ +void +dig_startup(void); + +/*%< + * Initiates the next lookup cycle + */ +void +dig_query_start(void); + +/*%< + * Cleans up the application + */ +void +dig_shutdown(void); + +ISC_LANG_ENDDECLS + +#endif /* ifndef DIG_H */ diff --git a/bin/dig/nslookup.c b/bin/dig/nslookup.c new file mode 100644 index 0000000..0fa691d --- /dev/null +++ b/bin/dig/nslookup.c @@ -0,0 +1,1047 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(HAVE_READLINE) +#if defined(HAVE_EDIT_READLINE_READLINE_H) +#include +#if defined(HAVE_EDIT_READLINE_HISTORY_H) +#include +#endif /* if defined(HAVE_EDIT_READLINE_HISTORY_H) */ +#elif defined(HAVE_EDITLINE_READLINE_H) +#include +#elif defined(HAVE_READLINE_READLINE_H) +/* Prevent deprecated functions being declared. */ +#define _FUNCTION_DEF 1 +/* Ensure rl_message() gets prototype. */ +#define USE_VARARGS 1 +#define PREFER_STDARG 1 +#include +#if defined(HAVE_READLINE_HISTORY_H) +#include +#endif /* if defined(HAVE_READLINE_HISTORY_H) */ +#endif /* if defined(HAVE_EDIT_READLINE_READLINE_H) */ +#endif /* if defined(HAVE_READLINE) */ + +static bool short_form = true, tcpmode = false, tcpmode_set = false, + identify = false, stats = true, comments = true, + section_question = true, section_answer = true, + section_authority = true, section_additional = true, recurse = true, + aaonly = false, nofail = true, default_lookups = true, + a_noanswer = false; + +static bool interactive; + +static bool in_use = false; +static char defclass[MXRD] = "IN"; +static char deftype[MXRD] = "A"; +static isc_event_t *global_event = NULL; +static int query_error = 1, print_error = 0; + +static char domainopt[DNS_NAME_MAXTEXT]; + +static const char *rcodetext[] = { "NOERROR", "FORMERR", "SERVFAIL", + "NXDOMAIN", "NOTIMP", "REFUSED", + "YXDOMAIN", "YXRRSET", "NXRRSET", + "NOTAUTH", "NOTZONE", "RESERVED11", + "RESERVED12", "RESERVED13", "RESERVED14", + "RESERVED15", "BADVERS" }; + +static const char *rtypetext[] = { + "rtype_0 = ", /* 0 */ + "internet address = ", /* 1 */ + "nameserver = ", /* 2 */ + "md = ", /* 3 */ + "mf = ", /* 4 */ + "canonical name = ", /* 5 */ + "soa = ", /* 6 */ + "mb = ", /* 7 */ + "mg = ", /* 8 */ + "mr = ", /* 9 */ + "rtype_10 = ", /* 10 */ + "protocol = ", /* 11 */ + "name = ", /* 12 */ + "hinfo = ", /* 13 */ + "minfo = ", /* 14 */ + "mail exchanger = ", /* 15 */ + "text = ", /* 16 */ + "rp = ", /* 17 */ + "afsdb = ", /* 18 */ + "x25 address = ", /* 19 */ + "isdn address = ", /* 20 */ + "rt = ", /* 21 */ + "nsap = ", /* 22 */ + "nsap_ptr = ", /* 23 */ + "signature = ", /* 24 */ + "key = ", /* 25 */ + "px = ", /* 26 */ + "gpos = ", /* 27 */ + "has AAAA address ", /* 28 */ + "loc = ", /* 29 */ + "next = ", /* 30 */ + "rtype_31 = ", /* 31 */ + "rtype_32 = ", /* 32 */ + "service = ", /* 33 */ + "rtype_34 = ", /* 34 */ + "naptr = ", /* 35 */ + "kx = ", /* 36 */ + "cert = ", /* 37 */ + "v6 address = ", /* 38 */ + "dname = ", /* 39 */ + "rtype_40 = ", /* 40 */ + "optional = " /* 41 */ +}; + +#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0])) + +static void +flush_lookup_list(void); +static void +getinput(isc_task_t *task, isc_event_t *event); + +static char * +rcode_totext(dns_rcode_t rcode) { + static char buf[sizeof("?65535")]; + union { + const char *consttext; + char *deconsttext; + } totext; + + if (rcode >= (sizeof(rcodetext) / sizeof(rcodetext[0]))) { + snprintf(buf, sizeof(buf), "?%u", rcode); + totext.deconsttext = buf; + } else { + totext.consttext = rcodetext[rcode]; + } + return (totext.deconsttext); +} + +static void +query_finished(void) { + isc_event_t *event = global_event; + + flush_lookup_list(); + debug("dighost_shutdown()"); + + if (!in_use) { + isc_app_shutdown(); + return; + } + + isc_task_send(global_task, &event); +} + +static void +printsoa(dns_rdata_t *rdata) { + dns_rdata_soa_t soa; + isc_result_t result; + char namebuf[DNS_NAME_FORMATSIZE]; + + result = dns_rdata_tostruct(rdata, &soa, NULL); + check_result(result, "dns_rdata_tostruct"); + + dns_name_format(&soa.origin, namebuf, sizeof(namebuf)); + printf("\torigin = %s\n", namebuf); + dns_name_format(&soa.contact, namebuf, sizeof(namebuf)); + printf("\tmail addr = %s\n", namebuf); + printf("\tserial = %u\n", soa.serial); + printf("\trefresh = %u\n", soa.refresh); + printf("\tretry = %u\n", soa.retry); + printf("\texpire = %u\n", soa.expire); + printf("\tminimum = %u\n", soa.minimum); + dns_rdata_freestruct(&soa); +} + +static void +printaddr(dns_rdata_t *rdata) { + isc_result_t result; + char text[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + isc_buffer_t b; + + isc_buffer_init(&b, text, sizeof(text)); + result = dns_rdata_totext(rdata, NULL, &b); + check_result(result, "dns_rdata_totext"); + printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b), + (char *)isc_buffer_base(&b)); +} + +static void +printrdata(dns_rdata_t *rdata) { + isc_result_t result; + isc_buffer_t *b = NULL; + unsigned int size = 1024; + bool done = false; + + if (rdata->type < N_KNOWN_RRTYPES) { + printf("%s", rtypetext[rdata->type]); + } else { + printf("rdata_%d = ", rdata->type); + } + + while (!done) { + isc_buffer_allocate(mctx, &b, size); + result = dns_rdata_totext(rdata, NULL, b); + if (result == ISC_R_SUCCESS) { + printf("%.*s\n", (int)isc_buffer_usedlength(b), + (char *)isc_buffer_base(b)); + done = true; + } else if (result != ISC_R_NOSPACE) { + check_result(result, "dns_rdata_totext"); + } + isc_buffer_free(&b); + size *= 2; + } +} + +static isc_result_t +printsection(dig_query_t *query, dns_message_t *msg, bool headers, + dns_section_t section) { + isc_result_t result, loopresult; + dns_name_t *name; + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + char namebuf[DNS_NAME_FORMATSIZE]; + + UNUSED(query); + UNUSED(headers); + + debug("printsection()"); + + result = dns_message_firstname(msg, section); + if (result == ISC_R_NOMORE) { + return (ISC_R_SUCCESS); + } else if (result != ISC_R_SUCCESS) { + return (result); + } + for (;;) { + name = NULL; + dns_message_currentname(msg, section, &name); + for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + loopresult = dns_rdataset_first(rdataset); + while (loopresult == ISC_R_SUCCESS) { + dns_rdataset_current(rdataset, &rdata); + switch (rdata.type) { + case dns_rdatatype_a: + case dns_rdatatype_aaaa: + if (section != DNS_SECTION_ANSWER) { + goto def_short_section; + } + dns_name_format(name, namebuf, + sizeof(namebuf)); + printf("Name:\t%s\n", namebuf); + printaddr(&rdata); + break; + case dns_rdatatype_soa: + dns_name_format(name, namebuf, + sizeof(namebuf)); + printf("%s\n", namebuf); + printsoa(&rdata); + break; + default: + def_short_section: + dns_name_format(name, namebuf, + sizeof(namebuf)); + printf("%s\t", namebuf); + printrdata(&rdata); + break; + } + dns_rdata_reset(&rdata); + loopresult = dns_rdataset_next(rdataset); + } + } + result = dns_message_nextname(msg, section); + if (result == ISC_R_NOMORE) { + break; + } else if (result != ISC_R_SUCCESS) { + return (result); + } + } + return (ISC_R_SUCCESS); +} + +static isc_result_t +detailsection(dig_query_t *query, dns_message_t *msg, bool headers, + dns_section_t section) { + isc_result_t result, loopresult; + dns_name_t *name; + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + char namebuf[DNS_NAME_FORMATSIZE]; + + UNUSED(query); + + debug("detailsection()"); + + if (headers) { + switch (section) { + case DNS_SECTION_QUESTION: + puts(" QUESTIONS:"); + break; + case DNS_SECTION_ANSWER: + puts(" ANSWERS:"); + break; + case DNS_SECTION_AUTHORITY: + puts(" AUTHORITY RECORDS:"); + break; + case DNS_SECTION_ADDITIONAL: + puts(" ADDITIONAL RECORDS:"); + break; + } + } + + result = dns_message_firstname(msg, section); + if (result == ISC_R_NOMORE) { + return (ISC_R_SUCCESS); + } else if (result != ISC_R_SUCCESS) { + return (result); + } + for (;;) { + name = NULL; + dns_message_currentname(msg, section, &name); + for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + if (section == DNS_SECTION_QUESTION) { + dns_name_format(name, namebuf, sizeof(namebuf)); + printf("\t%s, ", namebuf); + dns_rdatatype_format(rdataset->type, namebuf, + sizeof(namebuf)); + printf("type = %s, ", namebuf); + dns_rdataclass_format(rdataset->rdclass, + namebuf, sizeof(namebuf)); + printf("class = %s\n", namebuf); + } + loopresult = dns_rdataset_first(rdataset); + while (loopresult == ISC_R_SUCCESS) { + dns_rdataset_current(rdataset, &rdata); + + dns_name_format(name, namebuf, sizeof(namebuf)); + printf(" -> %s\n", namebuf); + + switch (rdata.type) { + case dns_rdatatype_soa: + printsoa(&rdata); + break; + default: + printf("\t"); + printrdata(&rdata); + } + dns_rdata_reset(&rdata); + printf("\tttl = %u\n", rdataset->ttl); + loopresult = dns_rdataset_next(rdataset); + } + } + result = dns_message_nextname(msg, section); + if (result == ISC_R_NOMORE) { + break; + } else if (result != ISC_R_SUCCESS) { + return (result); + } + } + return (ISC_R_SUCCESS); +} + +static void +received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) { + UNUSED(bytes); + UNUSED(from); + UNUSED(query); +} + +static void +trying(char *frm, dig_lookup_t *lookup) { + UNUSED(frm); + UNUSED(lookup); +} + +static void +chase_cnamechain(dns_message_t *msg, dns_name_t *qname) { + isc_result_t result; + dns_rdataset_t *rdataset; + dns_rdata_cname_t cname; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned int i = msg->counts[DNS_SECTION_ANSWER]; + + while (i-- > 0) { + rdataset = NULL; + result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, + dns_rdatatype_cname, 0, NULL, + &rdataset); + if (result != ISC_R_SUCCESS) { + return; + } + result = dns_rdataset_first(rdataset); + check_result(result, "dns_rdataset_first"); + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &cname, NULL); + check_result(result, "dns_rdata_tostruct"); + dns_name_copynf(&cname.cname, qname); + dns_rdata_freestruct(&cname); + } +} + +static isc_result_t +printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg, + bool headers) { + char servtext[ISC_SOCKADDR_FORMATSIZE]; + + UNUSED(msgbuf); + + /* I've we've gotten this far, we've reached a server. */ + query_error = 0; + + debug("printmessage()"); + + if (!default_lookups || query->lookup->rdtype == dns_rdatatype_a) { + isc_sockaddr_format(&query->sockaddr, servtext, + sizeof(servtext)); + printf("Server:\t\t%s\n", query->userarg); + printf("Address:\t%s\n", servtext); + + puts(""); + } + + if (!short_form) { + puts("------------"); + /* detailheader(query, msg);*/ + detailsection(query, msg, true, DNS_SECTION_QUESTION); + detailsection(query, msg, true, DNS_SECTION_ANSWER); + detailsection(query, msg, true, DNS_SECTION_AUTHORITY); + detailsection(query, msg, true, DNS_SECTION_ADDITIONAL); + puts("------------"); + } + + if (msg->rcode != 0) { + char nametext[DNS_NAME_FORMATSIZE]; + dns_name_format(query->lookup->name, nametext, + sizeof(nametext)); + printf("** server can't find %s: %s\n", nametext, + rcode_totext(msg->rcode)); + debug("returning with rcode == 0"); + + /* the lookup failed */ + print_error |= 1; + return (ISC_R_SUCCESS); + } + + if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) { + char namestr[DNS_NAME_FORMATSIZE]; + dig_lookup_t *lookup; + dns_fixedname_t fixed; + dns_name_t *name; + + /* Add AAAA lookup. */ + name = dns_fixedname_initname(&fixed); + dns_name_copynf(query->lookup->name, name); + chase_cnamechain(msg, name); + dns_name_format(name, namestr, sizeof(namestr)); + lookup = clone_lookup(query->lookup, false); + if (lookup != NULL) { + strlcpy(lookup->textname, namestr, + sizeof(lookup->textname)); + lookup->rdtype = dns_rdatatype_aaaa; + lookup->rdtypeset = true; + lookup->origin = NULL; + lookup->retries = tries; + ISC_LIST_APPEND(lookup_list, lookup, link); + } + } + + if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0 && + (!default_lookups || query->lookup->rdtype == dns_rdatatype_a)) + { + puts("Non-authoritative answer:"); + } + if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { + printsection(query, msg, headers, DNS_SECTION_ANSWER); + } else { + if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) + { + a_noanswer = true; + } else if (!default_lookups || + (query->lookup->rdtype == dns_rdatatype_aaaa && + a_noanswer)) + { + printf("*** Can't find %s: No answer\n", + query->lookup->textname); + } + } + + if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) && + (query->lookup->rdtype != dns_rdatatype_a) && + (query->lookup->rdtype != dns_rdatatype_aaaa)) + { + puts("\nAuthoritative answers can be found from:"); + printsection(query, msg, headers, DNS_SECTION_AUTHORITY); + printsection(query, msg, headers, DNS_SECTION_ADDITIONAL); + } + return (ISC_R_SUCCESS); +} + +static void +show_settings(bool full, bool serv_only) { + dig_server_t *srv; + isc_sockaddr_t sockaddr; + dig_searchlist_t *listent; + isc_result_t result; + + srv = ISC_LIST_HEAD(server_list); + + while (srv != NULL) { + char sockstr[ISC_SOCKADDR_FORMATSIZE]; + + result = get_address(srv->servername, port, &sockaddr); + check_result(result, "get_address"); + + isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr)); + printf("Default server: %s\nAddress: %s\n", srv->userarg, + sockstr); + if (!full) { + return; + } + srv = ISC_LIST_NEXT(srv, link); + } + if (serv_only) { + return; + } + printf("\nSet options:\n"); + printf(" %s\t\t\t%s\t\t%s\n", tcpmode ? "vc" : "novc", + short_form ? "nodebug" : "debug", debugging ? "d2" : "nod2"); + printf(" %s\t\t%s\n", usesearch ? "search" : "nosearch", + recurse ? "recurse" : "norecurse"); + printf(" timeout = %u\t\tretry = %d\tport = %u\tndots = %d\n", timeout, + tries, port, ndots); + printf(" querytype = %-8s\tclass = %s\n", deftype, defclass); + printf(" srchlist = "); + for (listent = ISC_LIST_HEAD(search_list); listent != NULL; + listent = ISC_LIST_NEXT(listent, link)) + { + printf("%s", listent->origin); + if (ISC_LIST_NEXT(listent, link) != NULL) { + printf("/"); + } + } + printf("\n"); +} + +static bool +testtype(char *typetext) { + isc_result_t result; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + + tr.base = typetext; + tr.length = strlen(typetext); + result = dns_rdatatype_fromtext(&rdtype, &tr); + if (result == ISC_R_SUCCESS) { + return (true); + } else { + printf("unknown query type: %s\n", typetext); + return (false); + } +} + +static bool +testclass(char *typetext) { + isc_result_t result; + isc_textregion_t tr; + dns_rdataclass_t rdclass; + + tr.base = typetext; + tr.length = strlen(typetext); + result = dns_rdataclass_fromtext(&rdclass, &tr); + if (result == ISC_R_SUCCESS) { + return (true); + } else { + printf("unknown query class: %s\n", typetext); + return (false); + } +} + +static void +set_port(const char *value) { + uint32_t n; + isc_result_t result = parse_uint(&n, value, 65535, "port"); + if (result == ISC_R_SUCCESS) { + port = (uint16_t)n; + } +} + +static void +set_timeout(const char *value) { + uint32_t n; + isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout"); + if (result == ISC_R_SUCCESS) { + timeout = n; + } +} + +static void +set_tries(const char *value) { + uint32_t n; + isc_result_t result = parse_uint(&n, value, INT_MAX, "tries"); + if (result == ISC_R_SUCCESS) { + tries = n; + } +} + +static void +set_ndots(const char *value) { + uint32_t n; + isc_result_t result = parse_uint(&n, value, 128, "ndots"); + if (result == ISC_R_SUCCESS) { + ndots = n; + } +} + +static void +version(void) { + fputs("nslookup " VERSION "\n", stderr); +} + +static void +setoption(char *opt) { + size_t l = strlen(opt); + +#define CHECKOPT(A, N) \ + ((l >= N) && (l < sizeof(A)) && (strncasecmp(opt, A, l) == 0)) + + if (CHECKOPT("all", 3)) { + show_settings(true, false); + } else if (strncasecmp(opt, "class=", 6) == 0) { + if (testclass(&opt[6])) { + strlcpy(defclass, &opt[6], sizeof(defclass)); + } + } else if (strncasecmp(opt, "cl=", 3) == 0) { + if (testclass(&opt[3])) { + strlcpy(defclass, &opt[3], sizeof(defclass)); + } + } else if (strncasecmp(opt, "type=", 5) == 0) { + if (testtype(&opt[5])) { + strlcpy(deftype, &opt[5], sizeof(deftype)); + default_lookups = false; + } + } else if (strncasecmp(opt, "ty=", 3) == 0) { + if (testtype(&opt[3])) { + strlcpy(deftype, &opt[3], sizeof(deftype)); + default_lookups = false; + } + } else if (strncasecmp(opt, "querytype=", 10) == 0) { + if (testtype(&opt[10])) { + strlcpy(deftype, &opt[10], sizeof(deftype)); + default_lookups = false; + } + } else if (strncasecmp(opt, "query=", 6) == 0) { + if (testtype(&opt[6])) { + strlcpy(deftype, &opt[6], sizeof(deftype)); + default_lookups = false; + } + } else if (strncasecmp(opt, "qu=", 3) == 0) { + if (testtype(&opt[3])) { + strlcpy(deftype, &opt[3], sizeof(deftype)); + default_lookups = false; + } + } else if (strncasecmp(opt, "q=", 2) == 0) { + if (testtype(&opt[2])) { + strlcpy(deftype, &opt[2], sizeof(deftype)); + default_lookups = false; + } + } else if (strncasecmp(opt, "domain=", 7) == 0) { + strlcpy(domainopt, &opt[7], sizeof(domainopt)); + set_search_domain(domainopt); + usesearch = true; + } else if (strncasecmp(opt, "do=", 3) == 0) { + strlcpy(domainopt, &opt[3], sizeof(domainopt)); + set_search_domain(domainopt); + usesearch = true; + } else if (strncasecmp(opt, "port=", 5) == 0) { + set_port(&opt[5]); + } else if (strncasecmp(opt, "po=", 3) == 0) { + set_port(&opt[3]); + } else if (strncasecmp(opt, "timeout=", 8) == 0) { + set_timeout(&opt[8]); + } else if (strncasecmp(opt, "t=", 2) == 0) { + set_timeout(&opt[2]); + } else if (CHECKOPT("recurse", 3)) { + recurse = true; + } else if (CHECKOPT("norecurse", 5)) { + recurse = false; + } else if (strncasecmp(opt, "retry=", 6) == 0) { + set_tries(&opt[6]); + } else if (strncasecmp(opt, "ret=", 4) == 0) { + set_tries(&opt[4]); + } else if (CHECKOPT("defname", 3)) { + usesearch = true; + } else if (CHECKOPT("nodefname", 5)) { + usesearch = false; + } else if (CHECKOPT("vc", 2)) { + tcpmode = true; + tcpmode_set = true; + } else if (CHECKOPT("novc", 4)) { + tcpmode = false; + tcpmode_set = true; + } else if (CHECKOPT("debug", 3)) { + short_form = false; + showsearch = true; + } else if (CHECKOPT("nodebug", 5)) { + short_form = true; + showsearch = false; + } else if (CHECKOPT("d2", 2)) { + debugging = true; + } else if (CHECKOPT("nod2", 4)) { + debugging = false; + } else if (CHECKOPT("search", 3)) { + usesearch = true; + } else if (CHECKOPT("nosearch", 5)) { + usesearch = false; + } else if (CHECKOPT("sil", 3)) { + /* deprecation_msg = false; */ + } else if (CHECKOPT("fail", 3)) { + nofail = false; + } else if (CHECKOPT("nofail", 5)) { + nofail = true; + } else if (strncasecmp(opt, "ndots=", 6) == 0) { + set_ndots(&opt[6]); + } else { + printf("*** Invalid option: %s\n", opt); + } +} + +static void +addlookup(char *opt) { + dig_lookup_t *lookup; + isc_result_t result; + isc_textregion_t tr; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + char store[MXNAME]; + + debug("addlookup()"); + + a_noanswer = false; + + tr.base = deftype; + tr.length = strlen(deftype); + result = dns_rdatatype_fromtext(&rdtype, &tr); + if (result != ISC_R_SUCCESS) { + printf("unknown query type: %s\n", deftype); + rdclass = dns_rdatatype_a; + } + tr.base = defclass; + tr.length = strlen(defclass); + result = dns_rdataclass_fromtext(&rdclass, &tr); + if (result != ISC_R_SUCCESS) { + printf("unknown query class: %s\n", defclass); + rdclass = dns_rdataclass_in; + } + lookup = make_empty_lookup(); + if (get_reverse(store, sizeof(store), opt, true) == ISC_R_SUCCESS) { + strlcpy(lookup->textname, store, sizeof(lookup->textname)); + lookup->rdtype = dns_rdatatype_ptr; + lookup->rdtypeset = true; + } else { + strlcpy(lookup->textname, opt, sizeof(lookup->textname)); + lookup->rdtype = rdtype; + lookup->rdtypeset = true; + } + lookup->rdclass = rdclass; + lookup->rdclassset = true; + lookup->trace = false; + lookup->trace_root = lookup->trace; + lookup->ns_search_only = false; + lookup->identify = identify; + lookup->recurse = recurse; + lookup->aaonly = aaonly; + lookup->retries = tries; + lookup->comments = comments; + if (lookup->rdtype == dns_rdatatype_any && !tcpmode_set) { + lookup->tcp_mode = true; + } else { + lookup->tcp_mode = tcpmode; + } + lookup->stats = stats; + lookup->section_question = section_question; + lookup->section_answer = section_answer; + lookup->section_authority = section_authority; + lookup->section_additional = section_additional; + lookup->new_search = true; + lookup->besteffort = false; + if (nofail) { + lookup->servfail_stops = false; + } + ISC_LIST_INIT(lookup->q); + ISC_LINK_INIT(lookup, link); + ISC_LIST_APPEND(lookup_list, lookup, link); + lookup->origin = NULL; + ISC_LIST_INIT(lookup->my_server_list); + debug("looking up %s", lookup->textname); +} + +static void +do_next_command(char *input) { + char *ptr, *arg, *last; + + if ((ptr = strtok_r(input, " \t\r\n", &last)) == NULL) { + return; + } + arg = strtok_r(NULL, " \t\r\n", &last); + if ((strcasecmp(ptr, "set") == 0) && (arg != NULL)) { + setoption(arg); + } else if ((strcasecmp(ptr, "server") == 0) || + (strcasecmp(ptr, "lserver") == 0)) + { + isc_app_block(); + set_nameserver(arg); + check_ra = false; + isc_app_unblock(); + show_settings(true, true); + } else if (strcasecmp(ptr, "exit") == 0) { + in_use = false; + } else if (strcasecmp(ptr, "help") == 0 || strcasecmp(ptr, "?") == 0) { + printf("The '%s' command is not yet implemented.\n", ptr); + } else if (strcasecmp(ptr, "finger") == 0 || + strcasecmp(ptr, "root") == 0 || strcasecmp(ptr, "ls") == 0 || + strcasecmp(ptr, "view") == 0) + { + printf("The '%s' command is not implemented.\n", ptr); + } else { + addlookup(ptr); + } +} + +static void +get_next_command(void) { + char *buf; + char *ptr; + + fflush(stdout); + buf = isc_mem_allocate(mctx, COMMSIZE); + isc_app_block(); + if (interactive) { +#ifdef HAVE_READLINE + ptr = readline("> "); + if (ptr != NULL) { + add_history(ptr); + } +#else /* ifdef HAVE_READLINE */ + fputs("> ", stderr); + fflush(stderr); + ptr = fgets(buf, COMMSIZE, stdin); +#endif /* ifdef HAVE_READLINE */ + } else { + ptr = fgets(buf, COMMSIZE, stdin); + } + isc_app_unblock(); + if (ptr == NULL) { + in_use = false; + } else { + do_next_command(ptr); + } +#ifdef HAVE_READLINE + if (interactive) { + free(ptr); + } +#endif /* ifdef HAVE_READLINE */ + isc_mem_free(mctx, buf); +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " nslookup [-opt ...] # interactive mode " + "using default server\n"); + fprintf(stderr, " nslookup [-opt ...] - server # interactive mode " + "using 'server'\n"); + fprintf(stderr, " nslookup [-opt ...] host # just look up " + "'host' using default server\n"); + fprintf(stderr, " nslookup [-opt ...] host server # just look up " + "'host' using 'server'\n"); + exit(1); +} + +static void +parse_args(int argc, char **argv) { + bool have_lookup = false; + + usesearch = true; + for (argc--, argv++; argc > 0 && argv[0] != NULL; argc--, argv++) { + debug("main parsing %s", argv[0]); + if (argv[0][0] == '-') { + if (strncasecmp(argv[0], "-ver", 4) == 0) { + version(); + exit(0); + } else if (argv[0][1] != 0) { + setoption(&argv[0][1]); + } else { + have_lookup = true; + } + } else { + if (!have_lookup) { + have_lookup = true; + in_use = true; + addlookup(argv[0]); + } else { + if (argv[1] != NULL) { + usage(); + } + set_nameserver(argv[0]); + check_ra = false; + } + } + } +} + +static void +flush_lookup_list(void) { + dig_lookup_t *l, *lp; + dig_query_t *q, *qp; + dig_server_t *s, *sp; + + lookup_counter = 0; + l = ISC_LIST_HEAD(lookup_list); + while (l != NULL) { + q = ISC_LIST_HEAD(l->q); + while (q != NULL) { + if (q->sock != NULL) { + isc_socket_cancel(q->sock, NULL, + ISC_SOCKCANCEL_ALL); + isc_socket_detach(&q->sock); + } + isc_buffer_invalidate(&q->recvbuf); + isc_buffer_invalidate(&q->lengthbuf); + qp = q; + q = ISC_LIST_NEXT(q, link); + ISC_LIST_DEQUEUE(l->q, qp, link); + isc_mem_free(mctx, qp); + } + s = ISC_LIST_HEAD(l->my_server_list); + while (s != NULL) { + sp = s; + s = ISC_LIST_NEXT(s, link); + ISC_LIST_DEQUEUE(l->my_server_list, sp, link); + isc_mem_free(mctx, sp); + } + if (l->sendmsg != NULL) { + dns_message_detach(&l->sendmsg); + } + lp = l; + l = ISC_LIST_NEXT(l, link); + ISC_LIST_DEQUEUE(lookup_list, lp, link); + isc_mem_free(mctx, lp); + } +} + +static void +getinput(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + if (global_event == NULL) { + global_event = event; + } + while (in_use) { + get_next_command(); + if (ISC_LIST_HEAD(lookup_list) != NULL) { + start_lookup(); + return; + } + } + isc_app_shutdown(); +} + +int +main(int argc, char **argv) { + isc_result_t result; + + interactive = isatty(0); + + ISC_LIST_INIT(lookup_list); + ISC_LIST_INIT(server_list); + ISC_LIST_INIT(search_list); + + check_ra = true; + + /* setup dighost callbacks */ + dighost_printmessage = printmessage; + dighost_received = received; + dighost_trying = trying; + dighost_shutdown = query_finished; + + result = isc_app_start(); + check_result(result, "isc_app_start"); + + setup_libs(); + progname = argv[0]; + + setup_system(false, false); + parse_args(argc, argv); + if (keyfile[0] != 0) { + setup_file_key(); + } else if (keysecret[0] != 0) { + setup_text_key(); + } + if (domainopt[0] != '\0') { + set_search_domain(domainopt); + } + if (in_use) { + result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); + } else { + result = isc_app_onrun(mctx, global_task, getinput, NULL); + } + check_result(result, "isc_app_onrun"); + in_use = !in_use; + + (void)isc_app_run(); + + puts(""); + debug("done, and starting to shut down"); + if (global_event != NULL) { + isc_event_free(&global_event); + } + cancel_all(); + destroy_libs(); + isc_app_finish(); + + return (query_error | print_error); +} diff --git a/bin/dig/nslookup.rst b/bin/dig/nslookup.rst new file mode 100644 index 0000000..2d1e123 --- /dev/null +++ b/bin/dig/nslookup.rst @@ -0,0 +1,206 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_nslookup: + +nslookup - query Internet name servers interactively +---------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`nslookup` [-option] [name | -] [server] + +Description +~~~~~~~~~~~ + +``nslookup`` is a program to query Internet domain name servers. +``nslookup`` has two modes: interactive and non-interactive. Interactive +mode allows the user to query name servers for information about various +hosts and domains or to print a list of hosts in a domain. +Non-interactive mode prints just the name and requested +information for a host or domain. + +Arguments +~~~~~~~~~ + +Interactive mode is entered in the following cases: + +a. when no arguments are given (the default name server is used); + +b. when the first argument is a hyphen (-) and the second argument is + the host name or Internet address of a name server. + +Non-interactive mode is used when the name or Internet address of the +host to be looked up is given as the first argument. The optional second +argument specifies the host name or address of a name server. + +Options can also be specified on the command line if they precede the +arguments and are prefixed with a hyphen. For example, to change the +default query type to host information, with an initial timeout of 10 +seconds, type: + +:: + + nslookup -query=hinfo -timeout=10 + +The ``-version`` option causes ``nslookup`` to print the version number +and immediately exit. + +Interactive Commands +~~~~~~~~~~~~~~~~~~~~ + +``host [server]`` + This command looks up information for ``host`` using the current default server or + using ``server``, if specified. If ``host`` is an Internet address and the + query type is A or PTR, the name of the host is returned. If ``host`` is + a name and does not have a trailing period (``.``), the search list is used + to qualify the name. + + To look up a host not in the current domain, append a period to the + name. + +``server domain`` | ``lserver domain`` + These commands change the default server to ``domain``; ``lserver`` uses the initial + server to look up information about ``domain``, while ``server`` uses the + current default server. If an authoritative answer cannot be found, + the names of servers that might have the answer are returned. + +``root`` + This command is not implemented. + +``finger`` + This command is not implemented. + +``ls`` + This command is not implemented. + +``view`` + This command is not implemented. + +``help`` + This command is not implemented. + +``?`` + This command is not implemented. + +``exit`` + This command exits the program. + +``set keyword[=value]`` + This command is used to change state information that affects the + lookups. Valid keywords are: + + ``all`` + This keyword prints the current values of the frequently used options to + ``set``. Information about the current default server and host is + also printed. + + ``class=value`` + This keyword changes the query class to one of: + + ``IN`` + the Internet class + + ``CH`` + the Chaos class + + ``HS`` + the Hesiod class + + ``ANY`` + wildcard + + The class specifies the protocol group of the information. The default + is ``IN``; the abbreviation for this keyword is ``cl``. + + ``nodebug`` + This keyword turns on or off the display of the full response packet, and any + intermediate response packets, when searching. The default for this keyword is + ``nodebug``; the abbreviation for this keyword is ``[no]deb``. + + ``nod2`` + This keyword turns debugging mode on or off. This displays more about what + nslookup is doing. The default is ``nod2``. + + ``domain=name`` + This keyword sets the search list to ``name``. + + ``nosearch`` + If the lookup request contains at least one period, but does not end + with a trailing period, this keyword appends the domain names in the domain + search list to the request until an answer is received. The default is ``search``. + + ``port=value`` + This keyword changes the default TCP/UDP name server port to ``value`` from + its default, port 53. The abbreviation for this keyword is ``po``. + + ``querytype=value`` | ``type=value`` + This keyword changes the type of the information query to ``value``. The + defaults are A and then AAAA; the abbreviations for these keywords are + ``q`` and ``ty``. + + Please note that it is only possible to specify one query type. Only the default + behavior looks up both when an alternative is not specified. + + ``norecurse`` + This keyword tells the name server to query other servers if it does not have + the information. The default is ``recurse``; the abbreviation for this + keyword is ``[no]rec``. + + ``ndots=number`` + This keyword sets the number of dots (label separators) in a domain that + disables searching. Absolute names always stop searching. + + ``retry=number`` + This keyword sets the number of retries to ``number``. + + ``timeout=number`` + This keyword changes the initial timeout interval to wait for a reply to + ``number``, in seconds. + + ``novc`` + This keyword indicates that a virtual circuit should always be used when sending requests to the server. + ``novc`` is the default. + + ``nofail`` + This keyword tries the next nameserver if a nameserver responds with SERVFAIL or + a referral (nofail), or terminates the query (fail) on such a response. The + default is ``nofail``. + +Return Values +~~~~~~~~~~~~~ + +``nslookup`` returns with an exit status of 1 if any query failed, and 0 +otherwise. + +IDN Support +~~~~~~~~~~~ + +If ``nslookup`` has been built with IDN (internationalized domain name) +support, it can accept and display non-ASCII domain names. ``nslookup`` +appropriately converts character encoding of a domain name before sending +a request to a DNS server or displaying a reply from the server. +To turn off IDN support, define the ``IDN_DISABLE`` +environment variable. IDN support is disabled if the variable is set +when ``nslookup`` runs, or when the standard output is not a tty. + +Files +~~~~~ + +``/etc/resolv.conf`` + +See Also +~~~~~~~~ + +:manpage:`dig(1)`, :manpage:`host(1)`, :manpage:`named(8)`. diff --git a/bin/dig/win32/dig.vcxproj.filters.in b/bin/dig/win32/dig.vcxproj.filters.in new file mode 100644 index 0000000..1d92732 --- /dev/null +++ b/bin/dig/win32/dig.vcxproj.filters.in @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dig/win32/dig.vcxproj.in b/bin/dig/win32/dig.vcxproj.in new file mode 100644 index 0000000..c65a103 --- /dev/null +++ b/bin/dig/win32/dig.vcxproj.in @@ -0,0 +1,122 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {F938F9B8-D395-4A40-BEC7-0122D289C692} + Win32Proj + dig + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\include;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@IDN_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dighost.lib;libisc.lib;libisccfg.lib;libirs.lib;libdns.lib;libbind9.lib;@IDN_LIB@ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\include;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@IDN_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dighost.lib;libisc.lib;libisccfg.lib;libirs.lib;libdns.lib;libbind9.lib;@IDN_LIB@ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + + + + diff --git a/bin/dig/win32/dig.vcxproj.user b/bin/dig/win32/dig.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dig/win32/dig.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dig/win32/dighost.vcxproj.filters.in b/bin/dig/win32/dighost.vcxproj.filters.in new file mode 100644 index 0000000..d108bfb --- /dev/null +++ b/bin/dig/win32/dighost.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dig/win32/dighost.vcxproj.in b/bin/dig/win32/dighost.vcxproj.in new file mode 100644 index 0000000..1ed120c --- /dev/null +++ b/bin/dig/win32/dighost.vcxproj.in @@ -0,0 +1,115 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {140DE800-E552-43CC-B0C7-A33A92E368CA} + Win32Proj + dighost + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + StaticLibrary + true + MultiByte + @PLATFORM_TOOLSET@ + + + StaticLibrary + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + .\$(Configuration)\ + .\$(Configuration)\ + None + + + false + .\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@IDN_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;..\..\..\lib\irs\include;..\..\..\lib\irs\win32\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@IDN_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;..\..\..\lib\irs\include;..\..\..\lib\irs\win32\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + false + + + + + + + + + diff --git a/bin/dig/win32/dighost.vcxproj.user b/bin/dig/win32/dighost.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dig/win32/dighost.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dig/win32/host.vcxproj.filters.in b/bin/dig/win32/host.vcxproj.filters.in new file mode 100644 index 0000000..56e7818 --- /dev/null +++ b/bin/dig/win32/host.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dig/win32/host.vcxproj.in b/bin/dig/win32/host.vcxproj.in new file mode 100644 index 0000000..091b4fb --- /dev/null +++ b/bin/dig/win32/host.vcxproj.in @@ -0,0 +1,119 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {BA1048A8-6961-4A20-BE12-08BE20611C9D} + Win32Proj + host + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\include;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@IDN_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dighost.lib;@IDN_LIB@libisc.lib;libisccfg.lib;libirs.lib;libdns.lib;libbind9.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\include;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@IDN_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dighost.lib;@IDN_LIB@libisc.lib;libisccfg.lib;libirs.lib;libdns.lib;libbind9.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/dig/win32/host.vcxproj.user b/bin/dig/win32/host.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dig/win32/host.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dig/win32/nslookup.vcxproj.filters.in b/bin/dig/win32/nslookup.vcxproj.filters.in new file mode 100644 index 0000000..7f4756e --- /dev/null +++ b/bin/dig/win32/nslookup.vcxproj.filters.in @@ -0,0 +1,21 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/bin/dig/win32/nslookup.vcxproj.in b/bin/dig/win32/nslookup.vcxproj.in new file mode 100644 index 0000000..565eb96 --- /dev/null +++ b/bin/dig/win32/nslookup.vcxproj.in @@ -0,0 +1,120 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {C15A6E1A-94CE-4686-99F9-6BC5FD623EB5} + Win32Proj + nslookup + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;USE_READLINE_STATIC;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\include;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@READLINE_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\irs\include;..\..\..\lib\irs\win32\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@READLINE_LIBD@@IDN_LIB@libisc.lib;libisccfg.lib;libirs.lib;libdns.lib;libbind9.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;USE_READLINE_STATIC;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\include;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@READLINE_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\include;..\..\..\lib\irs\include;..\..\..\lib\irs\win32\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@READLINE_LIB@@IDN_LIB@libisc.lib;libisccfg.lib;libirs.lib;libdns.lib;libbind9.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + + diff --git a/bin/dig/win32/nslookup.vcxproj.user b/bin/dig/win32/nslookup.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dig/win32/nslookup.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in new file mode 100644 index 0000000..f49f775 --- /dev/null +++ b/bin/dnssec/Makefile.in @@ -0,0 +1,112 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \ + ${OPENSSL_CFLAGS} + +CDEFINES = -DVERSION=\"${VERSION}\" -DNAMED_CONFFILE=\"${sysconfdir}/named.conf\" +CWARNINGS = + +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ + +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ + +DEPLIBS = ${DNSDEPLIBS} ${ISCCFGDEPLIBS} ${ISCDEPLIBS} + +LIBS = ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} @LIBS@ + +NOSYMLIBS = ${DNSLIBS} ${ISCCFGLIBS} ${ISCNOSYMLIBS} @LIBS@ + +# Alphabetically +TARGETS = dnssec-cds@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \ + dnssec-importkey@EXEEXT@ dnssec-keyfromlabel@EXEEXT@ \ + dnssec-keygen@EXEEXT@ dnssec-revoke@EXEEXT@ \ + dnssec-settime@EXEEXT@ dnssec-signzone@EXEEXT@ \ + dnssec-verify@EXEEXT@ + +OBJS = dnssectool.@O@ + +SRCS = dnssec-cds.c dnssec-dsfromkey.c dnssec-importkey.c \ + dnssec-keyfromlabel.c dnssec-keygen.c dnssec-revoke.c \ + dnssec-settime.c dnssec-signzone.c dnssec-verify.c \ + dnssectool.c + +@BIND9_MAKE_RULES@ + +dnssec-cds@EXEEXT@: dnssec-cds.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-cds.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +dnssec-dsfromkey@EXEEXT@: dnssec-dsfromkey.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-dsfromkey.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +dnssec-keyfromlabel@EXEEXT@: dnssec-keyfromlabel.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-keyfromlabel.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +dnssec-keygen@EXEEXT@: dnssec-keygen.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-keygen.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +dnssec-signzone.@O@: dnssec-signzone.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" \ + -c ${srcdir}/dnssec-signzone.c + +dnssec-signzone@EXEEXT@: dnssec-signzone.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-signzone.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +dnssec-verify.@O@: dnssec-verify.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" \ + -c ${srcdir}/dnssec-verify.c + +dnssec-verify@EXEEXT@: dnssec-verify.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-verify.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +dnssec-revoke@EXEEXT@: dnssec-revoke.@O@ ${OBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dnssec-revoke.@O@ ${OBJS} ${LIBS} + +dnssec-settime@EXEEXT@: dnssec-settime.@O@ ${OBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dnssec-settime.@O@ ${OBJS} ${LIBS} + +dnssec-importkey@EXEEXT@: dnssec-importkey.@O@ ${OBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dnssec-importkey.@O@ ${OBJS} ${LIBS} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8 + +install:: ${TARGETS} installdirs + for t in ${TARGETS}; do ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} $$t ${DESTDIR}${sbindir} || exit 1; done + +uninstall:: + for t in ${TARGETS}; do ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${sbindir}/$$t || exit 1; done + +clean distclean:: + rm -f ${TARGETS} diff --git a/bin/dnssec/dnssec-cds.c b/bin/dnssec/dnssec-cds.c new file mode 100644 index 0000000..15f9f4e --- /dev/null +++ b/bin/dnssec/dnssec-cds.c @@ -0,0 +1,1314 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Written by Tony Finch + * at Cambridge University Information Services + */ + +/*! \file */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include "dnssectool.h" + +const char *program = "dnssec-cds"; + +/* + * Infrastructure + */ +static isc_log_t *lctx = NULL; +static isc_mem_t *mctx = NULL; + +/* + * The domain we are working on + */ +static const char *namestr = NULL; +static dns_fixedname_t fixed; +static dns_name_t *name = NULL; +static dns_rdataclass_t rdclass = dns_rdataclass_in; + +static const char *startstr = NULL; /* from which we derive notbefore */ +static isc_stdtime_t notbefore = 0; /* restrict sig inception times */ +static dns_rdata_rrsig_t oldestsig; /* for recording inception time */ + +static int nkey; /* number of child zone DNSKEY records */ + +/* + * The validation strategy of this program is top-down. + * + * We start with an implicitly trusted authoritative dsset. + * + * The child DNSKEY RRset is scanned to find out which keys are + * authenticated by DS records, and the result is recorded in a key + * table as described later in this comment. + * + * The key table is used up to three times to verify the signatures on + * the child DNSKEY, CDNSKEY, and CDS RRsets. In this program, only keys + * that have matching DS records are used for validating signatures. + * + * For replay attack protection, signatures are ignored if their inception + * time is before the previously recorded inception time. We use the earliest + * signature so that another run of dnssec-cds with the same records will + * still accept all the signatures. + * + * A key table is an array of nkey keyinfo structures, like + * + * keyinfo_t key_tbl[nkey]; + * + * Each key is decoded into more useful representations, held in + * keyinfo->rdata + * keyinfo->dst + * + * If a key has no matching DS record then keyinfo->dst is NULL. + * + * The key algorithm and ID are saved in keyinfo->algo and + * keyinfo->tag for quicky skipping DS and RRSIG records that can't + * match. + */ +typedef struct keyinfo { + dns_rdata_t rdata; + dst_key_t *dst; + dns_secalg_t algo; + dns_keytag_t tag; +} keyinfo_t; + +/* A replaceable function that can generate a DS RRset from some input */ +typedef isc_result_t +ds_maker_func_t(dns_rdatalist_t *dslist, isc_buffer_t *buf, dns_rdata_t *rdata); + +static dns_rdataset_t cdnskey_set, cdnskey_sig; +static dns_rdataset_t cds_set, cds_sig; +static dns_rdataset_t dnskey_set, dnskey_sig; +static dns_rdataset_t old_ds_set, new_ds_set; + +static keyinfo_t *old_key_tbl, *new_key_tbl; + +isc_buffer_t *new_ds_buf = NULL; /* backing store for new_ds_set */ + +static void +verbose_time(int level, const char *msg, isc_stdtime_t time) { + isc_result_t result; + isc_buffer_t timebuf; + char timestr[32]; + + if (verbose < level) { + return; + } + + isc_buffer_init(&timebuf, timestr, sizeof(timestr)); + result = dns_time64_totext(time, &timebuf); + check_result(result, "dns_time64_totext()"); + isc_buffer_putuint8(&timebuf, 0); + if (verbose < 3) { + vbprintf(level, "%s %s\n", msg, timestr); + } else { + vbprintf(level, "%s %s (%" PRIu32 ")\n", msg, timestr, time); + } +} + +static void +initname(char *setname) { + isc_result_t result; + isc_buffer_t buf; + + name = dns_fixedname_initname(&fixed); + namestr = setname; + + isc_buffer_init(&buf, setname, strlen(setname)); + isc_buffer_add(&buf, strlen(setname)); + result = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fatal("could not initialize name %s", setname); + } +} + +static void +findset(dns_db_t *db, dns_dbnode_t *node, dns_rdatatype_t type, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { + isc_result_t result; + + dns_rdataset_init(rdataset); + if (sigrdataset != NULL) { + dns_rdataset_init(sigrdataset); + } + result = dns_db_findrdataset(db, node, NULL, type, 0, 0, rdataset, + sigrdataset); + if (result != ISC_R_NOTFOUND) { + check_result(result, "dns_db_findrdataset()"); + } +} + +static void +freeset(dns_rdataset_t *rdataset) { + if (dns_rdataset_isassociated(rdataset)) { + dns_rdataset_disassociate(rdataset); + } +} + +static void +freelist(dns_rdataset_t *rdataset) { + dns_rdatalist_t *rdlist; + dns_rdata_t *rdata; + + if (!dns_rdataset_isassociated(rdataset)) { + return; + } + + dns_rdatalist_fromrdataset(rdataset, &rdlist); + + for (rdata = ISC_LIST_HEAD(rdlist->rdata); rdata != NULL; + rdata = ISC_LIST_HEAD(rdlist->rdata)) + { + ISC_LIST_UNLINK(rdlist->rdata, rdata, link); + isc_mem_put(mctx, rdata, sizeof(*rdata)); + } + isc_mem_put(mctx, rdlist, sizeof(*rdlist)); + dns_rdataset_disassociate(rdataset); +} + +static void +free_all_sets(void) { + freeset(&cdnskey_set); + freeset(&cdnskey_sig); + freeset(&cds_set); + freeset(&cds_sig); + freeset(&dnskey_set); + freeset(&dnskey_sig); + freeset(&old_ds_set); + freelist(&new_ds_set); + if (new_ds_buf != NULL) { + isc_buffer_free(&new_ds_buf); + } +} + +static void +load_db(const char *filename, dns_db_t **dbp, dns_dbnode_t **nodep) { + isc_result_t result; + + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0, + NULL, dbp); + check_result(result, "dns_db_create()"); + + result = dns_db_load(*dbp, filename, dns_masterformat_text, + DNS_MASTER_HINT); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { + fatal("can't load %s: %s", filename, isc_result_totext(result)); + } + + result = dns_db_findnode(*dbp, name, false, nodep); + if (result != ISC_R_SUCCESS) { + fatal("can't find %s node in %s", namestr, filename); + } +} + +static void +free_db(dns_db_t **dbp, dns_dbnode_t **nodep) { + dns_db_detachnode(*dbp, nodep); + dns_db_detach(dbp); +} + +static void +load_child_sets(const char *file) { + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + + load_db(file, &db, &node); + findset(db, node, dns_rdatatype_dnskey, &dnskey_set, &dnskey_sig); + findset(db, node, dns_rdatatype_cdnskey, &cdnskey_set, &cdnskey_sig); + findset(db, node, dns_rdatatype_cds, &cds_set, &cds_sig); + free_db(&db, &node); +} + +static void +get_dsset_name(char *filename, size_t size, const char *path, + const char *suffix) { + isc_result_t result; + isc_buffer_t buf; + size_t len; + + isc_buffer_init(&buf, filename, size); + + len = strlen(path); + + /* allow room for a trailing slash */ + if (isc_buffer_availablelength(&buf) <= len) { + fatal("%s: pathname too long", path); + } + isc_buffer_putstr(&buf, path); + + if (isc_file_isdirectory(path) == ISC_R_SUCCESS) { + const char *prefix = "dsset-"; + + if (path[len - 1] != '/') { + isc_buffer_putstr(&buf, "/"); + } + + if (isc_buffer_availablelength(&buf) < strlen(prefix)) { + fatal("%s: pathname too long", path); + } + isc_buffer_putstr(&buf, prefix); + + result = dns_name_tofilenametext(name, false, &buf); + check_result(result, "dns_name_tofilenametext()"); + if (isc_buffer_availablelength(&buf) == 0) { + fatal("%s: pathname too long", path); + } + } + /* allow room for a trailing nul */ + if (isc_buffer_availablelength(&buf) <= strlen(suffix)) { + fatal("%s: pathname too long", path); + } + isc_buffer_putstr(&buf, suffix); + isc_buffer_putuint8(&buf, 0); +} + +static void +load_parent_set(const char *path) { + isc_result_t result; + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + isc_time_t modtime; + char filename[PATH_MAX + 1]; + + get_dsset_name(filename, sizeof(filename), path, ""); + + result = isc_file_getmodtime(filename, &modtime); + if (result != ISC_R_SUCCESS) { + fatal("could not get modification time of %s: %s", filename, + isc_result_totext(result)); + } + notbefore = isc_time_seconds(&modtime); + if (startstr != NULL) { + isc_stdtime_t now; + isc_stdtime_get(&now); + notbefore = strtotime(startstr, now, notbefore, NULL); + } + verbose_time(1, "child records must not be signed before", notbefore); + + load_db(filename, &db, &node); + findset(db, node, dns_rdatatype_ds, &old_ds_set, NULL); + + if (!dns_rdataset_isassociated(&old_ds_set)) { + fatal("could not find DS records for %s in %s", namestr, + filename); + } + + free_db(&db, &node); +} + +#define MAX_CDS_RDATA_TEXT_SIZE DNS_RDATA_MAXLENGTH * 2 + +static isc_buffer_t * +formatset(dns_rdataset_t *rdataset) { + isc_result_t result; + isc_buffer_t *buf = NULL; + dns_master_style_t *style = NULL; + unsigned int styleflags; + + styleflags = (rdataset->ttl == 0) ? DNS_STYLEFLAG_NO_TTL : 0; + + /* + * This style is for consistency with the output of dnssec-dsfromkey + * which just separates fields with spaces. The huge tab stop width + * eliminates any tab characters. + */ + result = dns_master_stylecreate(&style, styleflags, 0, 0, 0, 0, 0, + 1000000, 0, mctx); + check_result(result, "dns_master_stylecreate2 failed"); + + isc_buffer_allocate(mctx, &buf, MAX_CDS_RDATA_TEXT_SIZE); + result = dns_master_rdatasettotext(name, rdataset, style, NULL, buf); + + if ((result == ISC_R_SUCCESS) && isc_buffer_availablelength(buf) < 1) { + result = ISC_R_NOSPACE; + } + + check_result(result, "dns_rdataset_totext()"); + + isc_buffer_putuint8(buf, 0); + + dns_master_styledestroy(&style, mctx); + + return (buf); +} + +static void +write_parent_set(const char *path, const char *inplace, bool nsupdate, + dns_rdataset_t *rdataset) { + isc_result_t result; + isc_buffer_t *buf = NULL; + isc_region_t r; + isc_time_t filetime; + char backname[PATH_MAX + 1]; + char filename[PATH_MAX + 1]; + char tmpname[PATH_MAX + 1]; + FILE *fp = NULL; + + if (nsupdate && inplace == NULL) { + return; + } + + buf = formatset(rdataset); + isc_buffer_usedregion(buf, &r); + + /* + * Try to ensure a write error doesn't make a zone go insecure! + */ + if (inplace == NULL) { + printf("%s", (char *)r.base); + isc_buffer_free(&buf); + if (fflush(stdout) == EOF) { + fatal("error writing to stdout: %s", strerror(errno)); + } + return; + } + + if (inplace[0] != '\0') { + get_dsset_name(backname, sizeof(backname), path, inplace); + } + get_dsset_name(filename, sizeof(filename), path, ""); + get_dsset_name(tmpname, sizeof(tmpname), path, "-XXXXXXXXXX"); + + result = isc_file_openunique(tmpname, &fp); + if (result != ISC_R_SUCCESS) { + fatal("open %s: %s", tmpname, isc_result_totext(result)); + } + fprintf(fp, "%s", (char *)r.base); + isc_buffer_free(&buf); + if (fclose(fp) == EOF) { + int err = errno; + isc_file_remove(tmpname); + fatal("error writing to %s: %s", tmpname, strerror(err)); + } + + isc_time_set(&filetime, oldestsig.timesigned, 0); + result = isc_file_settime(tmpname, &filetime); + if (result != ISC_R_SUCCESS) { + isc_file_remove(tmpname); + fatal("can't set modification time of %s: %s", tmpname, + isc_result_totext(result)); + } + + if (inplace[0] != '\0') { + isc_file_rename(filename, backname); + } + isc_file_rename(tmpname, filename); +} + +typedef enum { LOOSE, TIGHT } strictness_t; + +/* + * Find out if any (C)DS record matches a particular (C)DNSKEY. + */ +static bool +match_key_dsset(keyinfo_t *ki, dns_rdataset_t *dsset, strictness_t strictness) { + isc_result_t result; + unsigned char dsbuf[DNS_DS_BUFFERSIZE]; + + for (result = dns_rdataset_first(dsset); result == ISC_R_SUCCESS; + result = dns_rdataset_next(dsset)) + { + dns_rdata_ds_t ds; + dns_rdata_t dsrdata = DNS_RDATA_INIT; + dns_rdata_t newdsrdata = DNS_RDATA_INIT; + bool c; + + dns_rdataset_current(dsset, &dsrdata); + result = dns_rdata_tostruct(&dsrdata, &ds, NULL); + check_result(result, "dns_rdata_tostruct(DS)"); + + if (ki->tag != ds.key_tag || ki->algo != ds.algorithm) { + continue; + } + + result = dns_ds_buildrdata(name, &ki->rdata, ds.digest_type, + dsbuf, &newdsrdata); + if (result != ISC_R_SUCCESS) { + vbprintf(3, + "dns_ds_buildrdata(" + "keytag=%d, algo=%d, digest=%d): %s\n", + ds.key_tag, ds.algorithm, ds.digest_type, + dns_result_totext(result)); + continue; + } + /* allow for both DS and CDS */ + c = dsrdata.type != dns_rdatatype_ds; + dsrdata.type = dns_rdatatype_ds; + if (dns_rdata_compare(&dsrdata, &newdsrdata) == 0) { + vbprintf(1, "found matching %s %d %d %d\n", + c ? "CDS" : "DS", ds.key_tag, ds.algorithm, + ds.digest_type); + return (true); + } else if (strictness == TIGHT) { + vbprintf(0, + "key does not match %s %d %d %d " + "when it looks like it should\n", + c ? "CDS" : "DS", ds.key_tag, ds.algorithm, + ds.digest_type); + return (false); + } + } + + vbprintf(1, "no matching %s for %s %d %d\n", + dsset->type == dns_rdatatype_cds ? "CDS" : "DS", + ki->rdata.type == dns_rdatatype_cdnskey ? "CDNSKEY" : "DNSKEY", + ki->tag, ki->algo); + + return (false); +} + +/* + * Find which (C)DNSKEY records match a (C)DS RRset. + * This creates a keyinfo_t key_tbl[nkey] array. + */ +static keyinfo_t * +match_keyset_dsset(dns_rdataset_t *keyset, dns_rdataset_t *dsset, + strictness_t strictness) { + isc_result_t result; + keyinfo_t *keytable; + int i; + + nkey = dns_rdataset_count(keyset); + + keytable = isc_mem_get(mctx, sizeof(keyinfo_t) * nkey); + + for (result = dns_rdataset_first(keyset), i = 0; + result == ISC_R_SUCCESS; result = dns_rdataset_next(keyset), i++) + { + keyinfo_t *ki; + dns_rdata_dnskey_t dnskey; + dns_rdata_t *keyrdata; + isc_region_t r; + + INSIST(i < nkey); + ki = &keytable[i]; + keyrdata = &ki->rdata; + + dns_rdata_init(keyrdata); + dns_rdataset_current(keyset, keyrdata); + + result = dns_rdata_tostruct(keyrdata, &dnskey, NULL); + check_result(result, "dns_rdata_tostruct(DNSKEY)"); + ki->algo = dnskey.algorithm; + + dns_rdata_toregion(keyrdata, &r); + ki->tag = dst_region_computeid(&r); + + ki->dst = NULL; + if (!match_key_dsset(ki, dsset, strictness)) { + continue; + } + + result = dns_dnssec_keyfromrdata(name, keyrdata, mctx, + &ki->dst); + if (result != ISC_R_SUCCESS) { + vbprintf(3, + "dns_dnssec_keyfromrdata(" + "keytag=%d, algo=%d): %s\n", + ki->tag, ki->algo, dns_result_totext(result)); + } + } + + return (keytable); +} + +static void +free_keytable(keyinfo_t **keytable_p) { + keyinfo_t *keytable = *keytable_p; + *keytable_p = NULL; + keyinfo_t *ki; + int i; + + for (i = 0; i < nkey; i++) { + ki = &keytable[i]; + if (ki->dst != NULL) { + dst_key_free(&ki->dst); + } + } + + isc_mem_put(mctx, keytable, sizeof(keyinfo_t) * nkey); +} + +/* + * Find out which keys have signed an RRset. Keys that do not match a + * DS record are skipped. + * + * The return value is an array with nkey elements, one for each key, + * either zero if the key was skipped or did not sign the RRset, or + * otherwise the key algorithm. This is used by the signature coverage + * check functions below. + */ +static dns_secalg_t * +matching_sigs(keyinfo_t *keytbl, dns_rdataset_t *rdataset, + dns_rdataset_t *sigset) { + isc_result_t result; + dns_secalg_t *algo; + int i; + + algo = isc_mem_get(mctx, nkey); + memset(algo, 0, nkey); + + for (result = dns_rdataset_first(sigset); result == ISC_R_SUCCESS; + result = dns_rdataset_next(sigset)) + { + dns_rdata_t sigrdata = DNS_RDATA_INIT; + dns_rdata_rrsig_t sig; + + dns_rdataset_current(sigset, &sigrdata); + result = dns_rdata_tostruct(&sigrdata, &sig, NULL); + check_result(result, "dns_rdata_tostruct(RRSIG)"); + + /* + * Replay attack protection: check against current age limit + */ + if (isc_serial_lt(sig.timesigned, notbefore)) { + vbprintf(1, "skip RRSIG by key %d: too old\n", + sig.keyid); + continue; + } + + for (i = 0; i < nkey; i++) { + keyinfo_t *ki = &keytbl[i]; + if (sig.keyid != ki->tag || sig.algorithm != ki->algo || + !dns_name_equal(&sig.signer, name)) + { + continue; + } + if (ki->dst == NULL) { + vbprintf(1, + "skip RRSIG by key %d:" + " no matching (C)DS\n", + sig.keyid); + continue; + } + + result = dns_dnssec_verify(name, rdataset, ki->dst, + false, 0, mctx, &sigrdata, + NULL); + + if (result != ISC_R_SUCCESS && + result != DNS_R_FROMWILDCARD) + { + vbprintf(1, + "skip RRSIG by key %d:" + " verification failed: %s\n", + sig.keyid, isc_result_totext(result)); + continue; + } + + vbprintf(1, "found RRSIG by key %d\n", ki->tag); + algo[i] = sig.algorithm; + + /* + * Replay attack protection: work out next age limit, + * only after the signature has been verified + */ + if (oldestsig.timesigned == 0 || + isc_serial_lt(sig.timesigned, oldestsig.timesigned)) + { + verbose_time(2, "this is the oldest so far", + sig.timesigned); + oldestsig = sig; + } + } + } + + return (algo); +} + +/* + * Consume the result of matching_sigs(). When checking records + * fetched from the child zone, any working signature is enough. + */ +static bool +signed_loose(dns_secalg_t *algo) { + bool ok = false; + int i; + for (i = 0; i < nkey; i++) { + if (algo[i] != 0) { + ok = true; + } + } + isc_mem_put(mctx, algo, nkey); + return (ok); +} + +/* + * Consume the result of matching_sigs(). To ensure that the new DS + * RRset does not break the chain of trust to the DNSKEY RRset, every + * key algorithm in the DS RRset must have a signature in the DNSKEY + * RRset. + */ +static bool +signed_strict(dns_rdataset_t *dsset, dns_secalg_t *algo) { + isc_result_t result; + bool all_ok = true; + + for (result = dns_rdataset_first(dsset); result == ISC_R_SUCCESS; + result = dns_rdataset_next(dsset)) + { + dns_rdata_t dsrdata = DNS_RDATA_INIT; + dns_rdata_ds_t ds; + bool ds_ok; + int i; + + dns_rdataset_current(dsset, &dsrdata); + result = dns_rdata_tostruct(&dsrdata, &ds, NULL); + check_result(result, "dns_rdata_tostruct(DS)"); + + ds_ok = false; + for (i = 0; i < nkey; i++) { + if (algo[i] == ds.algorithm) { + ds_ok = true; + } + } + if (!ds_ok) { + vbprintf(0, + "missing signature for algorithm %d " + "(key %d)\n", + ds.algorithm, ds.key_tag); + all_ok = false; + } + } + + isc_mem_put(mctx, algo, nkey); + return (all_ok); +} + +static dns_rdata_t * +rdata_get(void) { + dns_rdata_t *rdata; + + rdata = isc_mem_get(mctx, sizeof(*rdata)); + dns_rdata_init(rdata); + + return (rdata); +} + +static isc_result_t +rdata_put(isc_result_t result, dns_rdatalist_t *rdlist, dns_rdata_t *rdata) { + if (result == ISC_R_SUCCESS) { + ISC_LIST_APPEND(rdlist->rdata, rdata, link); + } else { + isc_mem_put(mctx, rdata, sizeof(*rdata)); + } + + return (result); +} + +/* + * This basically copies the rdata into the buffer, but going via the + * unpacked struct has the side-effect of changing the rdatatype. The + * dns_rdata_cds_t and dns_rdata_ds_t types are aliases. + */ +static isc_result_t +ds_from_cds(dns_rdatalist_t *dslist, isc_buffer_t *buf, dns_rdata_t *cds) { + isc_result_t result; + dns_rdata_ds_t ds; + dns_rdata_t *rdata; + + REQUIRE(buf != NULL); + + rdata = rdata_get(); + + result = dns_rdata_tostruct(cds, &ds, NULL); + check_result(result, "dns_rdata_tostruct(CDS)"); + ds.common.rdtype = dns_rdatatype_ds; + + result = dns_rdata_fromstruct(rdata, rdclass, dns_rdatatype_ds, &ds, + buf); + + return (rdata_put(result, dslist, rdata)); +} + +static isc_result_t +ds_from_cdnskey(dns_rdatalist_t *dslist, isc_buffer_t *buf, + dns_rdata_t *cdnskey) { + isc_result_t result; + unsigned i, n; + + REQUIRE(buf != NULL); + + n = sizeof(dtype) / sizeof(dtype[0]); + for (i = 0; i < n; i++) { + if (dtype[i] != 0) { + dns_rdata_t *rdata; + isc_region_t r; + + isc_buffer_availableregion(buf, &r); + if (r.length < DNS_DS_BUFFERSIZE) { + return (ISC_R_NOSPACE); + } + + rdata = rdata_get(); + result = dns_ds_buildrdata(name, cdnskey, dtype[i], + r.base, rdata); + if (result == ISC_R_SUCCESS) { + isc_buffer_add(buf, DNS_DS_BUFFERSIZE); + } + + result = rdata_put(result, dslist, rdata); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + } + + return (ISC_R_SUCCESS); +} + +static void +make_new_ds_set(ds_maker_func_t *ds_from_rdata, uint32_t ttl, + dns_rdataset_t *rdset) { + unsigned int size = 16; + for (;;) { + isc_result_t result; + dns_rdatalist_t *dslist; + + dslist = isc_mem_get(mctx, sizeof(*dslist)); + + dns_rdatalist_init(dslist); + dslist->rdclass = rdclass; + dslist->type = dns_rdatatype_ds; + dslist->ttl = ttl; + + dns_rdataset_init(&new_ds_set); + result = dns_rdatalist_tordataset(dslist, &new_ds_set); + check_result(result, "dns_rdatalist_tordataset(dslist)"); + + isc_buffer_allocate(mctx, &new_ds_buf, size); + + for (result = dns_rdataset_first(rdset); + result == ISC_R_SUCCESS; result = dns_rdataset_next(rdset)) + { + isc_result_t tresult; + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(rdset, &rdata); + + tresult = ds_from_rdata(dslist, new_ds_buf, &rdata); + if (tresult == ISC_R_NOSPACE) { + vbprintf(20, "DS list buffer size %u\n", size); + freelist(&new_ds_set); + isc_buffer_free(&new_ds_buf); + size *= 2; + break; + } + + check_result(tresult, "ds_from_rdata()"); + } + + if (result == ISC_R_NOMORE) { + break; + } + } +} + +static int +rdata_cmp(const void *rdata1, const void *rdata2) { + return (dns_rdata_compare((const dns_rdata_t *)rdata1, + (const dns_rdata_t *)rdata2)); +} + +/* + * Ensure that every key identified by the DS RRset has the same set of + * digest types. + */ +static bool +consistent_digests(dns_rdataset_t *dsset) { + isc_result_t result; + dns_rdata_t *arrdata; + dns_rdata_ds_t *ds; + dns_keytag_t key_tag; + dns_secalg_t algorithm; + bool match; + int i, j, n, d; + + /* + * First sort the dsset. DS rdata fields are tag, algorithm, digest, + * so sorting them brings together all the records for each key. + */ + + n = dns_rdataset_count(dsset); + + arrdata = isc_mem_get(mctx, n * sizeof(dns_rdata_t)); + + for (result = dns_rdataset_first(dsset), i = 0; result == ISC_R_SUCCESS; + result = dns_rdataset_next(dsset), i++) + { + dns_rdata_init(&arrdata[i]); + dns_rdataset_current(dsset, &arrdata[i]); + } + + qsort(arrdata, n, sizeof(dns_rdata_t), rdata_cmp); + + /* + * Convert sorted arrdata to more accessible format + */ + ds = isc_mem_get(mctx, n * sizeof(dns_rdata_ds_t)); + + for (i = 0; i < n; i++) { + result = dns_rdata_tostruct(&arrdata[i], &ds[i], NULL); + check_result(result, "dns_rdata_tostruct(DS)"); + } + + /* + * Count number of digest types (d) for first key + */ + key_tag = ds[0].key_tag; + algorithm = ds[0].algorithm; + for (d = 0, i = 0; i < n; i++, d++) { + if (ds[i].key_tag != key_tag || ds[i].algorithm != algorithm) { + break; + } + } + + /* + * Check subsequent keys match the first one + */ + match = true; + while (i < n) { + key_tag = ds[i].key_tag; + algorithm = ds[i].algorithm; + for (j = 0; j < d && i + j < n; j++) { + if (ds[i + j].key_tag != key_tag || + ds[i + j].algorithm != algorithm || + ds[i + j].digest_type != ds[j].digest_type) + { + match = false; + } + } + i += d; + } + + /* + * Done! + */ + isc_mem_put(mctx, ds, n * sizeof(dns_rdata_ds_t)); + isc_mem_put(mctx, arrdata, n * sizeof(dns_rdata_t)); + + return (match); +} + +static void +print_diff(const char *cmd, dns_rdataset_t *rdataset) { + isc_buffer_t *buf; + isc_region_t r; + unsigned char *nl; + size_t len; + + buf = formatset(rdataset); + isc_buffer_usedregion(buf, &r); + + while ((nl = memchr(r.base, '\n', r.length)) != NULL) { + len = nl - r.base + 1; + printf("update %s %.*s", cmd, (int)len, (char *)r.base); + isc_region_consume(&r, len); + } + + isc_buffer_free(&buf); +} + +static void +update_diff(const char *cmd, uint32_t ttl, dns_rdataset_t *addset, + dns_rdataset_t *delset) { + isc_result_t result; + dns_db_t *db; + dns_dbnode_t *node; + dns_dbversion_t *ver; + dns_rdataset_t diffset; + uint32_t save; + + db = NULL; + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0, + NULL, &db); + check_result(result, "dns_db_create()"); + + ver = NULL; + result = dns_db_newversion(db, &ver); + check_result(result, "dns_db_newversion()"); + + node = NULL; + result = dns_db_findnode(db, name, true, &node); + check_result(result, "dns_db_findnode()"); + + dns_rdataset_init(&diffset); + + result = dns_db_addrdataset(db, node, ver, 0, addset, DNS_DBADD_MERGE, + NULL); + check_result(result, "dns_db_addrdataset()"); + + result = dns_db_subtractrdataset(db, node, ver, delset, 0, &diffset); + if (result == DNS_R_UNCHANGED) { + save = addset->ttl; + addset->ttl = ttl; + print_diff(cmd, addset); + addset->ttl = save; + } else if (result != DNS_R_NXRRSET) { + check_result(result, "dns_db_subtractrdataset()"); + diffset.ttl = ttl; + print_diff(cmd, &diffset); + dns_rdataset_disassociate(&diffset); + } + + dns_db_detachnode(db, &node); + dns_db_closeversion(db, &ver, false); + dns_db_detach(&db); +} + +static void +nsdiff(uint32_t ttl, dns_rdataset_t *oldset, dns_rdataset_t *newset) { + if (ttl == 0) { + vbprintf(1, "warning: no TTL in nsupdate script\n"); + } + update_diff("add", ttl, newset, oldset); + update_diff("del", 0, oldset, newset); + if (verbose > 0) { + printf("show\nsend\nanswer\n"); + } else { + printf("send\n"); + } + if (fflush(stdout) == EOF) { + fatal("write stdout: %s", strerror(errno)); + } +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, + " %s options [options] -f -d \n", + program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "Options:\n" + " -a digest algorithm (SHA-1 / " + "SHA-256 / SHA-384)\n" + " -c of domain (default IN)\n" + " -D prefer CDNSKEY records instead " + "of CDS\n" + " -d where to find parent dsset- " + "file\n" + " -f child DNSKEY+CDNSKEY+CDS+RRSIG " + "records\n" + " -i[extension] update dsset- file in place\n" + " -s oldest permitted child " + "signatures\n" + " -u emit nsupdate script\n" + " -T TTL of DS records\n" + " -V print version\n" + " -v \n"); + exit(1); +} + +int +main(int argc, char *argv[]) { + const char *child_path = NULL; + const char *ds_path = NULL; + const char *inplace = NULL; + isc_result_t result; + bool prefer_cdnskey = false; + bool nsupdate = false; + uint32_t ttl = 0; + int ch; + char *endp; + + isc_mem_create(&mctx); + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + isc_commandline_errprint = false; + +#define OPTIONS "a:c:Dd:f:i:ms:T:uv:V" + while ((ch = isc_commandline_parse(argc, argv, OPTIONS)) != -1) { + switch (ch) { + case 'a': + add_dtype(strtodsdigest(isc_commandline_argument)); + break; + case 'c': + rdclass = strtoclass(isc_commandline_argument); + break; + case 'D': + prefer_cdnskey = true; + break; + case 'd': + ds_path = isc_commandline_argument; + break; + case 'f': + child_path = isc_commandline_argument; + break; + case 'i': + /* + * This is a bodge to make the argument optional, + * so that it works just like sed(1). + */ + if (isc_commandline_argument == + argv[isc_commandline_index - 1]) + { + isc_commandline_index--; + inplace = ""; + } else { + inplace = isc_commandline_argument; + } + break; + case 'm': + isc_mem_debugging = ISC_MEM_DEBUGTRACE | + ISC_MEM_DEBUGRECORD; + break; + case 's': + startstr = isc_commandline_argument; + break; + case 'T': + ttl = strtottl(isc_commandline_argument); + break; + case 'u': + nsupdate = true; + break; + case 'V': + /* Does not return. */ + version(program); + break; + case 'v': + verbose = strtoul(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("-v must be followed by a number"); + } + break; + default: + usage(); + break; + } + } + argv += isc_commandline_index; + argc -= isc_commandline_index; + + if (argc != 1) { + usage(); + } + initname(argv[0]); + + /* + * Default digest type if none specified. + */ + if (dtype[0] == 0) { + dtype[0] = DNS_DSDIGEST_SHA256; + } + + setup_logging(mctx, &lctx); + + result = dst_lib_init(mctx, NULL); + if (result != ISC_R_SUCCESS) { + fatal("could not initialize dst: %s", + isc_result_totext(result)); + } + + if (ds_path == NULL) { + fatal("missing -d DS pathname"); + } + load_parent_set(ds_path); + + /* + * Preserve the TTL if it wasn't overridden. + */ + if (ttl == 0) { + ttl = old_ds_set.ttl; + } + + if (child_path == NULL) { + fatal("path to file containing child data must be specified"); + } + + load_child_sets(child_path); + + /* + * Check child records have accompanying RRSIGs and DNSKEYs + */ + + if (!dns_rdataset_isassociated(&dnskey_set) || + !dns_rdataset_isassociated(&dnskey_sig)) + { + fatal("could not find signed DNSKEY RRset for %s", namestr); + } + + if (dns_rdataset_isassociated(&cdnskey_set) && + !dns_rdataset_isassociated(&cdnskey_sig)) + { + fatal("missing RRSIG CDNSKEY records for %s", namestr); + } + if (dns_rdataset_isassociated(&cds_set) && + !dns_rdataset_isassociated(&cds_sig)) + { + fatal("missing RRSIG CDS records for %s", namestr); + } + + vbprintf(1, "which child DNSKEY records match parent DS records?\n"); + old_key_tbl = match_keyset_dsset(&dnskey_set, &old_ds_set, LOOSE); + + /* + * We have now identified the keys that are allowed to authenticate + * the DNSKEY RRset (RFC 4035 section 5.2 bullet 2), and CDNSKEY and + * CDS RRsets (RFC 7344 section 4.1 bullet 2). + */ + + vbprintf(1, "verify DNSKEY signature(s)\n"); + if (!signed_loose(matching_sigs(old_key_tbl, &dnskey_set, &dnskey_sig))) + { + fatal("could not validate child DNSKEY RRset for %s", namestr); + } + + if (dns_rdataset_isassociated(&cdnskey_set)) { + vbprintf(1, "verify CDNSKEY signature(s)\n"); + if (!signed_loose(matching_sigs(old_key_tbl, &cdnskey_set, + &cdnskey_sig))) + { + fatal("could not validate child CDNSKEY RRset for %s", + namestr); + } + } + if (dns_rdataset_isassociated(&cds_set)) { + vbprintf(1, "verify CDS signature(s)\n"); + if (!signed_loose( + matching_sigs(old_key_tbl, &cds_set, &cds_sig))) + { + fatal("could not validate child CDS RRset for %s", + namestr); + } + } + + free_keytable(&old_key_tbl); + + /* + * Report the result of the replay attack protection checks + * used for the output file timestamp + */ + if (oldestsig.timesigned != 0 && verbose > 0) { + char type[32]; + dns_rdatatype_format(oldestsig.covered, type, sizeof(type)); + verbose_time(1, "child signature inception time", + oldestsig.timesigned); + vbprintf(2, "from RRSIG %s by key %d\n", type, oldestsig.keyid); + } + + /* + * Successfully do nothing if there's neither CDNSKEY nor CDS + * RFC 7344 section 4.1 first paragraph + */ + if (!dns_rdataset_isassociated(&cdnskey_set) && + !dns_rdataset_isassociated(&cds_set)) + { + vbprintf(1, "%s has neither CDS nor CDNSKEY records\n", + namestr); + write_parent_set(ds_path, inplace, nsupdate, &old_ds_set); + exit(0); + } + + /* + * Make DS records from the CDS or CDNSKEY records + * Prefer CDS if present, unless run with -D + */ + if (prefer_cdnskey && dns_rdataset_isassociated(&cdnskey_set)) { + make_new_ds_set(ds_from_cdnskey, ttl, &cdnskey_set); + } else if (dns_rdataset_isassociated(&cds_set)) { + make_new_ds_set(ds_from_cds, ttl, &cds_set); + } else { + make_new_ds_set(ds_from_cdnskey, ttl, &cdnskey_set); + } + + /* + * Now we have a candidate DS RRset, we need to check it + * won't break the delegation. + */ + vbprintf(1, "which child DNSKEY records match new DS records?\n"); + new_key_tbl = match_keyset_dsset(&dnskey_set, &new_ds_set, TIGHT); + + if (!consistent_digests(&new_ds_set)) { + fatal("CDS records at %s do not cover each key " + "with the same set of digest types", + namestr); + } + + vbprintf(1, "verify DNSKEY signature(s)\n"); + if (!signed_strict(&new_ds_set, matching_sigs(new_key_tbl, &dnskey_set, + &dnskey_sig))) + { + fatal("could not validate child DNSKEY RRset " + "with new DS records for %s", + namestr); + } + + free_keytable(&new_key_tbl); + + /* + * OK, it's all good! + */ + if (nsupdate) { + nsdiff(ttl, &old_ds_set, &new_ds_set); + } + + write_parent_set(ds_path, inplace, nsupdate, &new_ds_set); + + free_all_sets(); + cleanup_logging(&lctx); + dst_lib_destroy(); + if (verbose > 10) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + exit(0); +} diff --git a/bin/dnssec/dnssec-cds.rst b/bin/dnssec/dnssec-cds.rst new file mode 100644 index 0000000..4ba77fb --- /dev/null +++ b/bin/dnssec/dnssec-cds.rst @@ -0,0 +1,203 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-cds: + +dnssec-cds - change DS records for a child zone based on CDS/CDNSKEY +-------------------------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`dnssec-cds` [**-a** alg...] [**-c** class] [**-D**] {**-d** dsset-file} {**-f** child-file} [**-i**[extension]] [**-s** start-time] [**-T** ttl] [**-u**] [**-v** level] [**-V**] {domain} + +Description +~~~~~~~~~~~ + +The ``dnssec-cds`` command changes DS records at a delegation point +based on CDS or CDNSKEY records published in the child zone. If both CDS +and CDNSKEY records are present in the child zone, the CDS is preferred. +This enables a child zone to inform its parent of upcoming changes to +its key-signing keys (KSKs); by polling periodically with ``dnssec-cds``, the +parent can keep the DS records up-to-date and enable automatic rolling +of KSKs. + +Two input files are required. The ``-f child-file`` option specifies a +file containing the child's CDS and/or CDNSKEY records, plus RRSIG and +DNSKEY records so that they can be authenticated. The ``-d path`` option +specifies the location of a file containing the current DS records. For +example, this could be a ``dsset-`` file generated by +``dnssec-signzone``, or the output of ``dnssec-dsfromkey``, or the +output of a previous run of ``dnssec-cds``. + +The ``dnssec-cds`` command uses special DNSSEC validation logic +specified by :rfc:`7344`. It requires that the CDS and/or CDNSKEY records +be validly signed by a key represented in the existing DS records. This +is typically the pre-existing KSK. + +For protection against replay attacks, the signatures on the child +records must not be older than they were on a previous run of +``dnssec-cds``. Their age is obtained from the modification time of the +``dsset-`` file, or from the ``-s`` option. + +To protect against breaking the delegation, ``dnssec-cds`` ensures that +the DNSKEY RRset can be verified by every key algorithm in the new DS +RRset, and that the same set of keys are covered by every DS digest +type. + +By default, replacement DS records are written to the standard output; +with the ``-i`` option the input file is overwritten in place. The +replacement DS records are the same as the existing records, when no +change is required. The output can be empty if the CDS/CDNSKEY records +specify that the child zone wants to be insecure. + +.. warning:: + + Be careful not to delete the DS records when ``dnssec-cds`` fails! + +Alternatively, ``dnssec-cds -u`` writes an ``nsupdate`` script to the +standard output. The ``-u`` and ``-i`` options can be used together to +maintain a ``dsset-`` file as well as emit an ``nsupdate`` script. + +Options +~~~~~~~ + +``-a algorithm`` + This option specifies a digest algorithm to use when converting CDNSKEY records to + DS records. This option can be repeated, so that multiple DS records + are created for each CDNSKEY record. This option has no effect when + using CDS records. + + The algorithm must be one of SHA-1, SHA-256, or SHA-384. These values + are case-insensitive, and the hyphen may be omitted. If no algorithm + is specified, the default is SHA-256. + +``-c class`` + This option specifies the DNS class of the zones. + +``-D`` + This option generates DS records from CDNSKEY records if both CDS and CDNSKEY + records are present in the child zone. By default CDS records are + preferred. + +``-d path`` + This specifies the location of the parent DS records. The path can be the name of a file + containing the DS records; if it is a directory, ``dnssec-cds`` + looks for a ``dsset-`` file for the domain inside the directory. + + To protect against replay attacks, child records are rejected if they + were signed earlier than the modification time of the ``dsset-`` + file. This can be adjusted with the ``-s`` option. + +``-f child-file`` + This option specifies the file containing the child's CDS and/or CDNSKEY records, plus its + DNSKEY records and the covering RRSIG records, so that they can be + authenticated. + + The examples below describe how to generate this file. + +``-iextension`` + This option updates the ``dsset-`` file in place, instead of writing DS records to + the standard output. + + There must be no space between the ``-i`` and the extension. If + no extension is provided, the old ``dsset-`` is discarded. If an + extension is present, a backup of the old ``dsset-`` file is kept + with the extension appended to its filename. + + To protect against replay attacks, the modification time of the + ``dsset-`` file is set to match the signature inception time of the + child records, provided that it is later than the file's current + modification time. + +``-s start-time`` + This option specifies the date and time after which RRSIG records become + acceptable. This can be either an absolute or a relative time. An + absolute start time is indicated by a number in YYYYMMDDHHMMSS + notation; 20170827133700 denotes 13:37:00 UTC on August 27th, 2017. A + time relative to the ``dsset-`` file is indicated with ``-N``, which is N + seconds before the file modification time. A time relative to the + current time is indicated with ``now+N``. + + If no start-time is specified, the modification time of the + ``dsset-`` file is used. + +``-T ttl`` + This option specifies a TTL to be used for new DS records. If not specified, the + default is the TTL of the old DS records. If they had no explicit TTL, + the new DS records also have no explicit TTL. + +``-u`` + This option writes an ``nsupdate`` script to the standard output, instead of + printing the new DS reords. The output is empty if no change is + needed. + + Note: The TTL of new records needs to be specified: it can be done in the + original ``dsset-`` file, with the ``-T`` option, or using the + ``nsupdate`` ``ttl`` command. + +``-V`` + This option prints version information. + +``-v level`` + This option sets the debugging level. Level 1 is intended to be usefully verbose + for general users; higher levels are intended for developers. + +``domain`` + This indicates the name of the delegation point/child zone apex. + +Exit Status +~~~~~~~~~~~ + +The ``dnssec-cds`` command exits 0 on success, or non-zero if an error +occurred. + +If successful, the DS records may or may not need to be +changed. + +Examples +~~~~~~~~ + +Before running ``dnssec-signzone``, ensure that the delegations +are up-to-date by running ``dnssec-cds`` on every ``dsset-`` file. + +To fetch the child records required by ``dnssec-cds``, invoke +``dig`` as in the script below. It is acceptable if the ``dig`` fails, since +``dnssec-cds`` performs all the necessary checking. + +:: + + for f in dsset-* + do + d=${f#dsset-} + dig +dnssec +noall +answer $d DNSKEY $d CDNSKEY $d CDS | + dnssec-cds -i -f /dev/stdin -d $f $d + done + +When the parent zone is automatically signed by ``named``, +``dnssec-cds`` can be used with ``nsupdate`` to maintain a delegation as follows. +The ``dsset-`` file allows the script to avoid having to fetch and +validate the parent DS records, and it maintains the replay attack +protection time. + +:: + + dig +dnssec +noall +answer $d DNSKEY $d CDNSKEY $d CDS | + dnssec-cds -u -i -f /dev/stdin -d $f $d | + nsupdate -l + +See Also +~~~~~~~~ + +:manpage:`dig(1)`, :manpage:`dnssec-settime(8)`, :manpage:`dnssec-signzone(8)`, :manpage:`nsupdate(1)`, BIND 9 Administrator +Reference Manual, :rfc:`7344`. diff --git a/bin/dnssec/dnssec-dsfromkey.c b/bin/dnssec/dnssec-dsfromkey.c new file mode 100644 index 0000000..404239e --- /dev/null +++ b/bin/dnssec/dnssec-dsfromkey.c @@ -0,0 +1,568 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include "dnssectool.h" + +const char *program = "dnssec-dsfromkey"; + +static dns_rdataclass_t rdclass; +static dns_fixedname_t fixed; +static dns_name_t *name = NULL; +static isc_mem_t *mctx = NULL; +static uint32_t ttl; +static bool emitttl = false; + +static isc_result_t +initname(char *setname) { + isc_result_t result; + isc_buffer_t buf; + + name = dns_fixedname_initname(&fixed); + + isc_buffer_init(&buf, setname, strlen(setname)); + isc_buffer_add(&buf, strlen(setname)); + result = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL); + return (result); +} + +static void +db_load_from_stream(dns_db_t *db, FILE *fp) { + isc_result_t result; + dns_rdatacallbacks_t callbacks; + + dns_rdatacallbacks_init(&callbacks); + result = dns_db_beginload(db, &callbacks); + if (result != ISC_R_SUCCESS) { + fatal("dns_db_beginload failed: %s", isc_result_totext(result)); + } + + result = dns_master_loadstream(fp, name, name, rdclass, 0, &callbacks, + mctx); + if (result != ISC_R_SUCCESS) { + fatal("can't load from input: %s", isc_result_totext(result)); + } + + result = dns_db_endload(db, &callbacks); + if (result != ISC_R_SUCCESS) { + fatal("dns_db_endload failed: %s", isc_result_totext(result)); + } +} + +static isc_result_t +loadset(const char *filename, dns_rdataset_t *rdataset) { + isc_result_t result; + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + char setname[DNS_NAME_FORMATSIZE]; + + dns_name_format(name, setname, sizeof(setname)); + + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0, + NULL, &db); + if (result != ISC_R_SUCCESS) { + fatal("can't create database"); + } + + if (strcmp(filename, "-") == 0) { + db_load_from_stream(db, stdin); + filename = "input"; + } else { + result = dns_db_load(db, filename, dns_masterformat_text, 0); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { + fatal("can't load %s: %s", filename, + isc_result_totext(result)); + } + } + + result = dns_db_findnode(db, name, false, &node); + if (result != ISC_R_SUCCESS) { + fatal("can't find %s node in %s", setname, filename); + } + + result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0, + rdataset, NULL); + + if (result == ISC_R_NOTFOUND) { + fatal("no DNSKEY RR for %s in %s", setname, filename); + } else if (result != ISC_R_SUCCESS) { + fatal("dns_db_findrdataset"); + } + + if (node != NULL) { + dns_db_detachnode(db, &node); + } + if (db != NULL) { + dns_db_detach(&db); + } + return (result); +} + +static isc_result_t +loadkeyset(char *dirname, dns_rdataset_t *rdataset) { + isc_result_t result; + char filename[PATH_MAX + 1]; + isc_buffer_t buf; + + dns_rdataset_init(rdataset); + + isc_buffer_init(&buf, filename, sizeof(filename)); + if (dirname != NULL) { + /* allow room for a trailing slash */ + if (strlen(dirname) >= isc_buffer_availablelength(&buf)) { + return (ISC_R_NOSPACE); + } + isc_buffer_putstr(&buf, dirname); + if (dirname[strlen(dirname) - 1] != '/') { + isc_buffer_putstr(&buf, "/"); + } + } + + if (isc_buffer_availablelength(&buf) < 7) { + return (ISC_R_NOSPACE); + } + isc_buffer_putstr(&buf, "keyset-"); + + result = dns_name_tofilenametext(name, false, &buf); + check_result(result, "dns_name_tofilenametext()"); + if (isc_buffer_availablelength(&buf) == 0) { + return (ISC_R_NOSPACE); + } + isc_buffer_putuint8(&buf, 0); + + return (loadset(filename, rdataset)); +} + +static void +loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size, + dns_rdata_t *rdata) { + isc_result_t result; + dst_key_t *key = NULL; + isc_buffer_t keyb; + isc_region_t r; + + dns_rdata_init(rdata); + + isc_buffer_init(&keyb, key_buf, key_buf_size); + + result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC, mctx, + &key); + if (result != ISC_R_SUCCESS) { + fatal("can't load %s.key: %s", filename, + isc_result_totext(result)); + } + + if (verbose > 2) { + char keystr[DST_KEY_FORMATSIZE]; + + dst_key_format(key, keystr, sizeof(keystr)); + fprintf(stderr, "%s: %s\n", program, keystr); + } + + result = dst_key_todns(key, &keyb); + if (result != ISC_R_SUCCESS) { + fatal("can't decode key"); + } + + isc_buffer_usedregion(&keyb, &r); + dns_rdata_fromregion(rdata, dst_key_class(key), dns_rdatatype_dnskey, + &r); + + rdclass = dst_key_class(key); + + name = dns_fixedname_initname(&fixed); + dns_name_copynf(dst_key_name(key), name); + + dst_key_free(&key); +} + +static void +logkey(dns_rdata_t *rdata) { + isc_result_t result; + dst_key_t *key = NULL; + isc_buffer_t buf; + char keystr[DST_KEY_FORMATSIZE]; + + isc_buffer_init(&buf, rdata->data, rdata->length); + isc_buffer_add(&buf, rdata->length); + result = dst_key_fromdns(name, rdclass, &buf, mctx, &key); + if (result != ISC_R_SUCCESS) { + return; + } + + dst_key_format(key, keystr, sizeof(keystr)); + fprintf(stderr, "%s: %s\n", program, keystr); + + dst_key_free(&key); +} + +static void +emit(dns_dsdigest_t dt, bool showall, bool cds, dns_rdata_t *rdata) { + isc_result_t result; + unsigned char buf[DNS_DS_BUFFERSIZE]; + char text_buf[DST_KEY_MAXTEXTSIZE]; + char name_buf[DNS_NAME_MAXWIRE]; + char class_buf[10]; + isc_buffer_t textb, nameb, classb; + isc_region_t r; + dns_rdata_t ds; + dns_rdata_dnskey_t dnskey; + + isc_buffer_init(&textb, text_buf, sizeof(text_buf)); + isc_buffer_init(&nameb, name_buf, sizeof(name_buf)); + isc_buffer_init(&classb, class_buf, sizeof(class_buf)); + + dns_rdata_init(&ds); + + result = dns_rdata_tostruct(rdata, &dnskey, NULL); + if (result != ISC_R_SUCCESS) { + fatal("can't convert DNSKEY"); + } + + if ((dnskey.flags & DNS_KEYFLAG_REVOKE) != 0) { + return; + } + + if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 && !showall) { + return; + } + + result = dns_ds_buildrdata(name, rdata, dt, buf, &ds); + if (result != ISC_R_SUCCESS) { + fatal("can't build record"); + } + + result = dns_name_totext(name, false, &nameb); + if (result != ISC_R_SUCCESS) { + fatal("can't print name"); + } + + result = dns_rdata_tofmttext(&ds, (dns_name_t *)NULL, 0, 0, 0, "", + &textb); + + if (result != ISC_R_SUCCESS) { + fatal("can't print rdata"); + } + + result = dns_rdataclass_totext(rdclass, &classb); + if (result != ISC_R_SUCCESS) { + fatal("can't print class"); + } + + isc_buffer_usedregion(&nameb, &r); + printf("%.*s ", (int)r.length, r.base); + + if (emitttl) { + printf("%u ", ttl); + } + + isc_buffer_usedregion(&classb, &r); + printf("%.*s", (int)r.length, r.base); + + if (cds) { + printf(" CDS "); + } else { + printf(" DS "); + } + + isc_buffer_usedregion(&textb, &r); + printf("%.*s\n", (int)r.length, r.base); +} + +static void +emits(bool showall, bool cds, dns_rdata_t *rdata) { + unsigned i, n; + + n = sizeof(dtype) / sizeof(dtype[0]); + for (i = 0; i < n; i++) { + if (dtype[i] != 0) { + emit(dtype[i], showall, cds, rdata); + } + } +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s [options] keyfile\n\n", program); + fprintf(stderr, " %s [options] -f zonefile [zonename]\n\n", program); + fprintf(stderr, " %s [options] -s dnsname\n\n", program); + fprintf(stderr, " %s [-h|-V]\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "Options:\n" + " -1: digest algorithm SHA-1\n" + " -2: digest algorithm SHA-256\n" + " -a algorithm: digest algorithm (SHA-1, SHA-256 or " + "SHA-384)\n" + " -A: include all keys in DS set, not just KSKs (-f " + "only)\n" + " -c class: rdata class for DS set (default IN) (-f " + "or -s only)\n" + " -C: print CDS records\n" + " -f zonefile: read keys from a zone file\n" + " -h: print help information\n" + " -K directory: where to find key or keyset files\n" + " -s: read keys from keyset- file\n" + " -T: TTL of output records (omitted by default)\n" + " -v level: verbosity\n" + " -V: print version information\n"); + fprintf(stderr, "Output: DS or CDS RRs\n"); + + exit(-1); +} + +int +main(int argc, char **argv) { + char *classname = NULL; + char *filename = NULL, *dir = NULL, *namestr; + char *endp, *arg1; + int ch; + bool cds = false; + bool usekeyset = false; + bool showall = false; + isc_result_t result; + isc_log_t *log = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata; + + dns_rdata_init(&rdata); + + if (argc == 1) { + usage(); + } + + isc_mem_create(&mctx); + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + isc_commandline_errprint = false; + +#define OPTIONS "12Aa:Cc:d:Ff:K:l:sT:v:hV" + while ((ch = isc_commandline_parse(argc, argv, OPTIONS)) != -1) { + switch (ch) { + case '1': + add_dtype(DNS_DSDIGEST_SHA1); + break; + case '2': + add_dtype(DNS_DSDIGEST_SHA256); + break; + case 'A': + showall = true; + break; + case 'a': + add_dtype(strtodsdigest(isc_commandline_argument)); + break; + case 'C': + cds = true; + break; + case 'c': + classname = isc_commandline_argument; + break; + case 'd': + fprintf(stderr, + "%s: the -d option is deprecated; " + "use -K\n", + program); + /* fall through */ + case 'K': + dir = isc_commandline_argument; + if (strlen(dir) == 0U) { + fatal("directory must be non-empty string"); + } + break; + case 'f': + filename = isc_commandline_argument; + break; + case 'l': + fatal("-l option (DLV lookaside) is obsolete"); + break; + case 's': + usekeyset = true; + break; + case 'T': + emitttl = true; + ttl = strtottl(isc_commandline_argument); + break; + case 'v': + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("-v must be followed by a number"); + } + break; + case 'F': + /* Reserved for FIPS mode */ + FALLTHROUGH; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + } + FALLTHROUGH; + case 'h': + /* Does not return. */ + usage(); + + case 'V': + /* Does not return. */ + version(program); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + rdclass = strtoclass(classname); + + if (usekeyset && filename != NULL) { + fatal("cannot use both -s and -f"); + } + + /* When not using -f, -A is implicit */ + if (filename == NULL) { + showall = true; + } + + /* Default digest type if none specified. */ + if (dtype[0] == 0) { + dtype[0] = DNS_DSDIGEST_SHA256; + } + + /* + * Use local variable arg1 so that clang can correctly analyse + * reachable paths rather than 'argc < isc_commandline_index + 1'. + */ + arg1 = argv[isc_commandline_index]; + if (arg1 == NULL && filename == NULL) { + fatal("the key file name was not specified"); + } + if (arg1 != NULL && argv[isc_commandline_index + 1] != NULL) { + fatal("extraneous arguments"); + } + + result = dst_lib_init(mctx, NULL); + if (result != ISC_R_SUCCESS) { + fatal("could not initialize dst: %s", + isc_result_totext(result)); + } + + setup_logging(mctx, &log); + + dns_rdataset_init(&rdataset); + + if (usekeyset || filename != NULL) { + if (arg1 == NULL) { + /* using file name as the zone name */ + namestr = filename; + } else { + namestr = arg1; + } + + result = initname(namestr); + if (result != ISC_R_SUCCESS) { + fatal("could not initialize name %s", namestr); + } + + if (usekeyset) { + result = loadkeyset(dir, &rdataset); + } else { + INSIST(filename != NULL); + result = loadset(filename, &rdataset); + } + + if (result != ISC_R_SUCCESS) { + fatal("could not load DNSKEY set: %s\n", + isc_result_totext(result)); + } + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + dns_rdata_init(&rdata); + dns_rdataset_current(&rdataset, &rdata); + + if (verbose > 2) { + logkey(&rdata); + } + + emits(showall, cds, &rdata); + } + } else { + unsigned char key_buf[DST_KEY_MAXSIZE]; + + loadkey(arg1, key_buf, DST_KEY_MAXSIZE, &rdata); + + emits(showall, cds, &rdata); + } + + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + cleanup_logging(&log); + dst_lib_destroy(); + if (verbose > 10) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + fflush(stdout); + if (ferror(stdout)) { + fprintf(stderr, "write error\n"); + return (1); + } else { + return (0); + } +} diff --git a/bin/dnssec/dnssec-dsfromkey.rst b/bin/dnssec/dnssec-dsfromkey.rst new file mode 100644 index 0000000..6396733 --- /dev/null +++ b/bin/dnssec/dnssec-dsfromkey.rst @@ -0,0 +1,144 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-dsfromkey: + +dnssec-dsfromkey - DNSSEC DS RR generation tool +----------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`dnssec-dsfromkey` [ **-1** | **-2** | **-a** alg ] [ **-C** ] [**-T** TTL] [**-v** level] [**-K** directory] {keyfile} + +:program:`dnssec-dsfromkey` [ **-1** | **-2** | **-a** alg ] [ **-C** ] [**-T** TTL] [**-v** level] [**-c** class] [**-A**] {**-f** file} [dnsname] + +:program:`dnssec-dsfromkey` [ **-1** | **-2** | **-a** alg ] [ **-C** ] [**-T** TTL] [**-v** level] [**-c** class] [**-K** directory] {**-s**} {dnsname} + +:program:`dnssec-dsfromkey` [ **-h** | **-V** ] + +Description +~~~~~~~~~~~ + +The ``dnssec-dsfromkey`` command outputs DS (Delegation Signer) resource records +(RRs), or CDS (Child DS) RRs with the ``-C`` option. + +By default, only KSKs are converted (keys with flags = 257). The +``-A`` option includes ZSKs (flags = 256). Revoked keys are never +included. + +The input keys can be specified in a number of ways: + +By default, ``dnssec-dsfromkey`` reads a key file named in the format +``Knnnn.+aaa+iiiii.key``, as generated by ``dnssec-keygen``. + +With the ``-f file`` option, ``dnssec-dsfromkey`` reads keys from a zone +file or partial zone file (which can contain just the DNSKEY records). + +With the ``-s`` option, ``dnssec-dsfromkey`` reads a ``keyset-`` file, +as generated by ``dnssec-keygen`` ``-C``. + +Options +~~~~~~~ + +``-1`` + This option is an abbreviation for ``-a SHA1``. + +``-2`` + This option is an abbreviation for ``-a SHA-256``. + +``-a algorithm`` + This option specifies a digest algorithm to use when converting DNSKEY records to + DS records. This option can be repeated, so that multiple DS records + are created for each DNSKEY record. + + The algorithm must be one of SHA-1, SHA-256, or SHA-384. These values + are case-insensitive, and the hyphen may be omitted. If no algorithm + is specified, the default is SHA-256. + +``-A`` + This option indicates that ZSKs are to be included when generating DS records. Without this option, only + keys which have the KSK flag set are converted to DS records and + printed. This option is only useful in ``-f`` zone file mode. + +``-c class`` + This option specifies the DNS class; the default is IN. This option is only useful in ``-s`` keyset + or ``-f`` zone file mode. + +``-C`` + This option generates CDS records rather than DS records. + +``-f file`` + This option sets zone file mode, in which the final dnsname argument of ``dnssec-dsfromkey`` is the + DNS domain name of a zone whose master file can be read from + ``file``. If the zone name is the same as ``file``, then it may be + omitted. + + If ``file`` is ``-``, then the zone data is read from the standard + input. This makes it possible to use the output of the ``dig`` + command as input, as in: + + ``dig dnskey example.com | dnssec-dsfromkey -f - example.com`` + +``-h`` + This option prints usage information. + +``-K directory`` + This option tells BIND 9 to look for key files or ``keyset-`` files in ``directory``. + +``-s`` + This option enables keyset mode, in which the final dnsname argument from ``dnssec-dsfromkey`` is the DNS + domain name used to locate a ``keyset-`` file. + +``-T TTL`` + This option specifies the TTL of the DS records. By default the TTL is omitted. + +``-v level`` + This option sets the debugging level. + +``-V`` + This option prints version information. + +Example +~~~~~~~ + +To build the SHA-256 DS RR from the ``Kexample.com.+003+26160`` keyfile, +issue the following command: + +``dnssec-dsfromkey -2 Kexample.com.+003+26160`` + +The command returns something similar to: + +``example.com. IN DS 26160 5 2 3A1EADA7A74B8D0BA86726B0C227AA85AB8BBD2B2004F41A868A54F0C5EA0B94`` + +Files +~~~~~ + +The keyfile can be designated by the key identification +``Knnnn.+aaa+iiiii`` or the full file name ``Knnnn.+aaa+iiiii.key``, as +generated by ``dnssec-keygen``. + +The keyset file name is built from the ``directory``, the string +``keyset-``, and the ``dnsname``. + +Caveat +~~~~~~ + +A keyfile error may return "file not found," even if the file exists. + +See Also +~~~~~~~~ + +:manpage:`dnssec-keygen(8)`, :manpage:`dnssec-signzone(8)`, BIND 9 Administrator Reference Manual, +:rfc:`3658` (DS RRs), :rfc:`4509` (SHA-256 for DS RRs), +:rfc:`6605` (SHA-384 for DS RRs), :rfc:`7344` (CDS and CDNSKEY RRs). diff --git a/bin/dnssec/dnssec-importkey.c b/bin/dnssec/dnssec-importkey.c new file mode 100644 index 0000000..8a776c1 --- /dev/null +++ b/bin/dnssec/dnssec-importkey.c @@ -0,0 +1,485 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include "dnssectool.h" + +const char *program = "dnssec-importkey"; + +static dns_rdataclass_t rdclass; +static dns_fixedname_t fixed; +static dns_name_t *name = NULL; +static isc_mem_t *mctx = NULL; +static bool setpub = false, setdel = false; +static bool setttl = false; +static isc_stdtime_t pub = 0, del = 0; +static dns_ttl_t ttl = 0; +static isc_stdtime_t syncadd = 0, syncdel = 0; +static bool setsyncadd = false; +static bool setsyncdel = false; + +static isc_result_t +initname(char *setname) { + isc_result_t result; + isc_buffer_t buf; + + name = dns_fixedname_initname(&fixed); + + isc_buffer_init(&buf, setname, strlen(setname)); + isc_buffer_add(&buf, strlen(setname)); + result = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL); + return (result); +} + +static void +db_load_from_stream(dns_db_t *db, FILE *fp) { + isc_result_t result; + dns_rdatacallbacks_t callbacks; + + dns_rdatacallbacks_init(&callbacks); + result = dns_db_beginload(db, &callbacks); + if (result != ISC_R_SUCCESS) { + fatal("dns_db_beginload failed: %s", isc_result_totext(result)); + } + + result = dns_master_loadstream(fp, name, name, rdclass, 0, &callbacks, + mctx); + if (result != ISC_R_SUCCESS) { + fatal("can't load from input: %s", isc_result_totext(result)); + } + + result = dns_db_endload(db, &callbacks); + if (result != ISC_R_SUCCESS) { + fatal("dns_db_endload failed: %s", isc_result_totext(result)); + } +} + +static isc_result_t +loadset(const char *filename, dns_rdataset_t *rdataset) { + isc_result_t result; + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + char setname[DNS_NAME_FORMATSIZE]; + + dns_name_format(name, setname, sizeof(setname)); + + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0, + NULL, &db); + if (result != ISC_R_SUCCESS) { + fatal("can't create database"); + } + + if (strcmp(filename, "-") == 0) { + db_load_from_stream(db, stdin); + filename = "input"; + } else { + result = dns_db_load(db, filename, dns_masterformat_text, + DNS_MASTER_NOTTL); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { + fatal("can't load %s: %s", filename, + isc_result_totext(result)); + } + } + + result = dns_db_findnode(db, name, false, &node); + if (result != ISC_R_SUCCESS) { + fatal("can't find %s node in %s", setname, filename); + } + + result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0, + rdataset, NULL); + + if (result == ISC_R_NOTFOUND) { + fatal("no DNSKEY RR for %s in %s", setname, filename); + } else if (result != ISC_R_SUCCESS) { + fatal("dns_db_findrdataset"); + } + + if (node != NULL) { + dns_db_detachnode(db, &node); + } + if (db != NULL) { + dns_db_detach(&db); + } + return (result); +} + +static void +loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size, + dns_rdata_t *rdata) { + isc_result_t result; + dst_key_t *key = NULL; + isc_buffer_t keyb; + isc_region_t r; + + dns_rdata_init(rdata); + + isc_buffer_init(&keyb, key_buf, key_buf_size); + + result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC, mctx, + &key); + if (result != ISC_R_SUCCESS) { + fatal("invalid keyfile name %s: %s", filename, + isc_result_totext(result)); + } + + if (verbose > 2) { + char keystr[DST_KEY_FORMATSIZE]; + + dst_key_format(key, keystr, sizeof(keystr)); + fprintf(stderr, "%s: %s\n", program, keystr); + } + + result = dst_key_todns(key, &keyb); + if (result != ISC_R_SUCCESS) { + fatal("can't decode key"); + } + + isc_buffer_usedregion(&keyb, &r); + dns_rdata_fromregion(rdata, dst_key_class(key), dns_rdatatype_dnskey, + &r); + + rdclass = dst_key_class(key); + + name = dns_fixedname_initname(&fixed); + dns_name_copynf(dst_key_name(key), name); + + dst_key_free(&key); +} + +static void +emit(const char *dir, dns_rdata_t *rdata) { + isc_result_t result; + char keystr[DST_KEY_FORMATSIZE]; + char pubname[1024]; + char priname[1024]; + isc_buffer_t buf; + dst_key_t *key = NULL, *tmp = NULL; + + isc_buffer_init(&buf, rdata->data, rdata->length); + isc_buffer_add(&buf, rdata->length); + result = dst_key_fromdns(name, rdclass, &buf, mctx, &key); + if (result != ISC_R_SUCCESS) { + fatal("dst_key_fromdns: %s", isc_result_totext(result)); + } + + isc_buffer_init(&buf, pubname, sizeof(pubname)); + result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); + if (result != ISC_R_SUCCESS) { + fatal("Failed to build public key filename: %s", + isc_result_totext(result)); + } + isc_buffer_init(&buf, priname, sizeof(priname)); + result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); + if (result != ISC_R_SUCCESS) { + fatal("Failed to build private key filename: %s", + isc_result_totext(result)); + } + + result = dst_key_fromfile( + dst_key_name(key), dst_key_id(key), dst_key_alg(key), + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, dir, mctx, &tmp); + if (result == ISC_R_SUCCESS) { + if (dst_key_isprivate(tmp) && !dst_key_isexternal(tmp)) { + fatal("Private key already exists in %s", priname); + } + dst_key_free(&tmp); + } + + dst_key_setexternal(key, true); + if (setpub) { + dst_key_settime(key, DST_TIME_PUBLISH, pub); + } + if (setdel) { + dst_key_settime(key, DST_TIME_DELETE, del); + } + if (setsyncadd) { + dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncadd); + } + if (setsyncdel) { + dst_key_settime(key, DST_TIME_SYNCDELETE, syncdel); + } + + if (setttl) { + dst_key_setttl(key, ttl); + } + + result = dst_key_tofile(key, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, dir); + if (result != ISC_R_SUCCESS) { + dst_key_format(key, keystr, sizeof(keystr)); + fatal("Failed to write key %s: %s", keystr, + isc_result_totext(result)); + } + printf("%s\n", pubname); + + isc_buffer_clear(&buf); + result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); + if (result != ISC_R_SUCCESS) { + fatal("Failed to build private key filename: %s", + isc_result_totext(result)); + } + printf("%s\n", priname); + dst_key_free(&key); +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s options [-K dir] keyfile\n\n", program); + fprintf(stderr, " %s options -f file [keyname]\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -f file: read key from zone file\n"); + fprintf(stderr, " -K : directory in which to store " + "the key files\n"); + fprintf(stderr, " -L ttl: set default key TTL\n"); + fprintf(stderr, " -v \n"); + fprintf(stderr, " -V: print version information\n"); + fprintf(stderr, " -h: print usage and exit\n"); + fprintf(stderr, "Timing options:\n"); + fprintf(stderr, " -P date/[+-]offset/none: set/unset key " + "publication date\n"); + fprintf(stderr, " -P sync date/[+-]offset/none: set/unset " + "CDS and CDNSKEY publication date\n"); + fprintf(stderr, " -D date/[+-]offset/none: set/unset key " + "deletion date\n"); + fprintf(stderr, " -D sync date/[+-]offset/none: set/unset " + "CDS and CDNSKEY deletion date\n"); + + exit(-1); +} + +int +main(int argc, char **argv) { + char *classname = NULL; + char *filename = NULL, *dir = NULL, *namestr; + char *endp; + int ch; + isc_result_t result; + isc_log_t *log = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata; + isc_stdtime_t now; + + dns_rdata_init(&rdata); + isc_stdtime_get(&now); + + if (argc == 1) { + usage(); + } + + isc_mem_create(&mctx); + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + isc_commandline_errprint = false; + +#define CMDLINE_FLAGS "D:f:hK:L:P:v:V" + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case 'D': + /* -Dsync ? */ + if (isoptarg("sync", argv, usage)) { + if (setsyncdel) { + fatal("-D sync specified more than " + "once"); + } + + syncdel = strtotime(isc_commandline_argument, + now, now, &setsyncdel); + break; + } + /* -Ddnskey ? */ + (void)isoptarg("dnskey", argv, usage); + if (setdel) { + fatal("-D specified more than once"); + } + + del = strtotime(isc_commandline_argument, now, now, + &setdel); + break; + case 'K': + dir = isc_commandline_argument; + if (strlen(dir) == 0U) { + fatal("directory must be non-empty string"); + } + break; + case 'L': + ttl = strtottl(isc_commandline_argument); + setttl = true; + break; + case 'P': + /* -Psync ? */ + if (isoptarg("sync", argv, usage)) { + if (setsyncadd) { + fatal("-P sync specified more than " + "once"); + } + + syncadd = strtotime(isc_commandline_argument, + now, now, &setsyncadd); + break; + } + /* -Pdnskey ? */ + (void)isoptarg("dnskey", argv, usage); + if (setpub) { + fatal("-P specified more than once"); + } + + pub = strtotime(isc_commandline_argument, now, now, + &setpub); + break; + case 'f': + filename = isc_commandline_argument; + break; + case 'v': + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("-v must be followed by a number"); + } + break; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + } + FALLTHROUGH; + case 'h': + /* Does not return. */ + usage(); + + case 'V': + /* Does not return. */ + version(program); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + rdclass = strtoclass(classname); + + if (argc < isc_commandline_index + 1 && filename == NULL) { + fatal("the key file name was not specified"); + } + if (argc > isc_commandline_index + 1) { + fatal("extraneous arguments"); + } + + result = dst_lib_init(mctx, NULL); + if (result != ISC_R_SUCCESS) { + fatal("could not initialize dst: %s", + isc_result_totext(result)); + } + + setup_logging(mctx, &log); + + dns_rdataset_init(&rdataset); + + if (filename != NULL) { + if (argc < isc_commandline_index + 1) { + /* using filename as zone name */ + namestr = filename; + } else { + namestr = argv[isc_commandline_index]; + } + + result = initname(namestr); + if (result != ISC_R_SUCCESS) { + fatal("could not initialize name %s", namestr); + } + + result = loadset(filename, &rdataset); + + if (result != ISC_R_SUCCESS) { + fatal("could not load DNSKEY set: %s\n", + isc_result_totext(result)); + } + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + dns_rdata_init(&rdata); + dns_rdataset_current(&rdataset, &rdata); + emit(dir, &rdata); + } + } else { + unsigned char key_buf[DST_KEY_MAXSIZE]; + + loadkey(argv[isc_commandline_index], key_buf, DST_KEY_MAXSIZE, + &rdata); + + emit(dir, &rdata); + } + + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + cleanup_logging(&log); + dst_lib_destroy(); + if (verbose > 10) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + fflush(stdout); + if (ferror(stdout)) { + fprintf(stderr, "write error\n"); + return (1); + } else { + return (0); + } +} diff --git a/bin/dnssec/dnssec-importkey.rst b/bin/dnssec/dnssec-importkey.rst new file mode 100644 index 0000000..9e58fce --- /dev/null +++ b/bin/dnssec/dnssec-importkey.rst @@ -0,0 +1,113 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-importkey: + +dnssec-importkey - import DNSKEY records from external systems so they can be managed +------------------------------------------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`dnssec-importkey` [**-K** directory] [**-L** ttl] [**-P** date/offset] [**-P** sync date/offset] [**-D** date/offset] [**-D** sync date/offset] [**-h**] [**-v** level] [**-V**] {keyfile} + +:program:`dnssec-importkey` {**-f** filename} [**-K** directory] [**-L** ttl] [**-P** date/offset] [**-P** sync date/offset] [**-D** date/offset] [**-D** sync date/offset] [**-h**] [**-v** level] [**-V**] [dnsname] + +Description +~~~~~~~~~~~ + +``dnssec-importkey`` reads a public DNSKEY record and generates a pair +of .key/.private files. The DNSKEY record may be read from an +existing .key file, in which case a corresponding .private file is +generated, or it may be read from any other file or from the standard +input, in which case both .key and .private files are generated. + +The newly created .private file does *not* contain private key data, and +cannot be used for signing. However, having a .private file makes it +possible to set publication (``-P``) and deletion (``-D``) times for the +key, which means the public key can be added to and removed from the +DNSKEY RRset on schedule even if the true private key is stored offline. + +Options +~~~~~~~ + +``-f filename`` + This option indicates the zone file mode. Instead of a public keyfile name, the argument is the + DNS domain name of a zone master file, which can be read from + ``filename``. If the domain name is the same as ``filename``, then it may be + omitted. + + If ``filename`` is set to ``"-"``, then the zone data is read from the + standard input. + +``-K directory`` + This option sets the directory in which the key files are to reside. + +``-L ttl`` + This option sets the default TTL to use for this key when it is converted into a + DNSKEY RR. This is the TTL used when the key is imported into a zone, + unless there was already a DNSKEY RRset in + place, in which case the existing TTL takes precedence. Setting the default TTL to ``0`` or ``none`` + removes it from the key. + +``-h`` + This option emits a usage message and exits. + +``-v level`` + This option sets the debugging level. + +``-V`` + This option prints version information. + +Timing Options +~~~~~~~~~~~~~~ + +Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. If the +argument begins with a ``+`` or ``-``, it is interpreted as an offset from +the present time. For convenience, if such an offset is followed by one +of the suffixes ``y``, ``mo``, ``w``, ``d``, ``h``, or ``mi``, then the offset is +computed in years (defined as 365 24-hour days, ignoring leap years), +months (defined as 30 24-hour days), weeks, days, hours, or minutes, +respectively. Without a suffix, the offset is computed in seconds. To +explicitly prevent a date from being set, use ``none`` or ``never``. + +``-P date/offset`` + This option sets the date on which a key is to be published to the zone. After + that date, the key is included in the zone but is not used + to sign it. + +``-P sync date/offset`` + This option sets the date on which CDS and CDNSKEY records that match this key + are to be published to the zone. + +``-D date/offset`` + This option sets the date on which the key is to be deleted. After that date, the + key is no longer included in the zone. (However, it may remain in the key + repository.) + +``-D sync date/offset`` + This option sets the date on which the CDS and CDNSKEY records that match this + key are to be deleted. + +Files +~~~~~ + +A keyfile can be designed by the key identification ``Knnnn.+aaa+iiiii`` +or the full file name ``Knnnn.+aaa+iiiii.key``, as generated by +``dnssec-keygen``. + +See Also +~~~~~~~~ + +:manpage:`dnssec-keygen(8)`, :manpage:`dnssec-signzone(8)`, BIND 9 Administrator Reference Manual, +:rfc:`5011`. diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c new file mode 100644 index 0000000..26d8352 --- /dev/null +++ b/bin/dnssec/dnssec-keyfromlabel.c @@ -0,0 +1,782 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include "dnssectool.h" + +#define MAX_RSA 4096 /* should be long enough... */ + +const char *program = "dnssec-keyfromlabel"; + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s -l label [options] name\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "Required options:\n"); + fprintf(stderr, " -l label: label of the key pair\n"); + fprintf(stderr, " name: owner of the key\n"); + fprintf(stderr, "Other options:\n"); + fprintf(stderr, " -a algorithm: \n" + " DH | RSASHA1 |\n" + " NSEC3RSASHA1 |\n" + " RSASHA256 | RSASHA512 |\n" + " ECDSAP256SHA256 | ECDSAP384SHA384 |\n" + " ED25519 | ED448\n"); + fprintf(stderr, " -3: use NSEC3-capable algorithm\n"); + fprintf(stderr, " -c class (default: IN)\n"); + fprintf(stderr, " -E :\n"); +#if USE_PKCS11 + fprintf(stderr, + " path to PKCS#11 provider library " + "(default is %s)\n", + PK11_LIB_LOCATION); +#else /* if USE_PKCS11 */ + fprintf(stderr, " name of an OpenSSL engine to use\n"); +#endif /* if USE_PKCS11 */ + fprintf(stderr, " -f keyflag: KSK | REVOKE\n"); + fprintf(stderr, " -K directory: directory in which to place " + "key files\n"); + fprintf(stderr, " -k: generate a TYPE=KEY key\n"); + fprintf(stderr, " -L ttl: default key TTL\n"); + fprintf(stderr, " -n nametype: ZONE | HOST | ENTITY | USER | " + "OTHER\n"); + fprintf(stderr, " (DNSKEY generation defaults to ZONE\n"); + fprintf(stderr, " -p protocol: default: 3 [dnssec]\n"); + fprintf(stderr, " -t type: " + "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " + "(default: AUTHCONF)\n"); + fprintf(stderr, " -y: permit keys that might collide\n"); + fprintf(stderr, " -v verbose level\n"); + fprintf(stderr, " -V: print version information\n"); + fprintf(stderr, "Date options:\n"); + fprintf(stderr, " -P date/[+-]offset: set key publication date\n"); + fprintf(stderr, " -P sync date/[+-]offset: set CDS and CDNSKEY " + "publication date\n"); + fprintf(stderr, " -A date/[+-]offset: set key activation date\n"); + fprintf(stderr, " -R date/[+-]offset: set key revocation date\n"); + fprintf(stderr, " -I date/[+-]offset: set key inactivation date\n"); + fprintf(stderr, " -D date/[+-]offset: set key deletion date\n"); + fprintf(stderr, " -D sync date/[+-]offset: set CDS and CDNSKEY " + "deletion date\n"); + fprintf(stderr, " -G: generate key only; do not set -P or -A\n"); + fprintf(stderr, " -C: generate a backward-compatible key, omitting" + " all dates\n"); + fprintf(stderr, " -S : generate a successor to an existing " + "key\n"); + fprintf(stderr, " -i : prepublication interval for " + "successor key " + "(default: 30 days)\n"); + fprintf(stderr, "Output:\n"); + fprintf(stderr, " K++.key, " + "K++.private\n"); + + exit(-1); +} + +int +main(int argc, char **argv) { + char *algname = NULL, *freeit = NULL; + char *nametype = NULL, *type = NULL; + const char *directory = NULL; + const char *predecessor = NULL; + dst_key_t *prevkey = NULL; + const char *engine = NULL; + char *classname = NULL; + char *endp; + dst_key_t *key = NULL; + dns_fixedname_t fname; + dns_name_t *name; + uint16_t flags = 0, kskflag = 0, revflag = 0; + dns_secalg_t alg; + bool oldstyle = false; + isc_mem_t *mctx = NULL; + int ch; + int protocol = -1, signatory = 0; + isc_result_t ret; + isc_textregion_t r; + char filename[255]; + isc_buffer_t buf; + isc_log_t *log = NULL; + dns_rdataclass_t rdclass; + int options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC; + char *label = NULL; + dns_ttl_t ttl = 0; + isc_stdtime_t publish = 0, activate = 0, revoke = 0; + isc_stdtime_t inactive = 0, deltime = 0; + isc_stdtime_t now; + int prepub = -1; + bool setpub = false, setact = false; + bool setrev = false, setinact = false; + bool setdel = false, setttl = false; + bool unsetpub = false, unsetact = false; + bool unsetrev = false, unsetinact = false; + bool unsetdel = false; + bool genonly = false; + bool use_nsec3 = false; + bool avoid_collisions = true; + bool exact; + unsigned char c; + isc_stdtime_t syncadd = 0, syncdel = 0; + bool unsetsyncadd = false, setsyncadd = false; + bool unsetsyncdel = false, setsyncdel = false; + + if (argc == 1) { + usage(); + } + + isc_mem_create(&mctx); + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + isc_commandline_errprint = false; + + isc_stdtime_get(&now); + +#define CMDLINE_FLAGS "3A:a:Cc:D:E:Ff:GhI:i:kK:L:l:n:P:p:R:S:t:v:Vy" + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case '3': + use_nsec3 = true; + break; + case 'a': + algname = isc_commandline_argument; + break; + case 'C': + oldstyle = true; + break; + case 'c': + classname = isc_commandline_argument; + break; + case 'E': + engine = isc_commandline_argument; + break; + case 'f': + c = (unsigned char)(isc_commandline_argument[0]); + if (toupper(c) == 'K') { + kskflag = DNS_KEYFLAG_KSK; + } else if (toupper(c) == 'R') { + revflag = DNS_KEYFLAG_REVOKE; + } else { + fatal("unknown flag '%s'", + isc_commandline_argument); + } + break; + case 'K': + directory = isc_commandline_argument; + ret = try_dir(directory); + if (ret != ISC_R_SUCCESS) { + fatal("cannot open directory %s: %s", directory, + isc_result_totext(ret)); + } + break; + case 'k': + options |= DST_TYPE_KEY; + break; + case 'L': + ttl = strtottl(isc_commandline_argument); + setttl = true; + break; + case 'l': + label = isc_mem_strdup(mctx, isc_commandline_argument); + break; + case 'n': + nametype = isc_commandline_argument; + break; + case 'p': + protocol = strtol(isc_commandline_argument, &endp, 10); + if (*endp != '\0' || protocol < 0 || protocol > 255) { + fatal("-p must be followed by a number " + "[0..255]"); + } + break; + case 't': + type = isc_commandline_argument; + break; + case 'v': + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("-v must be followed by a number"); + } + break; + case 'y': + avoid_collisions = false; + break; + case 'G': + genonly = true; + break; + case 'P': + /* -Psync ? */ + if (isoptarg("sync", argv, usage)) { + if (unsetsyncadd || setsyncadd) { + fatal("-P sync specified more than " + "once"); + } + + syncadd = strtotime(isc_commandline_argument, + now, now, &setsyncadd); + unsetsyncadd = !setsyncadd; + break; + } + /* -Pdnskey ? */ + (void)isoptarg("dnskey", argv, usage); + if (setpub || unsetpub) { + fatal("-P specified more than once"); + } + + publish = strtotime(isc_commandline_argument, now, now, + &setpub); + unsetpub = !setpub; + break; + case 'A': + if (setact || unsetact) { + fatal("-A specified more than once"); + } + + activate = strtotime(isc_commandline_argument, now, now, + &setact); + unsetact = !setact; + break; + case 'R': + if (setrev || unsetrev) { + fatal("-R specified more than once"); + } + + revoke = strtotime(isc_commandline_argument, now, now, + &setrev); + unsetrev = !setrev; + break; + case 'I': + if (setinact || unsetinact) { + fatal("-I specified more than once"); + } + + inactive = strtotime(isc_commandline_argument, now, now, + &setinact); + unsetinact = !setinact; + break; + case 'D': + /* -Dsync ? */ + if (isoptarg("sync", argv, usage)) { + if (unsetsyncdel || setsyncdel) { + fatal("-D sync specified more than " + "once"); + } + + syncdel = strtotime(isc_commandline_argument, + now, now, &setsyncdel); + unsetsyncdel = !setsyncdel; + break; + } + /* -Ddnskey ? */ + (void)isoptarg("dnskey", argv, usage); + if (setdel || unsetdel) { + fatal("-D specified more than once"); + } + + deltime = strtotime(isc_commandline_argument, now, now, + &setdel); + unsetdel = !setdel; + break; + case 'S': + predecessor = isc_commandline_argument; + break; + case 'i': + prepub = strtottl(isc_commandline_argument); + break; + case 'F': + /* Reserved for FIPS mode */ + FALLTHROUGH; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + } + FALLTHROUGH; + case 'h': + /* Does not return. */ + usage(); + + case 'V': + /* Does not return. */ + version(program); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + ret = dst_lib_init(mctx, engine); + if (ret != ISC_R_SUCCESS) { + fatal("could not initialize dst: %s", isc_result_totext(ret)); + } + + setup_logging(mctx, &log); + + if (predecessor == NULL) { + if (label == NULL) { + fatal("the key label was not specified"); + } + if (argc < isc_commandline_index + 1) { + fatal("the key name was not specified"); + } + if (argc > isc_commandline_index + 1) { + fatal("extraneous arguments"); + } + + name = dns_fixedname_initname(&fname); + isc_buffer_init(&buf, argv[isc_commandline_index], + strlen(argv[isc_commandline_index])); + isc_buffer_add(&buf, strlen(argv[isc_commandline_index])); + ret = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL); + if (ret != ISC_R_SUCCESS) { + fatal("invalid key name %s: %s", + argv[isc_commandline_index], + isc_result_totext(ret)); + } + + if (strchr(label, ':') == NULL) { + char *l; + int len; + + len = strlen(label) + 8; + l = isc_mem_allocate(mctx, len); + snprintf(l, len, "pkcs11:%s", label); + isc_mem_free(mctx, label); + label = l; + } + + if (algname == NULL) { + fatal("no algorithm specified"); + } + + r.base = algname; + r.length = strlen(algname); + ret = dns_secalg_fromtext(&alg, &r); + if (ret != ISC_R_SUCCESS) { + fatal("unknown algorithm %s", algname); + } + if (alg == DST_ALG_DH) { + options |= DST_TYPE_KEY; + } + + if (use_nsec3) { + switch (alg) { + case DST_ALG_RSASHA1: + alg = DST_ALG_NSEC3RSASHA1; + break; + case DST_ALG_NSEC3RSASHA1: + case DST_ALG_RSASHA256: + case DST_ALG_RSASHA512: + case DST_ALG_ECDSA256: + case DST_ALG_ECDSA384: + case DST_ALG_ED25519: + case DST_ALG_ED448: + break; + default: + fatal("%s is incompatible with NSEC3; " + "do not use the -3 option", + algname); + } + } + + if (type != NULL && (options & DST_TYPE_KEY) != 0) { + if (strcasecmp(type, "NOAUTH") == 0) { + flags |= DNS_KEYTYPE_NOAUTH; + } else if (strcasecmp(type, "NOCONF") == 0) { + flags |= DNS_KEYTYPE_NOCONF; + } else if (strcasecmp(type, "NOAUTHCONF") == 0) { + flags |= (DNS_KEYTYPE_NOAUTH | + DNS_KEYTYPE_NOCONF); + } else if (strcasecmp(type, "AUTHCONF") == 0) { + /* nothing */ + } else { + fatal("invalid type %s", type); + } + } + + if (!oldstyle && prepub > 0) { + if (setpub && setact && (activate - prepub) < publish) { + fatal("Activation and publication dates " + "are closer together than the\n\t" + "prepublication interval."); + } + + if (!setpub && !setact) { + setpub = setact = true; + publish = now; + activate = now + prepub; + } else if (setpub && !setact) { + setact = true; + activate = publish + prepub; + } else if (setact && !setpub) { + setpub = true; + publish = activate - prepub; + } + + if ((activate - prepub) < now) { + fatal("Time until activation is shorter " + "than the\n\tprepublication interval."); + } + } + } else { + char keystr[DST_KEY_FORMATSIZE]; + isc_stdtime_t when; + int major, minor; + + if (prepub == -1) { + prepub = (30 * 86400); + } + + if (algname != NULL) { + fatal("-S and -a cannot be used together"); + } + if (nametype != NULL) { + fatal("-S and -n cannot be used together"); + } + if (type != NULL) { + fatal("-S and -t cannot be used together"); + } + if (setpub || unsetpub) { + fatal("-S and -P cannot be used together"); + } + if (setact || unsetact) { + fatal("-S and -A cannot be used together"); + } + if (use_nsec3) { + fatal("-S and -3 cannot be used together"); + } + if (oldstyle) { + fatal("-S and -C cannot be used together"); + } + if (genonly) { + fatal("-S and -G cannot be used together"); + } + + ret = dst_key_fromnamedfile(predecessor, directory, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, + mctx, &prevkey); + if (ret != ISC_R_SUCCESS) { + fatal("Invalid keyfile %s: %s", predecessor, + isc_result_totext(ret)); + } + if (!dst_key_isprivate(prevkey)) { + fatal("%s is not a private key", predecessor); + } + + name = dst_key_name(prevkey); + alg = dst_key_alg(prevkey); + flags = dst_key_flags(prevkey); + + dst_key_format(prevkey, keystr, sizeof(keystr)); + dst_key_getprivateformat(prevkey, &major, &minor); + if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) { + fatal("Key %s has incompatible format version %d.%d\n\t" + "It is not possible to generate a successor key.", + keystr, major, minor); + } + + ret = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &when); + if (ret != ISC_R_SUCCESS) { + fatal("Key %s has no activation date.\n\t" + "You must use dnssec-settime -A to set one " + "before generating a successor.", + keystr); + } + + ret = dst_key_gettime(prevkey, DST_TIME_INACTIVE, &activate); + if (ret != ISC_R_SUCCESS) { + fatal("Key %s has no inactivation date.\n\t" + "You must use dnssec-settime -I to set one " + "before generating a successor.", + keystr); + } + + publish = activate - prepub; + if (publish < now) { + fatal("Key %s becomes inactive\n\t" + "sooner than the prepublication period " + "for the new key ends.\n\t" + "Either change the inactivation date with " + "dnssec-settime -I,\n\t" + "or use the -i option to set a shorter " + "prepublication interval.", + keystr); + } + + ret = dst_key_gettime(prevkey, DST_TIME_DELETE, &when); + if (ret != ISC_R_SUCCESS) { + fprintf(stderr, + "%s: WARNING: Key %s has no removal " + "date;\n\t it will remain in the zone " + "indefinitely after rollover.\n\t " + "You can use dnssec-settime -D to " + "change this.\n", + program, keystr); + } + + setpub = setact = true; + } + + if (nametype == NULL) { + if ((options & DST_TYPE_KEY) != 0) { /* KEY */ + fatal("no nametype specified"); + } + flags |= DNS_KEYOWNER_ZONE; /* DNSKEY */ + } else if (strcasecmp(nametype, "zone") == 0) { + flags |= DNS_KEYOWNER_ZONE; + } else if ((options & DST_TYPE_KEY) != 0) { /* KEY */ + if (strcasecmp(nametype, "host") == 0 || + strcasecmp(nametype, "entity") == 0) + { + flags |= DNS_KEYOWNER_ENTITY; + } else if (strcasecmp(nametype, "user") == 0) { + flags |= DNS_KEYOWNER_USER; + } else { + fatal("invalid KEY nametype %s", nametype); + } + } else if (strcasecmp(nametype, "other") != 0) { /* DNSKEY */ + fatal("invalid DNSKEY nametype %s", nametype); + } + + rdclass = strtoclass(classname); + + if (directory == NULL) { + directory = "."; + } + + if ((options & DST_TYPE_KEY) != 0) { /* KEY */ + flags |= signatory; + } else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */ + flags |= kskflag; + flags |= revflag; + } + + if (protocol == -1) { + protocol = DNS_KEYPROTO_DNSSEC; + } else if ((options & DST_TYPE_KEY) == 0 && + protocol != DNS_KEYPROTO_DNSSEC) + { + fatal("invalid DNSKEY protocol: %d", protocol); + } + + if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { + if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0) { + fatal("specified null key with signing authority"); + } + } + + if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE && + alg == DNS_KEYALG_DH) + { + fatal("a key with algorithm '%s' cannot be a zone key", + algname); + } + + isc_buffer_init(&buf, filename, sizeof(filename) - 1); + + /* associate the key */ + ret = dst_key_fromlabel(name, alg, flags, protocol, rdclass, +#if USE_PKCS11 + "pkcs11", +#else /* if USE_PKCS11 */ + engine, +#endif /* if USE_PKCS11 */ + label, NULL, mctx, &key); + + if (ret != ISC_R_SUCCESS) { + char namestr[DNS_NAME_FORMATSIZE]; + char algstr[DNS_SECALG_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + dns_secalg_format(alg, algstr, sizeof(algstr)); + fatal("failed to get key %s/%s: %s", namestr, algstr, + isc_result_totext(ret)); + UNREACHABLE(); + exit(-1); + } + + /* + * Set key timing metadata (unless using -C) + * + * Publish and activation dates are set to "now" by default, but + * can be overridden. Creation date is always set to "now". + */ + if (!oldstyle) { + dst_key_settime(key, DST_TIME_CREATED, now); + + if (genonly && (setpub || setact)) { + fatal("cannot use -G together with -P or -A options"); + } + + if (setpub) { + dst_key_settime(key, DST_TIME_PUBLISH, publish); + } else if (setact) { + dst_key_settime(key, DST_TIME_PUBLISH, activate); + } else if (!genonly && !unsetpub) { + dst_key_settime(key, DST_TIME_PUBLISH, now); + } + + if (setact) { + dst_key_settime(key, DST_TIME_ACTIVATE, activate); + } else if (!genonly && !unsetact) { + dst_key_settime(key, DST_TIME_ACTIVATE, now); + } + + if (setrev) { + if (kskflag == 0) { + fprintf(stderr, + "%s: warning: Key is " + "not flagged as a KSK, but -R " + "was used. Revoking a ZSK is " + "legal, but undefined.\n", + program); + } + dst_key_settime(key, DST_TIME_REVOKE, revoke); + } + + if (setinact) { + dst_key_settime(key, DST_TIME_INACTIVE, inactive); + } + + if (setdel) { + dst_key_settime(key, DST_TIME_DELETE, deltime); + } + if (setsyncadd) { + dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncadd); + } + if (setsyncdel) { + dst_key_settime(key, DST_TIME_SYNCDELETE, syncdel); + } + } else { + if (setpub || setact || setrev || setinact || setdel || + unsetpub || unsetact || unsetrev || unsetinact || + unsetdel || genonly || setsyncadd || setsyncdel) + { + fatal("cannot use -C together with " + "-P, -A, -R, -I, -D, or -G options"); + } + /* + * Compatibility mode: Private-key-format + * should be set to 1.2. + */ + dst_key_setprivateformat(key, 1, 2); + } + + /* Set default key TTL */ + if (setttl) { + dst_key_setttl(key, ttl); + } + + /* + * Do not overwrite an existing key. Warn LOUDLY if there + * is a risk of ID collision due to this key or another key + * being revoked. + */ + if (key_collision(key, name, directory, mctx, &exact)) { + isc_buffer_clear(&buf); + ret = dst_key_buildfilename(key, 0, directory, &buf); + if (ret != ISC_R_SUCCESS) { + fatal("dst_key_buildfilename returned: %s\n", + isc_result_totext(ret)); + } + if (exact) { + fatal("%s: %s already exists\n", program, filename); + } + + if (avoid_collisions) { + fatal("%s: %s could collide with another key upon " + "revokation\n", + program, filename); + } + + fprintf(stderr, + "%s: WARNING: Key %s could collide with " + "another key upon revokation. If you plan " + "to revoke keys, destroy this key and " + "generate a different one.\n", + program, filename); + } + + ret = dst_key_tofile(key, options, directory); + if (ret != ISC_R_SUCCESS) { + char keystr[DST_KEY_FORMATSIZE]; + dst_key_format(key, keystr, sizeof(keystr)); + fatal("failed to write key %s: %s\n", keystr, + isc_result_totext(ret)); + } + + isc_buffer_clear(&buf); + ret = dst_key_buildfilename(key, 0, NULL, &buf); + if (ret != ISC_R_SUCCESS) { + fatal("dst_key_buildfilename returned: %s\n", + isc_result_totext(ret)); + } + printf("%s\n", filename); + dst_key_free(&key); + if (prevkey != NULL) { + dst_key_free(&prevkey); + } + + cleanup_logging(&log); + dst_lib_destroy(); + if (verbose > 10) { + isc_mem_stats(mctx, stdout); + } + isc_mem_free(mctx, label); + isc_mem_destroy(&mctx); + + if (freeit != NULL) { + free(freeit); + } + + return (0); +} diff --git a/bin/dnssec/dnssec-keyfromlabel.rst b/bin/dnssec/dnssec-keyfromlabel.rst new file mode 100644 index 0000000..57ab9c8 --- /dev/null +++ b/bin/dnssec/dnssec-keyfromlabel.rst @@ -0,0 +1,262 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-keyfromlabel: + +dnssec-keyfromlabel - DNSSEC key generation tool +------------------------------------------------ + +Synopsis +~~~~~~~~ + +:program:`dnssec-keyfromlabel` {**-l** label} [**-3**] [**-a** algorithm] [**-A** date/offset] [**-c** class] [**-D** date/offset] [**-D** sync date/offset] [**-E** engine] [**-f** flag] [**-G**] [**-I** date/offset] [**-i** interval] [**-k**] [**-K** directory] [**-L** ttl] [**-n** nametype] [**-P** date/offset] [**-P** sync date/offset] [**-p** protocol] [**-R** date/offset] [**-S** key] [**-t** type] [**-v** level] [**-V**] [**-y**] {name} + +Description +~~~~~~~~~~~ + +``dnssec-keyfromlabel`` generates a pair of key files that reference a +key object stored in a cryptographic hardware service module (HSM). The +private key file can be used for DNSSEC signing of zone data as if it +were a conventional signing key created by ``dnssec-keygen``, but the +key material is stored within the HSM and the actual signing takes +place there. + +The ``name`` of the key is specified on the command line. This must +match the name of the zone for which the key is being generated. + +Options +~~~~~~~ + +``-a algorithm`` + This option selects the cryptographic algorithm. The value of ``algorithm`` must + be one of RSASHA1, NSEC3RSASHA1, RSASHA256, RSASHA512, + ECDSAP256SHA256, ECDSAP384SHA384, ED25519, or ED448. + + These values are case-insensitive. In some cases, abbreviations are + supported, such as ECDSA256 for ECDSAP256SHA256 and ECDSA384 for + ECDSAP384SHA384. If RSASHA1 is specified along with the ``-3`` + option, then NSEC3RSASHA1 is used instead. + + This option is mandatory except when using the + ``-S`` option, which copies the algorithm from the predecessory key. + + .. versionchanged:: 9.12.0 + The default value RSASHA1 for newly generated keys was removed. + +``-3`` + This option uses an NSEC3-capable algorithm to generate a DNSSEC key. If this + option is used with an algorithm that has both NSEC and NSEC3 + versions, then the NSEC3 version is used; for example, + ``dnssec-keygen -3a RSASHA1`` specifies the NSEC3RSASHA1 algorithm. + +``-E engine`` + This option specifies the cryptographic hardware to use. + + When BIND 9 is built with OpenSSL, this needs to be set to the OpenSSL + engine identifier that drives the cryptographic accelerator or + hardware service module (usually ``pkcs11``). When BIND is + built with native PKCS#11 cryptography (``--enable-native-pkcs11``), it + defaults to the path of the PKCS#11 provider library specified via + ``--with-pkcs11``. + +``-l label`` + This option specifies the label for a key pair in the crypto hardware. + + When BIND 9 is built with OpenSSL-based PKCS#11 support, the label is + an arbitrary string that identifies a particular key. It may be + preceded by an optional OpenSSL engine name, followed by a colon, as + in ``pkcs11:keylabel``. + + When BIND 9 is built with native PKCS#11 support, the label is a + PKCS#11 URI string in the format + ``pkcs11:keyword\ =value[;\ keyword\ =value;...]``. Keywords + include ``token``, which identifies the HSM; ``object``, which identifies + the key; and ``pin-source``, which identifies a file from which the + HSM's PIN code can be obtained. The label is stored in the + on-disk ``private`` file. + + If the label contains a ``pin-source`` field, tools using the + generated key files are able to use the HSM for signing and other + operations without any need for an operator to manually enter a PIN. + Note: Making the HSM's PIN accessible in this manner may reduce the + security advantage of using an HSM; use caution + with this feature. + +``-n nametype`` + This option specifies the owner type of the key. The value of ``nametype`` must + either be ZONE (for a DNSSEC zone key (KEY/DNSKEY)), HOST or ENTITY + (for a key associated with a host (KEY)), USER (for a key associated + with a user (KEY)), or OTHER (DNSKEY). These values are + case-insensitive. + +``-C`` + This option enables compatibility mode, which generates an old-style key, without any metadata. + By default, ``dnssec-keyfromlabel`` includes the key's creation + date in the metadata stored with the private key; other dates may + be set there as well, including publication date, activation date, etc. Keys + that include this data may be incompatible with older versions of + BIND; the ``-C`` option suppresses them. + +``-c class`` + This option indicates that the DNS record containing the key should have the + specified class. If not specified, class IN is used. + +``-f flag`` + This option sets the specified flag in the ``flag`` field of the KEY/DNSKEY record. + The only recognized flags are KSK (Key-Signing Key) and REVOKE. + +``-G`` + This option generates a key, but does not publish it or sign with it. This option is + incompatible with ``-P`` and ``-A``. + +``-h`` + This option prints a short summary of the options and arguments to + ``dnssec-keyfromlabel``. + +``-K directory`` + This option sets the directory in which the key files are to be written. + +``-k`` + This option generates KEY records rather than DNSKEY records. + +``-L`` ttl + This option sets the default TTL to use for this key when it is converted into a + DNSKEY RR. This is the TTL used when the key is imported into a zone, + unless there was already a DNSKEY RRset in + place, in which case the existing TTL would take precedence. Setting + the default TTL to ``0`` or ``none`` removes it. + +``-p protocol`` + This option sets the protocol value for the key. The protocol is a number between + 0 and 255. The default is 3 (DNSSEC). Other possible values for this + argument are listed in :rfc:`2535` and its successors. + +``-S key`` + This option generates a key as an explicit successor to an existing key. The name, + algorithm, size, and type of the key are set to match the + predecessor. The activation date of the new key is set to the + inactivation date of the existing one. The publication date is + set to the activation date minus the prepublication interval, which + defaults to 30 days. + +``-t type`` + This option indicates the type of the key. ``type`` must be one of AUTHCONF, + NOAUTHCONF, NOAUTH, or NOCONF. The default is AUTHCONF. AUTH refers + to the ability to authenticate data, and CONF to the ability to encrypt + data. + +``-v level`` + This option sets the debugging level. + +``-V`` + This option prints version information. + +``-y`` + This option allows DNSSEC key files to be generated even if the key ID would + collide with that of an existing key, in the event of either key + being revoked. (This is only safe to enable if + :rfc:`5011` trust anchor maintenance is not used with either of the keys + involved.) + +Timing Options +~~~~~~~~~~~~~~ + +Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. If the +argument begins with a ``+`` or ``-``, it is interpreted as an offset from +the present time. For convenience, if such an offset is followed by one +of the suffixes ``y``, ``mo``, ``w``, ``d``, ``h``, or ``mi``, then the offset is +computed in years (defined as 365 24-hour days, ignoring leap years), +months (defined as 30 24-hour days), weeks, days, hours, or minutes, +respectively. Without a suffix, the offset is computed in seconds. To +explicitly prevent a date from being set, use ``none`` or ``never``. + +``-P date/offset`` + This option sets the date on which a key is to be published to the zone. After + that date, the key is included in the zone but is not used + to sign it. If not set, and if the ``-G`` option has not been used, the + default is the current date. + +``-P sync date/offset`` + This option sets the date on which CDS and CDNSKEY records that match this key + are to be published to the zone. + +``-A date/offset`` + This option sets the date on which the key is to be activated. After that date, + the key is included in the zone and used to sign it. If not set, + and if the ``-G`` option has not been used, the default is the current date. + +``-R date/offset`` + This option sets the date on which the key is to be revoked. After that date, the + key is flagged as revoked. It is included in the zone and + is used to sign it. + +``-I date/offset`` + This option sets the date on which the key is to be retired. After that date, the + key is still included in the zone, but it is not used to + sign it. + +``-D date/offset`` + This option sets the date on which the key is to be deleted. After that date, the + key is no longer included in the zone. (However, it may remain in the key + repository.) + +``-D sync date/offset`` + This option sets the date on which the CDS and CDNSKEY records that match this + key are to be deleted. + +``-i interval`` + This option sets the prepublication interval for a key. If set, then the + publication and activation dates must be separated by at least this + much time. If the activation date is specified but the publication + date is not, the publication date defaults to this much time + before the activation date; conversely, if the publication date is + specified but not the activation date, activation is set to + this much time after publication. + + If the key is being created as an explicit successor to another key, + then the default prepublication interval is 30 days; otherwise it is + zero. + + As with date offsets, if the argument is followed by one of the + suffixes ``y``, ``mo``, ``w``, ``d``, ``h``, or ``mi``, the interval is + measured in years, months, weeks, days, hours, or minutes, + respectively. Without a suffix, the interval is measured in seconds. + +Generated Key Files +~~~~~~~~~~~~~~~~~~~ + +When ``dnssec-keyfromlabel`` completes successfully, it prints a string +of the form ``Knnnn.+aaa+iiiii`` to the standard output. This is an +identification string for the key files it has generated. + +- ``nnnn`` is the key name. + +- ``aaa`` is the numeric representation of the algorithm. + +- ``iiiii`` is the key identifier (or footprint). + +``dnssec-keyfromlabel`` creates two files, with names based on the +printed string. ``Knnnn.+aaa+iiiii.key`` contains the public key, and +``Knnnn.+aaa+iiiii.private`` contains the private key. + +The ``.key`` file contains a DNS KEY record that can be inserted into a +zone file (directly or with an $INCLUDE statement). + +The ``.private`` file contains algorithm-specific fields. For obvious +security reasons, this file does not have general read permission. + +See Also +~~~~~~~~ + +:manpage:`dnssec-keygen(8)`, :manpage:`dnssec-signzone(8)`, BIND 9 Administrator Reference Manual, +:rfc:`4034`, :rfc:`7512`. diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c new file mode 100644 index 0000000..1c663e2 --- /dev/null +++ b/bin/dnssec/dnssec-keygen.c @@ -0,0 +1,1315 @@ +/* + * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + * + * Portions Copyright (C) Network Associates, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/*! \file */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include "dnssectool.h" + +#define MAX_RSA 4096 /* should be long enough... */ + +const char *program = "dnssec-keygen"; + +isc_log_t *lctx = NULL; + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +progress(int p); + +struct keygen_ctx { + const char *predecessor; + const char *policy; + const char *configfile; + const char *directory; + char *algname; + char *nametype; + char *type; + int generator; + int protocol; + int size; + int signatory; + dns_rdataclass_t rdclass; + int options; + int dbits; + dns_ttl_t ttl; + uint16_t kskflag; + uint16_t revflag; + dns_secalg_t alg; + /* timing data */ + int prepub; + isc_stdtime_t now; + isc_stdtime_t publish; + isc_stdtime_t activate; + isc_stdtime_t inactive; + isc_stdtime_t revokekey; + isc_stdtime_t deltime; + isc_stdtime_t syncadd; + isc_stdtime_t syncdel; + bool setpub; + bool setact; + bool setinact; + bool setrev; + bool setdel; + bool setsyncadd; + bool setsyncdel; + bool unsetpub; + bool unsetact; + bool unsetinact; + bool unsetrev; + bool unsetdel; + /* how to generate the key */ + bool setttl; + bool use_nsec3; + bool genonly; + bool showprogress; + bool quiet; + bool oldstyle; + /* state */ + time_t lifetime; + bool ksk; + bool zsk; +}; + +typedef struct keygen_ctx keygen_ctx_t; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s [options] name\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, " name: owner of the key\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -K : write keys into directory\n"); + fprintf(stderr, " -k : generate keys for dnssec-policy\n"); + fprintf(stderr, " -l : configuration file with dnssec-policy " + "statement\n"); + fprintf(stderr, " -a :\n"); + fprintf(stderr, " RSASHA1 | NSEC3RSASHA1 |\n"); + fprintf(stderr, " RSASHA256 | RSASHA512 |\n"); + fprintf(stderr, " ECDSAP256SHA256 | ECDSAP384SHA384 |\n"); + fprintf(stderr, " ED25519 | ED448 | DH\n"); + fprintf(stderr, " -3: use NSEC3-capable algorithm\n"); + fprintf(stderr, " -b :\n"); + fprintf(stderr, " RSASHA1:\t[1024..%d]\n", MAX_RSA); + fprintf(stderr, " NSEC3RSASHA1:\t[1024..%d]\n", MAX_RSA); + fprintf(stderr, " RSASHA256:\t[1024..%d]\n", MAX_RSA); + fprintf(stderr, " RSASHA512:\t[1024..%d]\n", MAX_RSA); + fprintf(stderr, " DH:\t\t[128..4096]\n"); + fprintf(stderr, " ECDSAP256SHA256:\tignored\n"); + fprintf(stderr, " ECDSAP384SHA384:\tignored\n"); + fprintf(stderr, " ED25519:\tignored\n"); + fprintf(stderr, " ED448:\tignored\n"); + fprintf(stderr, " (key size defaults are set according to\n" + " algorithm and usage (ZSK or KSK)\n"); + fprintf(stderr, " -n : ZONE | HOST | ENTITY | " + "USER | OTHER\n"); + fprintf(stderr, " (DNSKEY generation defaults to ZONE)\n"); + fprintf(stderr, " -c : (default: IN)\n"); + fprintf(stderr, " -d (0 => max, default)\n"); + fprintf(stderr, " -E :\n"); +#if USE_PKCS11 + fprintf(stderr, + " path to PKCS#11 provider library " + "(default is %s)\n", + PK11_LIB_LOCATION); +#else /* if USE_PKCS11 */ + fprintf(stderr, " name of an OpenSSL engine to use\n"); +#endif /* if USE_PKCS11 */ + fprintf(stderr, " -f : KSK | REVOKE\n"); + fprintf(stderr, " -g : use specified generator " + "(DH only)\n"); + fprintf(stderr, " -L : default key TTL\n"); + fprintf(stderr, " -p : (default: 3 [dnssec])\n"); + fprintf(stderr, " -s : strength value this key signs DNS " + "records with (default: 0)\n"); + fprintf(stderr, " -T : DNSKEY | KEY (default: DNSKEY; " + "use KEY for SIG(0))\n"); + fprintf(stderr, " -t : " + "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " + "(default: AUTHCONF)\n"); + fprintf(stderr, " -h: print usage and exit\n"); + fprintf(stderr, " -m :\n"); + fprintf(stderr, " usage | trace | record | size | mctx\n"); + fprintf(stderr, " -v : set verbosity level (0 - 10)\n"); + fprintf(stderr, " -V: print version information\n"); + fprintf(stderr, "Timing options:\n"); + fprintf(stderr, " -P date/[+-]offset/none: set key publication date " + "(default: now)\n"); + fprintf(stderr, " -P sync date/[+-]offset/none: set CDS and CDNSKEY " + "publication date\n"); + fprintf(stderr, " -A date/[+-]offset/none: set key activation date " + "(default: now)\n"); + fprintf(stderr, " -R date/[+-]offset/none: set key " + "revocation date\n"); + fprintf(stderr, " -I date/[+-]offset/none: set key " + "inactivation date\n"); + fprintf(stderr, " -D date/[+-]offset/none: set key deletion date\n"); + fprintf(stderr, " -D sync date/[+-]offset/none: set CDS and CDNSKEY " + "deletion date\n"); + + fprintf(stderr, " -G: generate key only; do not set -P or -A\n"); + fprintf(stderr, " -C: generate a backward-compatible key, omitting " + "all dates\n"); + fprintf(stderr, " -S : generate a successor to an existing " + "key\n"); + fprintf(stderr, " -i : prepublication interval for " + "successor key " + "(default: 30 days)\n"); + fprintf(stderr, "Output:\n"); + fprintf(stderr, " K++.key, " + "K++.private\n"); + + exit(-1); +} + +static void +progress(int p) { + char c = '*'; + + switch (p) { + case 0: + c = '.'; + break; + case 1: + c = '+'; + break; + case 2: + c = '*'; + break; + case 3: + c = ' '; + break; + default: + break; + } + (void)putc(c, stderr); + (void)fflush(stderr); +} + +static void +kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name, + dns_kasp_t **kaspp) { + const cfg_listelt_t *element; + const cfg_obj_t *kasps = NULL; + dns_kasp_t *kasp = NULL, *kasp_next; + isc_result_t result = ISC_R_NOTFOUND; + dns_kasplist_t kasplist; + + ISC_LIST_INIT(kasplist); + + (void)cfg_map_get(config, "dnssec-policy", &kasps); + for (element = cfg_list_first(kasps); element != NULL; + element = cfg_list_next(element)) + { + cfg_obj_t *kconfig = cfg_listelt_value(element); + kasp = NULL; + if (strcmp(cfg_obj_asstring(cfg_tuple_get(kconfig, "name")), + name) != 0) + { + continue; + } + + result = cfg_kasp_fromconfig(kconfig, NULL, mctx, lctx, + &kasplist, &kasp); + if (result != ISC_R_SUCCESS) { + fatal("failed to configure dnssec-policy '%s': %s", + cfg_obj_asstring(cfg_tuple_get(kconfig, "name")), + isc_result_totext(result)); + } + INSIST(kasp != NULL); + dns_kasp_freeze(kasp); + break; + } + + *kaspp = kasp; + + /* + * Cleanup kasp list. + */ + for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) { + kasp_next = ISC_LIST_NEXT(kasp, link); + ISC_LIST_UNLINK(kasplist, kasp, link); + dns_kasp_detach(&kasp); + } +} + +static void +keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) { + char filename[255]; + char algstr[DNS_SECALG_FORMATSIZE]; + uint16_t flags = 0; + int param = 0; + bool null_key = false; + bool conflict = false; + bool show_progress = false; + isc_buffer_t buf; + dns_name_t *name; + dns_fixedname_t fname; + isc_result_t ret; + dst_key_t *key = NULL; + dst_key_t *prevkey = NULL; + + UNUSED(argc); + + dns_secalg_format(ctx->alg, algstr, sizeof(algstr)); + + if (ctx->predecessor == NULL) { + if (ctx->prepub == -1) { + ctx->prepub = 0; + } + + name = dns_fixedname_initname(&fname); + isc_buffer_init(&buf, argv[isc_commandline_index], + strlen(argv[isc_commandline_index])); + isc_buffer_add(&buf, strlen(argv[isc_commandline_index])); + ret = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL); + if (ret != ISC_R_SUCCESS) { + fatal("invalid key name %s: %s", + argv[isc_commandline_index], + isc_result_totext(ret)); + } + + if (!dst_algorithm_supported(ctx->alg)) { + fatal("unsupported algorithm: %s", algstr); + } + + if (ctx->alg == DST_ALG_DH) { + ctx->options |= DST_TYPE_KEY; + } + + if (ctx->use_nsec3) { + switch (ctx->alg) { + case DST_ALG_RSASHA1: + ctx->alg = DST_ALG_NSEC3RSASHA1; + break; + case DST_ALG_NSEC3RSASHA1: + case DST_ALG_RSASHA256: + case DST_ALG_RSASHA512: + case DST_ALG_ECDSA256: + case DST_ALG_ECDSA384: + case DST_ALG_ED25519: + case DST_ALG_ED448: + break; + default: + fatal("algorithm %s is incompatible with NSEC3" + ", do not use the -3 option", + algstr); + } + } + + if (ctx->type != NULL && (ctx->options & DST_TYPE_KEY) != 0) { + if (strcasecmp(ctx->type, "NOAUTH") == 0) { + flags |= DNS_KEYTYPE_NOAUTH; + } else if (strcasecmp(ctx->type, "NOCONF") == 0) { + flags |= DNS_KEYTYPE_NOCONF; + } else if (strcasecmp(ctx->type, "NOAUTHCONF") == 0) { + flags |= (DNS_KEYTYPE_NOAUTH | + DNS_KEYTYPE_NOCONF); + if (ctx->size < 0) { + ctx->size = 0; + } + } else if (strcasecmp(ctx->type, "AUTHCONF") == 0) { + /* nothing */ + } else { + fatal("invalid type %s", ctx->type); + } + } + + if (ctx->size < 0) { + switch (ctx->alg) { + case DST_ALG_RSASHA1: + case DST_ALG_NSEC3RSASHA1: + case DST_ALG_RSASHA256: + case DST_ALG_RSASHA512: + ctx->size = 2048; + if (verbose > 0) { + fprintf(stderr, + "key size not " + "specified; defaulting" + " to %d\n", + ctx->size); + } + break; + case DST_ALG_ECDSA256: + case DST_ALG_ECDSA384: + case DST_ALG_ED25519: + case DST_ALG_ED448: + break; + default: + fatal("key size not specified (-b option)"); + } + } + + if (!ctx->oldstyle && ctx->prepub > 0) { + if (ctx->setpub && ctx->setact && + (ctx->activate - ctx->prepub) < ctx->publish) + { + fatal("Activation and publication dates " + "are closer together than the\n\t" + "prepublication interval."); + } + + if (!ctx->setpub && !ctx->setact) { + ctx->setpub = ctx->setact = true; + ctx->publish = ctx->now; + ctx->activate = ctx->now + ctx->prepub; + } else if (ctx->setpub && !ctx->setact) { + ctx->setact = true; + ctx->activate = ctx->publish + ctx->prepub; + } else if (ctx->setact && !ctx->setpub) { + ctx->setpub = true; + ctx->publish = ctx->activate - ctx->prepub; + } + + if ((ctx->activate - ctx->prepub) < ctx->now) { + fatal("Time until activation is shorter " + "than the\n\tprepublication interval."); + } + } + } else { + char keystr[DST_KEY_FORMATSIZE]; + isc_stdtime_t when; + int major, minor; + + if (ctx->prepub == -1) { + ctx->prepub = (30 * 86400); + } + + if (ctx->alg != 0) { + fatal("-S and -a cannot be used together"); + } + if (ctx->size >= 0) { + fatal("-S and -b cannot be used together"); + } + if (ctx->nametype != NULL) { + fatal("-S and -n cannot be used together"); + } + if (ctx->type != NULL) { + fatal("-S and -t cannot be used together"); + } + if (ctx->setpub || ctx->unsetpub) { + fatal("-S and -P cannot be used together"); + } + if (ctx->setact || ctx->unsetact) { + fatal("-S and -A cannot be used together"); + } + if (ctx->use_nsec3) { + fatal("-S and -3 cannot be used together"); + } + if (ctx->oldstyle) { + fatal("-S and -C cannot be used together"); + } + if (ctx->genonly) { + fatal("-S and -G cannot be used together"); + } + + ret = dst_key_fromnamedfile( + ctx->predecessor, ctx->directory, + (DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE), + mctx, &prevkey); + if (ret != ISC_R_SUCCESS) { + fatal("Invalid keyfile %s: %s", ctx->predecessor, + isc_result_totext(ret)); + } + if (!dst_key_isprivate(prevkey)) { + fatal("%s is not a private key", ctx->predecessor); + } + + name = dst_key_name(prevkey); + ctx->alg = dst_key_alg(prevkey); + ctx->size = dst_key_size(prevkey); + flags = dst_key_flags(prevkey); + + dst_key_format(prevkey, keystr, sizeof(keystr)); + dst_key_getprivateformat(prevkey, &major, &minor); + if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) { + fatal("Key %s has incompatible format version %d.%d\n\t" + "It is not possible to generate a successor key.", + keystr, major, minor); + } + + ret = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &when); + if (ret != ISC_R_SUCCESS) { + fatal("Key %s has no activation date.\n\t" + "You must use dnssec-settime -A to set one " + "before generating a successor.", + keystr); + } + + ret = dst_key_gettime(prevkey, DST_TIME_INACTIVE, + &ctx->activate); + if (ret != ISC_R_SUCCESS) { + fatal("Key %s has no inactivation date.\n\t" + "You must use dnssec-settime -I to set one " + "before generating a successor.", + keystr); + } + + ctx->publish = ctx->activate - ctx->prepub; + if (ctx->publish < ctx->now) { + fatal("Key %s becomes inactive\n\t" + "sooner than the prepublication period " + "for the new key ends.\n\t" + "Either change the inactivation date with " + "dnssec-settime -I,\n\t" + "or use the -i option to set a shorter " + "prepublication interval.", + keystr); + } + + ret = dst_key_gettime(prevkey, DST_TIME_DELETE, &when); + if (ret != ISC_R_SUCCESS) { + fprintf(stderr, + "%s: WARNING: Key %s has no removal " + "date;\n\t it will remain in the zone " + "indefinitely after rollover.\n\t " + "You can use dnssec-settime -D to " + "change this.\n", + program, keystr); + } + + ctx->setpub = ctx->setact = true; + } + + switch (ctx->alg) { + case DNS_KEYALG_RSASHA1: + case DNS_KEYALG_NSEC3RSASHA1: + case DNS_KEYALG_RSASHA256: + if (ctx->size != 0 && (ctx->size < 1024 || ctx->size > MAX_RSA)) + { + fatal("RSA key size %d out of range", ctx->size); + } + break; + case DNS_KEYALG_RSASHA512: + if (ctx->size != 0 && (ctx->size < 1024 || ctx->size > MAX_RSA)) + { + fatal("RSA key size %d out of range", ctx->size); + } + break; + case DNS_KEYALG_DH: + if (ctx->size != 0 && (ctx->size < 128 || ctx->size > 4096)) { + fatal("DH key size %d out of range", ctx->size); + } + break; + case DST_ALG_ECDSA256: + ctx->size = 256; + break; + case DST_ALG_ECDSA384: + ctx->size = 384; + break; + case DST_ALG_ED25519: + ctx->size = 256; + break; + case DST_ALG_ED448: + ctx->size = 456; + break; + } + + if (ctx->alg != DNS_KEYALG_DH && ctx->generator != 0) { + fatal("specified DH generator for a non-DH key"); + } + + if (ctx->nametype == NULL) { + if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */ + fatal("no nametype specified"); + } + flags |= DNS_KEYOWNER_ZONE; /* DNSKEY */ + } else if (strcasecmp(ctx->nametype, "zone") == 0) { + flags |= DNS_KEYOWNER_ZONE; + } else if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */ + if (strcasecmp(ctx->nametype, "host") == 0 || + strcasecmp(ctx->nametype, "entity") == 0) + { + flags |= DNS_KEYOWNER_ENTITY; + } else if (strcasecmp(ctx->nametype, "user") == 0) { + flags |= DNS_KEYOWNER_USER; + } else { + fatal("invalid KEY nametype %s", ctx->nametype); + } + } else if (strcasecmp(ctx->nametype, "other") != 0) { /* DNSKEY */ + fatal("invalid DNSKEY nametype %s", ctx->nametype); + } + + if (ctx->directory == NULL) { + ctx->directory = "."; + } + + if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */ + flags |= ctx->signatory; + } else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */ + flags |= ctx->kskflag; + flags |= ctx->revflag; + } + + if (ctx->protocol == -1) { + ctx->protocol = DNS_KEYPROTO_DNSSEC; + } else if ((ctx->options & DST_TYPE_KEY) == 0 && + ctx->protocol != DNS_KEYPROTO_DNSSEC) + { + fatal("invalid DNSKEY protocol: %d", ctx->protocol); + } + + if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { + if (ctx->size > 0) { + fatal("specified null key with non-zero size"); + } + if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0) { + fatal("specified null key with signing authority"); + } + } + + if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE && + ctx->alg == DNS_KEYALG_DH) + { + fatal("a key with algorithm %s cannot be a zone key", algstr); + } + + switch (ctx->alg) { + case DNS_KEYALG_RSASHA1: + case DNS_KEYALG_NSEC3RSASHA1: + case DNS_KEYALG_RSASHA256: + case DNS_KEYALG_RSASHA512: + show_progress = true; + break; + + case DNS_KEYALG_DH: + param = ctx->generator; + break; + + case DST_ALG_ECDSA256: + case DST_ALG_ECDSA384: + case DST_ALG_ED25519: + case DST_ALG_ED448: + show_progress = true; + break; + } + + if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { + null_key = true; + } + + isc_buffer_init(&buf, filename, sizeof(filename) - 1); + + do { + conflict = false; + + if (!ctx->quiet && show_progress) { + fprintf(stderr, "Generating key pair."); + ret = dst_key_generate(name, ctx->alg, ctx->size, param, + flags, ctx->protocol, + ctx->rdclass, mctx, &key, + &progress); + putc('\n', stderr); + fflush(stderr); + } else { + ret = dst_key_generate(name, ctx->alg, ctx->size, param, + flags, ctx->protocol, + ctx->rdclass, mctx, &key, NULL); + } + + if (ret != ISC_R_SUCCESS) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + fatal("failed to generate key %s/%s: %s\n", namestr, + algstr, isc_result_totext(ret)); + } + + dst_key_setbits(key, ctx->dbits); + + /* + * Set key timing metadata (unless using -C) + * + * Creation date is always set to "now". + * + * For a new key without an explicit predecessor, publish + * and activation dates are set to "now" by default, but + * can both be overridden. + * + * For a successor key, activation is set to match the + * predecessor's inactivation date. Publish is set to 30 + * days earlier than that (XXX: this should be configurable). + * If either of the resulting dates are in the past, that's + * an error; the inactivation date of the predecessor key + * must be updated before a successor key can be created. + */ + if (!ctx->oldstyle) { + dst_key_settime(key, DST_TIME_CREATED, ctx->now); + + if (ctx->genonly && (ctx->setpub || ctx->setact)) { + fatal("cannot use -G together with " + "-P or -A options"); + } + + if (ctx->setpub) { + dst_key_settime(key, DST_TIME_PUBLISH, + ctx->publish); + } else if (ctx->setact && !ctx->unsetpub) { + dst_key_settime(key, DST_TIME_PUBLISH, + ctx->activate - ctx->prepub); + } else if (!ctx->genonly && !ctx->unsetpub) { + dst_key_settime(key, DST_TIME_PUBLISH, + ctx->now); + } + + if (ctx->setact) { + dst_key_settime(key, DST_TIME_ACTIVATE, + ctx->activate); + } else if (!ctx->genonly && !ctx->unsetact) { + dst_key_settime(key, DST_TIME_ACTIVATE, + ctx->now); + } + + if (ctx->setrev) { + if (ctx->kskflag == 0) { + fprintf(stderr, + "%s: warning: Key is " + "not flagged as a KSK, but -R " + "was used. Revoking a ZSK is " + "legal, but undefined.\n", + program); + } + dst_key_settime(key, DST_TIME_REVOKE, + ctx->revokekey); + } + + if (ctx->setinact) { + dst_key_settime(key, DST_TIME_INACTIVE, + ctx->inactive); + } + + if (ctx->setdel) { + if (ctx->setinact && + ctx->deltime < ctx->inactive) + { + fprintf(stderr, + "%s: warning: Key is " + "scheduled to be deleted " + "before it is scheduled to be " + "made inactive.\n", + program); + } + dst_key_settime(key, DST_TIME_DELETE, + ctx->deltime); + } + + if (ctx->setsyncadd) { + dst_key_settime(key, DST_TIME_SYNCPUBLISH, + ctx->syncadd); + } + + if (ctx->setsyncdel) { + dst_key_settime(key, DST_TIME_SYNCDELETE, + ctx->syncdel); + } + } else { + if (ctx->setpub || ctx->setact || ctx->setrev || + ctx->setinact || ctx->setdel || ctx->unsetpub || + ctx->unsetact || ctx->unsetrev || ctx->unsetinact || + ctx->unsetdel || ctx->genonly || ctx->setsyncadd || + ctx->setsyncdel) + { + fatal("cannot use -C together with " + "-P, -A, -R, -I, -D, or -G options"); + } + /* + * Compatibility mode: Private-key-format + * should be set to 1.2. + */ + dst_key_setprivateformat(key, 1, 2); + } + + /* Set the default key TTL */ + if (ctx->setttl) { + dst_key_setttl(key, ctx->ttl); + } + + /* Set dnssec-policy related metadata */ + if (ctx->policy != NULL) { + dst_key_setnum(key, DST_NUM_LIFETIME, ctx->lifetime); + dst_key_setbool(key, DST_BOOL_KSK, ctx->ksk); + dst_key_setbool(key, DST_BOOL_ZSK, ctx->zsk); + } + + /* + * Do not overwrite an existing key, or create a key + * if there is a risk of ID collision due to this key + * or another key being revoked. + */ + if (key_collision(key, name, ctx->directory, mctx, NULL)) { + conflict = true; + if (null_key) { + dst_key_free(&key); + break; + } + + if (verbose > 0) { + isc_buffer_clear(&buf); + ret = dst_key_buildfilename( + key, 0, ctx->directory, &buf); + if (ret == ISC_R_SUCCESS) { + fprintf(stderr, + "%s: %s already exists, or " + "might collide with another " + "key upon revokation. " + "Generating a new key\n", + program, filename); + } + } + + dst_key_free(&key); + } + } while (conflict); + + if (conflict) { + fatal("cannot generate a null key due to possible key ID " + "collision"); + } + + if (ctx->predecessor != NULL && prevkey != NULL) { + dst_key_setnum(prevkey, DST_NUM_SUCCESSOR, dst_key_id(key)); + dst_key_setnum(key, DST_NUM_PREDECESSOR, dst_key_id(prevkey)); + + ret = dst_key_tofile(prevkey, ctx->options, ctx->directory); + if (ret != ISC_R_SUCCESS) { + char keystr[DST_KEY_FORMATSIZE]; + dst_key_format(prevkey, keystr, sizeof(keystr)); + fatal("failed to update predecessor %s: %s\n", keystr, + isc_result_totext(ret)); + } + } + + ret = dst_key_tofile(key, ctx->options, ctx->directory); + if (ret != ISC_R_SUCCESS) { + char keystr[DST_KEY_FORMATSIZE]; + dst_key_format(key, keystr, sizeof(keystr)); + fatal("failed to write key %s: %s\n", keystr, + isc_result_totext(ret)); + } + + isc_buffer_clear(&buf); + ret = dst_key_buildfilename(key, 0, NULL, &buf); + if (ret != ISC_R_SUCCESS) { + fatal("dst_key_buildfilename returned: %s\n", + isc_result_totext(ret)); + } + printf("%s\n", filename); + + dst_key_free(&key); + if (prevkey != NULL) { + dst_key_free(&prevkey); + } +} + +int +main(int argc, char **argv) { + char *algname = NULL, *freeit = NULL; + char *classname = NULL; + char *endp; + isc_mem_t *mctx = NULL; + isc_result_t ret; + isc_textregion_t r; + const char *engine = NULL; + unsigned char c; + int ch; + + keygen_ctx_t ctx = { + .options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC, + .prepub = -1, + .protocol = -1, + .size = -1, + }; + + if (argc == 1) { + usage(); + } + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + isc_commandline_errprint = false; + + /* + * Process memory debugging argument first. + */ +#define CMDLINE_FLAGS \ + "3A:a:b:Cc:D:d:E:eFf:Gg:hI:i:K:k:L:l:m:n:P:p:qR:r:S:s:" \ + "T:t:v:V" + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case 'm': + if (strcasecmp(isc_commandline_argument, "record") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + } + if (strcasecmp(isc_commandline_argument, "trace") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGTRACE; + } + if (strcasecmp(isc_commandline_argument, "usage") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; + } + if (strcasecmp(isc_commandline_argument, "size") == 0) { + isc_mem_debugging |= ISC_MEM_DEBUGSIZE; + } + if (strcasecmp(isc_commandline_argument, "mctx") == 0) { + isc_mem_debugging |= ISC_MEM_DEBUGCTX; + } + break; + default: + break; + } + } + isc_commandline_reset = true; + + isc_mem_create(&mctx); + isc_stdtime_get(&ctx.now); + + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case '3': + ctx.use_nsec3 = true; + break; + case 'a': + algname = isc_commandline_argument; + break; + case 'b': + ctx.size = strtol(isc_commandline_argument, &endp, 10); + if (*endp != '\0' || ctx.size < 0) { + fatal("-b requires a non-negative number"); + } + break; + case 'C': + ctx.oldstyle = true; + break; + case 'c': + classname = isc_commandline_argument; + break; + case 'd': + ctx.dbits = strtol(isc_commandline_argument, &endp, 10); + if (*endp != '\0' || ctx.dbits < 0) { + fatal("-d requires a non-negative number"); + } + break; + case 'E': + engine = isc_commandline_argument; + break; + case 'e': + fprintf(stderr, "phased-out option -e " + "(was 'use (RSA) large exponent')\n"); + break; + case 'f': + c = (unsigned char)(isc_commandline_argument[0]); + if (toupper(c) == 'K') { + ctx.kskflag = DNS_KEYFLAG_KSK; + } else if (toupper(c) == 'R') { + ctx.revflag = DNS_KEYFLAG_REVOKE; + } else { + fatal("unknown flag '%s'", + isc_commandline_argument); + } + break; + case 'g': + ctx.generator = strtol(isc_commandline_argument, &endp, + 10); + if (*endp != '\0' || ctx.generator <= 0) { + fatal("-g requires a positive number"); + } + break; + case 'K': + ctx.directory = isc_commandline_argument; + ret = try_dir(ctx.directory); + if (ret != ISC_R_SUCCESS) { + fatal("cannot open directory %s: %s", + ctx.directory, isc_result_totext(ret)); + } + break; + case 'k': + ctx.policy = isc_commandline_argument; + break; + case 'L': + ctx.ttl = strtottl(isc_commandline_argument); + ctx.setttl = true; + break; + case 'l': + ctx.configfile = isc_commandline_argument; + break; + case 'n': + ctx.nametype = isc_commandline_argument; + break; + case 'm': + break; + case 'p': + ctx.protocol = strtol(isc_commandline_argument, &endp, + 10); + if (*endp != '\0' || ctx.protocol < 0 || + ctx.protocol > 255) + { + fatal("-p must be followed by a number " + "[0..255]"); + } + break; + case 'q': + ctx.quiet = true; + break; + case 'r': + fatal("The -r option has been deprecated.\n" + "System random data is always used.\n"); + break; + case 's': + ctx.signatory = strtol(isc_commandline_argument, &endp, + 10); + if (*endp != '\0' || ctx.signatory < 0 || + ctx.signatory > 15) + { + fatal("-s must be followed by a number " + "[0..15]"); + } + break; + case 'T': + if (strcasecmp(isc_commandline_argument, "KEY") == 0) { + ctx.options |= DST_TYPE_KEY; + } else if (strcasecmp(isc_commandline_argument, + "DNSKE" + "Y") == 0) + { + /* default behavior */ + } else { + fatal("unknown type '%s'", + isc_commandline_argument); + } + break; + case 't': + ctx.type = isc_commandline_argument; + break; + case 'v': + endp = NULL; + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("-v must be followed by a number"); + } + break; + case 'G': + ctx.genonly = true; + break; + case 'P': + /* -Psync ? */ + if (isoptarg("sync", argv, usage)) { + if (ctx.setsyncadd) { + fatal("-P sync specified more than " + "once"); + } + + ctx.syncadd = strtotime( + isc_commandline_argument, ctx.now, + ctx.now, &ctx.setsyncadd); + break; + } + (void)isoptarg("dnskey", argv, usage); + if (ctx.setpub || ctx.unsetpub) { + fatal("-P specified more than once"); + } + + ctx.publish = strtotime(isc_commandline_argument, + ctx.now, ctx.now, &ctx.setpub); + ctx.unsetpub = !ctx.setpub; + break; + case 'A': + if (ctx.setact || ctx.unsetact) { + fatal("-A specified more than once"); + } + + ctx.activate = strtotime(isc_commandline_argument, + ctx.now, ctx.now, &ctx.setact); + ctx.unsetact = !ctx.setact; + break; + case 'R': + if (ctx.setrev || ctx.unsetrev) { + fatal("-R specified more than once"); + } + + ctx.revokekey = strtotime(isc_commandline_argument, + ctx.now, ctx.now, + &ctx.setrev); + ctx.unsetrev = !ctx.setrev; + break; + case 'I': + if (ctx.setinact || ctx.unsetinact) { + fatal("-I specified more than once"); + } + + ctx.inactive = strtotime(isc_commandline_argument, + ctx.now, ctx.now, + &ctx.setinact); + ctx.unsetinact = !ctx.setinact; + break; + case 'D': + /* -Dsync ? */ + if (isoptarg("sync", argv, usage)) { + if (ctx.setsyncdel) { + fatal("-D sync specified more than " + "once"); + } + + ctx.syncdel = strtotime( + isc_commandline_argument, ctx.now, + ctx.now, &ctx.setsyncdel); + break; + } + (void)isoptarg("dnskey", argv, usage); + if (ctx.setdel || ctx.unsetdel) { + fatal("-D specified more than once"); + } + + ctx.deltime = strtotime(isc_commandline_argument, + ctx.now, ctx.now, &ctx.setdel); + ctx.unsetdel = !ctx.setdel; + break; + case 'S': + ctx.predecessor = isc_commandline_argument; + break; + case 'i': + ctx.prepub = strtottl(isc_commandline_argument); + break; + case 'F': + /* Reserved for FIPS mode */ + FALLTHROUGH; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + } + FALLTHROUGH; + case 'h': + /* Does not return. */ + usage(); + + case 'V': + /* Does not return. */ + version(program); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + if (!isatty(0)) { + ctx.quiet = true; + } + + ret = dst_lib_init(mctx, engine); + if (ret != ISC_R_SUCCESS) { + fatal("could not initialize dst: %s", isc_result_totext(ret)); + } + + setup_logging(mctx, &lctx); + + ctx.rdclass = strtoclass(classname); + + if (ctx.configfile == NULL || ctx.configfile[0] == '\0') { + ctx.configfile = NAMED_CONFFILE; + } + + if (ctx.predecessor == NULL) { + if (argc < isc_commandline_index + 1) { + fatal("the key name was not specified"); + } + if (argc > isc_commandline_index + 1) { + fatal("extraneous arguments"); + } + } + + if (ctx.predecessor == NULL && ctx.policy == NULL) { + if (algname == NULL) { + fatal("no algorithm specified"); + } + r.base = algname; + r.length = strlen(algname); + ret = dns_secalg_fromtext(&ctx.alg, &r); + if (ret != ISC_R_SUCCESS) { + fatal("unknown algorithm %s", algname); + } + if (!dst_algorithm_supported(ctx.alg)) { + fatal("unsupported algorithm: %s", algname); + } + } + + if (ctx.policy != NULL) { + if (ctx.nametype != NULL) { + fatal("-k and -n cannot be used together"); + } + if (ctx.predecessor != NULL) { + fatal("-k and -S cannot be used together"); + } + if (ctx.oldstyle) { + fatal("-k and -C cannot be used together"); + } + if (ctx.setttl) { + fatal("-k and -L cannot be used together"); + } + if (ctx.prepub > 0) { + fatal("-k and -i cannot be used together"); + } + if (ctx.size != -1) { + fatal("-k and -b cannot be used together"); + } + if (ctx.kskflag || ctx.revflag) { + fatal("-k and -f cannot be used together"); + } + if (ctx.options & DST_TYPE_KEY) { + fatal("-k and -T KEY cannot be used together"); + } + if (ctx.use_nsec3) { + fatal("-k and -3 cannot be used together"); + } + + ctx.options |= DST_TYPE_STATE; + + if (strcmp(ctx.policy, "default") == 0) { + ctx.use_nsec3 = false; + ctx.alg = DST_ALG_ECDSA256; + ctx.size = 0; + ctx.kskflag = DNS_KEYFLAG_KSK; + ctx.ttl = 3600; + ctx.setttl = true; + ctx.ksk = true; + ctx.zsk = true; + ctx.lifetime = 0; + + keygen(&ctx, mctx, argc, argv); + } else { + cfg_parser_t *parser = NULL; + cfg_obj_t *config = NULL; + dns_kasp_t *kasp = NULL; + dns_kasp_key_t *kaspkey = NULL; + + RUNTIME_CHECK(cfg_parser_create(mctx, lctx, &parser) == + ISC_R_SUCCESS); + if (cfg_parse_file(parser, ctx.configfile, + &cfg_type_namedconf, + &config) != ISC_R_SUCCESS) + { + fatal("unable to load dnssec-policy '%s' from " + "'%s'", + ctx.policy, ctx.configfile); + } + + kasp_from_conf(config, mctx, ctx.policy, &kasp); + if (kasp == NULL) { + fatal("failed to load dnssec-policy '%s'", + ctx.policy); + } + if (ISC_LIST_EMPTY(dns_kasp_keys(kasp))) { + fatal("dnssec-policy '%s' has no keys " + "configured", + ctx.policy); + } + + ctx.ttl = dns_kasp_dnskeyttl(kasp); + ctx.setttl = true; + + kaspkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); + + while (kaspkey != NULL) { + ctx.use_nsec3 = false; + ctx.alg = dns_kasp_key_algorithm(kaspkey); + ctx.size = dns_kasp_key_size(kaspkey); + ctx.kskflag = dns_kasp_key_ksk(kaspkey) + ? DNS_KEYFLAG_KSK + : 0; + ctx.ksk = dns_kasp_key_ksk(kaspkey); + ctx.zsk = dns_kasp_key_zsk(kaspkey); + ctx.lifetime = dns_kasp_key_lifetime(kaspkey); + + keygen(&ctx, mctx, argc, argv); + + kaspkey = ISC_LIST_NEXT(kaspkey, link); + } + + dns_kasp_detach(&kasp); + cfg_obj_destroy(parser, &config); + cfg_parser_destroy(&parser); + } + } else { + keygen(&ctx, mctx, argc, argv); + } + + cleanup_logging(&lctx); + dst_lib_destroy(); + if (verbose > 10) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + if (freeit != NULL) { + free(freeit); + } + + return (0); +} diff --git a/bin/dnssec/dnssec-keygen.rst b/bin/dnssec/dnssec-keygen.rst new file mode 100644 index 0000000..3b6d46d --- /dev/null +++ b/bin/dnssec/dnssec-keygen.rst @@ -0,0 +1,318 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-keygen: + +dnssec-keygen: DNSSEC key generation tool +----------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`dnssec-keygen` [**-3**] [**-A** date/offset] [**-a** algorithm] [**-b** keysize] [**-C**] [**-c** class] [**-D** date/offset] [**-d** bits] [**-D** sync date/offset] [**-E** engine] [**-f** flag] [**-G**] [**-g** generator] [**-h**] [**-I** date/offset] [**-i** interval] [**-K** directory] [**-k** policy] [**-L** ttl] [**-l** file] [**-n** nametype] [**-P** date/offset] [**-P** sync date/offset] [**-p** protocol] [**-q**] [**-R** date/offset] [**-S** key] [**-s** strength] [**-T** rrtype] [**-t** type] [**-V**] [**-v** level] {name} + +Description +~~~~~~~~~~~ + +``dnssec-keygen`` generates keys for DNSSEC (Secure DNS), as defined in +:rfc:`2535` and :rfc:`4034`. It can also generate keys for use with TSIG +(Transaction Signatures) as defined in :rfc:`2845`, or TKEY (Transaction +Key) as defined in :rfc:`2930`. + +The ``name`` of the key is specified on the command line. For DNSSEC +keys, this must match the name of the zone for which the key is being +generated. + +The ``dnssec-keymgr`` command acts as a wrapper +around ``dnssec-keygen``, generating and updating keys +as needed to enforce defined security policies such as key rollover +scheduling. Using ``dnssec-keymgr`` may be preferable +to direct use of ``dnssec-keygen``. + +Options +~~~~~~~ + +``-3`` + This option uses an NSEC3-capable algorithm to generate a DNSSEC key. If this + option is used with an algorithm that has both NSEC and NSEC3 + versions, then the NSEC3 version is selected; for example, + ``dnssec-keygen -3 -a RSASHA1`` specifies the NSEC3RSASHA1 algorithm. + +``-a algorithm`` + This option selects the cryptographic algorithm. For DNSSEC keys, the value of + ``algorithm`` must be one of RSASHA1, NSEC3RSASHA1, RSASHA256, + RSASHA512, ECDSAP256SHA256, ECDSAP384SHA384, ED25519, or ED448. For + TKEY, the value must be DH (Diffie-Hellman); specifying this value + automatically sets the ``-T KEY`` option as well. + + These values are case-insensitive. In some cases, abbreviations are + supported, such as ECDSA256 for ECDSAP256SHA256 and ECDSA384 for + ECDSAP384SHA384. If RSASHA1 is specified along with the ``-3`` + option, NSEC3RSASHA1 is used instead. + + This parameter *must* be specified except when using the ``-S`` + option, which copies the algorithm from the predecessor key. + + In prior releases, HMAC algorithms could be generated for use as TSIG + keys, but that feature was removed in BIND 9.13.0. Use + ``tsig-keygen`` to generate TSIG keys. + +``-b keysize`` + This option specifies the number of bits in the key. The choice of key size + depends on the algorithm used: RSA keys must be between 1024 and 4096 + bits; Diffie-Hellman keys must be between 128 and 4096 bits. Elliptic + curve algorithms do not need this parameter. + + If the key size is not specified, some algorithms have pre-defined + defaults. For example, RSA keys for use as DNSSEC zone-signing keys + have a default size of 1024 bits; RSA keys for use as key-signing + keys (KSKs, generated with ``-f KSK``) default to 2048 bits. + +``-C`` + This option enables compatibility mode, which generates an old-style key, without any timing + metadata. By default, ``dnssec-keygen`` includes the key's + creation date in the metadata stored with the private key; other + dates may be set there as well, including publication date, activation date, + etc. Keys that include this data may be incompatible with older + versions of BIND; the ``-C`` option suppresses them. + +``-c class`` + This option indicates that the DNS record containing the key should have the + specified class. If not specified, class IN is used. + +``-d bits`` + This option specifies the key size in bits. For the algorithms RSASHA1, NSEC3RSASA1, RSASHA256, and + RSASHA512 the key size must be between 1024 and 4096 bits; DH size is between 128 + and 4096 bits. This option is ignored for algorithms ECDSAP256SHA256, + ECDSAP384SHA384, ED25519, and ED448. + +``-E engine`` + This option specifies the cryptographic hardware to use, when applicable. + + When BIND 9 is built with OpenSSL, this needs to be set to the OpenSSL + engine identifier that drives the cryptographic accelerator or + hardware service module (usually ``pkcs11``). When BIND is + built with native PKCS#11 cryptography (``--enable-native-pkcs11``), it + defaults to the path of the PKCS#11 provider library specified via + ``--with-pkcs11``. + +``-f flag`` + This option sets the specified flag in the flag field of the KEY/DNSKEY record. + The only recognized flags are KSK (Key-Signing Key) and REVOKE. + +``-G`` + This option generates a key, but does not publish it or sign with it. This option is + incompatible with ``-P`` and ``-A``. + +``-g generator`` + This option indicates the generator to use if generating a Diffie-Hellman key. Allowed + values are 2 and 5. If no generator is specified, a known prime from + :rfc:`2539` is used if possible; otherwise the default is 2. + +``-h`` + This option prints a short summary of the options and arguments to + ``dnssec-keygen``. + +``-K directory`` + This option sets the directory in which the key files are to be written. + +``-k policy`` + This option creates keys for a specific ``dnssec-policy``. If a policy uses multiple keys, + ``dnssec-keygen`` generates multiple keys. This also + creates a ".state" file to keep track of the key state. + + This option creates keys according to the ``dnssec-policy`` configuration, hence + it cannot be used at the same time as many of the other options that + ``dnssec-keygen`` provides. + +``-L ttl`` + This option sets the default TTL to use for this key when it is converted into a + DNSKEY RR. This is the TTL used when the key is imported into a zone, + unless there was already a DNSKEY RRset in + place, in which case the existing TTL takes precedence. If this + value is not set and there is no existing DNSKEY RRset, the TTL + defaults to the SOA TTL. Setting the default TTL to ``0`` or ``none`` + is the same as leaving it unset. + +``-l file`` + This option provides a configuration file that contains a ``dnssec-policy`` statement + (matching the policy set with ``-k``). + +``-n nametype`` + This option specifies the owner type of the key. The value of ``nametype`` must + either be ZONE (for a DNSSEC zone key (KEY/DNSKEY)), HOST or ENTITY + (for a key associated with a host (KEY)), USER (for a key associated + with a user (KEY)), or OTHER (DNSKEY). These values are + case-insensitive. The default is ZONE for DNSKEY generation. + +``-p protocol`` + This option sets the protocol value for the generated key, for use with + ``-T KEY``. The protocol is a number between 0 and 255. The default + is 3 (DNSSEC). Other possible values for this argument are listed in + :rfc:`2535` and its successors. + +``-q`` + This option sets quiet mode, which suppresses unnecessary output, including progress + indication. Without this option, when ``dnssec-keygen`` is run + interactively to generate an RSA or DSA key pair, it prints a + string of symbols to ``stderr`` indicating the progress of the key + generation. A ``.`` indicates that a random number has been found which + passed an initial sieve test; ``+`` means a number has passed a single + round of the Miller-Rabin primality test; and a space ( ) means that the + number has passed all the tests and is a satisfactory key. + +``-S key`` + This option creates a new key which is an explicit successor to an existing key. + The name, algorithm, size, and type of the key are set to match + the existing key. The activation date of the new key is set to + the inactivation date of the existing one. The publication date is + set to the activation date minus the prepublication interval, + which defaults to 30 days. + +``-s strength`` + This option specifies the strength value of the key. The strength is a number + between 0 and 15, and currently has no defined purpose in DNSSEC. + +``-T rrtype`` + This option specifies the resource record type to use for the key. ``rrtype`` + must be either DNSKEY or KEY. The default is DNSKEY when using a + DNSSEC algorithm, but it can be overridden to KEY for use with + SIG(0). + +``-t type`` + This option indicates the type of the key for use with ``-T KEY``. ``type`` + must be one of AUTHCONF, NOAUTHCONF, NOAUTH, or NOCONF. The default + is AUTHCONF. AUTH refers to the ability to authenticate data, and + CONF to the ability to encrypt data. + +``-V`` + This option prints version information. + +``-v level`` + This option sets the debugging level. + +Timing Options +~~~~~~~~~~~~~~ + +Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. If the +argument begins with a ``+`` or ``-``, it is interpreted as an offset from +the present time. For convenience, if such an offset is followed by one +of the suffixes ``y``, ``mo``, ``w``, ``d``, ``h``, or ``mi``, then the offset is +computed in years (defined as 365 24-hour days, ignoring leap years), +months (defined as 30 24-hour days), weeks, days, hours, or minutes, +respectively. Without a suffix, the offset is computed in seconds. To +explicitly prevent a date from being set, use ``none`` or ``never``. + +``-P date/offset`` + This option sets the date on which a key is to be published to the zone. After + that date, the key is included in the zone but is not used + to sign it. If not set, and if the ``-G`` option has not been used, the + default is the current date. + +``-P sync date/offset`` + This option sets the date on which CDS and CDNSKEY records that match this key + are to be published to the zone. + +``-A date/offset`` + This option sets the date on which the key is to be activated. After that date, + the key is included in the zone and used to sign it. If not set, + and if the ``-G`` option has not been used, the default is the current date. If set, + and ``-P`` is not set, the publication date is set to the + activation date minus the prepublication interval. + +``-R date/offset`` + This option sets the date on which the key is to be revoked. After that date, the + key is flagged as revoked. It is included in the zone and + is used to sign it. + +``-I date/offset`` + This option sets the date on which the key is to be retired. After that date, the + key is still included in the zone, but it is not used to + sign it. + +``-D date/offset`` + This option sets the date on which the key is to be deleted. After that date, the + key is no longer included in the zone. (However, it may remain in the key + repository.) + +``-D sync date/offset`` + This option sets the date on which the CDS and CDNSKEY records that match this + key are to be deleted. + +``-i interval`` + This option sets the prepublication interval for a key. If set, then the + publication and activation dates must be separated by at least this + much time. If the activation date is specified but the publication + date is not, the publication date defaults to this much time + before the activation date; conversely, if the publication date is + specified but not the activation date, activation is set to + this much time after publication. + + If the key is being created as an explicit successor to another key, + then the default prepublication interval is 30 days; otherwise it is + zero. + + As with date offsets, if the argument is followed by one of the + suffixes ``y``, ``mo``, ``w``, ``d``, ``h``, or ``mi``, the interval is + measured in years, months, weeks, days, hours, or minutes, + respectively. Without a suffix, the interval is measured in seconds. + +Generated Keys +~~~~~~~~~~~~~~ + +When ``dnssec-keygen`` completes successfully, it prints a string of the +form ``Knnnn.+aaa+iiiii`` to the standard output. This is an +identification string for the key it has generated. + +- ``nnnn`` is the key name. + +- ``aaa`` is the numeric representation of the algorithm. + +- ``iiiii`` is the key identifier (or footprint). + +``dnssec-keygen`` creates two files, with names based on the printed +string. ``Knnnn.+aaa+iiiii.key`` contains the public key, and +``Knnnn.+aaa+iiiii.private`` contains the private key. + +The ``.key`` file contains a DNSKEY or KEY record. When a zone is being +signed by ``named`` or ``dnssec-signzone -S``, DNSKEY records are +included automatically. In other cases, the ``.key`` file can be +inserted into a zone file manually or with an ``$INCLUDE`` statement. + +The ``.private`` file contains algorithm-specific fields. For obvious +security reasons, this file does not have general read permission. + +Example +~~~~~~~ + +To generate an ECDSAP256SHA256 zone-signing key for the zone +``example.com``, issue the command: + +``dnssec-keygen -a ECDSAP256SHA256 example.com`` + +The command prints a string of the form: + +``Kexample.com.+013+26160`` + +In this example, ``dnssec-keygen`` creates the files +``Kexample.com.+013+26160.key`` and ``Kexample.com.+013+26160.private``. + +To generate a matching key-signing key, issue the command: + +``dnssec-keygen -a ECDSAP256SHA256 -f KSK example.com`` + +See Also +~~~~~~~~ + +:manpage:`dnssec-signzone(8)`, BIND 9 Administrator Reference Manual, :rfc:`2539`, +:rfc:`2845`, :rfc:`4034`. diff --git a/bin/dnssec/dnssec-revoke.c b/bin/dnssec/dnssec-revoke.c new file mode 100644 index 0000000..c532463 --- /dev/null +++ b/bin/dnssec/dnssec-revoke.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include "dnssectool.h" + +const char *program = "dnssec-revoke"; + +static isc_mem_t *mctx = NULL; + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s [options] keyfile\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); +#if USE_PKCS11 + fprintf(stderr, + " -E engine: specify PKCS#11 provider " + "(default: %s)\n", + PK11_LIB_LOCATION); +#else /* if USE_PKCS11 */ + fprintf(stderr, " -E engine: specify OpenSSL engine\n"); +#endif /* if USE_PKCS11 */ + fprintf(stderr, " -f: force overwrite\n"); + fprintf(stderr, " -h: help\n"); + fprintf(stderr, " -K directory: use directory for key files\n"); + fprintf(stderr, " -r: remove old keyfiles after " + "creating revoked version\n"); + fprintf(stderr, " -v level: set level of verbosity\n"); + fprintf(stderr, " -V: print version information\n"); + fprintf(stderr, "Output:\n"); + fprintf(stderr, " K++.key, " + "K++.private\n"); + + exit(-1); +} + +int +main(int argc, char **argv) { + isc_result_t result; + const char *engine = NULL; + char const *filename = NULL; + char *dir = NULL; + char newname[1024], oldname[1024]; + char keystr[DST_KEY_FORMATSIZE]; + char *endp; + int ch; + dst_key_t *key = NULL; + uint32_t flags; + isc_buffer_t buf; + bool force = false; + bool removefile = false; + bool id = false; + + if (argc == 1) { + usage(); + } + + isc_mem_create(&mctx); + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + isc_commandline_errprint = false; + + while ((ch = isc_commandline_parse(argc, argv, "E:fK:rRhv:V")) != -1) { + switch (ch) { + case 'E': + engine = isc_commandline_argument; + break; + case 'f': + force = true; + break; + case 'K': + /* + * We don't have to copy it here, but do it to + * simplify cleanup later + */ + dir = isc_mem_strdup(mctx, isc_commandline_argument); + break; + case 'r': + removefile = true; + break; + case 'R': + id = true; + break; + case 'v': + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("-v must be followed by a number"); + } + break; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + } + FALLTHROUGH; + case 'h': + /* Does not return. */ + usage(); + + case 'V': + /* Does not return. */ + version(program); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + if (argc < isc_commandline_index + 1 || + argv[isc_commandline_index] == NULL) + { + fatal("The key file name was not specified"); + } + if (argc > isc_commandline_index + 1) { + fatal("Extraneous arguments"); + } + + if (dir != NULL) { + filename = argv[isc_commandline_index]; + } else { + result = isc_file_splitpath(mctx, argv[isc_commandline_index], + &dir, &filename); + if (result != ISC_R_SUCCESS) { + fatal("cannot process filename %s: %s", + argv[isc_commandline_index], + isc_result_totext(result)); + } + if (strcmp(dir, ".") == 0) { + isc_mem_free(mctx, dir); + dir = NULL; + } + } + + result = dst_lib_init(mctx, engine); + if (result != ISC_R_SUCCESS) { + fatal("Could not initialize dst: %s", + isc_result_totext(result)); + } + + result = dst_key_fromnamedfile( + filename, dir, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, mctx, &key); + if (result != ISC_R_SUCCESS) { + fatal("Invalid keyfile name %s: %s", filename, + isc_result_totext(result)); + } + + if (id) { + fprintf(stdout, "%u\n", dst_key_rid(key)); + goto cleanup; + } + dst_key_format(key, keystr, sizeof(keystr)); + + if (verbose > 2) { + fprintf(stderr, "%s: %s\n", program, keystr); + } + + if (force) { + set_keyversion(key); + } else { + check_keyversion(key, keystr); + } + + flags = dst_key_flags(key); + if ((flags & DNS_KEYFLAG_REVOKE) == 0) { + isc_stdtime_t now; + + if ((flags & DNS_KEYFLAG_KSK) == 0) { + fprintf(stderr, + "%s: warning: Key is not flagged " + "as a KSK. Revoking a ZSK is " + "legal, but undefined.\n", + program); + } + + isc_stdtime_get(&now); + dst_key_settime(key, DST_TIME_REVOKE, now); + + dst_key_setflags(key, flags | DNS_KEYFLAG_REVOKE); + + isc_buffer_init(&buf, newname, sizeof(newname)); + dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); + + if (access(newname, F_OK) == 0 && !force) { + fatal("Key file %s already exists; " + "use -f to force overwrite", + newname); + } + + result = dst_key_tofile(key, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, + dir); + if (result != ISC_R_SUCCESS) { + dst_key_format(key, keystr, sizeof(keystr)); + fatal("Failed to write key %s: %s", keystr, + isc_result_totext(result)); + } + + isc_buffer_clear(&buf); + dst_key_buildfilename(key, 0, dir, &buf); + printf("%s\n", newname); + + /* + * Remove old key file, if told to (and if + * it isn't the same as the new file) + */ + if (removefile) { + isc_buffer_init(&buf, oldname, sizeof(oldname)); + dst_key_setflags(key, flags & ~DNS_KEYFLAG_REVOKE); + dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); + if (strcmp(oldname, newname) == 0) { + goto cleanup; + } + (void)unlink(oldname); + isc_buffer_clear(&buf); + dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); + (void)unlink(oldname); + } + } else { + dst_key_format(key, keystr, sizeof(keystr)); + fatal("Key %s is already revoked", keystr); + } + +cleanup: + dst_key_free(&key); + dst_lib_destroy(); + if (verbose > 10) { + isc_mem_stats(mctx, stdout); + } + if (dir != NULL) { + isc_mem_free(mctx, dir); + } + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/dnssec/dnssec-revoke.rst b/bin/dnssec/dnssec-revoke.rst new file mode 100644 index 0000000..f664646 --- /dev/null +++ b/bin/dnssec/dnssec-revoke.rst @@ -0,0 +1,71 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-revoke: + +dnssec-revoke - set the REVOKED bit on a DNSSEC key +--------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`dnssec-revoke` [**-hr**] [**-v** level] [**-V**] [**-K** directory] [**-E** engine] [**-f**] [**-R**] {keyfile} + +Description +~~~~~~~~~~~ + +``dnssec-revoke`` reads a DNSSEC key file, sets the REVOKED bit on the +key as defined in :rfc:`5011`, and creates a new pair of key files +containing the now-revoked key. + +Options +~~~~~~~ + +``-h`` + This option emits a usage message and exits. + +``-K directory`` + This option sets the directory in which the key files are to reside. + +``-r`` + This option indicates to remove the original keyset files after writing the new keyset files. + +``-v level`` + This option sets the debugging level. + +``-V`` + This option prints version information. + +``-E engine`` + This option specifies the cryptographic hardware to use, when applicable. + + When BIND 9 is built with OpenSSL, this needs to be set to the OpenSSL + engine identifier that drives the cryptographic accelerator or + hardware service module (usually ``pkcs11``). When BIND is + built with native PKCS#11 cryptography (``--enable-native-pkcs11``), it + defaults to the path of the PKCS#11 provider library specified via + ``--with-pkcs11``. + +``-f`` + This option indicates a forced overwrite and causes ``dnssec-revoke`` to write the new key pair, + even if a file already exists matching the algorithm and key ID of + the revoked key. + +``-R`` + This option prints the key tag of the key with the REVOKE bit set, but does not + revoke the key. + +See Also +~~~~~~~~ + +:manpage:`dnssec-keygen(8)`, BIND 9 Administrator Reference Manual, :rfc:`5011`. diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c new file mode 100644 index 0000000..1df6af1 --- /dev/null +++ b/bin/dnssec/dnssec-settime.c @@ -0,0 +1,985 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include "dnssectool.h" + +const char *program = "dnssec-settime"; + +static isc_mem_t *mctx = NULL; + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s [options] keyfile\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "General options:\n"); +#if USE_PKCS11 + fprintf(stderr, + " -E engine: specify PKCS#11 provider " + "(default: %s)\n", + PK11_LIB_LOCATION); +#elif defined(USE_PKCS11) + fprintf(stderr, " -E engine: specify OpenSSL engine " + "(default \"pkcs11\")\n"); +#else /* if USE_PKCS11 */ + fprintf(stderr, " -E engine: specify OpenSSL engine\n"); +#endif /* if USE_PKCS11 */ + fprintf(stderr, " -f: force update of old-style " + "keys\n"); + fprintf(stderr, " -K directory: set key file location\n"); + fprintf(stderr, " -L ttl: set default key TTL\n"); + fprintf(stderr, " -v level: set level of verbosity\n"); + fprintf(stderr, " -V: print version information\n"); + fprintf(stderr, " -h: help\n"); + fprintf(stderr, "Timing options:\n"); + fprintf(stderr, " -P date/[+-]offset/none: set/unset key " + "publication date\n"); + fprintf(stderr, " -P ds date/[+-]offset/none: set/unset " + "DS publication date\n"); + fprintf(stderr, " -P sync date/[+-]offset/none: set/unset " + "CDS and CDNSKEY publication date\n"); + fprintf(stderr, " -A date/[+-]offset/none: set/unset key " + "activation date\n"); + fprintf(stderr, " -R date/[+-]offset/none: set/unset key " + "revocation date\n"); + fprintf(stderr, " -I date/[+-]offset/none: set/unset key " + "inactivation date\n"); + fprintf(stderr, " -D date/[+-]offset/none: set/unset key " + "deletion date\n"); + fprintf(stderr, " -D ds date/[+-]offset/none: set/unset " + "DS deletion date\n"); + fprintf(stderr, " -D sync date/[+-]offset/none: set/unset " + "CDS and CDNSKEY deletion date\n"); + fprintf(stderr, " -S : generate a successor to an existing " + "key\n"); + fprintf(stderr, " -i : prepublication interval for " + "successor key " + "(default: 30 days)\n"); + fprintf(stderr, "Key state options:\n"); + fprintf(stderr, " -s: update key state file (default no)\n"); + fprintf(stderr, " -g state: set the goal state for this key\n"); + fprintf(stderr, " -d state date/[+-]offset: set the DS state\n"); + fprintf(stderr, " -k state date/[+-]offset: set the DNSKEY state\n"); + fprintf(stderr, " -r state date/[+-]offset: set the RRSIG (KSK) " + "state\n"); + fprintf(stderr, " -z state date/[+-]offset: set the RRSIG (ZSK) " + "state\n"); + fprintf(stderr, "Printing options:\n"); + fprintf(stderr, " -p C/P/Psync/A/R/I/D/Dsync/all: print a " + "particular time value or values\n"); + fprintf(stderr, " -u: print times in unix epoch " + "format\n"); + fprintf(stderr, "Output:\n"); + fprintf(stderr, " K++.key, " + "K++.private\n"); + + exit(-1); +} + +static void +printtime(dst_key_t *key, int type, const char *tag, bool epoch, FILE *stream) { + isc_result_t result; + isc_stdtime_t when; + + if (tag != NULL) { + fprintf(stream, "%s: ", tag); + } + + result = dst_key_gettime(key, type, &when); + if (result == ISC_R_NOTFOUND) { + fprintf(stream, "UNSET\n"); + } else if (epoch) { + fprintf(stream, "%d\n", (int)when); + } else { + time_t now = when; + struct tm t, *tm = localtime_r(&now, &t); + unsigned int flen; + char timebuf[80]; + + if (tm == NULL) { + fprintf(stream, "INVALID\n"); + return; + } + + flen = strftime(timebuf, sizeof(timebuf), + "%a %b %e %H:%M:%S %Y", tm); + INSIST(flen > 0U && flen < sizeof(timebuf)); + fprintf(stream, "%s\n", timebuf); + } +} + +static void +writekey(dst_key_t *key, const char *directory, bool write_state) { + char newname[1024]; + char keystr[DST_KEY_FORMATSIZE]; + isc_buffer_t buf; + isc_result_t result; + int options = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE; + + if (write_state) { + options |= DST_TYPE_STATE; + } + + isc_buffer_init(&buf, newname, sizeof(newname)); + result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &buf); + if (result != ISC_R_SUCCESS) { + fatal("Failed to build public key filename: %s", + isc_result_totext(result)); + } + + result = dst_key_tofile(key, options, directory); + if (result != ISC_R_SUCCESS) { + dst_key_format(key, keystr, sizeof(keystr)); + fatal("Failed to write key %s: %s", keystr, + isc_result_totext(result)); + } + printf("%s\n", newname); + + isc_buffer_clear(&buf); + result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &buf); + if (result != ISC_R_SUCCESS) { + fatal("Failed to build private key filename: %s", + isc_result_totext(result)); + } + printf("%s\n", newname); + + if (write_state) { + isc_buffer_clear(&buf); + result = dst_key_buildfilename(key, DST_TYPE_STATE, directory, + &buf); + if (result != ISC_R_SUCCESS) { + fatal("Failed to build key state filename: %s", + isc_result_totext(result)); + } + printf("%s\n", newname); + } +} + +int +main(int argc, char **argv) { + isc_result_t result; + const char *engine = NULL; + const char *filename = NULL; + char *directory = NULL; + char keystr[DST_KEY_FORMATSIZE]; + char *endp, *p; + int ch; + const char *predecessor = NULL; + dst_key_t *prevkey = NULL; + dst_key_t *key = NULL; + dns_name_t *name = NULL; + dns_secalg_t alg = 0; + unsigned int size = 0; + uint16_t flags = 0; + int prepub = -1; + int options; + dns_ttl_t ttl = 0; + isc_stdtime_t now; + isc_stdtime_t dstime = 0, dnskeytime = 0; + isc_stdtime_t krrsigtime = 0, zrrsigtime = 0; + isc_stdtime_t pub = 0, act = 0, rev = 0, inact = 0, del = 0; + isc_stdtime_t prevact = 0, previnact = 0, prevdel = 0; + dst_key_state_t goal = DST_KEY_STATE_NA; + dst_key_state_t ds = DST_KEY_STATE_NA; + dst_key_state_t dnskey = DST_KEY_STATE_NA; + dst_key_state_t krrsig = DST_KEY_STATE_NA; + dst_key_state_t zrrsig = DST_KEY_STATE_NA; + bool setgoal = false, setds = false, setdnskey = false; + bool setkrrsig = false, setzrrsig = false; + bool setdstime = false, setdnskeytime = false; + bool setkrrsigtime = false, setzrrsigtime = false; + bool setpub = false, setact = false; + bool setrev = false, setinact = false; + bool setdel = false, setttl = false; + bool unsetpub = false, unsetact = false; + bool unsetrev = false, unsetinact = false; + bool unsetdel = false; + bool printcreate = false, printpub = false; + bool printact = false, printrev = false; + bool printinact = false, printdel = false; + bool force = false; + bool epoch = false; + bool changed = false; + bool write_state = false; + isc_log_t *log = NULL; + isc_stdtime_t syncadd = 0, syncdel = 0; + bool unsetsyncadd = false, setsyncadd = false; + bool unsetsyncdel = false, setsyncdel = false; + bool printsyncadd = false, printsyncdel = false; + isc_stdtime_t dsadd = 0, dsdel = 0; + bool unsetdsadd = false, setdsadd = false; + bool unsetdsdel = false, setdsdel = false; + bool printdsadd = false, printdsdel = false; + + options = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE; + + if (argc == 1) { + usage(); + } + + isc_mem_create(&mctx); + + setup_logging(mctx, &log); + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + isc_commandline_errprint = false; + + isc_stdtime_get(&now); + +#define CMDLINE_FLAGS "A:D:d:E:fg:hI:i:K:k:L:P:p:R:r:S:suv:Vz:" + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case 'A': + if (setact || unsetact) { + fatal("-A specified more than once"); + } + + changed = true; + act = strtotime(isc_commandline_argument, now, now, + &setact); + unsetact = !setact; + break; + case 'D': + /* -Dsync ? */ + if (isoptarg("sync", argv, usage)) { + if (unsetsyncdel || setsyncdel) { + fatal("-D sync specified more than " + "once"); + } + + changed = true; + syncdel = strtotime(isc_commandline_argument, + now, now, &setsyncdel); + unsetsyncdel = !setsyncdel; + break; + } + /* -Dds ? */ + if (isoptarg("ds", argv, usage)) { + if (unsetdsdel || setdsdel) { + fatal("-D ds specified more than once"); + } + + changed = true; + dsdel = strtotime(isc_commandline_argument, now, + now, &setdsdel); + unsetdsdel = !setdsdel; + break; + } + /* -Ddnskey ? */ + (void)isoptarg("dnskey", argv, usage); + if (setdel || unsetdel) { + fatal("-D specified more than once"); + } + + changed = true; + del = strtotime(isc_commandline_argument, now, now, + &setdel); + unsetdel = !setdel; + break; + case 'd': + if (setds) { + fatal("-d specified more than once"); + } + + ds = strtokeystate(isc_commandline_argument); + setds = true; + /* time */ + (void)isoptarg(isc_commandline_argument, argv, usage); + dstime = strtotime(isc_commandline_argument, now, now, + &setdstime); + break; + case 'E': + engine = isc_commandline_argument; + break; + case 'f': + force = true; + break; + case 'g': + if (setgoal) { + fatal("-g specified more than once"); + } + + goal = strtokeystate(isc_commandline_argument); + if (goal != DST_KEY_STATE_NA && + goal != DST_KEY_STATE_HIDDEN && + goal != DST_KEY_STATE_OMNIPRESENT) + { + fatal("-g must be either none, hidden, or " + "omnipresent"); + } + setgoal = true; + break; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + } + FALLTHROUGH; + case 'h': + /* Does not return. */ + usage(); + case 'I': + if (setinact || unsetinact) { + fatal("-I specified more than once"); + } + + changed = true; + inact = strtotime(isc_commandline_argument, now, now, + &setinact); + unsetinact = !setinact; + break; + case 'i': + prepub = strtottl(isc_commandline_argument); + break; + case 'K': + /* + * We don't have to copy it here, but do it to + * simplify cleanup later + */ + directory = isc_mem_strdup(mctx, + isc_commandline_argument); + break; + case 'k': + if (setdnskey) { + fatal("-k specified more than once"); + } + + dnskey = strtokeystate(isc_commandline_argument); + setdnskey = true; + /* time */ + (void)isoptarg(isc_commandline_argument, argv, usage); + dnskeytime = strtotime(isc_commandline_argument, now, + now, &setdnskeytime); + break; + case 'L': + ttl = strtottl(isc_commandline_argument); + setttl = true; + break; + case 'P': + /* -Psync ? */ + if (isoptarg("sync", argv, usage)) { + if (unsetsyncadd || setsyncadd) { + fatal("-P sync specified more than " + "once"); + } + + changed = true; + syncadd = strtotime(isc_commandline_argument, + now, now, &setsyncadd); + unsetsyncadd = !setsyncadd; + break; + } + /* -Pds ? */ + if (isoptarg("ds", argv, usage)) { + if (unsetdsadd || setdsadd) { + fatal("-P ds specified more than once"); + } + + changed = true; + dsadd = strtotime(isc_commandline_argument, now, + now, &setdsadd); + unsetdsadd = !setdsadd; + break; + } + /* -Pdnskey ? */ + (void)isoptarg("dnskey", argv, usage); + if (setpub || unsetpub) { + fatal("-P specified more than once"); + } + + changed = true; + pub = strtotime(isc_commandline_argument, now, now, + &setpub); + unsetpub = !setpub; + break; + case 'p': + p = isc_commandline_argument; + if (!strcasecmp(p, "all")) { + printcreate = true; + printpub = true; + printact = true; + printrev = true; + printinact = true; + printdel = true; + printsyncadd = true; + printsyncdel = true; + printdsadd = true; + printdsdel = true; + break; + } + + do { + switch (*p++) { + case 'A': + printact = true; + break; + case 'C': + printcreate = true; + break; + case 'D': + if (!strncmp(p, "sync", 4)) { + p += 4; + printsyncdel = true; + break; + } + if (!strncmp(p, "ds", 2)) { + p += 2; + printdsdel = true; + break; + } + printdel = true; + break; + case 'I': + printinact = true; + break; + case 'P': + if (!strncmp(p, "sync", 4)) { + p += 4; + printsyncadd = true; + break; + } + if (!strncmp(p, "ds", 2)) { + p += 2; + printdsadd = true; + break; + } + printpub = true; + break; + case 'R': + printrev = true; + break; + case ' ': + break; + default: + usage(); + break; + } + } while (*p != '\0'); + break; + case 'R': + if (setrev || unsetrev) { + fatal("-R specified more than once"); + } + + changed = true; + rev = strtotime(isc_commandline_argument, now, now, + &setrev); + unsetrev = !setrev; + break; + case 'r': + if (setkrrsig) { + fatal("-r specified more than once"); + } + + krrsig = strtokeystate(isc_commandline_argument); + setkrrsig = true; + /* time */ + (void)isoptarg(isc_commandline_argument, argv, usage); + krrsigtime = strtotime(isc_commandline_argument, now, + now, &setkrrsigtime); + break; + case 'S': + predecessor = isc_commandline_argument; + break; + case 's': + write_state = true; + break; + case 'u': + epoch = true; + break; + case 'V': + /* Does not return. */ + version(program); + case 'v': + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("-v must be followed by a number"); + } + break; + case 'z': + if (setzrrsig) { + fatal("-z specified more than once"); + } + + zrrsig = strtokeystate(isc_commandline_argument); + setzrrsig = true; + (void)isoptarg(isc_commandline_argument, argv, usage); + zrrsigtime = strtotime(isc_commandline_argument, now, + now, &setzrrsigtime); + break; + + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + if (argc < isc_commandline_index + 1 || + argv[isc_commandline_index] == NULL) + { + fatal("The key file name was not specified"); + } + if (argc > isc_commandline_index + 1) { + fatal("Extraneous arguments"); + } + + if ((setgoal || setds || setdnskey || setkrrsig || setzrrsig) && + !write_state) + { + fatal("Options -g, -d, -k, -r and -z require -s to be set"); + } + + result = dst_lib_init(mctx, engine); + if (result != ISC_R_SUCCESS) { + fatal("Could not initialize dst: %s", + isc_result_totext(result)); + } + + if (predecessor != NULL) { + int major, minor; + + if (prepub == -1) { + prepub = (30 * 86400); + } + + if (setpub || unsetpub) { + fatal("-S and -P cannot be used together"); + } + if (setact || unsetact) { + fatal("-S and -A cannot be used together"); + } + + result = dst_key_fromnamedfile(predecessor, directory, options, + mctx, &prevkey); + if (result != ISC_R_SUCCESS) { + fatal("Invalid keyfile %s: %s", filename, + isc_result_totext(result)); + } + if (!dst_key_isprivate(prevkey) && !dst_key_isexternal(prevkey)) + { + fatal("%s is not a private key", filename); + } + + name = dst_key_name(prevkey); + alg = dst_key_alg(prevkey); + size = dst_key_size(prevkey); + flags = dst_key_flags(prevkey); + + dst_key_format(prevkey, keystr, sizeof(keystr)); + dst_key_getprivateformat(prevkey, &major, &minor); + if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) { + fatal("Predecessor has incompatible format " + "version %d.%d\n\t", + major, minor); + } + + result = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &prevact); + if (result != ISC_R_SUCCESS) { + fatal("Predecessor has no activation date. " + "You must set one before\n\t" + "generating a successor."); + } + + result = dst_key_gettime(prevkey, DST_TIME_INACTIVE, + &previnact); + if (result != ISC_R_SUCCESS) { + fatal("Predecessor has no inactivation date. " + "You must set one before\n\t" + "generating a successor."); + } + + pub = previnact - prepub; + act = previnact; + + if ((previnact - prepub) < now && prepub != 0) { + fatal("Time until predecessor inactivation is\n\t" + "shorter than the prepublication interval. " + "Either change\n\t" + "predecessor inactivation date, or use the -i " + "option to set\n\t" + "a shorter prepublication interval."); + } + + result = dst_key_gettime(prevkey, DST_TIME_DELETE, &prevdel); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "%s: warning: Predecessor has no " + "removal date;\n\t" + "it will remain in the zone " + "indefinitely after rollover.\n", + program); + } else if (prevdel < previnact) { + fprintf(stderr, + "%s: warning: Predecessor is " + "scheduled to be deleted\n\t" + "before it is scheduled to be " + "inactive.\n", + program); + } + + changed = setpub = setact = true; + } else { + if (prepub < 0) { + prepub = 0; + } + + if (prepub > 0) { + if (setpub && setact && (act - prepub) < pub) { + fatal("Activation and publication dates " + "are closer together than the\n\t" + "prepublication interval."); + } + + if (setpub && !setact) { + setact = true; + act = pub + prepub; + } else if (setact && !setpub) { + setpub = true; + pub = act - prepub; + } + + if ((act - prepub) < now) { + fatal("Time until activation is shorter " + "than the\n\tprepublication interval."); + } + } + } + + if (directory != NULL) { + filename = argv[isc_commandline_index]; + } else { + result = isc_file_splitpath(mctx, argv[isc_commandline_index], + &directory, &filename); + if (result != ISC_R_SUCCESS) { + fatal("cannot process filename %s: %s", + argv[isc_commandline_index], + isc_result_totext(result)); + } + } + + result = dst_key_fromnamedfile(filename, directory, options, mctx, + &key); + if (result != ISC_R_SUCCESS) { + fatal("Invalid keyfile %s: %s", filename, + isc_result_totext(result)); + } + + if (!dst_key_isprivate(key) && !dst_key_isexternal(key)) { + fatal("%s is not a private key", filename); + } + + dst_key_format(key, keystr, sizeof(keystr)); + + if (predecessor != NULL) { + if (!dns_name_equal(name, dst_key_name(key))) { + fatal("Key name mismatch"); + } + if (alg != dst_key_alg(key)) { + fatal("Key algorithm mismatch"); + } + if (size != dst_key_size(key)) { + fatal("Key size mismatch"); + } + if (flags != dst_key_flags(key)) { + fatal("Key flags mismatch"); + } + } + + prevdel = previnact = 0; + if ((setdel && setinact && del < inact) || + (dst_key_gettime(key, DST_TIME_INACTIVE, &previnact) == + ISC_R_SUCCESS && + setdel && !setinact && !unsetinact && del < previnact) || + (dst_key_gettime(key, DST_TIME_DELETE, &prevdel) == ISC_R_SUCCESS && + setinact && !setdel && !unsetdel && prevdel < inact) || + (!setdel && !unsetdel && !setinact && !unsetinact && prevdel != 0 && + prevdel < previnact)) + { + fprintf(stderr, + "%s: warning: Key is scheduled to " + "be deleted before it is\n\t" + "scheduled to be inactive.\n", + program); + } + + if (force) { + set_keyversion(key); + } else { + check_keyversion(key, keystr); + } + + if (verbose > 2) { + fprintf(stderr, "%s: %s\n", program, keystr); + } + + /* + * Set time values. + */ + if (setpub) { + dst_key_settime(key, DST_TIME_PUBLISH, pub); + } else if (unsetpub) { + dst_key_unsettime(key, DST_TIME_PUBLISH); + } + + if (setact) { + dst_key_settime(key, DST_TIME_ACTIVATE, act); + } else if (unsetact) { + dst_key_unsettime(key, DST_TIME_ACTIVATE); + } + + if (setrev) { + if ((dst_key_flags(key) & DNS_KEYFLAG_REVOKE) != 0) { + fprintf(stderr, + "%s: warning: Key %s is already " + "revoked; changing the revocation date " + "will not affect this.\n", + program, keystr); + } + if ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0) { + fprintf(stderr, + "%s: warning: Key %s is not flagged as " + "a KSK, but -R was used. Revoking a " + "ZSK is legal, but undefined.\n", + program, keystr); + } + dst_key_settime(key, DST_TIME_REVOKE, rev); + } else if (unsetrev) { + if ((dst_key_flags(key) & DNS_KEYFLAG_REVOKE) != 0) { + fprintf(stderr, + "%s: warning: Key %s is already " + "revoked; removing the revocation date " + "will not affect this.\n", + program, keystr); + } + dst_key_unsettime(key, DST_TIME_REVOKE); + } + + if (setinact) { + dst_key_settime(key, DST_TIME_INACTIVE, inact); + } else if (unsetinact) { + dst_key_unsettime(key, DST_TIME_INACTIVE); + } + + if (setdel) { + dst_key_settime(key, DST_TIME_DELETE, del); + } else if (unsetdel) { + dst_key_unsettime(key, DST_TIME_DELETE); + } + + if (setsyncadd) { + dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncadd); + } else if (unsetsyncadd) { + dst_key_unsettime(key, DST_TIME_SYNCPUBLISH); + } + + if (setsyncdel) { + dst_key_settime(key, DST_TIME_SYNCDELETE, syncdel); + } else if (unsetsyncdel) { + dst_key_unsettime(key, DST_TIME_SYNCDELETE); + } + + if (setdsadd) { + dst_key_settime(key, DST_TIME_DSPUBLISH, dsadd); + } else if (unsetdsadd) { + dst_key_unsettime(key, DST_TIME_DSPUBLISH); + } + + if (setdsdel) { + dst_key_settime(key, DST_TIME_DSDELETE, dsdel); + } else if (unsetdsdel) { + dst_key_unsettime(key, DST_TIME_DSDELETE); + } + + if (setttl) { + dst_key_setttl(key, ttl); + } + + if (predecessor != NULL && prevkey != NULL) { + dst_key_setnum(prevkey, DST_NUM_SUCCESSOR, dst_key_id(key)); + dst_key_setnum(key, DST_NUM_PREDECESSOR, dst_key_id(prevkey)); + } + + /* + * No metadata changes were made but we're forcing an upgrade + * to the new format anyway: use "-P now -A now" as the default + */ + if (force && !changed) { + dst_key_settime(key, DST_TIME_PUBLISH, now); + dst_key_settime(key, DST_TIME_ACTIVATE, now); + changed = true; + } + + /* + * Make sure the key state goals are written. + */ + if (write_state) { + if (setgoal) { + if (goal == DST_KEY_STATE_NA) { + dst_key_unsetstate(key, DST_KEY_GOAL); + } else { + dst_key_setstate(key, DST_KEY_GOAL, goal); + } + changed = true; + } + if (setds) { + if (ds == DST_KEY_STATE_NA) { + dst_key_unsetstate(key, DST_KEY_DS); + dst_key_unsettime(key, DST_TIME_DS); + } else { + dst_key_setstate(key, DST_KEY_DS, ds); + dst_key_settime(key, DST_TIME_DS, dstime); + } + changed = true; + } + if (setdnskey) { + if (dnskey == DST_KEY_STATE_NA) { + dst_key_unsetstate(key, DST_KEY_DNSKEY); + dst_key_unsettime(key, DST_TIME_DNSKEY); + } else { + dst_key_setstate(key, DST_KEY_DNSKEY, dnskey); + dst_key_settime(key, DST_TIME_DNSKEY, + dnskeytime); + } + changed = true; + } + if (setkrrsig) { + if (krrsig == DST_KEY_STATE_NA) { + dst_key_unsetstate(key, DST_KEY_KRRSIG); + dst_key_unsettime(key, DST_TIME_KRRSIG); + } else { + dst_key_setstate(key, DST_KEY_KRRSIG, krrsig); + dst_key_settime(key, DST_TIME_KRRSIG, + krrsigtime); + } + changed = true; + } + if (setzrrsig) { + if (zrrsig == DST_KEY_STATE_NA) { + dst_key_unsetstate(key, DST_KEY_ZRRSIG); + dst_key_unsettime(key, DST_TIME_ZRRSIG); + } else { + dst_key_setstate(key, DST_KEY_ZRRSIG, zrrsig); + dst_key_settime(key, DST_TIME_ZRRSIG, + zrrsigtime); + } + changed = true; + } + } + + if (!changed && setttl) { + changed = true; + } + + /* + * Print out time values, if -p was used. + */ + if (printcreate) { + printtime(key, DST_TIME_CREATED, "Created", epoch, stdout); + } + + if (printpub) { + printtime(key, DST_TIME_PUBLISH, "Publish", epoch, stdout); + } + + if (printact) { + printtime(key, DST_TIME_ACTIVATE, "Activate", epoch, stdout); + } + + if (printrev) { + printtime(key, DST_TIME_REVOKE, "Revoke", epoch, stdout); + } + + if (printinact) { + printtime(key, DST_TIME_INACTIVE, "Inactive", epoch, stdout); + } + + if (printdel) { + printtime(key, DST_TIME_DELETE, "Delete", epoch, stdout); + } + + if (printsyncadd) { + printtime(key, DST_TIME_SYNCPUBLISH, "SYNC Publish", epoch, + stdout); + } + + if (printsyncdel) { + printtime(key, DST_TIME_SYNCDELETE, "SYNC Delete", epoch, + stdout); + } + + if (printdsadd) { + printtime(key, DST_TIME_DSPUBLISH, "DS Publish", epoch, stdout); + } + + if (printdsdel) { + printtime(key, DST_TIME_DSDELETE, "DS Delete", epoch, stdout); + } + + if (changed) { + writekey(key, directory, write_state); + if (predecessor != NULL && prevkey != NULL) { + writekey(prevkey, directory, write_state); + } + } + + if (prevkey != NULL) { + dst_key_free(&prevkey); + } + dst_key_free(&key); + dst_lib_destroy(); + if (verbose > 10) { + isc_mem_stats(mctx, stdout); + } + cleanup_logging(&log); + isc_mem_free(mctx, directory); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/dnssec/dnssec-settime.rst b/bin/dnssec/dnssec-settime.rst new file mode 100644 index 0000000..9f6c428 --- /dev/null +++ b/bin/dnssec/dnssec-settime.rst @@ -0,0 +1,231 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-settime: + +dnssec-settime: set the key timing metadata for a DNSSEC key +------------------------------------------------------------ + +Synopsis +~~~~~~~~ + +:program:`dnssec-settime` [**-f**] [**-K** directory] [**-L** ttl] [**-P** date/offset] [**-P** ds date/offset] [**-P** sync date/offset] [**-A** date/offset] [**-R** date/offset] [**-I** date/offset] [**-D** date/offset] [**-D** ds date/offset] [**-D** sync date/offset] [**-S** key] [**-i** interval] [**-h**] [**-V**] [**-v** level] [**-E** engine] {keyfile} [**-s**] [**-g** state] [**-d** state date/offset] [**-k** state date/offset] [**-r** state date/offset] [**-z** state date/offset] + +Description +~~~~~~~~~~~ + +``dnssec-settime`` reads a DNSSEC private key file and sets the key +timing metadata as specified by the ``-P``, ``-A``, ``-R``, ``-I``, and +``-D`` options. The metadata can then be used by ``dnssec-signzone`` or +other signing software to determine when a key is to be published, +whether it should be used for signing a zone, etc. + +If none of these options is set on the command line, +``dnssec-settime`` simply prints the key timing metadata already stored +in the key. + +When key metadata fields are changed, both files of a key pair +(``Knnnn.+aaa+iiiii.key`` and ``Knnnn.+aaa+iiiii.private``) are +regenerated. + +Metadata fields are stored in the private file. A +human-readable description of the metadata is also placed in comments in +the key file. The private file's permissions are always set to be +inaccessible to anyone other than the owner (mode 0600). + +When working with state files, it is possible to update the timing metadata in +those files as well with ``-s``. With this option, it is also possible to update key +states with ``-d`` (DS), ``-k`` (DNSKEY), ``-r`` (RRSIG of KSK), or ``-z`` +(RRSIG of ZSK). Allowed states are HIDDEN, RUMOURED, OMNIPRESENT, and +UNRETENTIVE. + +The goal state of the key can also be set with ``-g``. This should be either +HIDDEN or OMNIPRESENT, representing whether the key should be removed from the +zone or published. + +It is NOT RECOMMENDED to manipulate state files manually, except for testing +purposes. + +Options +~~~~~~~ + +``-f`` + This option forces an update of an old-format key with no metadata fields. Without + this option, ``dnssec-settime`` fails when attempting to update a + legacy key. With this option, the key is recreated in the new + format, but with the original key data retained. The key's creation + date is set to the present time. If no other values are + specified, then the key's publication and activation dates are also + set to the present time. + +``-K directory`` + This option sets the directory in which the key files are to reside. + +``-L ttl`` + This option sets the default TTL to use for this key when it is converted into a + DNSKEY RR. This is the TTL used when the key is imported into a zone, + unless there was already a DNSKEY RRset in + place, in which case the existing TTL takes precedence. If this + value is not set and there is no existing DNSKEY RRset, the TTL + defaults to the SOA TTL. Setting the default TTL to ``0`` or ``none`` + removes it from the key. + +``-h`` + This option emits a usage message and exits. + +``-V`` + This option prints version information. + +``-v level`` + This option sets the debugging level. + +``-E engine`` + This option specifies the cryptographic hardware to use, when applicable. + + When BIND 9 is built with OpenSSL, this needs to be set to the OpenSSL + engine identifier that drives the cryptographic accelerator or + hardware service module (usually ``pkcs11``). When BIND is + built with native PKCS#11 cryptography (``--enable-native-pkcs11``), it + defaults to the path of the PKCS#11 provider library specified via + ``--with-pkcs11``. + +Timing Options +~~~~~~~~~~~~~~ + +Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. If the +argument begins with a ``+`` or ``-``, it is interpreted as an offset from +the present time. For convenience, if such an offset is followed by one +of the suffixes ``y``, ``mo``, ``w``, ``d``, ``h``, or ``mi``, then the offset is +computed in years (defined as 365 24-hour days, ignoring leap years), +months (defined as 30 24-hour days), weeks, days, hours, or minutes, +respectively. Without a suffix, the offset is computed in seconds. To +explicitly prevent a date from being set, use ``none`` or ``never``. + +``-P date/offset`` + This option sets the date on which a key is to be published to the zone. After + that date, the key is included in the zone but is not used + to sign it. + +``-P ds date/offset`` + This option Sets the date on which DS records that match this key have been + seen in the parent zone. + +``-P sync date/offset`` + This option sets the date on which CDS and CDNSKEY records that match this key + are to be published to the zone. + +``-A date/offset`` + This option sets the date on which the key is to be activated. After that date, + the key is included in the zone and used to sign it. + +``-R date/offset`` + This option sets the date on which the key is to be revoked. After that date, the + key is flagged as revoked. It is included in the zone and + is used to sign it. + +``-I date/offset`` + This option sets the date on which the key is to be retired. After that date, the + key is still included in the zone, but it is not used to + sign it. + +``-D date/offset`` + This option sets the date on which the key is to be deleted. After that date, the + key is no longer included in the zone. (However, it may remain in the key + repository.) + +``-D ds date/offset`` + This option sets the date on which the DS records that match this key have + been seen removed from the parent zone. + +``-D sync date/offset`` + This option sets the date on which the CDS and CDNSKEY records that match this + key are to be deleted. + +``-S predecessor key`` + This option selects a key for which the key being modified is an explicit + successor. The name, algorithm, size, and type of the predecessor key + must exactly match those of the key being modified. The activation + date of the successor key is set to the inactivation date of the + predecessor. The publication date is set to the activation date + minus the prepublication interval, which defaults to 30 days. + +``-i interval`` + This option sets the prepublication interval for a key. If set, then the + publication and activation dates must be separated by at least this + much time. If the activation date is specified but the publication + date is not, the publication date defaults to this much time + before the activation date; conversely, if the publication date is + specified but not the activation date, activation is set to + this much time after publication. + + If the key is being created as an explicit successor to another key, + then the default prepublication interval is 30 days; otherwise it is + zero. + + As with date offsets, if the argument is followed by one of the + suffixes ``y``, ``mo``, ``w``, ``d``, ``h``, or ``mi``, the interval is + measured in years, months, weeks, days, hours, or minutes, + respectively. Without a suffix, the interval is measured in seconds. + +Key State Options +~~~~~~~~~~~~~~~~~ + +To test dnssec-policy it may be necessary to construct keys with artificial +state information; these options are used by the testing framework for that +purpose, but should never be used in production. + +Known key states are HIDDEN, RUMOURED, OMNIPRESENT, and UNRETENTIVE. + +``-s`` + This option indicates that when setting key timing data, the state file should also be updated. + +``-g state`` + This option sets the goal state for this key. Must be HIDDEN or OMNIPRESENT. + +``-d state date/offset`` + This option sets the DS state for this key as of the specified date, offset from the current date. + +``-k state date/offset`` + This option sets the DNSKEY state for this key as of the specified date, offset from the current date. + +``-r state date/offset`` + This option sets the RRSIG (KSK) state for this key as of the specified date, offset from the current date. + +``-z state date/offset`` + This option sets the RRSIG (ZSK) state for this key as of the specified date, offset from the current date. + +Printing Options +~~~~~~~~~~~~~~~~ + +``dnssec-settime`` can also be used to print the timing metadata +associated with a key. + +``-u`` + This option indicates that times should be printed in Unix epoch format. + +``-p C/P/Pds/Psync/A/R/I/D/Dds/Dsync/all`` + This option prints a specific metadata value or set of metadata values. + The ``-p`` option may be followed by one or more of the following letters or + strings to indicate which value or values to print: ``C`` for the + creation date, ``P`` for the publication date, ``Pds` for the DS publication + date, ``Psync`` for the CDS and CDNSKEY publication date, ``A`` for the + activation date, ``R`` for the revocation date, ``I`` for the inactivation + date, ``D`` for the deletion date, ``Dds`` for the DS deletion date, + and ``Dsync`` for the CDS and CDNSKEY deletion date. To print all of the + metadata, use ``all``. + +See Also +~~~~~~~~ + +:manpage:`dnssec-keygen(8)`, :manpage:`dnssec-signzone(8)`, BIND 9 Administrator Reference Manual, +:rfc:`5011`. diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c new file mode 100644 index 0000000..2d2c158 --- /dev/null +++ b/bin/dnssec/dnssec-signzone.c @@ -0,0 +1,4197 @@ +/* + * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + * + * Portions Copyright (C) Network Associates, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/*! \file */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include "dnssectool.h" + +const char *program = "dnssec-signzone"; + +typedef struct hashlist hashlist_t; + +static int nsec_datatype = dns_rdatatype_nsec; + +#define check_dns_dbiterator_current(result) \ + check_result((result == DNS_R_NEWORIGIN) ? ISC_R_SUCCESS : result, \ + "dns_dbiterator_current()") + +#define IS_NSEC3 (nsec_datatype == dns_rdatatype_nsec3) +#define OPTOUT(x) (((x)&DNS_NSEC3FLAG_OPTOUT) != 0) + +#define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0) + +#define BUFSIZE 2048 +#define MAXDSKEYS 8 + +#define SIGNER_EVENTCLASS ISC_EVENTCLASS(0x4453) +#define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0) +#define SIGNER_EVENT_WORK (SIGNER_EVENTCLASS + 1) + +#define SOA_SERIAL_KEEP 0 +#define SOA_SERIAL_INCREMENT 1 +#define SOA_SERIAL_UNIXTIME 2 +#define SOA_SERIAL_DATE 3 + +typedef struct signer_event sevent_t; +struct signer_event { + ISC_EVENT_COMMON(sevent_t); + dns_fixedname_t *fname; + dns_dbnode_t *node; +}; + +static dns_dnsseckeylist_t keylist; +static unsigned int keycount = 0; +static isc_rwlock_t keylist_lock; +static isc_stdtime_t starttime = 0, endtime = 0, dnskey_endtime = 0, now; +static int cycle = -1; +static int jitter = 0; +static bool tryverify = false; +static bool printstats = false; +static isc_mem_t *mctx = NULL; +static dns_ttl_t zone_soa_min_ttl; +static dns_ttl_t soa_ttl; +static FILE *outfp = NULL; +static char *tempfile = NULL; +static const dns_master_style_t *masterstyle; +static dns_masterformat_t inputformat = dns_masterformat_text; +static dns_masterformat_t outputformat = dns_masterformat_text; +static uint32_t rawversion = 1, serialnum = 0; +static bool snset = false; +static unsigned int nsigned = 0, nretained = 0, ndropped = 0; +static unsigned int nverified = 0, nverifyfailed = 0; +static const char *directory = NULL, *dsdir = NULL; +static isc_mutex_t namelock, statslock; +static isc_nm_t *netmgr = NULL; +static isc_taskmgr_t *taskmgr = NULL; +static dns_db_t *gdb; /* The database */ +static dns_dbversion_t *gversion; /* The database version */ +static dns_dbiterator_t *gdbiter; /* The database iterator */ +static dns_rdataclass_t gclass; /* The class */ +static dns_name_t *gorigin; /* The database origin */ +static int nsec3flags = 0; +static dns_iterations_t nsec3iter = 10U; +static unsigned char saltbuf[255]; +static unsigned char *gsalt = saltbuf; +static size_t salt_length = 0; +static isc_task_t *master = NULL; +static unsigned int ntasks = 0; +static atomic_bool shuttingdown; +static atomic_bool finished; +static bool nokeys = false; +static bool removefile = false; +static bool generateds = false; +static bool ignore_kskflag = false; +static bool keyset_kskonly = false; +static dns_master_style_t *dsstyle = NULL; +static unsigned int serialformat = SOA_SERIAL_KEEP; +static unsigned int hash_length = 0; +static bool unknownalg = false; +static bool disable_zone_check = false; +static bool update_chain = false; +static bool set_keyttl = false; +static dns_ttl_t keyttl; +static bool smartsign = false; +static bool remove_orphansigs = false; +static bool remove_inactkeysigs = false; +static bool output_dnssec_only = false; +static bool output_stdout = false; +static bool set_maxttl = false; +static dns_ttl_t maxttl = 0; +static bool no_max_check = false; + +#define INCSTAT(counter) \ + if (printstats) { \ + LOCK(&statslock); \ + counter++; \ + UNLOCK(&statslock); \ + } + +static void +sign(isc_task_t *task, isc_event_t *event); + +/*% + * Store a copy of 'name' in 'fzonecut' and return a pointer to that copy. + */ +static dns_name_t * +savezonecut(dns_fixedname_t *fzonecut, dns_name_t *name) { + dns_name_t *result; + + result = dns_fixedname_initname(fzonecut); + dns_name_copynf(name, result); + + return (result); +} + +static void +dumpnode(dns_name_t *name, dns_dbnode_t *node) { + dns_rdataset_t rds; + dns_rdatasetiter_t *iter = NULL; + isc_buffer_t *buffer = NULL; + isc_region_t r; + isc_result_t result; + unsigned bufsize = 4096; + + if (outputformat != dns_masterformat_text) { + return; + } + + if (!output_dnssec_only) { + result = dns_master_dumpnodetostream(mctx, gdb, gversion, node, + name, masterstyle, outfp); + check_result(result, "dns_master_dumpnodetostream"); + return; + } + + result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &iter); + check_result(result, "dns_db_allrdatasets"); + + dns_rdataset_init(&rds); + + isc_buffer_allocate(mctx, &buffer, bufsize); + + for (result = dns_rdatasetiter_first(iter); result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iter)) + { + dns_rdatasetiter_current(iter, &rds); + + if (rds.type != dns_rdatatype_rrsig && + rds.type != dns_rdatatype_nsec && + rds.type != dns_rdatatype_nsec3 && + rds.type != dns_rdatatype_nsec3param && + (!smartsign || rds.type != dns_rdatatype_dnskey)) + { + dns_rdataset_disassociate(&rds); + continue; + } + + for (;;) { + result = dns_master_rdatasettotext( + name, &rds, masterstyle, NULL, buffer); + if (result != ISC_R_NOSPACE) { + break; + } + + bufsize <<= 1; + isc_buffer_free(&buffer); + isc_buffer_allocate(mctx, &buffer, bufsize); + } + check_result(result, "dns_master_rdatasettotext"); + + isc_buffer_usedregion(buffer, &r); + result = isc_stdio_write(r.base, 1, r.length, outfp, NULL); + check_result(result, "isc_stdio_write"); + isc_buffer_clear(buffer); + + dns_rdataset_disassociate(&rds); + } + + isc_buffer_free(&buffer); + dns_rdatasetiter_destroy(&iter); +} + +/*% + * Sign the given RRset with given key, and add the signature record to the + * given tuple. + */ +static void +signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key, + dns_ttl_t ttl, dns_diff_t *add, const char *logmsg) { + isc_result_t result; + isc_stdtime_t jendtime, expiry; + char keystr[DST_KEY_FORMATSIZE]; + dns_rdata_t trdata = DNS_RDATA_INIT; + unsigned char array[BUFSIZE]; + isc_buffer_t b; + dns_difftuple_t *tuple; + + dst_key_format(key, keystr, sizeof(keystr)); + vbprintf(1, "\t%s %s\n", logmsg, keystr); + + if (rdataset->type == dns_rdatatype_dnskey) { + expiry = dnskey_endtime; + } else { + expiry = endtime; + } + + jendtime = (jitter != 0) ? expiry - isc_random_uniform(jitter) : expiry; + isc_buffer_init(&b, array, sizeof(array)); + result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime, + mctx, &b, &trdata); + if (result != ISC_R_SUCCESS) { + fatal("dnskey '%s' failed to sign data: %s", keystr, + isc_result_totext(result)); + } + INCSTAT(nsigned); + + if (tryverify) { + result = dns_dnssec_verify(name, rdataset, key, true, 0, mctx, + &trdata, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) { + vbprintf(3, "\tsignature verified\n"); + INCSTAT(nverified); + } else { + vbprintf(3, "\tsignature failed to verify\n"); + INCSTAT(nverifyfailed); + } + } + + tuple = NULL; + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name, ttl, + &trdata, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(add, &tuple); +} + +static bool +issigningkey(dns_dnsseckey_t *key) { + return (key->force_sign || key->hint_sign); +} + +static bool +ispublishedkey(dns_dnsseckey_t *key) { + return ((key->force_publish || key->hint_publish) && !key->hint_remove); +} + +static bool +iszonekey(dns_dnsseckey_t *key) { + return (dns_name_equal(dst_key_name(key->key), gorigin) && + dst_key_iszonekey(key->key)); +} + +static bool +isksk(dns_dnsseckey_t *key) { + return (key->ksk); +} + +static bool +iszsk(dns_dnsseckey_t *key) { + return (ignore_kskflag || !key->ksk); +} + +/*% + * Find the key that generated an RRSIG, if it is in the key list. If + * so, return a pointer to it, otherwise return NULL. + * + * No locking is performed here, this must be done by the caller. + */ +static dns_dnsseckey_t * +keythatsigned_unlocked(dns_rdata_rrsig_t *rrsig) { + dns_dnsseckey_t *key; + + for (key = ISC_LIST_HEAD(keylist); key != NULL; + key = ISC_LIST_NEXT(key, link)) + { + if (rrsig->keyid == dst_key_id(key->key) && + rrsig->algorithm == dst_key_alg(key->key) && + dns_name_equal(&rrsig->signer, dst_key_name(key->key))) + { + return (key); + } + } + return (NULL); +} + +/*% + * Finds the key that generated a RRSIG, if possible. First look at the keys + * that we've loaded already, and then see if there's a key on disk. + */ +static dns_dnsseckey_t * +keythatsigned(dns_rdata_rrsig_t *rrsig) { + isc_result_t result; + dst_key_t *pubkey = NULL, *privkey = NULL; + dns_dnsseckey_t *key = NULL; + + RWLOCK(&keylist_lock, isc_rwlocktype_read); + key = keythatsigned_unlocked(rrsig); + RWUNLOCK(&keylist_lock, isc_rwlocktype_read); + if (key != NULL) { + return (key); + } + + /* + * We did not find the key in our list. Get a write lock now, since + * we may be modifying the bits. We could do the tryupgrade() dance, + * but instead just get a write lock and check once again to see if + * it is on our list. It's possible someone else may have added it + * after all. + */ + isc_rwlock_lock(&keylist_lock, isc_rwlocktype_write); + key = keythatsigned_unlocked(rrsig); + if (key != NULL) { + isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write); + return (key); + } + + result = dst_key_fromfile(&rrsig->signer, rrsig->keyid, + rrsig->algorithm, DST_TYPE_PUBLIC, directory, + mctx, &pubkey); + if (result != ISC_R_SUCCESS) { + isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write); + return (NULL); + } + + result = dst_key_fromfile( + &rrsig->signer, rrsig->keyid, rrsig->algorithm, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, directory, mctx, &privkey); + if (result == ISC_R_SUCCESS) { + dst_key_free(&pubkey); + result = dns_dnsseckey_create(mctx, &privkey, &key); + } else { + result = dns_dnsseckey_create(mctx, &pubkey, &key); + } + + if (result == ISC_R_SUCCESS) { + key->force_publish = false; + key->force_sign = false; + key->index = keycount++; + ISC_LIST_APPEND(keylist, key, link); + } + + isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write); + return (key); +} + +/*% + * Check to see if we expect to find a key at this name. If we see a RRSIG + * and can't find the signing key that we expect to find, we drop the rrsig. + * I'm not sure if this is completely correct, but it seems to work. + */ +static bool +expecttofindkey(dns_name_t *name) { + unsigned int options = DNS_DBFIND_NOWILD; + dns_fixedname_t fname; + isc_result_t result; + char namestr[DNS_NAME_FORMATSIZE]; + + dns_fixedname_init(&fname); + result = dns_db_find(gdb, name, gversion, dns_rdatatype_dnskey, options, + 0, NULL, dns_fixedname_name(&fname), NULL, NULL); + switch (result) { + case ISC_R_SUCCESS: + case DNS_R_NXDOMAIN: + case DNS_R_NXRRSET: + return (true); + case DNS_R_DELEGATION: + case DNS_R_CNAME: + case DNS_R_DNAME: + return (false); + } + dns_name_format(name, namestr, sizeof(namestr)); + fatal("failure looking for '%s DNSKEY' in database: %s", namestr, + isc_result_totext(result)); + UNREACHABLE(); + return (false); /* removes a warning */ +} + +static bool +setverifies(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + dns_rdata_t *rrsig) { + isc_result_t result; + result = dns_dnssec_verify(name, set, key, false, 0, mctx, rrsig, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) { + INCSTAT(nverified); + return (true); + } else { + INCSTAT(nverifyfailed); + return (false); + } +} + +/*% + * Signs a set. Goes through contortions to decide if each RRSIG should + * be dropped or retained, and then determines if any new SIGs need to + * be generated. + */ +static void +signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, + dns_rdataset_t *set) { + dns_rdataset_t sigset; + dns_rdata_t sigrdata = DNS_RDATA_INIT; + dns_rdata_rrsig_t rrsig; + dns_dnsseckey_t *key; + isc_result_t result; + bool nosigs = false; + bool *wassignedby, *nowsignedby; + int arraysize; + dns_difftuple_t *tuple; + dns_ttl_t ttl; + int i; + char namestr[DNS_NAME_FORMATSIZE]; + char typestr[DNS_RDATATYPE_FORMATSIZE]; + char sigstr[SIG_FORMATSIZE]; + + dns_name_format(name, namestr, sizeof(namestr)); + dns_rdatatype_format(set->type, typestr, sizeof(typestr)); + + ttl = ISC_MIN(set->ttl, endtime - starttime); + + dns_rdataset_init(&sigset); + result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_rrsig, + set->type, 0, &sigset, NULL); + if (result == ISC_R_NOTFOUND) { + vbprintf(2, "no existing signatures for %s/%s\n", namestr, + typestr); + result = ISC_R_SUCCESS; + nosigs = true; + } + if (result != ISC_R_SUCCESS) { + fatal("failed while looking for '%s RRSIG %s': %s", namestr, + typestr, isc_result_totext(result)); + } + + vbprintf(1, "%s/%s:\n", namestr, typestr); + + arraysize = keycount; + if (!nosigs) { + arraysize += dns_rdataset_count(&sigset); + } + wassignedby = isc_mem_get(mctx, arraysize * sizeof(bool)); + nowsignedby = isc_mem_get(mctx, arraysize * sizeof(bool)); + + for (i = 0; i < arraysize; i++) { + wassignedby[i] = nowsignedby[i] = false; + } + + if (nosigs) { + result = ISC_R_NOMORE; + } else { + result = dns_rdataset_first(&sigset); + } + + while (result == ISC_R_SUCCESS) { + bool expired, future; + bool keep = false, resign = false; + + dns_rdataset_current(&sigset, &sigrdata); + + result = dns_rdata_tostruct(&sigrdata, &rrsig, NULL); + check_result(result, "dns_rdata_tostruct"); + + future = isc_serial_lt(now, rrsig.timesigned); + + key = keythatsigned(&rrsig); + sig_format(&rrsig, sigstr, sizeof(sigstr)); + expired = isc_serial_gt(now + cycle, rrsig.timeexpire); + + if (isc_serial_gt(rrsig.timesigned, rrsig.timeexpire)) { + /* rrsig is dropped and not replaced */ + vbprintf(2, + "\trrsig by %s dropped - " + "invalid validity period\n", + sigstr); + } else if (key == NULL && !future && + expecttofindkey(&rrsig.signer)) + { + /* rrsig is dropped and not replaced */ + vbprintf(2, + "\trrsig by %s dropped - " + "private dnskey not found\n", + sigstr); + } else if (key == NULL || future) { + keep = (!expired && !remove_orphansigs); + vbprintf(2, "\trrsig by %s %s - dnskey not found\n", + keep ? "retained" : "dropped", sigstr); + } else if (!dns_dnssec_keyactive(key->key, now) && + remove_inactkeysigs) + { + keep = false; + vbprintf(2, "\trrsig by %s dropped - key inactive\n", + sigstr); + } else if (issigningkey(key)) { + wassignedby[key->index] = true; + + if (!expired && rrsig.originalttl == set->ttl && + setverifies(name, set, key->key, &sigrdata)) + { + vbprintf(2, "\trrsig by %s retained\n", sigstr); + keep = true; + } else { + vbprintf(2, "\trrsig by %s dropped - %s\n", + sigstr, + expired ? "expired" + : rrsig.originalttl != set->ttl + ? "ttl change" + : "failed to " + "verify"); + resign = true; + } + } else if (!ispublishedkey(key) && remove_orphansigs) { + vbprintf(2, "\trrsig by %s dropped - dnskey removed\n", + sigstr); + } else if (iszonekey(key)) { + wassignedby[key->index] = true; + + if (!expired && rrsig.originalttl == set->ttl && + setverifies(name, set, key->key, &sigrdata)) + { + vbprintf(2, "\trrsig by %s retained\n", sigstr); + keep = true; + } else { + vbprintf(2, "\trrsig by %s dropped - %s\n", + sigstr, + expired ? "expired" + : rrsig.originalttl != set->ttl + ? "ttl change" + : "failed to " + "verify"); + } + } else if (!expired) { + vbprintf(2, "\trrsig by %s retained\n", sigstr); + keep = true; + } else { + vbprintf(2, "\trrsig by %s expired\n", sigstr); + } + + if (keep) { + if (key != NULL) { + nowsignedby[key->index] = true; + } + INCSTAT(nretained); + if (sigset.ttl != ttl) { + vbprintf(2, "\tfixing ttl %s\n", sigstr); + tuple = NULL; + result = dns_difftuple_create( + mctx, DNS_DIFFOP_DELRESIGN, name, + sigset.ttl, &sigrdata, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(del, &tuple); + result = dns_difftuple_create( + mctx, DNS_DIFFOP_ADDRESIGN, name, ttl, + &sigrdata, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(add, &tuple); + } + } else { + tuple = NULL; + vbprintf(2, "\tremoving signature by %s\n", sigstr); + result = dns_difftuple_create( + mctx, DNS_DIFFOP_DELRESIGN, name, sigset.ttl, + &sigrdata, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(del, &tuple); + INCSTAT(ndropped); + } + + if (resign) { + INSIST(!keep); + + signwithkey(name, set, key->key, ttl, add, + "resigning with dnskey"); + nowsignedby[key->index] = true; + } + + dns_rdata_reset(&sigrdata); + dns_rdata_freestruct(&rrsig); + result = dns_rdataset_next(&sigset); + } + if (result == ISC_R_NOMORE) { + result = ISC_R_SUCCESS; + } + + check_result(result, "dns_rdataset_first/next"); + if (dns_rdataset_isassociated(&sigset)) { + dns_rdataset_disassociate(&sigset); + } + + for (key = ISC_LIST_HEAD(keylist); key != NULL; + key = ISC_LIST_NEXT(key, link)) + { + if (nowsignedby[key->index]) { + continue; + } + + if (!issigningkey(key)) { + continue; + } + + if ((set->type == dns_rdatatype_cds || + set->type == dns_rdatatype_cdnskey || + set->type == dns_rdatatype_dnskey) && + dns_name_equal(name, gorigin)) + { + bool have_ksk; + dns_dnsseckey_t *curr; + + have_ksk = isksk(key); + for (curr = ISC_LIST_HEAD(keylist); curr != NULL; + curr = ISC_LIST_NEXT(curr, link)) + { + if (dst_key_alg(key->key) != + dst_key_alg(curr->key)) + { + continue; + } + if (REVOKE(curr->key)) { + continue; + } + if (isksk(curr)) { + have_ksk = true; + } + } + if (isksk(key) || !have_ksk || + (iszsk(key) && !keyset_kskonly)) + { + signwithkey(name, set, key->key, ttl, add, + "signing with dnskey"); + } + } else if (iszsk(key)) { + /* + * Sign with the ZSK unless there is a predecessor + * key that already signs this RRset. + */ + bool have_pre_sig = false; + dns_dnsseckey_t *curr; + uint32_t pre; + isc_result_t ret = dst_key_getnum( + key->key, DST_NUM_PREDECESSOR, &pre); + if (ret == ISC_R_SUCCESS) { + /* + * This key has a predecessor, look for the + * corresponding key in the keylist. The + * key we are looking for must be: + * - From the same cryptographic algorithm. + * - Have the ZSK type (iszsk). + * - Have key ID equal to the predecessor id. + * - Have a successor that matches 'key' id. + */ + for (curr = ISC_LIST_HEAD(keylist); + curr != NULL; + curr = ISC_LIST_NEXT(curr, link)) + { + uint32_t suc; + + if (dst_key_alg(key->key) != + dst_key_alg(curr->key) || + !iszsk(curr) || + dst_key_id(curr->key) != pre) + { + continue; + } + ret = dst_key_getnum(curr->key, + DST_NUM_SUCCESSOR, + &suc); + if (ret != ISC_R_SUCCESS || + dst_key_id(key->key) != suc) + { + continue; + } + + /* + * curr is the predecessor we were + * looking for. Check if this key + * signs this RRset. + */ + if (nowsignedby[curr->index]) { + have_pre_sig = true; + } + } + } + + /* + * If we have a signature of a predecessor key, + * skip signing with this key. + */ + if (!have_pre_sig) { + signwithkey(name, set, key->key, ttl, add, + "signing with dnskey"); + } + } + } + + isc_mem_put(mctx, wassignedby, arraysize * sizeof(bool)); + isc_mem_put(mctx, nowsignedby, arraysize * sizeof(bool)); +} + +struct hashlist { + unsigned char *hashbuf; + size_t entries; + size_t size; + size_t length; +}; + +static void +hashlist_init(hashlist_t *l, unsigned int nodes, unsigned int length) { + l->entries = 0; + l->length = length + 1; + + if (nodes != 0) { + l->size = nodes; + l->hashbuf = malloc(l->size * l->length); + if (l->hashbuf == NULL) { + l->size = 0; + } + } else { + l->size = 0; + l->hashbuf = NULL; + } +} + +static void +hashlist_free(hashlist_t *l) { + if (l->hashbuf) { + free(l->hashbuf); + l->hashbuf = NULL; + l->entries = 0; + l->length = 0; + l->size = 0; + } +} + +static void +hashlist_add(hashlist_t *l, const unsigned char *hash, size_t len) { + REQUIRE(len <= l->length); + + if (l->entries == l->size) { + l->size = l->size * 2 + 100; + l->hashbuf = realloc(l->hashbuf, l->size * l->length); + if (l->hashbuf == NULL) { + fatal("unable to grow hashlist: out of memory"); + } + } + memset(l->hashbuf + l->entries * l->length, 0, l->length); + memmove(l->hashbuf + l->entries * l->length, hash, len); + l->entries++; +} + +static void +hashlist_add_dns_name(hashlist_t *l, + /*const*/ dns_name_t *name, unsigned int hashalg, + unsigned int iterations, const unsigned char *salt, + size_t salt_len, bool speculative) { + char nametext[DNS_NAME_FORMATSIZE]; + unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1]; + unsigned int len; + size_t i; + + len = isc_iterated_hash(hash, hashalg, iterations, salt, (int)salt_len, + name->ndata, name->length); + if (verbose) { + dns_name_format(name, nametext, sizeof nametext); + for (i = 0; i < len; i++) { + fprintf(stderr, "%02x", hash[i]); + } + fprintf(stderr, " %s\n", nametext); + } + hash[len++] = speculative ? 1 : 0; + hashlist_add(l, hash, len); +} + +static int +hashlist_comp(const void *a, const void *b) { + return (memcmp(a, b, hash_length + 1)); +} + +static void +hashlist_sort(hashlist_t *l) { + INSIST(l->hashbuf != NULL || l->length == 0); + if (l->length > 0) { + qsort(l->hashbuf, l->entries, l->length, hashlist_comp); + } +} + +static bool +hashlist_hasdup(hashlist_t *l) { + unsigned char *current; + unsigned char *next = l->hashbuf; + size_t entries = l->entries; + + /* + * Skip initial speculative wild card hashes. + */ + while (entries > 0U && next[l->length - 1] != 0U) { + next += l->length; + entries--; + } + + current = next; + while (entries-- > 1U) { + next += l->length; + if (next[l->length - 1] != 0) { + continue; + } + if (isc_safe_memequal(current, next, l->length - 1)) { + return (true); + } + current = next; + } + return (false); +} + +static const unsigned char * +hashlist_findnext(const hashlist_t *l, + const unsigned char hash[NSEC3_MAX_HASH_LENGTH]) { + size_t entries = l->entries; + const unsigned char *next = bsearch(hash, l->hashbuf, l->entries, + l->length, hashlist_comp); + INSIST(next != NULL); + + do { + if (next < l->hashbuf + (l->entries - 1) * l->length) { + next += l->length; + } else { + next = l->hashbuf; + } + if (next[l->length - 1] == 0) { + break; + } + } while (entries-- > 1U); + INSIST(entries != 0U); + return (next); +} + +static bool +hashlist_exists(const hashlist_t *l, + const unsigned char hash[NSEC3_MAX_HASH_LENGTH]) { + if (bsearch(hash, l->hashbuf, l->entries, l->length, hashlist_comp)) { + return (true); + } else { + return (false); + } +} + +static void +addnowildcardhash(hashlist_t *l, + /*const*/ dns_name_t *name, unsigned int hashalg, + unsigned int iterations, const unsigned char *salt, + size_t salt_len) { + dns_fixedname_t fixed; + dns_name_t *wild; + dns_dbnode_t *node = NULL; + isc_result_t result; + char namestr[DNS_NAME_FORMATSIZE]; + + wild = dns_fixedname_initname(&fixed); + + result = dns_name_concatenate(dns_wildcardname, name, wild, NULL); + if (result == ISC_R_NOSPACE) { + return; + } + check_result(result, "addnowildcardhash: dns_name_concatenate()"); + + result = dns_db_findnode(gdb, wild, false, &node); + if (result == ISC_R_SUCCESS) { + dns_db_detachnode(gdb, &node); + return; + } + + if (verbose) { + dns_name_format(wild, namestr, sizeof(namestr)); + fprintf(stderr, "adding no-wildcardhash for %s\n", namestr); + } + + hashlist_add_dns_name(l, wild, hashalg, iterations, salt, salt_len, + true); +} + +static void +opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass, + dns_db_t **dbp) { + char filename[PATH_MAX]; + isc_buffer_t b; + isc_result_t result; + + isc_buffer_init(&b, filename, sizeof(filename)); + if (dsdir != NULL) { + /* allow room for a trailing slash */ + if (strlen(dsdir) >= isc_buffer_availablelength(&b)) { + fatal("path '%s' is too long", dsdir); + } + isc_buffer_putstr(&b, dsdir); + if (dsdir[strlen(dsdir) - 1] != '/') { + isc_buffer_putstr(&b, "/"); + } + } + if (strlen(prefix) > isc_buffer_availablelength(&b)) { + fatal("path '%s' is too long", dsdir); + } + isc_buffer_putstr(&b, prefix); + result = dns_name_tofilenametext(name, false, &b); + check_result(result, "dns_name_tofilenametext()"); + if (isc_buffer_availablelength(&b) == 0) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + fatal("name '%s' is too long", namestr); + } + isc_buffer_putuint8(&b, 0); + + result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone, + rdclass, 0, NULL, dbp); + check_result(result, "dns_db_create()"); + + result = dns_db_load(*dbp, filename, inputformat, DNS_MASTER_HINT); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { + dns_db_detach(dbp); + } +} + +/*% + * Load the DS set for a child zone, if a dsset-* file can be found. + * If not, try to find a keyset-* file from an earlier version of + * dnssec-signzone, and build DS records from that. + */ +static isc_result_t +loadds(dns_name_t *name, uint32_t ttl, dns_rdataset_t *dsset) { + dns_db_t *db = NULL; + dns_dbversion_t *ver = NULL; + dns_dbnode_t *node = NULL; + isc_result_t result; + dns_rdataset_t keyset; + dns_rdata_t key, ds; + unsigned char dsbuf[DNS_DS_BUFFERSIZE]; + dns_diff_t diff; + dns_difftuple_t *tuple = NULL; + + opendb("dsset-", name, gclass, &db); + if (db != NULL) { + result = dns_db_findnode(db, name, false, &node); + if (result == ISC_R_SUCCESS) { + dns_rdataset_init(dsset); + result = dns_db_findrdataset(db, node, NULL, + dns_rdatatype_ds, 0, 0, + dsset, NULL); + dns_db_detachnode(db, &node); + if (result == ISC_R_SUCCESS) { + vbprintf(2, "found DS records\n"); + dsset->ttl = ttl; + dns_db_detach(&db); + return (result); + } + } + dns_db_detach(&db); + } + + /* No DS records found; try again, looking for DNSKEY records */ + opendb("keyset-", name, gclass, &db); + if (db == NULL) { + return (ISC_R_NOTFOUND); + } + + result = dns_db_findnode(db, name, false, &node); + if (result != ISC_R_SUCCESS) { + dns_db_detach(&db); + return (result); + } + + dns_rdataset_init(&keyset); + result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0, + &keyset, NULL); + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(db, &node); + dns_db_detach(&db); + return (result); + } + vbprintf(2, "found DNSKEY records\n"); + + result = dns_db_newversion(db, &ver); + check_result(result, "dns_db_newversion"); + dns_diff_init(mctx, &diff); + + for (result = dns_rdataset_first(&keyset); result == ISC_R_SUCCESS; + result = dns_rdataset_next(&keyset)) + { + dns_rdata_init(&key); + dns_rdata_init(&ds); + dns_rdataset_current(&keyset, &key); + result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256, + dsbuf, &ds); + check_result(result, "dns_ds_buildrdata"); + + result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name, + ttl, &ds, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(&diff, &tuple); + } + + result = dns_diff_apply(&diff, db, ver); + check_result(result, "dns_diff_apply"); + dns_diff_clear(&diff); + + dns_db_closeversion(db, &ver, true); + + result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0, 0, + dsset, NULL); + check_result(result, "dns_db_findrdataset"); + + dns_rdataset_disassociate(&keyset); + dns_db_detachnode(db, &node); + dns_db_detach(&db); + return (result); +} + +static bool +secure(dns_name_t *name, dns_dbnode_t *node) { + dns_rdataset_t dsset; + isc_result_t result; + + if (dns_name_equal(name, gorigin)) { + return (false); + } + + dns_rdataset_init(&dsset); + result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ds, 0, + 0, &dsset, NULL); + if (dns_rdataset_isassociated(&dsset)) { + dns_rdataset_disassociate(&dsset); + } + + return (result == ISC_R_SUCCESS); +} + +static bool +is_delegation(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, + dns_name_t *name, dns_dbnode_t *node, uint32_t *ttlp) { + dns_rdataset_t nsset; + isc_result_t result; + + if (dns_name_equal(name, origin)) { + return (false); + } + + dns_rdataset_init(&nsset); + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_ns, 0, 0, + &nsset, NULL); + if (dns_rdataset_isassociated(&nsset)) { + if (ttlp != NULL) { + *ttlp = nsset.ttl; + } + dns_rdataset_disassociate(&nsset); + } + + return ((result == ISC_R_SUCCESS)); +} + +/*% + * Return true if version 'ver' of database 'db' contains a DNAME RRset at + * 'node'; return false otherwise. + */ +static bool +has_dname(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node) { + dns_rdataset_t dnameset; + isc_result_t result; + + dns_rdataset_init(&dnameset); + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dname, 0, 0, + &dnameset, NULL); + if (dns_rdataset_isassociated(&dnameset)) { + dns_rdataset_disassociate(&dnameset); + } + + return ((result == ISC_R_SUCCESS)); +} + +/*% + * Signs all records at a name. + */ +static void +signname(dns_dbnode_t *node, dns_name_t *name) { + isc_result_t result; + dns_rdataset_t rdataset; + dns_rdatasetiter_t *rdsiter; + bool isdelegation = false; + dns_diff_t del, add; + char namestr[DNS_NAME_FORMATSIZE]; + + dns_rdataset_init(&rdataset); + dns_name_format(name, namestr, sizeof(namestr)); + + /* + * Determine if this is a delegation point. + */ + if (is_delegation(gdb, gversion, gorigin, name, node, NULL)) { + isdelegation = true; + } + + /* + * Now iterate through the rdatasets. + */ + dns_diff_init(mctx, &del); + dns_diff_init(mctx, &add); + rdsiter = NULL; + result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &rdataset); + + /* If this is a RRSIG set, skip it. */ + if (rdataset.type == dns_rdatatype_rrsig) { + goto skip; + } + + /* + * If this name is a delegation point, skip all records + * except NSEC and DS sets. Otherwise check that there + * isn't a DS record. + */ + if (isdelegation) { + if (rdataset.type != nsec_datatype && + rdataset.type != dns_rdatatype_ds) + { + goto skip; + } + } else if (rdataset.type == dns_rdatatype_ds) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namebuf, sizeof(namebuf)); + fatal("'%s': found DS RRset without NS RRset\n", + namebuf); + } + + signset(&del, &add, node, name, &rdataset); + + skip: + dns_rdataset_disassociate(&rdataset); + result = dns_rdatasetiter_next(rdsiter); + } + if (result != ISC_R_NOMORE) { + fatal("rdataset iteration for name '%s' failed: %s", namestr, + isc_result_totext(result)); + } + + dns_rdatasetiter_destroy(&rdsiter); + + result = dns_diff_applysilently(&del, gdb, gversion); + if (result != ISC_R_SUCCESS) { + fatal("failed to delete SIGs at node '%s': %s", namestr, + isc_result_totext(result)); + } + + result = dns_diff_applysilently(&add, gdb, gversion); + if (result != ISC_R_SUCCESS) { + fatal("failed to add SIGs at node '%s': %s", namestr, + isc_result_totext(result)); + } + + dns_diff_clear(&del); + dns_diff_clear(&add); +} + +/* + * See if the node contains any non RRSIG/NSEC records and report to + * caller. Clean out extraneous RRSIG records for node. + */ +static bool +active_node(dns_dbnode_t *node) { + dns_rdatasetiter_t *rdsiter = NULL; + dns_rdatasetiter_t *rdsiter2 = NULL; + bool active = false; + isc_result_t result; + dns_rdataset_t rdataset; + dns_rdatatype_t type; + dns_rdatatype_t covers; + bool found; + + dns_rdataset_init(&rdataset); + result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &rdataset); + if (rdataset.type != dns_rdatatype_nsec && + rdataset.type != dns_rdatatype_nsec3 && + rdataset.type != dns_rdatatype_rrsig) + { + active = true; + } + dns_rdataset_disassociate(&rdataset); + if (!active) { + result = dns_rdatasetiter_next(rdsiter); + } else { + result = ISC_R_NOMORE; + } + } + if (result != ISC_R_NOMORE) { + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + } + + if (!active && nsec_datatype == dns_rdatatype_nsec) { + /*% + * The node is empty of everything but NSEC / RRSIG records. + */ + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) + { + dns_rdatasetiter_current(rdsiter, &rdataset); + result = dns_db_deleterdataset(gdb, node, gversion, + rdataset.type, + rdataset.covers); + check_result(result, "dns_db_deleterdataset()"); + dns_rdataset_disassociate(&rdataset); + } + if (result != ISC_R_NOMORE) { + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + } + } else { + /* + * Delete RRSIGs for types that no longer exist. + */ + result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, + &rdsiter2); + check_result(result, "dns_db_allrdatasets()"); + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) + { + dns_rdatasetiter_current(rdsiter, &rdataset); + type = rdataset.type; + covers = rdataset.covers; + dns_rdataset_disassociate(&rdataset); + /* + * Delete the NSEC chain if we are signing with + * NSEC3. + */ + if (nsec_datatype == dns_rdatatype_nsec3 && + (type == dns_rdatatype_nsec || + covers == dns_rdatatype_nsec)) + { + result = dns_db_deleterdataset( + gdb, node, gversion, type, covers); + check_result(result, "dns_db_deleterdataset(" + "nsec/rrsig)"); + continue; + } + if (type != dns_rdatatype_rrsig) { + continue; + } + found = false; + for (result = dns_rdatasetiter_first(rdsiter2); + !found && result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter2)) + { + dns_rdatasetiter_current(rdsiter2, &rdataset); + if (rdataset.type == covers) { + found = true; + } + dns_rdataset_disassociate(&rdataset); + } + if (!found) { + if (result != ISC_R_NOMORE) { + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + } + result = dns_db_deleterdataset( + gdb, node, gversion, type, covers); + check_result(result, "dns_db_deleterdataset(" + "rrsig)"); + } else if (result != ISC_R_NOMORE && + result != ISC_R_SUCCESS) + { + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + } + } + if (result != ISC_R_NOMORE) { + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + } + dns_rdatasetiter_destroy(&rdsiter2); + } + dns_rdatasetiter_destroy(&rdsiter); + + return (active); +} + +/*% + * Extracts the minimum TTL from the SOA record, and the SOA record's TTL. + */ +static void +get_soa_ttls(void) { + dns_rdataset_t soaset; + dns_fixedname_t fname; + dns_name_t *name; + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + + name = dns_fixedname_initname(&fname); + dns_rdataset_init(&soaset); + result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa, 0, 0, + NULL, name, &soaset, NULL); + if (result != ISC_R_SUCCESS) { + fatal("failed to find an SOA at the zone apex: %s", + isc_result_totext(result)); + } + + result = dns_rdataset_first(&soaset); + check_result(result, "dns_rdataset_first"); + dns_rdataset_current(&soaset, &rdata); + soa_ttl = soaset.ttl; + zone_soa_min_ttl = ISC_MIN(dns_soa_getminimum(&rdata), soa_ttl); + if (set_maxttl) { + zone_soa_min_ttl = ISC_MIN(zone_soa_min_ttl, maxttl); + soa_ttl = ISC_MIN(soa_ttl, maxttl); + } + dns_rdataset_disassociate(&soaset); +} + +/*% + * Increment (or set if nonzero) the SOA serial + */ +static isc_result_t +setsoaserial(uint32_t serial, dns_updatemethod_t method) { + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + uint32_t old_serial, new_serial = 0; + dns_updatemethod_t used = dns_updatemethod_none; + + result = dns_db_getoriginnode(gdb, &node); + if (result != ISC_R_SUCCESS) { + return (result); + } + + dns_rdataset_init(&rdataset); + + result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_soa, 0, + 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = dns_rdataset_first(&rdataset); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + dns_rdataset_current(&rdataset, &rdata); + + old_serial = dns_soa_getserial(&rdata); + + if (method == dns_updatemethod_date || + method == dns_updatemethod_unixtime) + { + new_serial = dns_update_soaserial(old_serial, method, &used); + } else if (serial != 0 || method == dns_updatemethod_none) { + /* Set SOA serial to the value provided. */ + new_serial = serial; + used = method; + } else { + new_serial = dns_update_soaserial(old_serial, method, &used); + } + + if (method != used) { + fprintf(stderr, + "%s: warning: Serial number would not advance, " + "using increment method instead\n", + program); + } + + /* If the new serial is not likely to cause a zone transfer + * (a/ixfr) from servers having the old serial, warn the user. + * + * RFC1982 section 7 defines the maximum increment to be + * (2^(32-1))-1. Using u_int32_t arithmetic, we can do a single + * comparison. (5 - 6 == (2^32)-1, not negative-one) + */ + if (new_serial == old_serial || (new_serial - old_serial) > 0x7fffffffU) + { + fprintf(stderr, + "%s: warning: Serial number not advanced, " + "zone may not transfer\n", + program); + } + + dns_soa_setserial(new_serial, &rdata); + + result = dns_db_deleterdataset(gdb, node, gversion, dns_rdatatype_soa, + 0); + check_result(result, "dns_db_deleterdataset"); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = dns_db_addrdataset(gdb, node, gversion, 0, &rdataset, 0, NULL); + check_result(result, "dns_db_addrdataset"); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + +cleanup: + dns_rdataset_disassociate(&rdataset); + if (node != NULL) { + dns_db_detachnode(gdb, &node); + } + dns_rdata_reset(&rdata); + + return (result); +} + +/*% + * Delete any RRSIG records at a node. + */ +static void +cleannode(dns_db_t *db, dns_dbversion_t *dbversion, dns_dbnode_t *node) { + dns_rdatasetiter_t *rdsiter = NULL; + dns_rdataset_t set; + isc_result_t result, dresult; + + if (outputformat != dns_masterformat_text || !disable_zone_check) { + return; + } + + dns_rdataset_init(&set); + result = dns_db_allrdatasets(db, node, dbversion, 0, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets"); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + bool destroy = false; + dns_rdatatype_t covers = 0; + dns_rdatasetiter_current(rdsiter, &set); + if (set.type == dns_rdatatype_rrsig) { + covers = set.covers; + destroy = true; + } + dns_rdataset_disassociate(&set); + result = dns_rdatasetiter_next(rdsiter); + if (destroy) { + dresult = dns_db_deleterdataset(db, node, dbversion, + dns_rdatatype_rrsig, + covers); + check_result(dresult, "dns_db_deleterdataset"); + } + } + if (result != ISC_R_NOMORE) { + fatal("rdataset iteration failed: %s", + isc_result_totext(result)); + } + dns_rdatasetiter_destroy(&rdsiter); +} + +/*% + * Set up the iterator and global state before starting the tasks. + */ +static void +presign(void) { + isc_result_t result; + + gdbiter = NULL; + result = dns_db_createiterator(gdb, 0, &gdbiter); + check_result(result, "dns_db_createiterator()"); +} + +/*% + * Clean up the iterator and global state after the tasks complete. + */ +static void +postsign(void) { + dns_dbiterator_destroy(&gdbiter); +} + +/*% + * Sign the apex of the zone. + * Note the origin may not be the first node if there are out of zone + * records. + */ +static void +signapex(void) { + dns_dbnode_t *node = NULL; + dns_fixedname_t fixed; + dns_name_t *name; + isc_result_t result; + + name = dns_fixedname_initname(&fixed); + result = dns_dbiterator_seek(gdbiter, gorigin); + check_result(result, "dns_dbiterator_seek()"); + result = dns_dbiterator_current(gdbiter, &node, name); + check_dns_dbiterator_current(result); + signname(node, name); + dumpnode(name, node); + cleannode(gdb, gversion, node); + dns_db_detachnode(gdb, &node); + result = dns_dbiterator_first(gdbiter); + if (result == ISC_R_NOMORE) { + atomic_store(&finished, true); + } else if (result != ISC_R_SUCCESS) { + fatal("failure iterating database: %s", + isc_result_totext(result)); + } +} + +/*% + * Assigns a node to a worker thread. This is protected by the master task's + * lock. + */ +static void +assignwork(isc_task_t *task, isc_task_t *worker) { + dns_fixedname_t *fname; + dns_name_t *name; + dns_dbnode_t *node; + sevent_t *sevent; + dns_rdataset_t nsec; + bool found; + isc_result_t result; + static dns_name_t *zonecut = NULL; /* Protected by namelock. */ + static dns_fixedname_t fzonecut; /* Protected by namelock. */ + static unsigned int ended = 0; /* Protected by namelock. */ + + if (atomic_load(&shuttingdown)) { + return; + } + + LOCK(&namelock); + if (atomic_load(&finished)) { + ended++; + if (ended == ntasks) { + isc_task_detach(&task); + isc_app_shutdown(); + } + goto unlock; + } + + fname = isc_mem_get(mctx, sizeof(dns_fixedname_t)); + name = dns_fixedname_initname(fname); + node = NULL; + found = false; + while (!found) { + result = dns_dbiterator_current(gdbiter, &node, name); + check_dns_dbiterator_current(result); + /* + * The origin was handled by signapex(). + */ + if (dns_name_equal(name, gorigin)) { + dns_db_detachnode(gdb, &node); + goto next; + } + /* + * Sort the zone data from the glue and out-of-zone data. + * For NSEC zones nodes with zone data have NSEC records. + * For NSEC3 zones the NSEC3 nodes are zone data but + * outside of the zone name space. For the rest we need + * to track the bottom of zone cuts. + * Nodes which don't need to be signed are dumped here. + */ + dns_rdataset_init(&nsec); + result = dns_db_findrdataset(gdb, node, gversion, nsec_datatype, + 0, 0, &nsec, NULL); + if (dns_rdataset_isassociated(&nsec)) { + dns_rdataset_disassociate(&nsec); + } + if (result == ISC_R_SUCCESS) { + found = true; + } else if (nsec_datatype == dns_rdatatype_nsec3) { + if (dns_name_issubdomain(name, gorigin) && + (zonecut == NULL || + !dns_name_issubdomain(name, zonecut))) + { + if (is_delegation(gdb, gversion, gorigin, name, + node, NULL)) + { + zonecut = savezonecut(&fzonecut, name); + if (!OPTOUT(nsec3flags) || + secure(name, node)) + { + found = true; + } + } else if (has_dname(gdb, gversion, node)) { + zonecut = savezonecut(&fzonecut, name); + found = true; + } else { + found = true; + } + } + } + + if (!found) { + dumpnode(name, node); + dns_db_detachnode(gdb, &node); + } + + next: + result = dns_dbiterator_next(gdbiter); + if (result == ISC_R_NOMORE) { + atomic_store(&finished, true); + break; + } else if (result != ISC_R_SUCCESS) { + fatal("failure iterating database: %s", + isc_result_totext(result)); + } + } + if (!found) { + ended++; + if (ended == ntasks) { + isc_task_detach(&task); + isc_app_shutdown(); + } + isc_mem_put(mctx, fname, sizeof(dns_fixedname_t)); + goto unlock; + } + sevent = (sevent_t *)isc_event_allocate(mctx, task, SIGNER_EVENT_WORK, + sign, NULL, sizeof(sevent_t)); + + sevent->node = node; + sevent->fname = fname; + isc_task_send(worker, ISC_EVENT_PTR(&sevent)); +unlock: + UNLOCK(&namelock); +} + +/*% + * Start a worker task + */ +static void +startworker(isc_task_t *task, isc_event_t *event) { + isc_task_t *worker; + + worker = (isc_task_t *)event->ev_arg; + assignwork(task, worker); + isc_event_free(&event); +} + +/*% + * Write a node to the output file, and restart the worker task. + */ +static void +writenode(isc_task_t *task, isc_event_t *event) { + isc_task_t *worker; + sevent_t *sevent = (sevent_t *)event; + + worker = (isc_task_t *)event->ev_sender; + dumpnode(dns_fixedname_name(sevent->fname), sevent->node); + cleannode(gdb, gversion, sevent->node); + dns_db_detachnode(gdb, &sevent->node); + isc_mem_put(mctx, sevent->fname, sizeof(dns_fixedname_t)); + assignwork(task, worker); + isc_event_free(&event); +} + +/*% + * Sign a database node. + */ +static void +sign(isc_task_t *task, isc_event_t *event) { + dns_fixedname_t *fname; + dns_dbnode_t *node; + sevent_t *sevent, *wevent; + + sevent = (sevent_t *)event; + node = sevent->node; + fname = sevent->fname; + isc_event_free(&event); + + signname(node, dns_fixedname_name(fname)); + wevent = (sevent_t *)isc_event_allocate(mctx, task, SIGNER_EVENT_WRITE, + writenode, NULL, + sizeof(sevent_t)); + wevent->node = node; + wevent->fname = fname; + isc_task_send(master, ISC_EVENT_PTR(&wevent)); +} + +/*% + * Update / remove the DS RRset. Preserve RRSIG(DS) if possible. + */ +static void +add_ds(dns_name_t *name, dns_dbnode_t *node, uint32_t nsttl) { + dns_rdataset_t dsset; + dns_rdataset_t sigdsset; + isc_result_t result; + + dns_rdataset_init(&dsset); + dns_rdataset_init(&sigdsset); + result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ds, 0, + 0, &dsset, &sigdsset); + if (result == ISC_R_SUCCESS) { + dns_rdataset_disassociate(&dsset); + result = dns_db_deleterdataset(gdb, node, gversion, + dns_rdatatype_ds, 0); + check_result(result, "dns_db_deleterdataset"); + } + + result = loadds(name, nsttl, &dsset); + if (result == ISC_R_SUCCESS) { + result = dns_db_addrdataset(gdb, node, gversion, 0, &dsset, 0, + NULL); + check_result(result, "dns_db_addrdataset"); + dns_rdataset_disassociate(&dsset); + if (dns_rdataset_isassociated(&sigdsset)) { + dns_rdataset_disassociate(&sigdsset); + } + } else if (dns_rdataset_isassociated(&sigdsset)) { + result = dns_db_deleterdataset(gdb, node, gversion, + dns_rdatatype_rrsig, + dns_rdatatype_ds); + check_result(result, "dns_db_deleterdataset"); + dns_rdataset_disassociate(&sigdsset); + } +} + +/* + * Remove records of the given type and their signatures. + */ +static void +remove_records(dns_dbnode_t *node, dns_rdatatype_t which, bool checknsec) { + isc_result_t result; + dns_rdatatype_t type, covers; + dns_rdatasetiter_t *rdsiter = NULL; + dns_rdataset_t rdataset; + + dns_rdataset_init(&rdataset); + + /* + * Delete any records of the given type at the apex. + */ + result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) + { + dns_rdatasetiter_current(rdsiter, &rdataset); + type = rdataset.type; + covers = rdataset.covers; + dns_rdataset_disassociate(&rdataset); + if (type == which || covers == which) { + if (which == dns_rdatatype_nsec && checknsec && + !update_chain) + { + fatal("Zone contains NSEC records. Use -u " + "to update to NSEC3."); + } + if (which == dns_rdatatype_nsec3param && checknsec && + !update_chain) + { + fatal("Zone contains NSEC3 chains. Use -u " + "to update to NSEC."); + } + result = dns_db_deleterdataset(gdb, node, gversion, + type, covers); + check_result(result, "dns_db_deleterdataset()"); + } + } + dns_rdatasetiter_destroy(&rdsiter); +} + +/* + * Remove signatures covering the given type. If type == 0, + * then remove all signatures, unless this is a delegation, in + * which case remove all signatures except for DS or nsec_datatype + */ +static void +remove_sigs(dns_dbnode_t *node, bool delegation, dns_rdatatype_t which) { + isc_result_t result; + dns_rdatatype_t type, covers; + dns_rdatasetiter_t *rdsiter = NULL; + dns_rdataset_t rdataset; + + dns_rdataset_init(&rdataset); + result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) + { + dns_rdatasetiter_current(rdsiter, &rdataset); + type = rdataset.type; + covers = rdataset.covers; + dns_rdataset_disassociate(&rdataset); + + if (type != dns_rdatatype_rrsig) { + continue; + } + + if (which == 0 && delegation && + (dns_rdatatype_atparent(covers) || + (nsec_datatype == dns_rdatatype_nsec && + covers == nsec_datatype))) + { + continue; + } + + if (which != 0 && covers != which) { + continue; + } + + result = dns_db_deleterdataset(gdb, node, gversion, type, + covers); + check_result(result, "dns_db_deleterdataset()"); + } + dns_rdatasetiter_destroy(&rdsiter); +} + +/*% + * Generate NSEC records for the zone and remove NSEC3/NSEC3PARAM records. + */ +static void +nsecify(void) { + dns_dbiterator_t *dbiter = NULL; + dns_dbnode_t *node = NULL, *nextnode = NULL; + dns_fixedname_t fname, fnextname, fzonecut; + dns_name_t *name, *nextname, *zonecut; + dns_rdataset_t rdataset; + dns_rdatasetiter_t *rdsiter = NULL; + dns_rdatatype_t type, covers; + bool done = false; + isc_result_t result; + uint32_t nsttl = 0; + + dns_rdataset_init(&rdataset); + name = dns_fixedname_initname(&fname); + nextname = dns_fixedname_initname(&fnextname); + zonecut = NULL; + + /* + * Remove any NSEC3 chains. + */ + result = dns_db_createiterator(gdb, DNS_DB_NSEC3ONLY, &dbiter); + check_result(result, "dns_db_createiterator()"); + for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS; + result = dns_dbiterator_next(dbiter)) + { + result = dns_dbiterator_current(dbiter, &node, name); + check_dns_dbiterator_current(result); + result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, + &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) + { + dns_rdatasetiter_current(rdsiter, &rdataset); + type = rdataset.type; + covers = rdataset.covers; + dns_rdataset_disassociate(&rdataset); + result = dns_db_deleterdataset(gdb, node, gversion, + type, covers); + check_result(result, "dns_db_deleterdataset(nsec3param/" + "rrsig)"); + } + dns_rdatasetiter_destroy(&rdsiter); + dns_db_detachnode(gdb, &node); + } + dns_dbiterator_destroy(&dbiter); + + result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter); + check_result(result, "dns_db_createiterator()"); + + result = dns_dbiterator_first(dbiter); + check_result(result, "dns_dbiterator_first()"); + + while (!done) { + result = dns_dbiterator_current(dbiter, &node, name); + check_dns_dbiterator_current(result); + /* + * Skip out-of-zone records. + */ + if (!dns_name_issubdomain(name, gorigin)) { + result = dns_dbiterator_next(dbiter); + if (result == ISC_R_NOMORE) { + done = true; + } else { + check_result(result, "dns_dbiterator_next()"); + } + dns_db_detachnode(gdb, &node); + continue; + } + + if (dns_name_equal(name, gorigin)) { + remove_records(node, dns_rdatatype_nsec3param, true); + /* Clean old rrsigs at apex. */ + (void)active_node(node); + } + + if (is_delegation(gdb, gversion, gorigin, name, node, &nsttl)) { + zonecut = savezonecut(&fzonecut, name); + remove_sigs(node, true, 0); + if (generateds) { + add_ds(name, node, nsttl); + } + } else if (has_dname(gdb, gversion, node)) { + zonecut = savezonecut(&fzonecut, name); + } + + result = dns_dbiterator_next(dbiter); + nextnode = NULL; + while (result == ISC_R_SUCCESS) { + bool active = false; + result = dns_dbiterator_current(dbiter, &nextnode, + nextname); + check_dns_dbiterator_current(result); + active = active_node(nextnode); + if (!active) { + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + if (!dns_name_issubdomain(nextname, gorigin) || + (zonecut != NULL && + dns_name_issubdomain(nextname, zonecut))) + { + remove_sigs(nextnode, false, 0); + remove_records(nextnode, dns_rdatatype_nsec, + false); + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + dns_db_detachnode(gdb, &nextnode); + break; + } + if (result == ISC_R_NOMORE) { + dns_name_clone(gorigin, nextname); + done = true; + } else if (result != ISC_R_SUCCESS) { + fatal("iterating through the database failed: %s", + isc_result_totext(result)); + } + dns_dbiterator_pause(dbiter); + result = dns_nsec_build(gdb, gversion, node, nextname, + zone_soa_min_ttl); + check_result(result, "dns_nsec_build()"); + dns_db_detachnode(gdb, &node); + } + + dns_dbiterator_destroy(&dbiter); +} + +static void +addnsec3param(const unsigned char *salt, size_t salt_len, + dns_iterations_t iterations) { + dns_dbnode_t *node = NULL; + dns_rdata_nsec3param_t nsec3param; + unsigned char nsec3parambuf[5 + 255]; + dns_rdatalist_t rdatalist; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_buffer_t b; + isc_result_t result; + + dns_rdataset_init(&rdataset); + + nsec3param.common.rdclass = gclass; + nsec3param.common.rdtype = dns_rdatatype_nsec3param; + ISC_LINK_INIT(&nsec3param.common, link); + nsec3param.mctx = NULL; + nsec3param.flags = 0; + nsec3param.hash = unknownalg ? DNS_NSEC3_UNKNOWNALG : dns_hash_sha1; + nsec3param.iterations = iterations; + nsec3param.salt_length = (unsigned char)salt_len; + DE_CONST(salt, nsec3param.salt); + + isc_buffer_init(&b, nsec3parambuf, sizeof(nsec3parambuf)); + result = dns_rdata_fromstruct(&rdata, gclass, dns_rdatatype_nsec3param, + &nsec3param, &b); + check_result(result, "dns_rdata_fromstruct()"); + dns_rdatalist_init(&rdatalist); + rdatalist.rdclass = rdata.rdclass; + rdatalist.type = rdata.type; + ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); + result = dns_rdatalist_tordataset(&rdatalist, &rdataset); + check_result(result, "dns_rdatalist_tordataset()"); + + result = dns_db_findnode(gdb, gorigin, true, &node); + check_result(result, "dns_db_findnode(gorigin)"); + + /* + * Delete any current NSEC3PARAM records. + */ + result = dns_db_deleterdataset(gdb, node, gversion, + dns_rdatatype_nsec3param, 0); + if (result == DNS_R_UNCHANGED) { + result = ISC_R_SUCCESS; + } + check_result(result, "dddnsec3param: dns_db_deleterdataset()"); + + result = dns_db_addrdataset(gdb, node, gversion, 0, &rdataset, + DNS_DBADD_MERGE, NULL); + if (result == DNS_R_UNCHANGED) { + result = ISC_R_SUCCESS; + } + check_result(result, "addnsec3param: dns_db_addrdataset()"); + dns_db_detachnode(gdb, &node); +} + +static void +addnsec3(dns_name_t *name, dns_dbnode_t *node, const unsigned char *salt, + size_t salt_len, unsigned int iterations, hashlist_t *hashlist, + dns_ttl_t ttl) { + unsigned char hash[NSEC3_MAX_HASH_LENGTH]; + const unsigned char *nexthash; + unsigned char nsec3buffer[DNS_NSEC3_BUFFERSIZE]; + dns_fixedname_t hashname; + dns_rdatalist_t rdatalist; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_result_t result; + dns_dbnode_t *nsec3node = NULL; + char namebuf[DNS_NAME_FORMATSIZE]; + size_t hash_len; + + dns_name_format(name, namebuf, sizeof(namebuf)); + + dns_fixedname_init(&hashname); + dns_rdataset_init(&rdataset); + + dns_name_downcase(name, name, NULL); + result = dns_nsec3_hashname(&hashname, hash, &hash_len, name, gorigin, + dns_hash_sha1, iterations, salt, salt_len); + check_result(result, "addnsec3: dns_nsec3_hashname()"); + nexthash = hashlist_findnext(hashlist, hash); + result = dns_nsec3_buildrdata( + gdb, gversion, node, + unknownalg ? DNS_NSEC3_UNKNOWNALG : dns_hash_sha1, nsec3flags, + iterations, salt, salt_len, nexthash, ISC_SHA1_DIGESTLENGTH, + nsec3buffer, &rdata); + check_result(result, "addnsec3: dns_nsec3_buildrdata()"); + dns_rdatalist_init(&rdatalist); + rdatalist.rdclass = rdata.rdclass; + rdatalist.type = rdata.type; + rdatalist.ttl = ttl; + ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); + result = dns_rdatalist_tordataset(&rdatalist, &rdataset); + check_result(result, "dns_rdatalist_tordataset()"); + result = dns_db_findnsec3node(gdb, dns_fixedname_name(&hashname), true, + &nsec3node); + check_result(result, "addnsec3: dns_db_findnode()"); + result = dns_db_addrdataset(gdb, nsec3node, gversion, 0, &rdataset, 0, + NULL); + if (result == DNS_R_UNCHANGED) { + result = ISC_R_SUCCESS; + } + check_result(result, "addnsec3: dns_db_addrdataset()"); + dns_db_detachnode(gdb, &nsec3node); +} + +/*% + * Clean out NSEC3 record and RRSIG(NSEC3) that are not in the hash list. + * + * Extract the hash from the first label of 'name' then see if it + * is in hashlist. If 'name' is not in the hashlist then delete the + * any NSEC3 records which have the same parameters as the chain we + * are building. + * + * XXXMPA Should we also check that it of the form <hash>.<origin>? + */ +static void +nsec3clean(dns_name_t *name, dns_dbnode_t *node, unsigned int hashalg, + unsigned int iterations, const unsigned char *salt, size_t salt_len, + hashlist_t *hashlist) { + dns_label_t label; + dns_rdata_nsec3_t nsec3; + dns_rdata_t rdata, delrdata; + dns_rdatalist_t rdatalist; + dns_rdataset_t rdataset, delrdataset; + bool delete_rrsigs = false; + isc_buffer_t target; + isc_result_t result; + unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1]; + bool exists; + + /* + * Get the first label. + */ + dns_name_getlabel(name, 0, &label); + + /* + * We want just the label contents. + */ + isc_region_consume(&label, 1); + + /* + * Decode base32hex string. + */ + isc_buffer_init(&target, hash, sizeof(hash) - 1); + result = isc_base32hex_decoderegion(&label, &target); + if (result != ISC_R_SUCCESS) { + return; + } + + hash[isc_buffer_usedlength(&target)] = 0; + + exists = hashlist_exists(hashlist, hash); + + /* + * Verify that the NSEC3 parameters match the current ones + * otherwise we are dealing with a different NSEC3 chain. + */ + dns_rdataset_init(&rdataset); + dns_rdataset_init(&delrdataset); + + result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_nsec3, + 0, 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) { + return; + } + + /* + * Delete any NSEC3 records which are not part of the current + * NSEC3 chain. + */ + for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + dns_rdata_init(&rdata); + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &nsec3, NULL); + check_result(result, "dns_rdata_tostruct"); + if (exists && nsec3.hash == hashalg && + nsec3.iterations == iterations && + nsec3.salt_length == salt_len && + isc_safe_memequal(nsec3.salt, salt, salt_len)) + { + continue; + } + dns_rdatalist_init(&rdatalist); + rdatalist.rdclass = rdata.rdclass; + rdatalist.type = rdata.type; + if (set_maxttl) { + rdatalist.ttl = ISC_MIN(rdataset.ttl, maxttl); + } + dns_rdata_init(&delrdata); + dns_rdata_clone(&rdata, &delrdata); + ISC_LIST_APPEND(rdatalist.rdata, &delrdata, link); + result = dns_rdatalist_tordataset(&rdatalist, &delrdataset); + check_result(result, "dns_rdatalist_tordataset()"); + result = dns_db_subtractrdataset(gdb, node, gversion, + &delrdataset, 0, NULL); + dns_rdataset_disassociate(&delrdataset); + if (result != ISC_R_SUCCESS && result != DNS_R_NXRRSET) { + check_result(result, "dns_db_subtractrdataset(NSEC3)"); + } + delete_rrsigs = true; + } + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_NOMORE) { + check_result(result, "dns_rdataset_first/next"); + } + + if (!delete_rrsigs) { + return; + } + /* + * Delete the NSEC3 RRSIGs + */ + result = dns_db_deleterdataset(gdb, node, gversion, dns_rdatatype_rrsig, + dns_rdatatype_nsec3); + if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) { + check_result(result, "dns_db_deleterdataset(RRSIG(NSEC3))"); + } +} + +static void +rrset_cleanup(dns_name_t *name, dns_rdataset_t *rdataset, dns_diff_t *add, + dns_diff_t *del) { + isc_result_t result; + unsigned int count1 = 0; + dns_rdataset_t tmprdataset; + char namestr[DNS_NAME_FORMATSIZE]; + char typestr[DNS_RDATATYPE_FORMATSIZE]; + + dns_name_format(name, namestr, sizeof(namestr)); + dns_rdatatype_format(rdataset->type, typestr, sizeof(typestr)); + + dns_rdataset_init(&tmprdataset); + for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) + { + dns_rdata_t rdata1 = DNS_RDATA_INIT; + unsigned int count2 = 0; + + count1++; + dns_rdataset_current(rdataset, &rdata1); + dns_rdataset_clone(rdataset, &tmprdataset); + for (result = dns_rdataset_first(&tmprdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&tmprdataset)) + { + dns_rdata_t rdata2 = DNS_RDATA_INIT; + dns_difftuple_t *tuple = NULL; + count2++; + dns_rdataset_current(&tmprdataset, &rdata2); + if (count1 < count2 && + dns_rdata_casecompare(&rdata1, &rdata2) == 0) + { + vbprintf(2, "removing duplicate at %s/%s\n", + namestr, typestr); + result = dns_difftuple_create( + mctx, DNS_DIFFOP_DELRESIGN, name, + rdataset->ttl, &rdata2, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(del, &tuple); + } else if (set_maxttl && rdataset->ttl > maxttl) { + vbprintf(2, + "reducing ttl of %s/%s " + "from %d to %d\n", + namestr, typestr, rdataset->ttl, + maxttl); + result = dns_difftuple_create( + mctx, DNS_DIFFOP_DELRESIGN, name, + rdataset->ttl, &rdata2, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(del, &tuple); + tuple = NULL; + result = dns_difftuple_create( + mctx, DNS_DIFFOP_ADDRESIGN, name, + maxttl, &rdata2, &tuple); + check_result(result, "dns_difftuple_create"); + dns_diff_append(add, &tuple); + } + } + dns_rdataset_disassociate(&tmprdataset); + } +} + +static void +cleanup_zone(void) { + isc_result_t result; + dns_dbiterator_t *dbiter = NULL; + dns_rdatasetiter_t *rdsiter = NULL; + dns_diff_t add, del; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_fixedname_t fname; + dns_name_t *name; + + dns_diff_init(mctx, &add); + dns_diff_init(mctx, &del); + name = dns_fixedname_initname(&fname); + dns_rdataset_init(&rdataset); + + result = dns_db_createiterator(gdb, 0, &dbiter); + check_result(result, "dns_db_createiterator()"); + + for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS; + result = dns_dbiterator_next(dbiter)) + { + result = dns_dbiterator_current(dbiter, &node, name); + check_dns_dbiterator_current(result); + result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, + &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) + { + dns_rdatasetiter_current(rdsiter, &rdataset); + rrset_cleanup(name, &rdataset, &add, &del); + dns_rdataset_disassociate(&rdataset); + } + if (result != ISC_R_NOMORE) { + fatal("rdatasets iteration failed."); + } + dns_rdatasetiter_destroy(&rdsiter); + dns_db_detachnode(gdb, &node); + } + if (result != ISC_R_NOMORE) { + fatal("zone iteration failed."); + } + + result = dns_diff_applysilently(&del, gdb, gversion); + check_result(result, "dns_diff_applysilently"); + + result = dns_diff_applysilently(&add, gdb, gversion); + check_result(result, "dns_diff_applysilently"); + + dns_diff_clear(&del); + dns_diff_clear(&add); + dns_dbiterator_destroy(&dbiter); +} + +/* + * Generate NSEC3 records for the zone. + */ +static void +nsec3ify(unsigned int hashalg, dns_iterations_t iterations, + const unsigned char *salt, size_t salt_len, hashlist_t *hashlist) { + dns_dbiterator_t *dbiter = NULL; + dns_dbnode_t *node = NULL, *nextnode = NULL; + dns_fixedname_t fname, fnextname, fzonecut; + dns_name_t *name, *nextname, *zonecut; + dns_rdataset_t rdataset; + int order; + bool active; + bool done = false; + isc_result_t result; + uint32_t nsttl = 0; + unsigned int count, nlabels; + + dns_rdataset_init(&rdataset); + name = dns_fixedname_initname(&fname); + nextname = dns_fixedname_initname(&fnextname); + zonecut = NULL; + + /* + * Walk the zone generating the hash names. + */ + result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter); + check_result(result, "dns_db_createiterator()"); + + result = dns_dbiterator_first(dbiter); + check_result(result, "dns_dbiterator_first()"); + + while (!done) { + result = dns_dbiterator_current(dbiter, &node, name); + check_dns_dbiterator_current(result); + /* + * Skip out-of-zone records. + */ + if (!dns_name_issubdomain(name, gorigin)) { + result = dns_dbiterator_next(dbiter); + if (result == ISC_R_NOMORE) { + done = true; + } else { + check_result(result, "dns_dbiterator_next()"); + } + dns_db_detachnode(gdb, &node); + continue; + } + + if (dns_name_equal(name, gorigin)) { + remove_records(node, dns_rdatatype_nsec, true); + /* Clean old rrsigs at apex. */ + (void)active_node(node); + } + + if (has_dname(gdb, gversion, node)) { + zonecut = savezonecut(&fzonecut, name); + } + + result = dns_dbiterator_next(dbiter); + nextnode = NULL; + while (result == ISC_R_SUCCESS) { + result = dns_dbiterator_current(dbiter, &nextnode, + nextname); + check_dns_dbiterator_current(result); + active = active_node(nextnode); + if (!active) { + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + if (!dns_name_issubdomain(nextname, gorigin) || + (zonecut != NULL && + dns_name_issubdomain(nextname, zonecut))) + { + remove_sigs(nextnode, false, 0); + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + if (is_delegation(gdb, gversion, gorigin, nextname, + nextnode, &nsttl)) + { + zonecut = savezonecut(&fzonecut, nextname); + remove_sigs(nextnode, true, 0); + if (generateds) { + add_ds(nextname, nextnode, nsttl); + } + if (OPTOUT(nsec3flags) && + !secure(nextname, nextnode)) + { + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + } else if (has_dname(gdb, gversion, nextnode)) { + zonecut = savezonecut(&fzonecut, nextname); + } + dns_db_detachnode(gdb, &nextnode); + break; + } + if (result == ISC_R_NOMORE) { + dns_name_copynf(gorigin, nextname); + done = true; + } else if (result != ISC_R_SUCCESS) { + fatal("iterating through the database failed: %s", + isc_result_totext(result)); + } + dns_name_downcase(name, name, NULL); + hashlist_add_dns_name(hashlist, name, hashalg, iterations, salt, + salt_len, false); + dns_db_detachnode(gdb, &node); + /* + * Add hashes for empty nodes. Use closest encloser logic. + * The closest encloser either has data or is a empty + * node for another span so we don't add + * it here. Empty labels on nextname are within the span. + */ + dns_name_downcase(nextname, nextname, NULL); + dns_name_fullcompare(name, nextname, &order, &nlabels); + addnowildcardhash(hashlist, name, hashalg, iterations, salt, + salt_len); + count = dns_name_countlabels(nextname); + while (count > nlabels + 1) { + count--; + dns_name_split(nextname, count, NULL, nextname); + hashlist_add_dns_name(hashlist, nextname, hashalg, + iterations, salt, salt_len, + false); + addnowildcardhash(hashlist, nextname, hashalg, + iterations, salt, salt_len); + } + } + dns_dbiterator_destroy(&dbiter); + + /* + * We have all the hashes now so we can sort them. + */ + hashlist_sort(hashlist); + + /* + * Check for duplicate hashes. If found the salt needs to + * be changed. + */ + if (hashlist_hasdup(hashlist)) { + fatal("Duplicate hash detected. Pick a different salt."); + } + + /* + * Generate the nsec3 records. + */ + zonecut = NULL; + done = false; + + addnsec3param(salt, salt_len, iterations); + + /* + * Clean out NSEC3 records which don't match this chain. + */ + result = dns_db_createiterator(gdb, DNS_DB_NSEC3ONLY, &dbiter); + check_result(result, "dns_db_createiterator()"); + + for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS; + result = dns_dbiterator_next(dbiter)) + { + result = dns_dbiterator_current(dbiter, &node, name); + check_dns_dbiterator_current(result); + nsec3clean(name, node, hashalg, iterations, salt, salt_len, + hashlist); + dns_db_detachnode(gdb, &node); + } + dns_dbiterator_destroy(&dbiter); + + /* + * Generate / complete the new chain. + */ + result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter); + check_result(result, "dns_db_createiterator()"); + + result = dns_dbiterator_first(dbiter); + check_result(result, "dns_dbiterator_first()"); + + while (!done) { + result = dns_dbiterator_current(dbiter, &node, name); + check_dns_dbiterator_current(result); + /* + * Skip out-of-zone records. + */ + if (!dns_name_issubdomain(name, gorigin)) { + result = dns_dbiterator_next(dbiter); + if (result == ISC_R_NOMORE) { + done = true; + } else { + check_result(result, "dns_dbiterator_next()"); + } + dns_db_detachnode(gdb, &node); + continue; + } + + if (has_dname(gdb, gversion, node)) { + zonecut = savezonecut(&fzonecut, name); + } + + result = dns_dbiterator_next(dbiter); + nextnode = NULL; + while (result == ISC_R_SUCCESS) { + result = dns_dbiterator_current(dbiter, &nextnode, + nextname); + check_dns_dbiterator_current(result); + active = active_node(nextnode); + if (!active) { + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + if (!dns_name_issubdomain(nextname, gorigin) || + (zonecut != NULL && + dns_name_issubdomain(nextname, zonecut))) + { + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + if (is_delegation(gdb, gversion, gorigin, nextname, + nextnode, NULL)) + { + zonecut = savezonecut(&fzonecut, nextname); + if (OPTOUT(nsec3flags) && + !secure(nextname, nextnode)) + { + dns_db_detachnode(gdb, &nextnode); + result = dns_dbiterator_next(dbiter); + continue; + } + } else if (has_dname(gdb, gversion, nextnode)) { + zonecut = savezonecut(&fzonecut, nextname); + } + dns_db_detachnode(gdb, &nextnode); + break; + } + if (result == ISC_R_NOMORE) { + dns_name_copynf(gorigin, nextname); + done = true; + } else if (result != ISC_R_SUCCESS) { + fatal("iterating through the database failed: %s", + isc_result_totext(result)); + } + /* + * We need to pause here to release the lock on the database. + */ + dns_dbiterator_pause(dbiter); + addnsec3(name, node, salt, salt_len, iterations, hashlist, + zone_soa_min_ttl); + dns_db_detachnode(gdb, &node); + /* + * Add NSEC3's for empty nodes. Use closest encloser logic. + */ + dns_name_fullcompare(name, nextname, &order, &nlabels); + count = dns_name_countlabels(nextname); + while (count > nlabels + 1) { + count--; + dns_name_split(nextname, count, NULL, nextname); + addnsec3(nextname, NULL, salt, salt_len, iterations, + hashlist, zone_soa_min_ttl); + } + } + dns_dbiterator_destroy(&dbiter); +} + +/*% + * Load the zone file from disk + */ +static void +loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) { + isc_buffer_t b; + int len; + dns_fixedname_t fname; + dns_name_t *name; + isc_result_t result; + + len = strlen(origin); + isc_buffer_init(&b, origin, len); + isc_buffer_add(&b, len); + + name = dns_fixedname_initname(&fname); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fatal("failed converting name '%s' to dns format: %s", origin, + isc_result_totext(result)); + } + + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0, + NULL, db); + check_result(result, "dns_db_create()"); + + result = dns_db_load(*db, file, inputformat, 0); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { + fatal("failed loading zone from '%s': %s", file, + isc_result_totext(result)); + } +} + +/*% + * Finds all public zone keys in the zone, and attempts to load the + * private keys from disk. + */ +static void +loadzonekeys(bool preserve_keys, bool load_public) { + dns_dbnode_t *node; + dns_dbversion_t *currentversion = NULL; + isc_result_t result; + dns_rdataset_t rdataset, keysigs, soasigs; + + node = NULL; + result = dns_db_findnode(gdb, gorigin, false, &node); + if (result != ISC_R_SUCCESS) { + fatal("failed to find the zone's origin: %s", + isc_result_totext(result)); + } + + dns_db_currentversion(gdb, ¤tversion); + + dns_rdataset_init(&rdataset); + dns_rdataset_init(&soasigs); + dns_rdataset_init(&keysigs); + + /* Make note of the keys which signed the SOA, if any */ + result = dns_db_findrdataset(gdb, node, currentversion, + dns_rdatatype_soa, 0, 0, &rdataset, + &soasigs); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + /* Preserve the TTL of the DNSKEY RRset, if any */ + dns_rdataset_disassociate(&rdataset); + result = dns_db_findrdataset(gdb, node, currentversion, + dns_rdatatype_dnskey, 0, 0, &rdataset, + &keysigs); + + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + if (set_keyttl && keyttl != rdataset.ttl) { + fprintf(stderr, + "User-specified TTL %u conflicts " + "with existing DNSKEY RRset TTL.\n", + keyttl); + fprintf(stderr, + "Imported keys will use the RRSet " + "TTL %u instead.\n", + rdataset.ttl); + } + keyttl = rdataset.ttl; + + /* Load keys corresponding to the existing DNSKEY RRset. */ + result = dns_dnssec_keylistfromrdataset( + gorigin, directory, mctx, &rdataset, &keysigs, &soasigs, + preserve_keys, load_public, &keylist); + if (result != ISC_R_SUCCESS) { + fatal("failed to load the zone keys: %s", + isc_result_totext(result)); + } + +cleanup: + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + if (dns_rdataset_isassociated(&keysigs)) { + dns_rdataset_disassociate(&keysigs); + } + if (dns_rdataset_isassociated(&soasigs)) { + dns_rdataset_disassociate(&soasigs); + } + dns_db_detachnode(gdb, &node); + dns_db_closeversion(gdb, ¤tversion, false); +} + +static void +loadexplicitkeys(char *keyfiles[], int n, bool setksk) { + isc_result_t result; + int i; + + for (i = 0; i < n; i++) { + dns_dnsseckey_t *key = NULL; + dst_key_t *newkey = NULL; + + result = dst_key_fromnamedfile( + keyfiles[i], directory, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, mctx, &newkey); + if (result != ISC_R_SUCCESS) { + fatal("cannot load dnskey %s: %s", keyfiles[i], + isc_result_totext(result)); + } + + if (!dns_name_equal(gorigin, dst_key_name(newkey))) { + fatal("key %s not at origin\n", keyfiles[i]); + } + + if (!dst_key_isprivate(newkey)) { + fatal("cannot sign zone with non-private dnskey %s", + keyfiles[i]); + } + + /* Skip any duplicates */ + for (key = ISC_LIST_HEAD(keylist); key != NULL; + key = ISC_LIST_NEXT(key, link)) + { + if (dst_key_id(key->key) == dst_key_id(newkey) && + dst_key_alg(key->key) == dst_key_alg(newkey)) + { + break; + } + } + + if (key == NULL) { + /* We haven't seen this key before */ + dns_dnsseckey_create(mctx, &newkey, &key); + ISC_LIST_APPEND(keylist, key, link); + key->source = dns_keysource_user; + } else { + dst_key_free(&key->key); + key->key = newkey; + } + + key->force_publish = true; + key->force_sign = true; + + if (setksk) { + key->ksk = true; + } + } +} + +static void +report(const char *format, ...) { + if (!quiet) { + FILE *out = output_stdout ? stderr : stdout; + char buf[4096]; + va_list args; + + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + fprintf(out, "%s\n", buf); + } +} + +static void +clear_keylist(dns_dnsseckeylist_t *list) { + dns_dnsseckey_t *key; + while (!ISC_LIST_EMPTY(*list)) { + key = ISC_LIST_HEAD(*list); + ISC_LIST_UNLINK(*list, key, link); + dns_dnsseckey_destroy(mctx, &key); + } +} + +static void +build_final_keylist(void) { + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_dbversion_t *ver = NULL; + dns_diff_t diff; + dns_dnsseckeylist_t rmkeys, matchkeys; + char name[DNS_NAME_FORMATSIZE]; + dns_rdataset_t cdsset, cdnskeyset, soaset; + + ISC_LIST_INIT(rmkeys); + ISC_LIST_INIT(matchkeys); + + dns_rdataset_init(&soaset); + dns_rdataset_init(&cdsset); + dns_rdataset_init(&cdnskeyset); + + /* + * Find keys that match this zone in the key repository. + */ + result = dns_dnssec_findmatchingkeys(gorigin, directory, now, mctx, + &matchkeys); + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + } + check_result(result, "dns_dnssec_findmatchingkeys"); + + result = dns_db_newversion(gdb, &ver); + check_result(result, "dns_db_newversion"); + + result = dns_db_getoriginnode(gdb, &node); + check_result(result, "dns_db_getoriginnode"); + + /* Get the CDS rdataset */ + result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_cds, + dns_rdatatype_none, 0, &cdsset, NULL); + if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdsset)) { + dns_rdataset_disassociate(&cdsset); + } + + /* Get the CDNSKEY rdataset */ + result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_cdnskey, + dns_rdatatype_none, 0, &cdnskeyset, NULL); + if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdnskeyset)) { + dns_rdataset_disassociate(&cdnskeyset); + } + + dns_diff_init(mctx, &diff); + + /* + * Update keylist with information from from the key repository. + */ + dns_dnssec_updatekeys(&keylist, &matchkeys, NULL, gorigin, keyttl, + &diff, mctx, report); + + /* + * Update keylist with sync records. + */ + dns_dnssec_syncupdate(&keylist, &rmkeys, &cdsset, &cdnskeyset, now, + keyttl, &diff, mctx); + + dns_name_format(gorigin, name, sizeof(name)); + + result = dns_diff_applysilently(&diff, gdb, ver); + if (result != ISC_R_SUCCESS) { + fatal("failed to update DNSKEY RRset at node '%s': %s", name, + isc_result_totext(result)); + } + + dns_db_detachnode(gdb, &node); + dns_db_closeversion(gdb, &ver, true); + + dns_diff_clear(&diff); + + if (dns_rdataset_isassociated(&cdsset)) { + dns_rdataset_disassociate(&cdsset); + } + if (dns_rdataset_isassociated(&cdnskeyset)) { + dns_rdataset_disassociate(&cdnskeyset); + } + + clear_keylist(&rmkeys); + clear_keylist(&matchkeys); +} + +static void +warnifallksk(dns_db_t *db) { + dns_dbversion_t *currentversion = NULL; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_result_t result; + dns_rdata_dnskey_t dnskey; + bool have_non_ksk = false; + + dns_db_currentversion(db, ¤tversion); + + result = dns_db_findnode(db, gorigin, false, &node); + if (result != ISC_R_SUCCESS) { + fatal("failed to find the zone's origin: %s", + isc_result_totext(result)); + } + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, currentversion, + dns_rdatatype_dnskey, 0, 0, &rdataset, + NULL); + if (result != ISC_R_SUCCESS) { + fatal("failed to find keys at the zone apex: %s", + isc_result_totext(result)); + } + result = dns_rdataset_first(&rdataset); + check_result(result, "dns_rdataset_first"); + while (result == ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &dnskey, NULL); + check_result(result, "dns_rdata_tostruct"); + if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0) { + have_non_ksk = true; + result = ISC_R_NOMORE; + } else { + result = dns_rdataset_next(&rdataset); + } + dns_rdata_freestruct(&dnskey); + } + dns_rdataset_disassociate(&rdataset); + dns_db_detachnode(db, &node); + dns_db_closeversion(db, ¤tversion, false); + if (!have_non_ksk && !ignore_kskflag) { + if (disable_zone_check) { + fprintf(stderr, + "%s: warning: No non-KSK DNSKEY found; " + "supply a ZSK or use '-z'.\n", + program); + } else { + fatal("No non-KSK DNSKEY found; " + "supply a ZSK or use '-z'."); + } + } +} + +static void +set_nsec3params(bool update, bool set_salt, bool set_optout, bool set_iter) { + isc_result_t result; + dns_dbversion_t *ver = NULL; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_nsec3_t nsec3; + dns_fixedname_t fname; + dns_name_t *hashname; + unsigned char orig_salt[255]; + size_t orig_saltlen; + dns_hash_t orig_hash; + uint16_t orig_iter; + + dns_db_currentversion(gdb, &ver); + dns_rdataset_init(&rdataset); + + orig_saltlen = sizeof(orig_salt); + result = dns_db_getnsec3parameters(gdb, ver, &orig_hash, NULL, + &orig_iter, orig_salt, + &orig_saltlen); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + nsec_datatype = dns_rdatatype_nsec3; + + if (!update && set_salt) { + if (salt_length != orig_saltlen || + !isc_safe_memequal(saltbuf, orig_salt, salt_length)) + { + fatal("An NSEC3 chain exists with a different salt. " + "Use -u to update it."); + } + } else if (!set_salt) { + salt_length = orig_saltlen; + memmove(saltbuf, orig_salt, orig_saltlen); + gsalt = saltbuf; + } + + if (!update && set_iter) { + if (nsec3iter != orig_iter) { + fatal("An NSEC3 chain exists with different " + "iterations. Use -u to update it."); + } + } else if (!set_iter) { + nsec3iter = orig_iter; + } + + /* + * Find an NSEC3 record to get the current OPTOUT value. + * (This assumes all NSEC3 records agree.) + */ + + hashname = dns_fixedname_initname(&fname); + result = dns_nsec3_hashname(&fname, NULL, NULL, gorigin, gorigin, + dns_hash_sha1, orig_iter, orig_salt, + orig_saltlen); + check_result(result, "dns_nsec3_hashname"); + + result = dns_db_findnsec3node(gdb, hashname, false, &node); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_nsec3, 0, 0, + &rdataset, NULL); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = dns_rdataset_first(&rdataset); + check_result(result, "dns_rdataset_first"); + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &nsec3, NULL); + check_result(result, "dns_rdata_tostruct"); + + if (!update && set_optout) { + if (nsec3flags != nsec3.flags) { + fatal("An NSEC3 chain exists with%s OPTOUT. " + "Use -u -%s to %s it.", + OPTOUT(nsec3.flags) ? "" : "out", + OPTOUT(nsec3.flags) ? "AA" : "A", + OPTOUT(nsec3.flags) ? "clear" : "set"); + } + } else if (!set_optout) { + nsec3flags = nsec3.flags; + } + + dns_rdata_freestruct(&nsec3); + +cleanup: + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + if (node != NULL) { + dns_db_detachnode(gdb, &node); + } + dns_db_closeversion(gdb, &ver, false); +} + +static void +writeset(const char *prefix, dns_rdatatype_t type) { + char *filename; + char namestr[DNS_NAME_FORMATSIZE]; + dns_db_t *db = NULL; + dns_dbversion_t *dbversion = NULL; + dns_diff_t diff; + dns_difftuple_t *tuple = NULL; + dns_name_t *name; + dns_rdata_t rdata, ds; + bool have_ksk = false; + bool have_non_ksk = false; + isc_buffer_t b; + isc_buffer_t namebuf; + isc_region_t r; + isc_result_t result; + dns_dnsseckey_t *key, *curr; + unsigned char dsbuf[DNS_DS_BUFFERSIZE]; + unsigned char keybuf[DST_KEY_MAXSIZE]; + unsigned int filenamelen; + const dns_master_style_t *style = (type == dns_rdatatype_dnskey) + ? masterstyle + : dsstyle; + + isc_buffer_init(&namebuf, namestr, sizeof(namestr)); + result = dns_name_tofilenametext(gorigin, false, &namebuf); + check_result(result, "dns_name_tofilenametext"); + isc_buffer_putuint8(&namebuf, 0); + filenamelen = strlen(prefix) + strlen(namestr) + 1; + if (dsdir != NULL) { + filenamelen += strlen(dsdir) + 1; + } + filename = isc_mem_get(mctx, filenamelen); + if (dsdir != NULL) { + snprintf(filename, filenamelen, "%s/", dsdir); + } else { + filename[0] = 0; + } + strlcat(filename, prefix, filenamelen); + strlcat(filename, namestr, filenamelen); + + dns_diff_init(mctx, &diff); + + name = gorigin; + + for (key = ISC_LIST_HEAD(keylist); key != NULL; + key = ISC_LIST_NEXT(key, link)) + { + if (REVOKE(key->key)) { + continue; + } + if (isksk(key)) { + have_ksk = true; + have_non_ksk = false; + } else { + have_ksk = false; + have_non_ksk = true; + } + for (curr = ISC_LIST_HEAD(keylist); curr != NULL; + curr = ISC_LIST_NEXT(curr, link)) + { + if (dst_key_alg(key->key) != dst_key_alg(curr->key)) { + continue; + } + if (REVOKE(curr->key)) { + continue; + } + if (isksk(curr)) { + have_ksk = true; + } else { + have_non_ksk = true; + } + } + if (have_ksk && have_non_ksk && !isksk(key)) { + continue; + } + dns_rdata_init(&rdata); + dns_rdata_init(&ds); + isc_buffer_init(&b, keybuf, sizeof(keybuf)); + result = dst_key_todns(key->key, &b); + check_result(result, "dst_key_todns"); + isc_buffer_usedregion(&b, &r); + dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_dnskey, &r); + if (type != dns_rdatatype_dnskey) { + result = dns_ds_buildrdata(gorigin, &rdata, + DNS_DSDIGEST_SHA256, dsbuf, + &ds); + check_result(result, "dns_ds_buildrdata"); + result = dns_difftuple_create(mctx, + DNS_DIFFOP_ADDRESIGN, + name, 0, &ds, &tuple); + } else { + result = dns_difftuple_create( + mctx, DNS_DIFFOP_ADDRESIGN, gorigin, + zone_soa_min_ttl, &rdata, &tuple); + } + check_result(result, "dns_difftuple_create"); + dns_diff_append(&diff, &tuple); + } + + result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone, + gclass, 0, NULL, &db); + check_result(result, "dns_db_create"); + + result = dns_db_newversion(db, &dbversion); + check_result(result, "dns_db_newversion"); + + result = dns_diff_apply(&diff, db, dbversion); + check_result(result, "dns_diff_apply"); + dns_diff_clear(&diff); + + result = dns_master_dump(mctx, db, dbversion, style, filename, + dns_masterformat_text, NULL); + check_result(result, "dns_master_dump"); + + isc_mem_put(mctx, filename, filenamelen); + + dns_db_closeversion(db, &dbversion, false); + dns_db_detach(&db); +} + +static void +print_time(FILE *fp) { + time_t currenttime = time(NULL); + struct tm t, *tm = localtime_r(¤ttime, &t); + unsigned int flen; + char timebuf[80]; + + if (tm == NULL || outputformat != dns_masterformat_text) { + return; + } + + flen = strftime(timebuf, sizeof(timebuf), "%a %b %e %H:%M:%S %Y", tm); + INSIST(flen > 0U && flen < sizeof(timebuf)); + fprintf(fp, "; File written on %s\n", timebuf); +} + +static void +print_version(FILE *fp) { + if (outputformat != dns_masterformat_text) { + return; + } + + fprintf(fp, "; dnssec_signzone version " VERSION "\n"); +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\t%s [options] zonefile [keys]\n", program); + + fprintf(stderr, "\n"); + + fprintf(stderr, "Version: %s\n", VERSION); + + fprintf(stderr, "Options: (default value in parenthesis) \n"); + fprintf(stderr, "\t-S:\tsmart signing: automatically finds key files\n" + "\t\tfor the zone and determines how they are to " + "be used\n"); + fprintf(stderr, "\t-K directory:\n"); + fprintf(stderr, "\t\tdirectory to find key files (.)\n"); + fprintf(stderr, "\t-d directory:\n"); + fprintf(stderr, "\t\tdirectory to find dsset-* files (.)\n"); + fprintf(stderr, "\t-g:\t"); + fprintf(stderr, "update DS records based on child zones' " + "dsset-* files\n"); + fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n"); + fprintf(stderr, "\t\tRRSIG start time " + "- absolute|offset (now - 1 hour)\n"); + fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n"); + fprintf(stderr, "\t\tRRSIG end time " + "- absolute|from start|from now " + "(now + 30 days)\n"); + fprintf(stderr, "\t-X [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n"); + fprintf(stderr, "\t\tDNSKEY RRSIG end " + "- absolute|from start|from now " + "(matches -e)\n"); + fprintf(stderr, "\t-i interval:\n"); + fprintf(stderr, "\t\tcycle interval - resign " + "if < interval from end ( (end-start)/4 )\n"); + fprintf(stderr, "\t-j jitter:\n"); + fprintf(stderr, "\t\trandomize signature end time up to jitter " + "seconds\n"); + fprintf(stderr, "\t-v debuglevel (0)\n"); + fprintf(stderr, "\t-q quiet\n"); + fprintf(stderr, "\t-V:\tprint version information\n"); + fprintf(stderr, "\t-o origin:\n"); + fprintf(stderr, "\t\tzone origin (name of zonefile)\n"); + fprintf(stderr, "\t-f outfile:\n"); + fprintf(stderr, "\t\tfile the signed zone is written in " + "(zonefile + .signed)\n"); + fprintf(stderr, "\t-I format:\n"); + fprintf(stderr, "\t\tfile format of input zonefile (text)\n"); + fprintf(stderr, "\t-O format:\n"); + fprintf(stderr, "\t\tfile format of signed zone file (text)\n"); + fprintf(stderr, "\t-N format:\n"); + fprintf(stderr, "\t\tsoa serial format of signed zone file (keep)\n"); + fprintf(stderr, "\t-D:\n"); + fprintf(stderr, "\t\toutput only DNSSEC-related records\n"); + fprintf(stderr, "\t-a:\t"); + fprintf(stderr, "verify generated signatures\n"); + fprintf(stderr, "\t-c class (IN)\n"); + fprintf(stderr, "\t-E engine:\n"); +#if USE_PKCS11 + fprintf(stderr, + "\t\tpath to PKCS#11 provider library " + "(default is %s)\n", + PK11_LIB_LOCATION); +#else /* if USE_PKCS11 */ + fprintf(stderr, "\t\tname of an OpenSSL engine to use\n"); +#endif /* if USE_PKCS11 */ + fprintf(stderr, "\t-P:\t"); + fprintf(stderr, "disable post-sign verification\n"); + fprintf(stderr, "\t-Q:\t"); + fprintf(stderr, "remove signatures from keys that are no " + "longer active\n"); + fprintf(stderr, "\t-R:\t"); + fprintf(stderr, "remove signatures from keys that no longer exist\n"); + fprintf(stderr, "\t-T TTL:\tTTL for newly added DNSKEYs\n"); + fprintf(stderr, "\t-t:\t"); + fprintf(stderr, "print statistics\n"); + fprintf(stderr, "\t-u:\t"); + fprintf(stderr, "update or replace an existing NSEC/NSEC3 chain\n"); + fprintf(stderr, "\t-x:\tsign DNSKEY record with KSKs only, not ZSKs\n"); + fprintf(stderr, "\t-z:\tsign all records with KSKs\n"); + fprintf(stderr, "\t-C:\tgenerate a keyset file, for compatibility\n" + "\t\twith older versions of dnssec-signzone -g\n"); + fprintf(stderr, "\t-n ncpus (number of cpus present)\n"); + fprintf(stderr, "\t-k key_signing_key\n"); + fprintf(stderr, "\t-3 NSEC3 salt\n"); + fprintf(stderr, "\t-H NSEC3 iterations (10)\n"); + fprintf(stderr, "\t-A NSEC3 optout\n"); + + fprintf(stderr, "\n"); + + fprintf(stderr, "Signing Keys: "); + fprintf(stderr, "(default: all zone keys that have private keys)\n"); + fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n"); + + exit(0); +} + +static void +removetempfile(void) { + if (removefile) { + isc_file_remove(tempfile); + } +} + +static void +print_stats(isc_time_t *timer_start, isc_time_t *timer_finish, + isc_time_t *sign_start, isc_time_t *sign_finish) { + uint64_t time_us; /* Time in microseconds */ + uint64_t time_ms; /* Time in milliseconds */ + uint64_t sig_ms; /* Signatures per millisecond */ + FILE *out = output_stdout ? stderr : stdout; + + fprintf(out, "Signatures generated: %10u\n", nsigned); + fprintf(out, "Signatures retained: %10u\n", nretained); + fprintf(out, "Signatures dropped: %10u\n", ndropped); + fprintf(out, "Signatures successfully verified: %10u\n", nverified); + fprintf(out, + "Signatures unsuccessfully " + "verified: %10u\n", + nverifyfailed); + + time_us = isc_time_microdiff(sign_finish, sign_start); + time_ms = time_us / 1000; + fprintf(out, "Signing time in seconds: %7u.%03u\n", + (unsigned int)(time_ms / 1000), (unsigned int)(time_ms % 1000)); + if (time_us > 0) { + sig_ms = ((uint64_t)nsigned * 1000000000) / time_us; + fprintf(out, "Signatures per second: %7u.%03u\n", + (unsigned int)sig_ms / 1000, + (unsigned int)sig_ms % 1000); + } + + time_us = isc_time_microdiff(timer_finish, timer_start); + time_ms = time_us / 1000; + fprintf(out, "Runtime in seconds: %7u.%03u\n", + (unsigned int)(time_ms / 1000), (unsigned int)(time_ms % 1000)); +} + +int +main(int argc, char *argv[]) { + int i, ch; + char *startstr = NULL, *endstr = NULL, *classname = NULL; + char *dnskey_endstr = NULL; + char *origin = NULL, *file = NULL, *output = NULL; + char *inputformatstr = NULL, *outputformatstr = NULL; + char *serialformatstr = NULL; + char *dskeyfile[MAXDSKEYS]; + int ndskeys = 0; + char *endp; + isc_time_t timer_start, timer_finish; + isc_time_t sign_start, sign_finish; + dns_dnsseckey_t *key; + isc_result_t result, vresult; + isc_log_t *log = NULL; + const char *engine = NULL; + bool free_output = false; + int tempfilelen = 0; + dns_rdataclass_t rdclass; + isc_task_t **tasks = NULL; + hashlist_t hashlist; + bool make_keyset = false; + bool set_salt = false; + bool set_optout = false; + bool set_iter = false; + bool nonsecify = false; + + atomic_init(&shuttingdown, false); + atomic_init(&finished, false); + + /* Unused letters: Bb G J q Yy (and F is reserved). */ +#define CMDLINE_FLAGS \ + "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:M:n:N:o:O:PpQqRr:s:ST:tuUv:VX:" \ + "xzZ:" + + /* + * Process memory debugging argument first. + */ + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case 'm': + if (strcasecmp(isc_commandline_argument, "record") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + } + if (strcasecmp(isc_commandline_argument, "trace") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGTRACE; + } + if (strcasecmp(isc_commandline_argument, "usage") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; + } + if (strcasecmp(isc_commandline_argument, "size") == 0) { + isc_mem_debugging |= ISC_MEM_DEBUGSIZE; + } + if (strcasecmp(isc_commandline_argument, "mctx") == 0) { + isc_mem_debugging |= ISC_MEM_DEBUGCTX; + } + break; + default: + break; + } + } + isc_commandline_reset = true; + +#ifdef _WIN32 + InitSockets(); +#endif /* ifdef _WIN32 */ + + masterstyle = &dns_master_style_explicitttl; + + check_result(isc_app_start(), "isc_app_start"); + + isc_mem_create(&mctx); + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + isc_commandline_errprint = false; + + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case '3': + set_salt = true; + nsec_datatype = dns_rdatatype_nsec3; + if (strcmp(isc_commandline_argument, "-") != 0) { + isc_buffer_t target; + char *sarg; + + sarg = isc_commandline_argument; + isc_buffer_init(&target, saltbuf, + sizeof(saltbuf)); + result = isc_hex_decodestring(sarg, &target); + check_result(result, "isc_hex_decodestring(" + "salt)"); + salt_length = isc_buffer_usedlength(&target); + } + break; + + case 'A': + set_optout = true; + if (OPTOUT(nsec3flags)) { + nsec3flags &= ~DNS_NSEC3FLAG_OPTOUT; + } else { + nsec3flags |= DNS_NSEC3FLAG_OPTOUT; + } + break; + + case 'a': + tryverify = true; + break; + + case 'C': + make_keyset = true; + break; + + case 'c': + classname = isc_commandline_argument; + break; + + case 'd': + dsdir = isc_commandline_argument; + if (strlen(dsdir) == 0U) { + fatal("DS directory must be non-empty string"); + } + result = try_dir(dsdir); + if (result != ISC_R_SUCCESS) { + fatal("cannot open directory %s: %s", dsdir, + isc_result_totext(result)); + } + break; + + case 'D': + output_dnssec_only = true; + break; + + case 'E': + engine = isc_commandline_argument; + break; + + case 'e': + endstr = isc_commandline_argument; + break; + + case 'f': + output = isc_commandline_argument; + if (strcmp(output, "-") == 0) { + output_stdout = true; + } + break; + + case 'g': + generateds = true; + break; + + case 'H': + set_iter = true; + /* too-many is NOT DOCUMENTED */ + if (strcmp(isc_commandline_argument, "too-many") == 0) { + nsec3iter = 151; + no_max_check = true; + break; + } + nsec3iter = strtoul(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("iterations must be numeric"); + } + if (nsec3iter > 0xffffU) { + fatal("iterations too big"); + } + break; + + case 'I': + inputformatstr = isc_commandline_argument; + break; + + case 'i': + endp = NULL; + cycle = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0' || cycle < 0) { + fatal("cycle period must be numeric and " + "positive"); + } + break; + + case 'j': + endp = NULL; + jitter = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0' || jitter < 0) { + fatal("jitter must be numeric and positive"); + } + break; + + case 'K': + directory = isc_commandline_argument; + break; + + case 'k': + if (ndskeys == MAXDSKEYS) { + fatal("too many key-signing keys specified"); + } + dskeyfile[ndskeys++] = isc_commandline_argument; + break; + + case 'L': + snset = true; + endp = NULL; + serialnum = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fprintf(stderr, "source serial number " + "must be numeric"); + exit(1); + } + break; + + case 'l': + fatal("-l option (DLV lookaside) is obsolete"); + break; + + case 'M': + endp = NULL; + set_maxttl = true; + maxttl = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fprintf(stderr, "maximum TTL " + "must be numeric"); + exit(1); + } + break; + + case 'm': + break; + + case 'N': + serialformatstr = isc_commandline_argument; + break; + + case 'n': + endp = NULL; + ntasks = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0' || ntasks > INT32_MAX) { + fatal("number of cpus must be numeric"); + } + break; + + case 'O': + outputformatstr = isc_commandline_argument; + break; + + case 'o': + origin = isc_commandline_argument; + break; + + case 'P': + disable_zone_check = true; + break; + + case 'p': + fatal("The -p option has been deprecated.\n"); + break; + + case 'Q': + remove_inactkeysigs = true; + break; + + case 'R': + remove_orphansigs = true; + break; + + case 'r': + fatal("The -r options has been deprecated.\n"); + break; + + case 'S': + smartsign = true; + break; + + case 's': + startstr = isc_commandline_argument; + break; + + case 'T': + endp = NULL; + set_keyttl = true; + keyttl = strtottl(isc_commandline_argument); + break; + + case 't': + printstats = true; + break; + + case 'U': /* Undocumented for testing only. */ + unknownalg = true; + break; + + case 'u': + update_chain = true; + break; + + case 'v': + endp = NULL; + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("verbose level must be numeric"); + } + break; + + case 'q': + quiet = true; + break; + + case 'X': + dnskey_endstr = isc_commandline_argument; + break; + + case 'x': + keyset_kskonly = true; + break; + + case 'z': + ignore_kskflag = true; + break; + + case 'F': + /* Reserved for FIPS mode */ + FALLTHROUGH; + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + } + FALLTHROUGH; + case 'h': + /* Does not return. */ + usage(); + + case 'V': + /* Does not return. */ + version(program); + + case 'Z': /* Undocumented test options */ + if (!strcmp(isc_commandline_argument, "nonsecify")) { + nonsecify = true; + } + break; + + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + result = dst_lib_init(mctx, engine); + if (result != ISC_R_SUCCESS) { + fatal("could not initialize dst: %s", + isc_result_totext(result)); + } + + isc_stdtime_get(&now); + + if (startstr != NULL) { + starttime = strtotime(startstr, now, now, NULL); + } else { + starttime = now - 3600; /* Allow for some clock skew. */ + } + + if (endstr != NULL) { + endtime = strtotime(endstr, now, starttime, NULL); + } else { + endtime = starttime + (30 * 24 * 60 * 60); + } + + if (dnskey_endstr != NULL) { + dnskey_endtime = strtotime(dnskey_endstr, now, starttime, NULL); + if (endstr != NULL && dnskey_endtime == endtime) { + fprintf(stderr, "WARNING: -e and -X were both set, " + "but have identical values.\n"); + } + } else { + dnskey_endtime = endtime; + } + + if (cycle == -1) { + cycle = (endtime - starttime) / 4; + } + + if (ntasks == 0) { + ntasks = isc_os_ncpus() * 2; + } + vbprintf(4, "using %d cpus\n", ntasks); + + rdclass = strtoclass(classname); + + if (directory == NULL) { + directory = "."; + } + + setup_logging(mctx, &log); + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc < 1) { + usage(); + } + + file = argv[0]; + + argc -= 1; + argv += 1; + + if (origin == NULL) { + origin = file; + } + + if (output == NULL) { + size_t size; + free_output = true; + size = strlen(file) + strlen(".signed") + 1; + output = isc_mem_allocate(mctx, size); + snprintf(output, size, "%s.signed", file); + } + + if (inputformatstr != NULL) { + if (strcasecmp(inputformatstr, "text") == 0) { + inputformat = dns_masterformat_text; + } else if (strcasecmp(inputformatstr, "map") == 0) { + inputformat = dns_masterformat_map; + } else if (strcasecmp(inputformatstr, "raw") == 0) { + inputformat = dns_masterformat_raw; + } else if (strncasecmp(inputformatstr, "raw=", 4) == 0) { + inputformat = dns_masterformat_raw; + fprintf(stderr, "WARNING: input format version " + "ignored\n"); + } else { + fatal("unknown file format: %s", inputformatstr); + } + } + + if (outputformatstr != NULL) { + if (strcasecmp(outputformatstr, "text") == 0) { + outputformat = dns_masterformat_text; + } else if (strcasecmp(outputformatstr, "full") == 0) { + outputformat = dns_masterformat_text; + masterstyle = &dns_master_style_full; + } else if (strcasecmp(outputformatstr, "map") == 0) { + outputformat = dns_masterformat_map; + } else if (strcasecmp(outputformatstr, "raw") == 0) { + outputformat = dns_masterformat_raw; + } else if (strncasecmp(outputformatstr, "raw=", 4) == 0) { + char *end; + + outputformat = dns_masterformat_raw; + rawversion = strtol(outputformatstr + 4, &end, 10); + if (end == outputformatstr + 4 || *end != '\0' || + rawversion > 1U) + { + fprintf(stderr, "unknown raw format version\n"); + exit(1); + } + } else { + fatal("unknown file format: %s", outputformatstr); + } + } + + if (serialformatstr != NULL) { + if (strcasecmp(serialformatstr, "keep") == 0) { + serialformat = SOA_SERIAL_KEEP; + } else if (strcasecmp(serialformatstr, "increment") == 0 || + strcasecmp(serialformatstr, "incr") == 0) + { + serialformat = SOA_SERIAL_INCREMENT; + } else if (strcasecmp(serialformatstr, "unixtime") == 0) { + serialformat = SOA_SERIAL_UNIXTIME; + } else if (strcasecmp(serialformatstr, "date") == 0) { + serialformat = SOA_SERIAL_DATE; + } else { + fatal("unknown soa serial format: %s", serialformatstr); + } + } + + if (output_dnssec_only && outputformat != dns_masterformat_text) { + fatal("option -D can only be used with \"-O text\""); + } + + if (output_dnssec_only && serialformat != SOA_SERIAL_KEEP) { + fatal("option -D can only be used with \"-N keep\""); + } + + if (output_dnssec_only && set_maxttl) { + fatal("option -D cannot be used with -M"); + } + + result = dns_master_stylecreate(&dsstyle, DNS_STYLEFLAG_NO_TTL, 0, 24, + 0, 0, 0, 8, 0xffffffff, mctx); + check_result(result, "dns_master_stylecreate"); + + gdb = NULL; + TIME_NOW(&timer_start); + loadzone(file, origin, rdclass, &gdb); + gorigin = dns_db_origin(gdb); + gclass = dns_db_class(gdb); + get_soa_ttls(); + + if (set_maxttl && set_keyttl && keyttl > maxttl) { + fprintf(stderr, + "%s: warning: Specified key TTL %u " + "exceeds maximum zone TTL; reducing to %u\n", + program, keyttl, maxttl); + keyttl = maxttl; + } + + if (!set_keyttl) { + keyttl = soa_ttl; + } + + /* + * Check for any existing NSEC3 parameters in the zone, + * and use them as defaults if -u was not specified. + */ + if (update_chain && !set_optout && !set_iter && !set_salt) { + nsec_datatype = dns_rdatatype_nsec; + } else { + set_nsec3params(update_chain, set_salt, set_optout, set_iter); + } + + /* + * We need to do this early on, as we start messing with the list + * of keys rather early. + */ + ISC_LIST_INIT(keylist); + isc_rwlock_init(&keylist_lock, 0, 0); + + /* + * Fill keylist with: + * 1) Keys listed in the DNSKEY set that have + * private keys associated, *if* no keys were + * set on the command line. + * 2) ZSKs set on the command line + * 3) KSKs set on the command line + * 4) Any keys remaining in the DNSKEY set which + * do not have private keys associated and were + * not specified on the command line. + */ + if (argc == 0 || smartsign) { + loadzonekeys(!smartsign, false); + } + loadexplicitkeys(argv, argc, false); + loadexplicitkeys(dskeyfile, ndskeys, true); + loadzonekeys(!smartsign, true); + + /* + * If we're doing smart signing, look in the key repository for + * key files with metadata, and merge them with the keylist + * we have now. + */ + if (smartsign) { + build_final_keylist(); + } + + /* Now enumerate the key list */ + for (key = ISC_LIST_HEAD(keylist); key != NULL; + key = ISC_LIST_NEXT(key, link)) + { + key->index = keycount++; + } + + if (keycount == 0) { + if (disable_zone_check) { + fprintf(stderr, + "%s: warning: No keys specified " + "or found\n", + program); + } else { + fatal("No signing keys specified or found."); + } + nokeys = true; + } + + warnifallksk(gdb); + + if (IS_NSEC3) { + bool answer; + + hash_length = dns_nsec3_hashlength(dns_hash_sha1); + hashlist_init(&hashlist, dns_db_nodecount(gdb) * 2, + hash_length); + result = dns_nsec_nseconly(gdb, gversion, &answer); + if (result == ISC_R_NOTFOUND) { + fprintf(stderr, + "%s: warning: NSEC3 generation " + "requested with no DNSKEY; ignoring\n", + program); + } else if (result != ISC_R_SUCCESS) { + check_result(result, "dns_nsec_nseconly"); + } else if (answer) { + fatal("NSEC3 generation requested with " + "NSEC-only DNSKEY"); + } + + if (nsec3iter > dns_nsec3_maxiterations()) { + if (no_max_check) { + fprintf(stderr, + "Ignoring max iterations check.\n"); + } else { + fatal("NSEC3 iterations too big. Maximum " + "iterations allowed %u.", + dns_nsec3_maxiterations()); + } + } + } else { + hashlist_init(&hashlist, 0, 0); /* silence clang */ + } + + gversion = NULL; + result = dns_db_newversion(gdb, &gversion); + check_result(result, "dns_db_newversion()"); + + switch (serialformat) { + case SOA_SERIAL_INCREMENT: + setsoaserial(0, dns_updatemethod_increment); + break; + case SOA_SERIAL_UNIXTIME: + setsoaserial(now, dns_updatemethod_unixtime); + break; + case SOA_SERIAL_DATE: + setsoaserial(now, dns_updatemethod_date); + break; + case SOA_SERIAL_KEEP: + default: + /* do nothing */ + break; + } + + /* Remove duplicates and cap TTLs at maxttl */ + cleanup_zone(); + + if (!nonsecify) { + if (IS_NSEC3) { + nsec3ify(dns_hash_sha1, nsec3iter, gsalt, salt_length, + &hashlist); + } else { + nsecify(); + } + } + + if (!nokeys) { + writeset("dsset-", dns_rdatatype_ds); + if (make_keyset) { + writeset("keyset-", dns_rdatatype_dnskey); + } + } + + if (output_stdout) { + outfp = stdout; + if (outputformatstr == NULL) { + masterstyle = &dns_master_style_full; + } + } else { + tempfilelen = strlen(output) + 20; + tempfile = isc_mem_get(mctx, tempfilelen); + + result = isc_file_mktemplate(output, tempfile, tempfilelen); + check_result(result, "isc_file_mktemplate"); + + if (outputformat == dns_masterformat_text) { + result = isc_file_openunique(tempfile, &outfp); + } else { + result = isc_file_bopenunique(tempfile, &outfp); + } + if (result != ISC_R_SUCCESS) { + fatal("failed to open temporary output file: %s", + isc_result_totext(result)); + } + removefile = true; + setfatalcallback(&removetempfile); + } + + print_time(outfp); + print_version(outfp); + + result = isc_managers_create(mctx, ntasks, 0, &netmgr, &taskmgr); + if (result != ISC_R_SUCCESS) { + fatal("failed to create task manager: %s", + isc_result_totext(result)); + } + + master = NULL; + result = isc_task_create(taskmgr, 0, &master); + if (result != ISC_R_SUCCESS) { + fatal("failed to create task: %s", isc_result_totext(result)); + } + + tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *)); + for (i = 0; i < (int)ntasks; i++) { + tasks[i] = NULL; + result = isc_task_create(taskmgr, 0, &tasks[i]); + if (result != ISC_R_SUCCESS) { + fatal("failed to create task: %s", + isc_result_totext(result)); + } + } + + isc_mutex_init(&namelock); + + if (printstats) { + isc_mutex_init(&statslock); + } + + presign(); + TIME_NOW(&sign_start); + signapex(); + if (!atomic_load(&finished)) { + /* + * There is more work to do. Spread it out over multiple + * processors if possible. + */ + for (i = 0; i < (int)ntasks; i++) { + result = isc_app_onrun(mctx, master, startworker, + tasks[i]); + if (result != ISC_R_SUCCESS) { + fatal("failed to start task: %s", + isc_result_totext(result)); + } + } + (void)isc_app_run(); + if (!atomic_load(&finished)) { + fatal("process aborted by user"); + } + } else { + isc_task_detach(&master); + } + atomic_store(&shuttingdown, true); + for (i = 0; i < (int)ntasks; i++) { + isc_task_detach(&tasks[i]); + } + isc_managers_destroy(&netmgr, &taskmgr); + isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *)); + postsign(); + TIME_NOW(&sign_finish); + + if (disable_zone_check) { + vresult = ISC_R_SUCCESS; + } else { + vresult = dns_zoneverify_dnssec(NULL, gdb, gversion, gorigin, + NULL, mctx, ignore_kskflag, + keyset_kskonly, report); + if (vresult != ISC_R_SUCCESS) { + fprintf(output_stdout ? stderr : stdout, + "Zone verification failed (%s)\n", + isc_result_totext(vresult)); + } + } + + if (outputformat != dns_masterformat_text) { + dns_masterrawheader_t header; + dns_master_initrawheader(&header); + if (rawversion == 0U) { + header.flags = DNS_MASTERRAW_COMPAT; + } else if (snset) { + header.flags = DNS_MASTERRAW_SOURCESERIALSET; + header.sourceserial = serialnum; + } + result = dns_master_dumptostream(mctx, gdb, gversion, + masterstyle, outputformat, + &header, outfp); + check_result(result, "dns_master_dumptostream3"); + } + + isc_mutex_destroy(&namelock); + if (printstats) { + isc_mutex_destroy(&statslock); + } + + if (!output_stdout) { + result = isc_stdio_close(outfp); + check_result(result, "isc_stdio_close"); + removefile = false; + + if (vresult == ISC_R_SUCCESS) { + result = isc_file_rename(tempfile, output); + if (result != ISC_R_SUCCESS) { + fatal("failed to rename temp file to %s: %s", + output, isc_result_totext(result)); + } + printf("%s\n", output); + } else { + isc_file_remove(tempfile); + } + } + + dns_db_closeversion(gdb, &gversion, false); + dns_db_detach(&gdb); + + hashlist_free(&hashlist); + + while (!ISC_LIST_EMPTY(keylist)) { + key = ISC_LIST_HEAD(keylist); + ISC_LIST_UNLINK(keylist, key, link); + dns_dnsseckey_destroy(mctx, &key); + } + + if (tempfilelen != 0) { + isc_mem_put(mctx, tempfile, tempfilelen); + } + + if (free_output) { + isc_mem_free(mctx, output); + } + + dns_master_styledestroy(&dsstyle, mctx); + + cleanup_logging(&log); + dst_lib_destroy(); + if (verbose > 10) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + (void)isc_app_finish(); + + if (printstats) { + TIME_NOW(&timer_finish); + print_stats(&timer_start, &timer_finish, &sign_start, + &sign_finish); + } + +#ifdef _WIN32 + DestroySockets(); +#endif /* ifdef _WIN32 */ + return (vresult == ISC_R_SUCCESS ? 0 : 1); +} diff --git a/bin/dnssec/dnssec-signzone.rst b/bin/dnssec/dnssec-signzone.rst new file mode 100644 index 0000000..f5056bb --- /dev/null +++ b/bin/dnssec/dnssec-signzone.rst @@ -0,0 +1,396 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-signzone: + +dnssec-signzone - DNSSEC zone signing tool +------------------------------------------ + +Synopsis +~~~~~~~~ + +:program:`dnssec-signzone` [**-a**] [**-c** class] [**-d** directory] [**-D**] [**-E** engine] [**-e** end-time] [**-f** output-file] [**-g**] [**-h**] [**-i** interval] [**-I** input-format] [**-j** jitter] [**-K** directory] [**-k** key] [**-L** serial] [**-M** maxttl] [**-N** soa-serial-format] [**-o** origin] [**-O** output-format] [**-P**] [**-Q**] [**-q**] [**-R**] [**-S**] [**-s** start-time] [**-T** ttl] [**-t**] [**-u**] [**-v** level] [**-V**] [**-X** extended end-time] [**-x**] [**-z**] [**-3** salt] [**-H** iterations] [**-A**] {zonefile} [key...] + +Description +~~~~~~~~~~~ + +``dnssec-signzone`` signs a zone; it generates NSEC and RRSIG records +and produces a signed version of the zone. The security status of +delegations from the signed zone (that is, whether the child zones are +secure) is determined by the presence or absence of a ``keyset`` +file for each child zone. + +Options +~~~~~~~ + +``-a`` + This option verifies all generated signatures. + +``-c class`` + This option specifies the DNS class of the zone. + +``-C`` + This option sets compatibility mode, in which a ``keyset-zonename`` file is generated in addition + to ``dsset-zonename`` when signing a zone, for use by older versions + of ``dnssec-signzone``. + +``-d directory`` + This option indicates the directory where BIND 9 should look for ``dsset-`` or ``keyset-`` files. + +``-D`` + This option indicates that only those record types automatically managed by + ``dnssec-signzone``, i.e., RRSIG, NSEC, NSEC3 and NSEC3PARAM records, should be included in the output. + If smart signing (``-S``) is used, DNSKEY records are also included. + The resulting file can be included in the original zone file with + ``$INCLUDE``. This option cannot be combined with ``-O raw``, + ``-O map``, or serial-number updating. + +``-E engine`` + This option specifies the hardware to use for cryptographic + operations, such as a secure key store used for signing, when applicable. + + When BIND 9 is built with OpenSSL, this needs to be set to the OpenSSL + engine identifier that drives the cryptographic accelerator or + hardware service module (usually ``pkcs11``). When BIND is + built with native PKCS#11 cryptography (``--enable-native-pkcs11``), it + defaults to the path of the PKCS#11 provider library specified via + ``--with-pkcs11``. + +``-g`` + This option indicates that DS records for child zones should be generated from a ``dsset-`` or ``keyset-`` + file. Existing DS records are removed. + +``-K directory`` + This option specifies the directory to search for DNSSEC keys. If not + specified, it defaults to the current directory. + +``-k key`` + This option tells BIND 9 to treat the specified key as a key-signing key, ignoring any key flags. This + option may be specified multiple times. + +``-M maxttl`` + This option sets the maximum TTL for the signed zone. Any TTL higher than ``maxttl`` + in the input zone is reduced to ``maxttl`` in the output. This + provides certainty as to the largest possible TTL in the signed zone, + which is useful to know when rolling keys. The maxttl is the longest + possible time before signatures that have been retrieved by resolvers + expire from resolver caches. Zones that are signed with this + option should be configured to use a matching ``max-zone-ttl`` in + ``named.conf``. (Note: This option is incompatible with ``-D``, + because it modifies non-DNSSEC data in the output zone.) + +``-s start-time`` + This option specifies the date and time when the generated RRSIG records become + valid. This can be either an absolute or relative time. An absolute + start time is indicated by a number in YYYYMMDDHHMMSS notation; + 20000530144500 denotes 14:45:00 UTC on May 30th, 2000. A relative + start time is indicated by ``+N``, which is N seconds from the current + time. If no ``start-time`` is specified, the current time minus 1 + hour (to allow for clock skew) is used. + +``-e end-time`` + This option specifies the date and time when the generated RRSIG records expire. As + with ``start-time``, an absolute time is indicated in YYYYMMDDHHMMSS + notation. A time relative to the start time is indicated with ``+N``, + which is N seconds from the start time. A time relative to the + current time is indicated with ``now+N``. If no ``end-time`` is + specified, 30 days from the start time is the default. + ``end-time`` must be later than ``start-time``. + +``-X extended end-time`` + This option specifies the date and time when the generated RRSIG records for the + DNSKEY RRset expire. This is to be used in cases when the DNSKEY + signatures need to persist longer than signatures on other records; + e.g., when the private component of the KSK is kept offline and the + KSK signature is to be refreshed manually. + + As with ``end-time``, an absolute time is indicated in + YYYYMMDDHHMMSS notation. A time relative to the start time is + indicated with ``+N``, which is N seconds from the start time. A time + relative to the current time is indicated with ``now+N``. If no + ``extended end-time`` is specified, the value of ``end-time`` is used + as the default. (``end-time``, in turn, defaults to 30 days from the + start time.) ``extended end-time`` must be later than ``start-time``. + +``-f output-file`` + This option indicates the name of the output file containing the signed zone. The default + is to append ``.signed`` to the input filename. If ``output-file`` is + set to ``-``, then the signed zone is written to the standard + output, with a default output format of ``full``. + +``-h`` + This option prints a short summary of the options and arguments to + ``dnssec-signzone``. + +``-V`` + This option prints version information. + +``-i interval`` + This option indicates that, when a previously signed zone is passed as input, records may be + re-signed. The ``interval`` option specifies the cycle interval as an + offset from the current time, in seconds. If a RRSIG record expires + after the cycle interval, it is retained; otherwise, it is considered + to be expiring soon and it is replaced. + + The default cycle interval is one quarter of the difference between + the signature end and start times. So if neither ``end-time`` nor + ``start-time`` is specified, ``dnssec-signzone`` generates + signatures that are valid for 30 days, with a cycle interval of 7.5 + days. Therefore, if any existing RRSIG records are due to expire in + less than 7.5 days, they are replaced. + +``-I input-format`` + This option sets the format of the input zone file. Possible formats are ``text`` + (the default), ``raw``, and ``map``. This option is primarily + intended to be used for dynamic signed zones, so that the dumped zone + file in a non-text format containing updates can be signed directly. + This option is not useful for non-dynamic zones. + +``-j jitter`` + When signing a zone with a fixed signature lifetime, all RRSIG + records issued at the time of signing expire simultaneously. If the + zone is incrementally signed, i.e., a previously signed zone is passed + as input to the signer, all expired signatures must be regenerated + at approximately the same time. The ``jitter`` option specifies a jitter + window that is used to randomize the signature expire time, thus + spreading incremental signature regeneration over time. + + Signature lifetime jitter also, to some extent, benefits validators and + servers by spreading out cache expiration, i.e., if large numbers of + RRSIGs do not expire at the same time from all caches, there is + less congestion than if all validators need to refetch at around the + same time. + +``-L serial`` + When writing a signed zone to "raw" or "map" format, this option sets the "source + serial" value in the header to the specified ``serial`` number. (This is + expected to be used primarily for testing purposes.) + +``-n ncpus`` + This option specifies the number of threads to use. By default, one thread is + started for each detected CPU. + +``-N soa-serial-format`` + This option sets the SOA serial number format of the signed zone. Possible formats are + ``keep`` (the default), ``increment``, ``unixtime``, and + ``date``. + + **keep** + This format indicates that the SOA serial number should not be modified. + + **increment** + This format increments the SOA serial number using :rfc:`1982` arithmetic. + + **unixtime** + This format sets the SOA serial number to the number of seconds + since the beginning of the Unix epoch, unless the serial + number is already greater than or equal to that value, in + which case it is simply incremented by one. + + **date** + This format sets the SOA serial number to today's date, in + YYYYMMDDNN format, unless the serial number is already greater + than or equal to that value, in which case it is simply + incremented by one. + +``-o origin`` + This option sets the zone origin. If not specified, the name of the zone file is + assumed to be the origin. + +``-O output-format`` + This option sets the format of the output file containing the signed zone. Possible + formats are ``text`` (the default), which is the standard textual + representation of the zone; ``full``, which is text output in a + format suitable for processing by external scripts; and ``map``, + ``raw``, and ``raw=N``, which store the zone in binary formats + for rapid loading by ``named``. ``raw=N`` specifies the format + version of the raw zone file: if N is 0, the raw file can be read by + any version of ``named``; if N is 1, the file can be read by release + 9.9.0 or higher. The default is 1. + +``-P`` + This option disables post-sign verification tests. + + The post-sign verification tests ensure that for each algorithm in + use there is at least one non-revoked self-signed KSK key, that all + revoked KSK keys are self-signed, and that all records in the zone + are signed by the algorithm. This option skips these tests. + +``-Q`` + This option removes signatures from keys that are no longer active. + + Normally, when a previously signed zone is passed as input to the + signer, and a DNSKEY record has been removed and replaced with a new + one, signatures from the old key that are still within their validity + period are retained. This allows the zone to continue to validate + with cached copies of the old DNSKEY RRset. The ``-Q`` option forces + ``dnssec-signzone`` to remove signatures from keys that are no longer + active. This enables ZSK rollover using the procedure described in + :rfc:`4641#4.2.1.1` ("Pre-Publish Key Rollover"). + +``-q`` + This option enables quiet mode, which suppresses unnecessary output. Without this option, when + ``dnssec-signzone`` is run it prints three pieces of information to standard output: the number of + keys in use; the algorithms used to verify the zone was signed correctly and + other status information; and the filename containing the signed + zone. With the option that output is suppressed, leaving only the filename. + +``-R`` + This option removes signatures from keys that are no longer published. + + This option is similar to ``-Q``, except it forces + ``dnssec-signzone`` to remove signatures from keys that are no longer + published. This enables ZSK rollover using the procedure described in + :rfc:`4641#4.2.1.2` ("Double Signature Zone Signing Key + Rollover"). + +``-S`` + This option enables smart signing, which instructs ``dnssec-signzone`` to search the key + repository for keys that match the zone being signed, and to include + them in the zone if appropriate. + + When a key is found, its timing metadata is examined to determine how + it should be used, according to the following rules. Each successive + rule takes priority over the prior ones: + + If no timing metadata has been set for the key, the key is + published in the zone and used to sign the zone. + + If the key's publication date is set and is in the past, the key + is published in the zone. + + If the key's activation date is set and is in the past, the key is + published (regardless of publication date) and used to sign the + zone. + + If the key's revocation date is set and is in the past, and the key + is published, then the key is revoked, and the revoked key is used + to sign the zone. + + If either the key's unpublication or deletion date is set and + in the past, the key is NOT published or used to sign the zone, + regardless of any other metadata. + + If the key's sync publication date is set and is in the past, + synchronization records (type CDS and/or CDNSKEY) are created. + + If the key's sync deletion date is set and is in the past, + synchronization records (type CDS and/or CDNSKEY) are removed. + +``-T ttl`` + This option specifies a TTL to be used for new DNSKEY records imported into the + zone from the key repository. If not specified, the default is the + TTL value from the zone's SOA record. This option is ignored when + signing without ``-S``, since DNSKEY records are not imported from + the key repository in that case. It is also ignored if there are any + pre-existing DNSKEY records at the zone apex, in which case new + records' TTL values are set to match them, or if any of the + imported DNSKEY records had a default TTL value. In the event of a + conflict between TTL values in imported keys, the shortest one is + used. + +``-t`` + This option prints statistics at completion. + +``-u`` + This option updates the NSEC/NSEC3 chain when re-signing a previously signed zone. + With this option, a zone signed with NSEC can be switched to NSEC3, + or a zone signed with NSEC3 can be switched to NSEC or to NSEC3 with + different parameters. Without this option, ``dnssec-signzone`` + retains the existing chain when re-signing. + +``-v level`` + This option sets the debugging level. + +``-x`` + This option indicates that BIND 9 should only sign the DNSKEY, CDNSKEY, and CDS RRsets with key-signing keys, + and should omit signatures from zone-signing keys. (This is similar to the + ``dnssec-dnskey-kskonly yes;`` zone option in ``named``.) + +``-z`` + This option indicates that BIND 9 should ignore the KSK flag on keys when determining what to sign. This causes + KSK-flagged keys to sign all records, not just the DNSKEY RRset. + (This is similar to the ``update-check-ksk no;`` zone option in + ``named``.) + +``-3 salt`` + This option generates an NSEC3 chain with the given hex-encoded salt. A dash + (-) can be used to indicate that no salt is to be used when + generating the NSEC3 chain. + + .. note:: + ``-3 -`` is the recommended configuration. Adding salt provides no practical benefits. + +``-H iterations`` + This option indicates that, when generating an NSEC3 chain, BIND 9 should use this many iterations. The default + is 10. + + .. warning:: + Values greater than 0 cause interoperability issues and also increase the risk of CPU-exhausting DoS attacks. The default value has not been changed because the best practices has changed only after BIND 9.16 reached Extended Support Version status. + +``-A`` + This option indicates that, when generating an NSEC3 chain, BIND 9 should set the OPTOUT flag on all NSEC3 + records and should not generate NSEC3 records for insecure delegations. + + .. warning:: + Do not use this option unless all its implications are fully understood. This option is intended only for extremely large zones (comparable to ``com.``) with sparse secure delegations. + + Using this option twice (i.e., ``-AA``) turns the OPTOUT flag off for + all records. This is useful when using the ``-u`` option to modify an + NSEC3 chain which previously had OPTOUT set. + +``zonefile`` + This option sets the file containing the zone to be signed. + +``key`` + This option specifies which keys should be used to sign the zone. If no keys are + specified, the zone is examined for DNSKEY records at the + zone apex. If these records are found and there are matching private keys in + the current directory, they are used for signing. + +Example +~~~~~~~ + +The following command signs the ``example.com`` zone with the +ECDSAP256SHA256 key generated by ``dnssec-keygen`` +(Kexample.com.+013+17247). Because the ``-S`` option is not being used, +the zone's keys must be in the master file (``db.example.com``). This +invocation looks for ``dsset`` files in the current directory, so that +DS records can be imported from them (``-g``). + +:: + + % dnssec-signzone -g -o example.com db.example.com \ + Kexample.com.+013+17247 + db.example.com.signed + % + +In the above example, ``dnssec-signzone`` creates the file +``db.example.com.signed``. This file should be referenced in a zone +statement in the ``named.conf`` file. + +This example re-signs a previously signed zone with default parameters. +The private keys are assumed to be in the current directory. + +:: + + % cp db.example.com.signed db.example.com + % dnssec-signzone -o example.com db.example.com + db.example.com.signed + % + +See Also +~~~~~~~~ + +:manpage:`dnssec-keygen(8)`, BIND 9 Administrator Reference Manual, :rfc:`4033`, +:rfc:`4641`. diff --git a/bin/dnssec/dnssec-verify.c b/bin/dnssec/dnssec-verify.c new file mode 100644 index 0000000..85cc54b --- /dev/null +++ b/bin/dnssec/dnssec-verify.c @@ -0,0 +1,366 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include "dnssectool.h" + +const char *program = "dnssec-verify"; + +static isc_stdtime_t now; +static isc_mem_t *mctx = NULL; +static dns_masterformat_t inputformat = dns_masterformat_text; +static dns_db_t *gdb; /* The database */ +static dns_dbversion_t *gversion; /* The database version */ +static dns_rdataclass_t gclass; /* The class */ +static dns_name_t *gorigin; /* The database origin */ +static bool ignore_kskflag = false; +static bool keyset_kskonly = false; + +static void +report(const char *format, ...) { + if (!quiet) { + char buf[4096]; + va_list args; + + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + fprintf(stdout, "%s\n", buf); + } +} + +/*% + * Load the zone file from disk + */ +static void +loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) { + isc_buffer_t b; + int len; + dns_fixedname_t fname; + dns_name_t *name; + isc_result_t result; + + len = strlen(origin); + isc_buffer_init(&b, origin, len); + isc_buffer_add(&b, len); + + name = dns_fixedname_initname(&fname); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fatal("failed converting name '%s' to dns format: %s", origin, + isc_result_totext(result)); + } + + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0, + NULL, db); + check_result(result, "dns_db_create()"); + + result = dns_db_load(*db, file, inputformat, 0); + switch (result) { + case DNS_R_SEENINCLUDE: + case ISC_R_SUCCESS: + break; + case DNS_R_NOTZONETOP: + /* + * Comparing pointers (vs. using strcmp()) is intentional: we + * want to check whether -o was supplied on the command line, + * not whether origin and file contain the same string. + */ + if (origin == file) { + fatal("failed loading zone '%s' from file '%s': " + "use -o to specify a different zone origin", + origin, file); + } + FALLTHROUGH; + default: + fatal("failed loading zone from '%s': %s", file, + isc_result_totext(result)); + } +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\t%s [options] zonefile [keys]\n", program); + + fprintf(stderr, "\n"); + + fprintf(stderr, "Version: %s\n", VERSION); + + fprintf(stderr, "Options: (default value in parenthesis) \n"); + fprintf(stderr, "\t-v debuglevel (0)\n"); + fprintf(stderr, "\t-q quiet\n"); + fprintf(stderr, "\t-V:\tprint version information\n"); + fprintf(stderr, "\t-o origin:\n"); + fprintf(stderr, "\t\tzone origin (name of zonefile)\n"); + fprintf(stderr, "\t-I format:\n"); + fprintf(stderr, "\t\tfile format of input zonefile (text)\n"); + fprintf(stderr, "\t-c class (IN)\n"); + fprintf(stderr, "\t-E engine:\n"); +#if USE_PKCS11 + fprintf(stderr, + "\t\tpath to PKCS#11 provider library " + "(default is %s)\n", + PK11_LIB_LOCATION); +#else /* if USE_PKCS11 */ + fprintf(stderr, "\t\tname of an OpenSSL engine to use\n"); +#endif /* if USE_PKCS11 */ + fprintf(stderr, "\t-x:\tDNSKEY record signed with KSKs only, " + "not ZSKs\n"); + fprintf(stderr, "\t-z:\tAll records signed with KSKs\n"); + exit(0); +} + +int +main(int argc, char *argv[]) { + char *origin = NULL, *file = NULL; + char *inputformatstr = NULL; + isc_result_t result; + isc_log_t *log = NULL; + const char *engine = NULL; + char *classname = NULL; + dns_rdataclass_t rdclass; + char *endp; + int ch; + +#define CMDLINE_FLAGS "c:E:hm:o:I:qv:Vxz" + + /* + * Process memory debugging argument first. + */ + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case 'm': + if (strcasecmp(isc_commandline_argument, "record") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + } + if (strcasecmp(isc_commandline_argument, "trace") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGTRACE; + } + if (strcasecmp(isc_commandline_argument, "usage") == 0) + { + isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; + } + if (strcasecmp(isc_commandline_argument, "size") == 0) { + isc_mem_debugging |= ISC_MEM_DEBUGSIZE; + } + if (strcasecmp(isc_commandline_argument, "mctx") == 0) { + isc_mem_debugging |= ISC_MEM_DEBUGCTX; + } + break; + default: + break; + } + } + isc_commandline_reset = true; + check_result(isc_app_start(), "isc_app_start"); + + isc_mem_create(&mctx); + +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + dns_result_register(); + + isc_commandline_errprint = false; + + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case 'c': + classname = isc_commandline_argument; + break; + + case 'E': + engine = isc_commandline_argument; + break; + + case 'I': + inputformatstr = isc_commandline_argument; + break; + + case 'm': + break; + + case 'o': + origin = isc_commandline_argument; + break; + + case 'v': + endp = NULL; + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fatal("verbose level must be numeric"); + } + break; + + case 'q': + quiet = true; + break; + + case 'x': + keyset_kskonly = true; + break; + + case 'z': + ignore_kskflag = true; + break; + + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + } + FALLTHROUGH; + + case 'h': + /* Does not return. */ + usage(); + + case 'V': + /* Does not return. */ + version(program); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + result = dst_lib_init(mctx, engine); + if (result != ISC_R_SUCCESS) { + fatal("could not initialize dst: %s", + isc_result_totext(result)); + } + + isc_stdtime_get(&now); + + rdclass = strtoclass(classname); + + setup_logging(mctx, &log); + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc < 1) { + usage(); + } + + file = argv[0]; + + argc -= 1; + argv += 1; + + POST(argc); + POST(argv); + + if (origin == NULL) { + origin = file; + } + + if (inputformatstr != NULL) { + if (strcasecmp(inputformatstr, "text") == 0) { + inputformat = dns_masterformat_text; + } else if (strcasecmp(inputformatstr, "raw") == 0) { + inputformat = dns_masterformat_raw; + } else { + fatal("unknown file format: %s\n", inputformatstr); + } + } + + gdb = NULL; + report("Loading zone '%s' from file '%s'\n", origin, file); + loadzone(file, origin, rdclass, &gdb); + gorigin = dns_db_origin(gdb); + gclass = dns_db_class(gdb); + + gversion = NULL; + result = dns_db_newversion(gdb, &gversion); + check_result(result, "dns_db_newversion()"); + + result = dns_zoneverify_dnssec(NULL, gdb, gversion, gorigin, NULL, mctx, + ignore_kskflag, keyset_kskonly, report); + + dns_db_closeversion(gdb, &gversion, false); + dns_db_detach(&gdb); + + cleanup_logging(&log); + dst_lib_destroy(); + if (verbose > 10) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + (void)isc_app_finish(); + + return (result == ISC_R_SUCCESS ? 0 : 1); +} diff --git a/bin/dnssec/dnssec-verify.rst b/bin/dnssec/dnssec-verify.rst new file mode 100644 index 0000000..4a0c8e7 --- /dev/null +++ b/bin/dnssec/dnssec-verify.rst @@ -0,0 +1,98 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-verify: + +dnssec-verify - DNSSEC zone verification tool +--------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`dnssec-verify` [**-c** class] [**-E** engine] [**-I** input-format] [**-o** origin] [**-q**] [**-v** level] [**-V**] [**-x**] [**-z**] {zonefile} + +Description +~~~~~~~~~~~ + +``dnssec-verify`` verifies that a zone is fully signed for each +algorithm found in the DNSKEY RRset for the zone, and that the +NSEC/NSEC3 chains are complete. + +Options +~~~~~~~ + +``-c class`` + This option specifies the DNS class of the zone. + +``-E engine`` + This option specifies the cryptographic hardware to use, when applicable. + + When BIND 9 is built with OpenSSL, this needs to be set to the OpenSSL + engine identifier that drives the cryptographic accelerator or + hardware service module (usually ``pkcs11``). When BIND is + built with native PKCS#11 cryptography (``--enable-native-pkcs11``), it + defaults to the path of the PKCS#11 provider library specified via + ``--with-pkcs11``. + +``-I input-format`` + This option sets the format of the input zone file. Possible formats are ``text`` + (the default) and ``raw``. This option is primarily intended to be used + for dynamic signed zones, so that the dumped zone file in a non-text + format containing updates can be verified independently. + This option is not useful for non-dynamic zones. + +``-o origin`` + This option indicates the zone origin. If not specified, the name of the zone file is + assumed to be the origin. + +``-v level`` + This option sets the debugging level. + +``-V`` + This option prints version information. + +``-q`` + This option sets quiet mode, which suppresses output. Without this option, when ``dnssec-verify`` + is run it prints to standard output the number of keys in use, the + algorithms used to verify the zone was signed correctly, and other status + information. With this option, all non-error output is suppressed, and only the exit + code indicates success. + +``-x`` + This option verifies only that the DNSKEY RRset is signed with key-signing keys. + Without this flag, it is assumed that the DNSKEY RRset is signed + by all active keys. When this flag is set, it is not an error if + the DNSKEY RRset is not signed by zone-signing keys. This corresponds + to the ``-x`` option in ``dnssec-signzone``. + +``-z`` + This option indicates that the KSK flag on the keys should be ignored when determining whether the zone is + correctly signed. Without this flag, it is assumed that there is + a non-revoked, self-signed DNSKEY with the KSK flag set for each + algorithm, and that RRsets other than DNSKEY RRset are signed with + a different DNSKEY without the KSK flag set. + + With this flag set, BIND 9 only requires that for each algorithm, there + be at least one non-revoked, self-signed DNSKEY, regardless of + the KSK flag state, and that other RRsets be signed by a + non-revoked key for the same algorithm that includes the self-signed + key; the same key may be used for both purposes. This corresponds to + the ``-z`` option in ``dnssec-signzone``. + +``zonefile`` + This option indicates the file containing the zone to be signed. + +See Also +~~~~~~~~ + +:manpage:`dnssec-signzone(8)`, BIND 9 Administrator Reference Manual, :rfc:`4033`. diff --git a/bin/dnssec/dnssectool.c b/bin/dnssec/dnssectool.c new file mode 100644 index 0000000..ce903ca --- /dev/null +++ b/bin/dnssec/dnssectool.c @@ -0,0 +1,594 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +/*% + * DNSSEC Support Routines. + */ + +#include +#include +#include + +#ifdef _WIN32 +#include +#endif /* ifdef _WIN32 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dnssectool.h" + +#define KEYSTATES_NVALUES 4 +static const char *keystates[KEYSTATES_NVALUES] = { + "hidden", + "rumoured", + "omnipresent", + "unretentive", +}; + +int verbose = 0; +bool quiet = false; +uint8_t dtype[8]; + +static fatalcallback_t *fatalcallback = NULL; + +void +fatal(const char *format, ...) { + va_list args; + + fprintf(stderr, "%s: fatal: ", program); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + if (fatalcallback != NULL) { + (*fatalcallback)(); + } + exit(1); +} + +void +setfatalcallback(fatalcallback_t *callback) { + fatalcallback = callback; +} + +void +check_result(isc_result_t result, const char *message) { + if (result != ISC_R_SUCCESS) { + fatal("%s: %s", message, isc_result_totext(result)); + } +} + +void +vbprintf(int level, const char *fmt, ...) { + va_list ap; + if (level > verbose) { + return; + } + va_start(ap, fmt); + fprintf(stderr, "%s: ", program); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void +version(const char *name) { + fprintf(stderr, "%s %s\n", name, VERSION); + exit(0); +} + +void +sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) { + char namestr[DNS_NAME_FORMATSIZE]; + char algstr[DNS_NAME_FORMATSIZE]; + + dns_name_format(&sig->signer, namestr, sizeof(namestr)); + dns_secalg_format(sig->algorithm, algstr, sizeof(algstr)); + snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid); +} + +void +setup_logging(isc_mem_t *mctx, isc_log_t **logp) { + isc_logdestination_t destination; + isc_logconfig_t *logconfig = NULL; + isc_log_t *log = NULL; + int level; + + if (verbose < 0) { + verbose = 0; + } + switch (verbose) { + case 0: + /* + * We want to see warnings about things like out-of-zone + * data in the master file even when not verbose. + */ + level = ISC_LOG_WARNING; + break; + case 1: + level = ISC_LOG_INFO; + break; + default: + level = ISC_LOG_DEBUG(verbose - 2 + 1); + break; + } + + isc_log_create(mctx, &log, &logconfig); + isc_log_setcontext(log); + dns_log_init(log); + dns_log_setcontext(log); + isc_log_settag(logconfig, program); + + /* + * Set up a channel similar to default_stderr except: + * - the logging level is passed in + * - the program name and logging level are printed + * - no time stamp is printed + */ + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, level, + &destination, + ISC_LOG_PRINTTAG | ISC_LOG_PRINTLEVEL); + + RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL) == + ISC_R_SUCCESS); + + *logp = log; +} + +void +cleanup_logging(isc_log_t **logp) { + isc_log_t *log; + + REQUIRE(logp != NULL); + + log = *logp; + *logp = NULL; + + if (log == NULL) { + return; + } + + isc_log_destroy(&log); + isc_log_setcontext(NULL); + dns_log_setcontext(NULL); +} + +static isc_stdtime_t +time_units(isc_stdtime_t offset, char *suffix, const char *str) { + switch (suffix[0]) { + case 'Y': + case 'y': + return (offset * (365 * 24 * 3600)); + case 'M': + case 'm': + switch (suffix[1]) { + case 'O': + case 'o': + return (offset * (30 * 24 * 3600)); + case 'I': + case 'i': + return (offset * 60); + case '\0': + fatal("'%s' ambiguous: use 'mi' for minutes " + "or 'mo' for months", + str); + default: + fatal("time value %s is invalid", str); + } + UNREACHABLE(); + break; + case 'W': + case 'w': + return (offset * (7 * 24 * 3600)); + case 'D': + case 'd': + return (offset * (24 * 3600)); + case 'H': + case 'h': + return (offset * 3600); + case 'S': + case 's': + case '\0': + return (offset); + default: + fatal("time value %s is invalid", str); + } + UNREACHABLE(); + return (0); /* silence compiler warning */ +} + +static bool +isnone(const char *str) { + return ((strcasecmp(str, "none") == 0) || + (strcasecmp(str, "never") == 0)); +} + +dns_ttl_t +strtottl(const char *str) { + const char *orig = str; + dns_ttl_t ttl; + char *endp; + + if (isnone(str)) { + return ((dns_ttl_t)0); + } + + ttl = strtol(str, &endp, 0); + if (ttl == 0 && endp == str) { + fatal("TTL must be numeric"); + } + ttl = time_units(ttl, endp, orig); + return (ttl); +} + +dst_key_state_t +strtokeystate(const char *str) { + if (isnone(str)) { + return (DST_KEY_STATE_NA); + } + + for (int i = 0; i < KEYSTATES_NVALUES; i++) { + if (keystates[i] != NULL && strcasecmp(str, keystates[i]) == 0) + { + return ((dst_key_state_t)i); + } + } + fatal("unknown key state %s", str); +} + +isc_stdtime_t +strtotime(const char *str, int64_t now, int64_t base, bool *setp) { + int64_t val, offset; + isc_result_t result; + const char *orig = str; + char *endp; + size_t n; + + if (isnone(str)) { + if (setp != NULL) { + *setp = false; + } + return ((isc_stdtime_t)0); + } + + if (setp != NULL) { + *setp = true; + } + + if ((str[0] == '0' || str[0] == '-') && str[1] == '\0') { + return ((isc_stdtime_t)0); + } + + /* + * We accept times in the following formats: + * now([+-]offset) + * YYYYMMDD([+-]offset) + * YYYYMMDDhhmmss([+-]offset) + * [+-]offset + */ + n = strspn(str, "0123456789"); + if ((n == 8u || n == 14u) && + (str[n] == '\0' || str[n] == '-' || str[n] == '+')) + { + char timestr[15]; + + strlcpy(timestr, str, sizeof(timestr)); + timestr[n] = 0; + if (n == 8u) { + strlcat(timestr, "000000", sizeof(timestr)); + } + result = dns_time64_fromtext(timestr, &val); + if (result != ISC_R_SUCCESS) { + fatal("time value %s is invalid: %s", orig, + isc_result_totext(result)); + } + base = val; + str += n; + } else if (strncmp(str, "now", 3) == 0) { + base = now; + str += 3; + } + + if (str[0] == '\0') { + return ((isc_stdtime_t)base); + } else if (str[0] == '+') { + offset = strtol(str + 1, &endp, 0); + offset = time_units((isc_stdtime_t)offset, endp, orig); + val = base + offset; + } else if (str[0] == '-') { + offset = strtol(str + 1, &endp, 0); + offset = time_units((isc_stdtime_t)offset, endp, orig); + val = base - offset; + } else { + fatal("time value %s is invalid", orig); + } + + return ((isc_stdtime_t)val); +} + +dns_rdataclass_t +strtoclass(const char *str) { + isc_textregion_t r; + dns_rdataclass_t rdclass; + isc_result_t result; + + if (str == NULL) { + return (dns_rdataclass_in); + } + DE_CONST(str, r.base); + r.length = strlen(str); + result = dns_rdataclass_fromtext(&rdclass, &r); + if (result != ISC_R_SUCCESS) { + fatal("unknown class %s", str); + } + return (rdclass); +} + +unsigned int +strtodsdigest(const char *str) { + isc_textregion_t r; + dns_dsdigest_t alg; + isc_result_t result; + + DE_CONST(str, r.base); + r.length = strlen(str); + result = dns_dsdigest_fromtext(&alg, &r); + if (result != ISC_R_SUCCESS) { + fatal("unknown DS algorithm %s", str); + } + return (alg); +} + +static int +cmp_dtype(const void *ap, const void *bp) { + int a = *(const uint8_t *)ap; + int b = *(const uint8_t *)bp; + return (a - b); +} + +void +add_dtype(unsigned int dt) { + unsigned i, n; + + /* ensure there is space for a zero terminator */ + n = sizeof(dtype) / sizeof(dtype[0]) - 1; + for (i = 0; i < n; i++) { + if (dtype[i] == dt) { + return; + } + if (dtype[i] == 0) { + dtype[i] = dt; + qsort(dtype, i + 1, 1, cmp_dtype); + return; + } + } + fatal("too many -a digest type arguments"); +} + +isc_result_t +try_dir(const char *dirname) { + isc_result_t result; + isc_dir_t d; + + isc_dir_init(&d); + result = isc_dir_open(&d, dirname); + if (result == ISC_R_SUCCESS) { + isc_dir_close(&d); + } + return (result); +} + +/* + * Check private key version compatibility. + */ +void +check_keyversion(dst_key_t *key, char *keystr) { + int major, minor; + dst_key_getprivateformat(key, &major, &minor); + INSIST(major <= DST_MAJOR_VERSION); /* invalid private key */ + + if (major < DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) { + fatal("Key %s has incompatible format version %d.%d, " + "use -f to force upgrade to new version.", + keystr, major, minor); + } + if (minor > DST_MINOR_VERSION) { + fatal("Key %s has incompatible format version %d.%d, " + "use -f to force downgrade to current version.", + keystr, major, minor); + } +} + +void +set_keyversion(dst_key_t *key) { + int major, minor; + dst_key_getprivateformat(key, &major, &minor); + INSIST(major <= DST_MAJOR_VERSION); + + if (major != DST_MAJOR_VERSION || minor != DST_MINOR_VERSION) { + dst_key_setprivateformat(key, DST_MAJOR_VERSION, + DST_MINOR_VERSION); + } + + /* + * If the key is from a version older than 1.3, set + * set the creation date + */ + if (major < 1 || (major == 1 && minor <= 2)) { + isc_stdtime_t now; + isc_stdtime_get(&now); + dst_key_settime(key, DST_TIME_CREATED, now); + } +} + +bool +key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir, + isc_mem_t *mctx, bool *exact) { + isc_result_t result; + bool conflict = false; + dns_dnsseckeylist_t matchkeys; + dns_dnsseckey_t *key = NULL; + uint16_t id, oldid; + uint32_t rid, roldid; + dns_secalg_t alg; + char filename[NAME_MAX]; + isc_buffer_t fileb; + isc_stdtime_t now; + + if (exact != NULL) { + *exact = false; + } + + id = dst_key_id(dstkey); + rid = dst_key_rid(dstkey); + alg = dst_key_alg(dstkey); + + /* + * For Diffie Hellman just check if there is a direct collision as + * they can't be revoked. Additionally dns_dnssec_findmatchingkeys + * only handles DNSKEY which is not used for HMAC. + */ + if (alg == DST_ALG_DH) { + isc_buffer_init(&fileb, filename, sizeof(filename)); + result = dst_key_buildfilename(dstkey, DST_TYPE_PRIVATE, dir, + &fileb); + if (result != ISC_R_SUCCESS) { + return (true); + } + return (isc_file_exists(filename)); + } + + ISC_LIST_INIT(matchkeys); + isc_stdtime_get(&now); + result = dns_dnssec_findmatchingkeys(name, dir, now, mctx, &matchkeys); + if (result == ISC_R_NOTFOUND) { + return (false); + } + + while (!ISC_LIST_EMPTY(matchkeys) && !conflict) { + key = ISC_LIST_HEAD(matchkeys); + if (dst_key_alg(key->key) != alg) { + goto next; + } + + oldid = dst_key_id(key->key); + roldid = dst_key_rid(key->key); + + if (oldid == rid || roldid == id || id == oldid) { + conflict = true; + if (id != oldid) { + if (verbose > 1) { + fprintf(stderr, + "Key ID %d could " + "collide with %d\n", + id, oldid); + } + } else { + if (exact != NULL) { + *exact = true; + } + if (verbose > 1) { + fprintf(stderr, "Key ID %d exists\n", + id); + } + } + } + + next: + ISC_LIST_UNLINK(matchkeys, key, link); + dns_dnsseckey_destroy(mctx, &key); + } + + /* Finish freeing the list */ + while (!ISC_LIST_EMPTY(matchkeys)) { + key = ISC_LIST_HEAD(matchkeys); + ISC_LIST_UNLINK(matchkeys, key, link); + dns_dnsseckey_destroy(mctx, &key); + } + + return (conflict); +} + +bool +isoptarg(const char *arg, char **argv, void (*usage)(void)) { + if (!strcasecmp(isc_commandline_argument, arg)) { + if (argv[isc_commandline_index] == NULL) { + fprintf(stderr, "%s: missing argument -%c %s\n", + program, isc_commandline_option, + isc_commandline_argument); + usage(); + } + isc_commandline_argument = argv[isc_commandline_index]; + /* skip to next argument */ + isc_commandline_index++; + return (true); + } + return (false); +} + +#ifdef _WIN32 +void +InitSockets(void) { + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD(2, 0); + + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + fprintf(stderr, "WSAStartup() failed: %d\n", err); + exit(1); + } +} + +void +DestroySockets(void) { + WSACleanup(); +} +#endif /* ifdef _WIN32 */ diff --git a/bin/dnssec/dnssectool.h b/bin/dnssec/dnssectool.h new file mode 100644 index 0000000..4ce8490 --- /dev/null +++ b/bin/dnssec/dnssectool.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef DNSSECTOOL_H +#define DNSSECTOOL_H 1 + +#include +#include + +#include +#include +#include + +#include + +#include + +/*! verbosity: set by -v and -q option in each program, defined in dnssectool.c + */ +extern int verbose; +extern bool quiet; + +/*! program name, statically initialized in each program */ +extern const char *program; + +/*! + * List of DS digest types used by dnssec-cds and dnssec-dsfromkey, + * defined in dnssectool.c. Filled in by add_dtype() from -a + * arguments, sorted (so that DS records are in a canonical order) and + * terminated by a zero. The size of the array is an arbitrary limit + * which should be greater than the number of known digest types. + */ +extern uint8_t dtype[8]; + +typedef void(fatalcallback_t)(void); + +#ifndef CPPCHECK +ISC_PLATFORM_NORETURN_PRE void +fatal(const char *format, ...) + ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; +#else /* CPPCHECK */ +#define fatal(...) exit(1) +#endif + +void +setfatalcallback(fatalcallback_t *callback); + +void +check_result(isc_result_t result, const char *message); + +void +vbprintf(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); + +ISC_PLATFORM_NORETURN_PRE void +version(const char *program) ISC_PLATFORM_NORETURN_POST; + +void +sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size); +#define SIG_FORMATSIZE \ + (DNS_NAME_FORMATSIZE + DNS_SECALG_FORMATSIZE + sizeof("65535")) + +void +setup_logging(isc_mem_t *mctx, isc_log_t **logp); + +void +cleanup_logging(isc_log_t **logp); + +dns_ttl_t +strtottl(const char *str); + +dst_key_state_t +strtokeystate(const char *str); + +isc_stdtime_t +strtotime(const char *str, int64_t now, int64_t base, bool *setp); + +dns_rdataclass_t +strtoclass(const char *str); + +unsigned int +strtodsdigest(const char *str); + +void +add_dtype(unsigned int dt); + +isc_result_t +try_dir(const char *dirname); + +void +check_keyversion(dst_key_t *key, char *keystr); + +void +set_keyversion(dst_key_t *key); + +bool +key_collision(dst_key_t *key, dns_name_t *name, const char *dir, + isc_mem_t *mctx, bool *exact); + +bool +isoptarg(const char *arg, char **argv, void (*usage)(void)); + +#ifdef _WIN32 +void +InitSockets(void); +void +DestroySockets(void); +#endif /* ifdef _WIN32 */ + +#endif /* DNSSEC_DNSSECTOOL_H */ diff --git a/bin/dnssec/win32/cds.vcxproj.filters.in b/bin/dnssec/win32/cds.vcxproj.filters.in new file mode 100644 index 0000000..b6893db --- /dev/null +++ b/bin/dnssec/win32/cds.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + diff --git a/bin/dnssec/win32/cds.vcxproj.in b/bin/dnssec/win32/cds.vcxproj.in new file mode 100644 index 0000000..0a543eb --- /dev/null +++ b/bin/dnssec/win32/cds.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {0EB1727E-2BBD-47A6-AD12-418F9DEB0531} + Win32Proj + cds + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/dnssec/win32/cds.vcxproj.user b/bin/dnssec/win32/cds.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/cds.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/win32/dnssectool.vcxproj.filters.in b/bin/dnssec/win32/dnssectool.vcxproj.filters.in new file mode 100644 index 0000000..1743f84 --- /dev/null +++ b/bin/dnssec/win32/dnssectool.vcxproj.filters.in @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dnssec/win32/dnssectool.vcxproj.in b/bin/dnssec/win32/dnssectool.vcxproj.in new file mode 100644 index 0000000..be87bca --- /dev/null +++ b/bin/dnssec/win32/dnssectool.vcxproj.in @@ -0,0 +1,118 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + + + + + + + {2CB7DC75-023B-4AA3-AF3A-AE5046A4EE70} + Win32Proj + dnssectool + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + StaticLibrary + true + MultiByte + @PLATFORM_TOOLSET@ + + + StaticLibrary + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + .\$(Configuration)\ + + + .\$(Configuration)\ + None + + + .\$(Configuration)\ + + + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Windows + true + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Windows + true + true + true + false + + + + + + diff --git a/bin/dnssec/win32/dnssectool.vcxproj.user b/bin/dnssec/win32/dnssectool.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/dnssectool.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/win32/dsfromkey.vcxproj.filters.in b/bin/dnssec/win32/dsfromkey.vcxproj.filters.in new file mode 100644 index 0000000..7d0a58e --- /dev/null +++ b/bin/dnssec/win32/dsfromkey.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dnssec/win32/dsfromkey.vcxproj.in b/bin/dnssec/win32/dsfromkey.vcxproj.in new file mode 100644 index 0000000..5b2b51d --- /dev/null +++ b/bin/dnssec/win32/dsfromkey.vcxproj.in @@ -0,0 +1,147 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {6E6297F4-69D7-4533-85E1-BD17C30017C8} + Win32Proj + dsfromkey + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + +@IF PYTHON + + cd ..\..\python +copy /Y dnssec-checkds.py ..\..\Build\$(Configuration)\dnssec-checkds.py +copy /Y dnssec-coverage.py ..\..\Build\$(Configuration)\dnssec-coverage.py +copy /Y dnssec-keymgr.py ..\..\Build\$(Configuration)\dnssec-keymgr.py +cd isc +@PYTHON@ policy.py parse \dev\nul > nul +set PYTHONPATH=. +@PYTHON@ -m parsetab + + +@END PYTHON + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + +@IF PYTHON + + cd ..\..\python +copy /Y dnssec-checkds.py ..\..\Build\$(Configuration)\dnssec-checkds.py +copy /Y dnssec-coverage.py ..\..\Build\$(Configuration)\dnssec-coverage.py +copy /Y dnssec-keymgr.py ..\..\Build\$(Configuration)\dnssec-keymgr.py +cd isc +@PYTHON@ policy.py parse \dev\nul > nul +set PYTHONPATH=. +@PYTHON@ -m parsetab + + +@END PYTHON + + + + + + + + diff --git a/bin/dnssec/win32/dsfromkey.vcxproj.user b/bin/dnssec/win32/dsfromkey.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/dsfromkey.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/win32/importkey.vcxproj.filters.in b/bin/dnssec/win32/importkey.vcxproj.filters.in new file mode 100644 index 0000000..0bced36 --- /dev/null +++ b/bin/dnssec/win32/importkey.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + diff --git a/bin/dnssec/win32/importkey.vcxproj.in b/bin/dnssec/win32/importkey.vcxproj.in new file mode 100644 index 0000000..f1d10d0 --- /dev/null +++ b/bin/dnssec/win32/importkey.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {AB6690A0-055E-458f-BAC5-BF38BCC5834F} + Win32Proj + importkey + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/dnssec/win32/importkey.vcxproj.user b/bin/dnssec/win32/importkey.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/importkey.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/win32/keyfromlabel.vcxproj.filters.in b/bin/dnssec/win32/keyfromlabel.vcxproj.filters.in new file mode 100644 index 0000000..bb54f81 --- /dev/null +++ b/bin/dnssec/win32/keyfromlabel.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dnssec/win32/keyfromlabel.vcxproj.in b/bin/dnssec/win32/keyfromlabel.vcxproj.in new file mode 100644 index 0000000..496e2b9 --- /dev/null +++ b/bin/dnssec/win32/keyfromlabel.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {17455DC6-5FBB-47C3-8F44-7DB574A188D3} + Win32Proj + keyfromlabel + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/dnssec/win32/keyfromlabel.vcxproj.user b/bin/dnssec/win32/keyfromlabel.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/keyfromlabel.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/win32/keygen.vcxproj.filters.in b/bin/dnssec/win32/keygen.vcxproj.filters.in new file mode 100644 index 0000000..5d1fa4c --- /dev/null +++ b/bin/dnssec/win32/keygen.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dnssec/win32/keygen.vcxproj.in b/bin/dnssec/win32/keygen.vcxproj.in new file mode 100644 index 0000000..6051dbf --- /dev/null +++ b/bin/dnssec/win32/keygen.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {0BF11E21-168C-4CAA-B784-429D126BBAE5} + Win32Proj + keygen + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\win32;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libisccfg.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccfg\win32;..\..\..\lib\isccfg\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libisccfg.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + + + + + + + + + diff --git a/bin/dnssec/win32/keygen.vcxproj.user b/bin/dnssec/win32/keygen.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/keygen.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/win32/revoke.vcxproj.filters.in b/bin/dnssec/win32/revoke.vcxproj.filters.in new file mode 100644 index 0000000..46e7310 --- /dev/null +++ b/bin/dnssec/win32/revoke.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dnssec/win32/revoke.vcxproj.in b/bin/dnssec/win32/revoke.vcxproj.in new file mode 100644 index 0000000..28e6868 --- /dev/null +++ b/bin/dnssec/win32/revoke.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {D171F185-D3C2-4463-9CF3-ED1D0B1D6832} + Win32Proj + revoke + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/dnssec/win32/revoke.vcxproj.user b/bin/dnssec/win32/revoke.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/revoke.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/win32/settime.vcxproj.filters.in b/bin/dnssec/win32/settime.vcxproj.filters.in new file mode 100644 index 0000000..62b0e82 --- /dev/null +++ b/bin/dnssec/win32/settime.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dnssec/win32/settime.vcxproj.in b/bin/dnssec/win32/settime.vcxproj.in new file mode 100644 index 0000000..f5a6152 --- /dev/null +++ b/bin/dnssec/win32/settime.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {03FB7588-C5A7-4572-968F-14F1206BC69C} + Win32Proj + settime + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + + + + + + + + + diff --git a/bin/dnssec/win32/settime.vcxproj.user b/bin/dnssec/win32/settime.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/settime.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/win32/signzone.vcxproj.filters.in b/bin/dnssec/win32/signzone.vcxproj.filters.in new file mode 100644 index 0000000..682ae55 --- /dev/null +++ b/bin/dnssec/win32/signzone.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dnssec/win32/signzone.vcxproj.in b/bin/dnssec/win32/signzone.vcxproj.in new file mode 100644 index 0000000..2afa4dd --- /dev/null +++ b/bin/dnssec/win32/signzone.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {205ED8A9-2E4C-41CC-9385-F3613402AA90} + Win32Proj + signzone + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/dnssec/win32/signzone.vcxproj.user b/bin/dnssec/win32/signzone.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/signzone.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/dnssec/win32/verify.vcxproj.filters.in b/bin/dnssec/win32/verify.vcxproj.filters.in new file mode 100644 index 0000000..3b194bd --- /dev/null +++ b/bin/dnssec/win32/verify.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/dnssec/win32/verify.vcxproj.in b/bin/dnssec/win32/verify.vcxproj.in new file mode 100644 index 0000000..971eccd --- /dev/null +++ b/bin/dnssec/win32/verify.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {FD653434-F1A8-44A9-85B2-A7468491DA6D} + Win32Proj + verify + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + dnssec-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@dnssectool.lib;libisc.lib;libdns.lib;ws2_32.lib;%(AdditionalDependencies) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + + + + + + + + + diff --git a/bin/dnssec/win32/verify.vcxproj.user b/bin/dnssec/win32/verify.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/dnssec/win32/verify.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in new file mode 100644 index 0000000..3cbcb27 --- /dev/null +++ b/bin/named/Makefile.in @@ -0,0 +1,180 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +# Attempt to disable parallel processing. +.NOTPARALLEL: +.NO_PARALLEL: + +VERSION=@BIND9_VERSION@ + +@BIND9_PRODUCT@ + +@BIND9_DESCRIPTION@ + +@BIND9_SRCID@ + +@BIND9_CONFIGARGS@ + +@BIND9_MAKE_INCLUDES@ + +# +# Add database drivers here. +# +DBDRIVER_OBJS = +DBDRIVER_SRCS = +DBDRIVER_INCLUDES = +DBDRIVER_LIBS = + +DLZ_DRIVER_DIR = ${top_srcdir}/contrib/dlz/drivers + +DLZDRIVER_OBJS = @DLZ_DRIVER_OBJS@ +DLZDRIVER_SRCS = @DLZ_DRIVER_SRCS@ +DLZDRIVER_INCLUDES = @DLZ_DRIVER_INCLUDES@ +DLZDRIVER_LIBS = @DLZ_DRIVER_LIBS@ + +CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ + ${NS_INCLUDES} ${DNS_INCLUDES} \ + ${BIND9_INCLUDES} ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} \ + ${ISC_INCLUDES} ${DLZDRIVER_INCLUDES} \ + ${DBDRIVER_INCLUDES} \ + ${LIBUV_CFLAGS} \ + ${FSTRM_CFLAGS} \ + ${LMDB_CFLAGS} \ + ${OPENSSL_CFLAGS} \ + ${PROTOBUF_C_CFLAGS} \ + ${JSON_C_CFLAGS} \ + ${LIBXML2_CFLAGS} \ + ${MAXMINDDB_CFLAGS} + +CDEFINES = @CONTRIB_DLZ@ + +CWARNINGS = + +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCLIBS = ../../lib/isccc/libisccc.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +BIND9LIBS = ../../lib/bind9/libbind9.@A@ +NSLIBS = ../../lib/ns/libns.@A@ + +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCDEPLIBS = ../../lib/isccc/libisccc.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ +NSDEPLIBS = ../../lib/ns/libns.@A@ + +DEPLIBS = ${NSDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \ + ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${ISCDEPLIBS} + +LIBS = ${NSLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \ + ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBCAP_LIBS@ \ + ${FSTRM_LIBS} ${PROTOBUF_C_LIBS} ${LMDB_LIBS} ${ZLIB_LIBS} \ + ${JSON_C_LIBS} ${LIBXML2_LIBS} ${MAXMINDDB_LIBS} \ + ${LIBUV_LIBS} ${OPENSSL_LIBS} @LIBS@ + +NOSYMLIBS = ${NSLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCNOSYMLIBS} \ + ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBCAP_LIBS@ \ + ${FSTRM_LIBS} ${PROTOBUF_C_LIBS} ${LMDB_LIBS} ${ZLIB_LIBS} \ + ${LIBUV_LIBS} @LIBS@ + +SUBDIRS = unix + +TARGETS = named@EXEEXT@ + +GEOIP2LINKOBJS = geoip.@O@ + +OBJS = builtin.@O@ config.@O@ control.@O@ \ + controlconf.@O@ fuzz.@O@ \ + @GEOIP2LINKOBJS@ \ + log.@O@ logconf.@O@ main.@O@ \ + server.@O@ statschannel.@O@ \ + tkeyconf.@O@ tsigconf.@O@ zoneconf.@O@ \ + ${DLZDRIVER_OBJS} ${DBDRIVER_OBJS} + +UOBJS = unix/os.@O@ unix/dlz_dlopen_driver.@O@ + +SYMOBJS = symtbl.@O@ + +GEOIP2LINKSRCS = geoip.c + +SRCS = builtin.c config.c control.c \ + controlconf.c fuzz.c \ + @GEOIP2LINKSRCS@ \ + log.c logconf.c main.c \ + server.c statschannel.c \ + tkeyconf.c tsigconf.c zoneconf.c \ + ${DLZDRIVER_SRCS} ${DBDRIVER_SRCS} + +@BIND9_MAKE_RULES@ + +main.@O@: main.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -DPRODUCT=\"${PRODUCT}\" \ + -DDESCRIPTION=\"${DESCRIPTION}\" \ + -DSRCID=\"${SRCID}\" \ + -DCONFIGARGS="\"${CONFIGARGS}\"" \ + -DBUILDER="\"make\"" \ + -DNAMED_LOCALSTATEDIR=\"${localstatedir}\" \ + -DNAMED_SYSCONFDIR=\"${sysconfdir}\" -c ${srcdir}/main.c + +config.@O@: config.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -DSRCID=\"${SRCID}\" \ + -DDYNDB_LIBDIR=\"@libdir@/bind\" \ + -DNAMED_LOCALSTATEDIR=\"${localstatedir}\" \ + -DNAMED_SYSCONFDIR=\"${sysconfdir}\" \ + -DMAXMINDDB_PREFIX=\"@MAXMINDDB_PREFIX@\" \ + -c ${srcdir}/config.c + +server.@O@: server.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DPRODUCT=\"${PRODUCT}\" \ + -DVERSION=\"${VERSION}\" -c ${srcdir}/server.c + +named@EXEEXT@: ${OBJS} ${DEPLIBS} + export MAKE_SYMTABLE="yes"; \ + export BASEOBJS="${OBJS} ${UOBJS}"; \ + ${FINALBUILDCMD} + +clean distclean maintainer-clean:: + rm -f ${TARGETS} ${OBJS} + +maintainer-clean:: + +bind9.xsl.h: bind9.xsl ${srcdir}/convertxsl.pl + ${PERL} ${srcdir}/convertxsl.pl < ${srcdir}/bind9.xsl > bind9.xsl.h + +depend: bind9.xsl.h +statschannel.@O@: bind9.xsl.h + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} + +install:: named@EXEEXT@ installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named@EXEEXT@ ${DESTDIR}${sbindir} + +uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${sbindir}/named@EXEEXT@ + +@DLZ_DRIVER_RULES@ + +named-symtbl.@O@: named-symtbl.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c named-symtbl.c diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl new file mode 100644 index 0000000..309e5d4 --- /dev/null +++ b/bin/named/bind9.xsl @@ -0,0 +1,1144 @@ + + + + + + + + + + + + + + + + + + ISC BIND 9 Statistics + + +
+

ISC Bind 9 Configuration and Statistics

+
+

Alternate statistics views: All, + Status, + Server, + Zones, + Network, + Tasks, + Memory and + Traffic Size

+
+

Server Status

+ + + + + + + + + + + + + + + + + +
Boot time: + +
Last reconfigured: + +
Current time: + +
Server version: + +
+
+ + +

Incoming Requests by DNS Opcode

+ +
+ [cannot display chart] +
+
+ + + + + + even + odd + + + + + + + + + + + +
+ + + +
Total: + +
+
+
+ + + +

Incoming Queries by Query Type

+
+ [cannot display chart] +
+
+ + + + + + even + odd + + + + + + + + + + + +
+ + + +
Total: + +
+
+
+ +

Outgoing Queries per view

+ +

View

+ + + + + + +
[no data to display]
+
+ + + + + + even + odd + + + + + + + +
+ + + +
+
+
+
+ +

Server Statistics

+ + + +
[no data to display]
+
+ + + + + + even + odd + + + + + + + +
+ + + +
+
+
+ + +

Zone Maintenance Statistics

+ + +
[no data to display]
+
+ + + + + + even + odd + + + + + + + +
+ + + +
+
+ +

Resolver Statistics (Common)

+ + + + + + even + odd + + + + + + + +
+ + + +
+
+ + +

Resolver Statistics for View

+ + + + + + even + odd + + + + + + + +
+ + + +
+
+
+ + +

ADB Statistics for View

+ + + + + + even + odd + + + + + + + +
+ + + +
+
+
+ + +

Cache Statistics for View

+ + + + + + even + odd + + + + + + + +
+ + + +
+
+
+ + +

Cache DB RRsets for View

+ + + + + even + odd + + + + + + + +
+ + + +
+
+
+
+ +

Traffic Size Statistics

+
+ +

UDP Requests Received

+ + + + + even + odd + + + + + + + + +
+ + + +
+
+
+ +

UDP Responses Sent

+ + + + + even + odd + + + + + + + + +
+ + + +
+
+
+ +

TCP Requests Received

+ + + + + even + odd + + + + + + + + +
+ + + +
+
+
+ +

TCP Responses Sent

+ + + + + even + odd + + + + + + + + +
+ + + +
+
+
+ +

Socket I/O Statistics

+ + + + + even + odd + + + + + + + +
+ + + +
+
+
+ + +

Zones for View

+ + + + + + + even + odd + + + + + + + + + + + + +
NameClassTypeSerialLoadedExpiresRefresh
+
+
+ +

Received QTYPES per view/zone

+ +

View

+ + + + + +

Zone

+ + + + + + +
[no data to display]
+
+ + + + + + even + odd + + + + + + + +
+ + + +
+
+
+
+
+ +

Response Codes per view/zone

+ +

View

+ + + + + +

Zone

+ + + + + + +
[no data to display]
+
+ + + + + + even + odd + + + + + + + +
+ + + +
+
+
+
+
+ +

Glue cache statistics

+ +

View

+ + + + + +

Zone

+ + + + + + even + odd + + + + + + + +
+ + + +
+
+
+
+
+ +

Network Status

+ + + + + + + + + + + + + + + even + odd + + + + + + + + + + + + +
IDNameTypeReferencesLocalAddressPeerAddressState
+ + + + + + + + + + + + + + + +
+
+
+ +

Task Manager Configuration

+ + + + + + + + + + + + + + + + + + + + + +
Thread-Model + +
Worker Threads + +
Default Quantum + +
Tasks Running + +
Tasks Ready + +
+
+
+ +

Tasks

+ + + + + + + + + + + + + + even + odd + + + + + + + + + + + +
IDNameReferencesStateQuantumEvents
+ + + + + + + + + + + +
+
+
+ +

Memory Usage Summary

+ + + + + even + odd + + + + + + + +
+ + + +
+
+
+ +

Memory Contexts

+ + + + + + + + + + + + + + + + + + + + even + odd + + + + + + + + + + + + + + + + + +
IDNameReferencesTotalUseInUseMaxUseMallocedMaxMallocedBlockSizePoolsHiWaterLoWater
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + diff --git a/bin/named/bind9.xsl.h b/bin/named/bind9.xsl.h new file mode 100644 index 0000000..fabb5fa --- /dev/null +++ b/bin/named/bind9.xsl.h @@ -0,0 +1,1267 @@ +/* + * Generated by convertxsl.pl 1.14 2008/07/17 23:43:26 jinmei Exp + * From unknown + */ +static char xslmsg[] = + "\n" + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ISC BIND 9 Statistics\n" + " \n" + " \n" + "
\n" + "

ISC Bind 9 Configuration and Statistics

\n" + "
\n" + "

Alternate statistics views: All,\n" + " Status,\n" + " Server,\n" + " Zones,\n" + " Network,\n" + " Tasks,\n" + " Memory and\n" + " Traffic Size

\n" + "
\n" + "

Server Status

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Boot time:\n" + " \n" + "
Last reconfigured:\n" + " \n" + "
Current time:\n" + " \n" + "
Server version:\n" + " \n" + "
\n" + "
\n" + " \n" + " \n" + "

Incoming Requests by DNS Opcode

\n" + " \n" + "
\n" + " [cannot display chart]\n" + "
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
Total:\n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + " \n" + " \n" + "

Incoming Queries by Query Type

\n" + "
\n" + " [cannot display chart]\n" + "
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
Total:\n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + "

Outgoing Queries per view

\n" + " \n" + "

View

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
[no " + "data to display]
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + " \n" + "

Server Statistics

\n" + " \n" + " \n" + " \n" + "
[no data to " + "display]
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + " \n" + "

Zone Maintenance Statistics

\n" + " \n" + " \n" + "
[no data to " + "display]
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + " \n" + "

Resolver Statistics (Common)

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + " \n" + " \n" + "

Resolver Statistics for View

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + " \n" + "

ADB Statistics for View

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + " \n" + "

Cache Statistics for View

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + " \n" + "

Cache DB RRsets for View

\n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + " \n" + "

Traffic Size Statistics

\n" + "
\n" + " \n" + "

UDP Requests Received

\n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + "

UDP Responses Sent

\n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + "

TCP Requests Received

\n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + "

TCP Responses Sent

\n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + "

Socket I/O Statistics

\n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + " \n" + "

Zones for View

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
NameClassTypeSerialLoadedExpiresRefresh
\n" + "
\n" + "
\n" + " \n" + "

Received QTYPES per view/zone

\n" + " \n" + "

View

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "

Zone

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
[no data " + "to display]
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + " \n" + "

Response Codes per view/zone

\n" + " \n" + "

View

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "

Zone

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
[no " + "data to display]
\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + " \n" + "

Glue cache statistics

\n" + " \n" + "

View

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "

Zone

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + " \n" + "

Network Status

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
IDNameTypeReferencesLocalAddressPeerAddressState
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + "

Task Manager Configuration

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Thread-Model\n" + " \n" + "
Worker Threads\n" + " \n" + "
Default Quantum\n" + " \n" + "
Tasks Running\n" + " \n" + "
Tasks Ready\n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + "

Tasks

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
IDNameReferencesStateQuantumEvents
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + "

Memory Usage Summary

\n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + " \n" + "

Memory Contexts

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " even\n" + " odd\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
IDNameReferencesTotalUseInUseMaxUseMallocedMaxMallocedBlockSizePoolsHiWaterLoWater
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + "
\n" + "
\n" + "

Internet Systems Consortium Inc.
http://www.isc.org

\n" + " \n" + " \n" + "
\n" + "
\n"; diff --git a/bin/named/builtin.c b/bin/named/builtin.c new file mode 100644 index 0000000..6781c3d --- /dev/null +++ b/bin/named/builtin.c @@ -0,0 +1,592 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file + * \brief + * The built-in "version", "hostname", "id", "authors" and "empty" databases. + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +typedef struct builtin builtin_t; + +static isc_result_t +do_version_lookup(dns_sdblookup_t *lookup); +static isc_result_t +do_hostname_lookup(dns_sdblookup_t *lookup); +static isc_result_t +do_authors_lookup(dns_sdblookup_t *lookup); +static isc_result_t +do_id_lookup(dns_sdblookup_t *lookup); +static isc_result_t +do_empty_lookup(dns_sdblookup_t *lookup); +static isc_result_t +do_dns64_lookup(dns_sdblookup_t *lookup); + +/* + * We can't use function pointers as the db_data directly + * because ANSI C does not guarantee that function pointers + * can safely be cast to void pointers and back. + */ + +struct builtin { + isc_result_t (*do_lookup)(dns_sdblookup_t *lookup); + char *server; + char *contact; +}; + +static builtin_t version_builtin = { do_version_lookup, NULL, NULL }; +static builtin_t hostname_builtin = { do_hostname_lookup, NULL, NULL }; +static builtin_t authors_builtin = { do_authors_lookup, NULL, NULL }; +static builtin_t id_builtin = { do_id_lookup, NULL, NULL }; +static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL }; +static builtin_t dns64_builtin = { do_dns64_lookup, NULL, NULL }; + +static dns_sdbimplementation_t *builtin_impl; +static dns_sdbimplementation_t *dns64_impl; + +/* + * Pre computed HEX * 16 or 1 table. + */ +static const unsigned char hex16[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*00*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*20*/ + 0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 1, 1, 1, 1, 1, 1, /*30*/ + 1, 160, 176, 192, 208, 224, 240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*50*/ + 1, 160, 176, 192, 208, 224, 240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*A0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*B0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*C0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*D0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*E0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /*F0*/ +}; + +const unsigned char decimal[] = "0123456789"; + +static size_t +dns64_rdata(unsigned char *v, size_t start, unsigned char *rdata) { + size_t i, j = 0; + + for (i = 0; i < 4U; i++) { + unsigned char c = v[start++]; + if (start == 7U) { + start++; + } + if (c > 99) { + rdata[j++] = 3; + rdata[j++] = decimal[c / 100]; + c = c % 100; + rdata[j++] = decimal[c / 10]; + c = c % 10; + rdata[j++] = decimal[c]; + } else if (c > 9) { + rdata[j++] = 2; + rdata[j++] = decimal[c / 10]; + c = c % 10; + rdata[j++] = decimal[c]; + } else { + rdata[j++] = 1; + rdata[j++] = decimal[c]; + } + } + memmove(&rdata[j], "\07in-addr\04arpa", 14); + return (j + 14); +} + +static isc_result_t +dns64_cname(const dns_name_t *zone, const dns_name_t *name, + dns_sdblookup_t *lookup) { + size_t zlen, nlen, j, len; + unsigned char v[16], n; + unsigned int i; + unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")]; + unsigned char *ndata; + + /* + * The combined length of the zone and name is 74. + * + * The minimum zone length is 10 ((3)ip6(4)arpa(0)). + * + * The length of name should always be even as we are expecting + * a series of nibbles. + */ + zlen = zone->length; + nlen = name->length; + if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U) { + return (ISC_R_NOTFOUND); + } + + /* + * We assume the zone name is well formed. + */ + + /* + * XXXMPA We could check the dns64 suffix here if we need to. + */ + /* + * Check that name is a series of nibbles. + * Compute the byte values that correspond to the nibbles as we go. + * + * Shift the final result 4 bits, by setting 'i' to 1, if we if we + * have a odd number of nibbles so that "must be zero" tests below + * are byte aligned and we correctly return ISC_R_NOTFOUND or + * ISC_R_SUCCESS. We will not generate a CNAME in this case. + */ + ndata = name->ndata; + i = (nlen % 4) == 2U ? 1 : 0; + j = nlen; + memset(v, 0, sizeof(v)); + while (j != 0U) { + INSIST((i / 2) < sizeof(v)); + if (ndata[0] != 1) { + return (ISC_R_NOTFOUND); + } + n = hex16[ndata[1] & 0xff]; + if (n == 1) { + return (ISC_R_NOTFOUND); + } + v[i / 2] = n | (v[i / 2] >> 4); + j -= 2; + ndata += 2; + i++; + } + + /* + * If we get here then we know name only consisted of nibbles. + * Now we need to determine if the name exists or not and whether + * it corresponds to a empty node in the zone or there should be + * a CNAME. + */ +#define ZLEN(x) (10 + (x) / 2) + switch (zlen) { + case ZLEN(32): /* prefix len 32 */ + /* + * The nibbles that map to this byte must be zero for 'name' + * to exist in the zone. + */ + if (nlen > 16U && v[(nlen - 1) / 4 - 4] != 0) { + return (ISC_R_NOTFOUND); + } + /* + * If the total length is not 74 then this is a empty node + * so return success. + */ + if (nlen + zlen != 74U) { + return (ISC_R_SUCCESS); + } + len = dns64_rdata(v, 8, rdata); + break; + case ZLEN(40): /* prefix len 40 */ + /* + * The nibbles that map to this byte must be zero for 'name' + * to exist in the zone. + */ + if (nlen > 12U && v[(nlen - 1) / 4 - 3] != 0) { + return (ISC_R_NOTFOUND); + } + /* + * If the total length is not 74 then this is a empty node + * so return success. + */ + if (nlen + zlen != 74U) { + return (ISC_R_SUCCESS); + } + len = dns64_rdata(v, 6, rdata); + break; + case ZLEN(48): /* prefix len 48 */ + /* + * The nibbles that map to this byte must be zero for 'name' + * to exist in the zone. + */ + if (nlen > 8U && v[(nlen - 1) / 4 - 2] != 0) { + return (ISC_R_NOTFOUND); + } + /* + * If the total length is not 74 then this is a empty node + * so return success. + */ + if (nlen + zlen != 74U) { + return (ISC_R_SUCCESS); + } + len = dns64_rdata(v, 5, rdata); + break; + case ZLEN(56): /* prefix len 56 */ + /* + * The nibbles that map to this byte must be zero for 'name' + * to exist in the zone. + */ + if (nlen > 4U && v[(nlen - 1) / 4 - 1] != 0) { + return (ISC_R_NOTFOUND); + } + /* + * If the total length is not 74 then this is a empty node + * so return success. + */ + if (nlen + zlen != 74U) { + return (ISC_R_SUCCESS); + } + len = dns64_rdata(v, 4, rdata); + break; + case ZLEN(64): /* prefix len 64 */ + /* + * The nibbles that map to this byte must be zero for 'name' + * to exist in the zone. + */ + if (v[(nlen - 1) / 4] != 0) { + return (ISC_R_NOTFOUND); + } + /* + * If the total length is not 74 then this is a empty node + * so return success. + */ + if (nlen + zlen != 74U) { + return (ISC_R_SUCCESS); + } + len = dns64_rdata(v, 3, rdata); + break; + case ZLEN(96): /* prefix len 96 */ + /* + * If the total length is not 74 then this is a empty node + * so return success. + */ + if (nlen + zlen != 74U) { + return (ISC_R_SUCCESS); + } + len = dns64_rdata(v, 0, rdata); + break; + default: + /* + * This should never be reached unless someone adds a + * zone declaration with this internal type to named.conf. + */ + return (ISC_R_NOTFOUND); + } + return (dns_sdb_putrdata(lookup, dns_rdatatype_cname, 600, rdata, + (unsigned int)len)); +} + +static isc_result_t +builtin_lookup(const char *zone, const char *name, void *dbdata, + dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo) { + builtin_t *b = (builtin_t *)dbdata; + + UNUSED(zone); + UNUSED(methods); + UNUSED(clientinfo); + + if (strcmp(name, "@") == 0) { + return (b->do_lookup(lookup)); + } else { + return (ISC_R_NOTFOUND); + } +} + +static isc_result_t +dns64_lookup(const dns_name_t *zone, const dns_name_t *name, void *dbdata, + dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo) { + builtin_t *b = (builtin_t *)dbdata; + + UNUSED(methods); + UNUSED(clientinfo); + + if (name->labels == 0 && name->length == 0) { + return (b->do_lookup(lookup)); + } else { + return (dns64_cname(zone, name, lookup)); + } +} + +static isc_result_t +put_txt(dns_sdblookup_t *lookup, const char *text) { + unsigned char buf[256]; + unsigned int len = strlen(text); + if (len > 255) { + len = 255; /* Silently truncate */ + } + buf[0] = len; + memmove(&buf[1], text, len); + return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1)); +} + +static isc_result_t +do_version_lookup(dns_sdblookup_t *lookup) { + if (named_g_server->version_set) { + if (named_g_server->version == NULL) { + return (ISC_R_SUCCESS); + } else { + return (put_txt(lookup, named_g_server->version)); + } + } else { + return (put_txt(lookup, named_g_version)); + } +} + +static isc_result_t +do_hostname_lookup(dns_sdblookup_t *lookup) { + if (named_g_server->hostname_set) { + if (named_g_server->hostname == NULL) { + return (ISC_R_SUCCESS); + } else { + return (put_txt(lookup, named_g_server->hostname)); + } + } else { + char buf[256]; + isc_result_t result = named_os_gethostname(buf, sizeof(buf)); + if (result != ISC_R_SUCCESS) { + return (result); + } + return (put_txt(lookup, buf)); + } +} + +static isc_result_t +do_authors_lookup(dns_sdblookup_t *lookup) { + isc_result_t result; + const char **p; + static const char *authors[] = { + "Mark Andrews", "Curtis Blackburn", "James Brister", + "Ben Cottrell", "John H. DuBois III", "Francis Dupont", + "Michael Graff", "Andreas Gustafsson", "Bob Halley", + "Evan Hunt", "JINMEI Tatuya", "Witold Krecicki", + "David Lawrence", "Scott Mann", "Danny Mayer", + "Damien Neil", "Matt Nelson", "Jeremy C. Reed", + "Michael Sawyer", "Brian Wellington", NULL + }; + + /* + * If a version string is specified, disable the authors.bind zone. + */ + if (named_g_server->version_set) { + return (ISC_R_SUCCESS); + } + + for (p = authors; *p != NULL; p++) { + result = put_txt(lookup, *p); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + return (ISC_R_SUCCESS); +} + +static isc_result_t +do_id_lookup(dns_sdblookup_t *lookup) { + if (named_g_server->sctx->gethostname != NULL) { + char buf[256]; + isc_result_t result; + + result = named_g_server->sctx->gethostname(buf, sizeof(buf)); + if (result != ISC_R_SUCCESS) { + return (result); + } + return (put_txt(lookup, buf)); + } else if (named_g_server->sctx->server_id != NULL) { + return (put_txt(lookup, named_g_server->sctx->server_id)); + } else { + return (ISC_R_SUCCESS); + } +} + +static isc_result_t +do_dns64_lookup(dns_sdblookup_t *lookup) { + UNUSED(lookup); + return (ISC_R_SUCCESS); +} + +static isc_result_t +do_empty_lookup(dns_sdblookup_t *lookup) { + UNUSED(lookup); + return (ISC_R_SUCCESS); +} + +static isc_result_t +builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) { + isc_result_t result; + const char *contact = "hostmaster"; + const char *server = "@"; + builtin_t *b = (builtin_t *)dbdata; + + UNUSED(zone); + UNUSED(dbdata); + + if (b == &empty_builtin) { + server = "."; + contact = "."; + } else { + if (b->server != NULL) { + server = b->server; + } + if (b->contact != NULL) { + contact = b->contact; + } + } + + result = dns_sdb_putsoa(lookup, server, contact, 0); + if (result != ISC_R_SUCCESS) { + return (ISC_R_FAILURE); + } + + result = dns_sdb_putrr(lookup, "ns", 0, server); + if (result != ISC_R_SUCCESS) { + return (ISC_R_FAILURE); + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +builtin_create(const char *zone, int argc, char **argv, void *driverdata, + void **dbdata) { + REQUIRE(argc >= 1); + + UNUSED(zone); + UNUSED(driverdata); + + if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) { + if (argc != 3) { + return (DNS_R_SYNTAX); + } + } else if (argc != 1) { + return (DNS_R_SYNTAX); + } + + if (strcmp(argv[0], "version") == 0) { + *dbdata = &version_builtin; + } else if (strcmp(argv[0], "hostname") == 0) { + *dbdata = &hostname_builtin; + } else if (strcmp(argv[0], "authors") == 0) { + *dbdata = &authors_builtin; + } else if (strcmp(argv[0], "id") == 0) { + *dbdata = &id_builtin; + } else if (strcmp(argv[0], "empty") == 0 || + strcmp(argv[0], "dns64") == 0) + { + builtin_t *empty; + char *server; + char *contact; + /* + * We don't want built-in zones to fail. Fallback to + * the static configuration if memory allocation fails. + */ + empty = isc_mem_get(named_g_mctx, sizeof(*empty)); + server = isc_mem_strdup(named_g_mctx, argv[1]); + contact = isc_mem_strdup(named_g_mctx, argv[2]); + if (empty == NULL || server == NULL || contact == NULL) { + if (strcmp(argv[0], "empty") == 0) { + *dbdata = &empty_builtin; + } else { + *dbdata = &dns64_builtin; + } + if (server != NULL) { + isc_mem_free(named_g_mctx, server); + } + if (contact != NULL) { + isc_mem_free(named_g_mctx, contact); + } + if (empty != NULL) { + isc_mem_put(named_g_mctx, empty, + sizeof(*empty)); + } + } else { + if (strcmp(argv[0], "empty") == 0) { + memmove(empty, &empty_builtin, + sizeof(empty_builtin)); + } else { + memmove(empty, &dns64_builtin, + sizeof(empty_builtin)); + } + empty->server = server; + empty->contact = contact; + *dbdata = empty; + } + } else { + return (ISC_R_NOTIMPLEMENTED); + } + return (ISC_R_SUCCESS); +} + +static void +builtin_destroy(const char *zone, void *driverdata, void **dbdata) { + builtin_t *b = (builtin_t *)*dbdata; + + UNUSED(zone); + UNUSED(driverdata); + + /* + * Don't free the static versions. + */ + if (*dbdata == &version_builtin || *dbdata == &hostname_builtin || + *dbdata == &authors_builtin || *dbdata == &id_builtin || + *dbdata == &empty_builtin || *dbdata == &dns64_builtin) + { + return; + } + + isc_mem_free(named_g_mctx, b->server); + isc_mem_free(named_g_mctx, b->contact); + isc_mem_put(named_g_mctx, b, sizeof(*b)); +} + +static dns_sdbmethods_t builtin_methods = { + builtin_lookup, builtin_authority, NULL, /* allnodes */ + builtin_create, builtin_destroy, NULL +}; + +static dns_sdbmethods_t dns64_methods = { + NULL, builtin_authority, NULL, /* allnodes */ + builtin_create, builtin_destroy, dns64_lookup, +}; + +isc_result_t +named_builtin_init(void) { + RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL, + DNS_SDBFLAG_RELATIVEOWNER | + DNS_SDBFLAG_RELATIVERDATA, + named_g_mctx, + &builtin_impl) == ISC_R_SUCCESS); + RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods, NULL, + DNS_SDBFLAG_RELATIVEOWNER | + DNS_SDBFLAG_RELATIVERDATA | + DNS_SDBFLAG_DNS64, + named_g_mctx, + &dns64_impl) == ISC_R_SUCCESS); + return (ISC_R_SUCCESS); +} + +void +named_builtin_deinit(void) { + dns_sdb_unregister(&builtin_impl); + dns_sdb_unregister(&dns64_impl); +} diff --git a/bin/named/config.c b/bin/named/config.c new file mode 100644 index 0000000..4941470 --- /dev/null +++ b/bin/named/config.c @@ -0,0 +1,1090 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +/*% default configuration */ +static char defaultconf[] = "\ +options {\n\ + answer-cookie true;\n\ + automatic-interface-scan yes;\n\ + bindkeys-file \"" NAMED_SYSCONFDIR "/bind.keys\";\n\ +# blackhole {none;};\n\ + cookie-algorithm siphash24;\n" +#ifndef WIN32 + " coresize default;\n\ + datasize default;\n" +#endif /* ifndef WIN32 */ + "\ +# directory \n\ + dnssec-policy \"none\";\n\ + dump-file \"named_dump.db\";\n\ + edns-udp-size 1232;\n" +#ifndef WIN32 + " files unlimited;\n" +#endif /* ifndef WIN32 */ +#if defined(HAVE_GEOIP2) && !defined(WIN32) + " geoip-directory \"" MAXMINDDB_PREFIX + "/share/GeoIP\";\n" +#elif defined(HAVE_GEOIP2) + " geoip-directory \".\";\n" +#endif /* if defined(HAVE_GEOIP2) && !defined(WIN32) */ + "\ + heartbeat-interval 60;\n\ + interface-interval 60;\n\ +# keep-response-order {none;};\n\ + listen-on {any;};\n\ + listen-on-v6 {any;};\n\ +# lock-file \"" NAMED_LOCALSTATEDIR "/run/named/named.lock\";\n\ + match-mapped-addresses no;\n\ + max-ixfr-ratio unlimited;\n\ + max-rsa-exponent-size 0; /* no limit */\n\ + max-udp-size 1232;\n\ + memstatistics-file \"named.memstats\";\n\ + nocookie-udp-size 4096;\n\ + notify-rate 20;\n\ + nta-lifetime 3600;\n\ + nta-recheck 300;\n\ +# pid-file \"" NAMED_LOCALSTATEDIR "/run/named/named.pid\"; \n\ + port 53;\n" +#if HAVE_SO_REUSEPORT_LB + "\ + reuseport yes;\n" +#else + "\ + reuseport no;\n" +#endif + "\ + prefetch 2 9;\n\ + recursing-file \"named.recursing\";\n\ + recursive-clients 1000;\n\ + request-nsid false;\n\ + reserved-sockets 512;\n\ + resolver-query-timeout 10;\n\ + rrset-order { order random; };\n\ + secroots-file \"named.secroots\";\n\ + send-cookie true;\n\ + serial-query-rate 20;\n\ + server-id none;\n\ + session-keyalg hmac-sha256;\n\ +# session-keyfile \"" NAMED_LOCALSTATEDIR "/run/named/session.key\";\n\ + session-keyname local-ddns;\n" +#ifndef WIN32 + " stacksize default;\n" +#endif /* ifndef WIN32 */ + " startup-notify-rate 20;\n\ + statistics-file \"named.stats\";\n\ + tcp-advertised-timeout 300;\n\ + tcp-clients 150;\n\ + tcp-idle-timeout 300;\n\ + tcp-initial-timeout 300;\n\ + tcp-keepalive-timeout 300;\n\ + tcp-listen-queue 10;\n\ +# tkey-dhkey \n\ +# tkey-domain \n\ +# tkey-gssapi-credential \n\ + transfer-message-size 20480;\n\ + transfers-in 10;\n\ + transfers-out 10;\n\ + transfers-per-ns 2;\n\ + trust-anchor-telemetry yes;\n\ + update-quota 100;\n\ +\n\ + /* view */\n\ + allow-new-zones no;\n\ + allow-notify {none;};\n\ + allow-query-cache { localnets; localhost; };\n\ + allow-query-cache-on { any; };\n\ + allow-recursion { localnets; localhost; };\n\ + allow-recursion-on { any; };\n\ + allow-update-forwarding {none;};\n\ + auth-nxdomain false;\n\ + check-dup-records warn;\n\ + check-mx warn;\n\ + check-names primary fail;\n\ + check-names response ignore;\n\ + check-names secondary warn;\n\ + check-spf warn;\n\ + clients-per-query 10;\n\ + dnssec-accept-expired no;\n\ + dnssec-validation " VALIDATION_DEFAULT "; \n" +#ifdef HAVE_DNSTAP + " dnstap-identity hostname;\n" +#endif /* ifdef HAVE_DNSTAP */ + "\ + fetch-quota-params 100 0.1 0.3 0.7;\n\ + fetches-per-server 0;\n\ + fetches-per-zone 0;\n\ + glue-cache yes;\n\ + lame-ttl 0;\n" +#ifdef HAVE_LMDB + " lmdb-mapsize 32M;\n" +#endif /* ifdef HAVE_LMDB */ + " max-cache-size 90%;\n\ + max-cache-ttl 604800; /* 1 week */\n\ + max-clients-per-query 100;\n\ + max-ncache-ttl 10800; /* 3 hours */\n\ + max-recursion-depth 7;\n\ + max-recursion-queries 100;\n\ + max-stale-ttl 86400; /* 1 day */\n\ + message-compression yes;\n\ + min-ncache-ttl 0; /* 0 hours */\n\ + min-cache-ttl 0; /* 0 seconds */\n\ + minimal-any false;\n\ + minimal-responses no-auth-recursive;\n\ + notify-source *;\n\ + notify-source-v6 *;\n\ + nsec3-test-zone no;\n\ + parental-source *;\n\ + parental-source-v6 *;\n\ + provide-ixfr true;\n\ + qname-minimization relaxed;\n\ + query-source address *;\n\ + query-source-v6 address *;\n\ + recursion true;\n\ + request-expire true;\n\ + request-ixfr true;\n\ + require-server-cookie no;\n\ + resolver-nonbackoff-tries 3;\n\ + resolver-retry-interval 800; /* in milliseconds */\n\ + root-key-sentinel yes;\n\ + servfail-ttl 1;\n\ +# sortlist \n\ + stale-answer-client-timeout off;\n\ + stale-answer-enable false;\n\ + stale-answer-ttl 30; /* 30 seconds */\n\ + stale-cache-enable true;\n\ + stale-refresh-time 30; /* 30 seconds */\n\ + synth-from-dnssec no;\n\ +# topology \n\ + transfer-format many-answers;\n\ + v6-bias 50;\n\ + zero-no-soa-ttl-cache no;\n\ +\n\ + /* zone */\n\ + allow-query {any;};\n\ + allow-query-on {any;};\n\ + allow-transfer {any;};\n\ +# also-notify \n\ + alt-transfer-source *;\n\ + alt-transfer-source-v6 *;\n\ + check-integrity yes;\n\ + check-mx-cname warn;\n\ + check-sibling yes;\n\ + check-srv-cname warn;\n\ + check-wildcard yes;\n\ + dialup no;\n\ + dnssec-dnskey-kskonly no;\n\ + dnssec-loadkeys-interval 60;\n\ + dnssec-secure-to-insecure no;\n\ + dnssec-update-mode maintain;\n\ +# forward \n\ +# forwarders \n\ +# inline-signing no;\n\ + ixfr-from-differences false;\n\ + max-journal-size default;\n\ + max-records 0;\n\ + max-refresh-time 2419200; /* 4 weeks */\n\ + max-retry-time 1209600; /* 2 weeks */\n\ + max-transfer-idle-in 60;\n\ + max-transfer-idle-out 60;\n\ + max-transfer-time-in 120;\n\ + max-transfer-time-out 120;\n\ + min-refresh-time 300;\n\ + min-retry-time 500;\n\ + multi-master no;\n\ + notify yes;\n\ + notify-delay 5;\n\ + notify-to-soa no;\n\ + serial-update-method increment;\n\ + sig-signing-nodes 100;\n\ + sig-signing-signatures 10;\n\ + sig-signing-type 65534;\n\ + sig-validity-interval 30; /* days */\n\ + dnskey-sig-validity 0; /* default: sig-validity-interval */\n\ + transfer-source *;\n\ + transfer-source-v6 *;\n\ + try-tcp-refresh yes; /* BIND 8 compat */\n\ + update-check-ksk yes;\n\ + zero-no-soa-ttl yes;\n\ + zone-statistics terse;\n\ +};\n\ +" + + "#\n\ +# Zones in the \"_bind\" view are NOT counted in the count of zones.\n\ +#\n\ +view \"_bind\" chaos {\n\ + recursion no;\n\ + notify no;\n\ + allow-new-zones no;\n\ + max-cache-size 2M;\n\ +\n\ + # Prevent use of this zone in DNS amplified reflection DoS attacks\n\ + rate-limit {\n\ + responses-per-second 3;\n\ + slip 0;\n\ + min-table-size 10;\n\ + };\n\ +\n\ + zone \"version.bind\" chaos {\n\ + type primary;\n\ + database \"_builtin version\";\n\ + };\n\ +\n\ + zone \"hostname.bind\" chaos {\n\ + type primary;\n\ + database \"_builtin hostname\";\n\ + };\n\ +\n\ + zone \"authors.bind\" chaos {\n\ + type primary;\n\ + database \"_builtin authors\";\n\ + };\n\ +\n\ + zone \"id.server\" chaos {\n\ + type primary;\n\ + database \"_builtin id\";\n\ + };\n\ +};\n\ +" + "#\n\ +# Default trusted key(s), used if \n\ +# \"dnssec-validation auto;\" is set and\n\ +# " NAMED_SYSCONFDIR "/bind.keys doesn't exist).\n\ +#\n\ +# BEGIN TRUST ANCHORS\n" + + /* Imported from bind.keys.h: */ + TRUST_ANCHORS + + "# END TRUST ANCHORS\n\ +\n\ +primaries " DEFAULT_IANA_ROOT_ZONE_PRIMARIES " {\n\ + 2001:500:200::b; # b.root-servers.net\n\ + 2001:500:2::c; # c.root-servers.net\n\ + 2001:500:2f::f; # f.root-servers.net\n\ + 2001:500:12::d0d; # g.root-servers.net\n\ + 2001:7fd::1; # k.root-servers.net\n\ + 2620:0:2830:202::132; # xfr.cjr.dns.icann.org\n\ + 2620:0:2d0:202::132; # xfr.lax.dns.icann.org\n\ + 199.9.14.201; # b.root-servers.net\n\ + 192.33.4.12; # c.root-servers.net\n\ + 192.5.5.241; # f.root-servers.net\n\ + 192.112.36.4; # g.root-servers.net\n\ + 193.0.14.129; # k.root-servers.net\n\ + 192.0.47.132; # xfr.cjr.dns.icann.org\n\ + 192.0.32.132; # xfr.lax.dns.icann.org\n\ +};\n\ +"; + +isc_result_t +named_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) { + isc_buffer_t b; + + isc_buffer_init(&b, defaultconf, sizeof(defaultconf) - 1); + isc_buffer_add(&b, sizeof(defaultconf) - 1); + return (cfg_parse_buffer(parser, &b, __FILE__, 0, &cfg_type_namedconf, + CFG_PCTX_NODEPRECATED, conf)); +} + +const char * +named_config_getdefault(void) { + return (defaultconf); +} + +isc_result_t +named_config_get(cfg_obj_t const *const *maps, const char *name, + const cfg_obj_t **obj) { + int i; + + for (i = 0; maps[i] != NULL; i++) { + if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) { + return (ISC_R_SUCCESS); + } + } + return (ISC_R_NOTFOUND); +} + +isc_result_t +named_checknames_get(const cfg_obj_t **maps, const char *const names[], + const cfg_obj_t **obj) { + const cfg_listelt_t *element; + const cfg_obj_t *checknames; + const cfg_obj_t *type; + const cfg_obj_t *value; + int i; + + REQUIRE(maps != NULL); + REQUIRE(names != NULL); + REQUIRE(obj != NULL && *obj == NULL); + + for (i = 0; maps[i] != NULL; i++) { + checknames = NULL; + if (cfg_map_get(maps[i], "check-names", &checknames) == + ISC_R_SUCCESS) + { + /* + * Zone map entry is not a list. + */ + if (checknames != NULL && !cfg_obj_islist(checknames)) { + *obj = checknames; + return (ISC_R_SUCCESS); + } + for (element = cfg_list_first(checknames); + element != NULL; element = cfg_list_next(element)) + { + value = cfg_listelt_value(element); + type = cfg_tuple_get(value, "type"); + + for (size_t j = 0; names[j] != NULL; j++) { + if (strcasecmp(cfg_obj_asstring(type), + names[j]) == 0) + { + *obj = cfg_tuple_get(value, + "mode"); + return (ISC_R_SUCCESS); + } + } + } + } + } + return (ISC_R_NOTFOUND); +} + +int +named_config_listcount(const cfg_obj_t *list) { + const cfg_listelt_t *e; + int i = 0; + + for (e = cfg_list_first(list); e != NULL; e = cfg_list_next(e)) { + i++; + } + + return (i); +} + +isc_result_t +named_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass, + dns_rdataclass_t *classp) { + isc_textregion_t r; + isc_result_t result; + + if (!cfg_obj_isstring(classobj)) { + *classp = defclass; + return (ISC_R_SUCCESS); + } + DE_CONST(cfg_obj_asstring(classobj), r.base); + r.length = strlen(r.base); + result = dns_rdataclass_fromtext(classp, &r); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(classobj, named_g_lctx, ISC_LOG_ERROR, + "unknown class '%s'", r.base); + } + return (result); +} + +isc_result_t +named_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype, + dns_rdatatype_t *typep) { + isc_textregion_t r; + isc_result_t result; + + if (!cfg_obj_isstring(typeobj)) { + *typep = deftype; + return (ISC_R_SUCCESS); + } + DE_CONST(cfg_obj_asstring(typeobj), r.base); + r.length = strlen(r.base); + result = dns_rdatatype_fromtext(typep, &r); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(typeobj, named_g_lctx, ISC_LOG_ERROR, + "unknown type '%s'", r.base); + } + return (result); +} + +dns_zonetype_t +named_config_getzonetype(const cfg_obj_t *zonetypeobj) { + dns_zonetype_t ztype = dns_zone_none; + const char *str; + + str = cfg_obj_asstring(zonetypeobj); + if (strcasecmp(str, "primary") == 0 || strcasecmp(str, "master") == 0) { + ztype = dns_zone_primary; + } else if (strcasecmp(str, "secondary") == 0 || + strcasecmp(str, "slave") == 0) + { + ztype = dns_zone_secondary; + } else if (strcasecmp(str, "mirror") == 0) { + ztype = dns_zone_mirror; + } else if (strcasecmp(str, "stub") == 0) { + ztype = dns_zone_stub; + } else if (strcasecmp(str, "static-stub") == 0) { + ztype = dns_zone_staticstub; + } else if (strcasecmp(str, "redirect") == 0) { + ztype = dns_zone_redirect; + } else { + UNREACHABLE(); + } + return (ztype); +} + +isc_result_t +named_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, + in_port_t defport, isc_mem_t *mctx, + isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp, + uint32_t *countp) { + int count, i = 0; + const cfg_obj_t *addrlist; + const cfg_obj_t *portobj, *dscpobj; + const cfg_listelt_t *element; + isc_sockaddr_t *addrs; + in_port_t port; + isc_dscp_t dscp = -1, *dscps = NULL; + isc_result_t result; + + INSIST(addrsp != NULL && *addrsp == NULL); + INSIST(dscpsp == NULL || *dscpsp == NULL); + INSIST(countp != NULL); + + addrlist = cfg_tuple_get(list, "addresses"); + count = named_config_listcount(addrlist); + + portobj = cfg_tuple_get(list, "port"); + if (cfg_obj_isuint32(portobj)) { + uint32_t val = cfg_obj_asuint32(portobj); + if (val > UINT16_MAX) { + cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR, + "port '%u' out of range", val); + return (ISC_R_RANGE); + } + port = (in_port_t)val; + } else if (defport != 0) { + port = defport; + } else { + result = named_config_getport(config, &port); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + + if (dscpsp != NULL) { + dscpobj = cfg_tuple_get(list, "dscp"); + if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) { + if (cfg_obj_asuint32(dscpobj) > 63) { + cfg_obj_log(dscpobj, named_g_lctx, + ISC_LOG_ERROR, + "dscp value '%u' is out of range", + cfg_obj_asuint32(dscpobj)); + return (ISC_R_RANGE); + } + dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + } + + dscps = isc_mem_get(mctx, count * sizeof(isc_dscp_t)); + } + + addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t)); + + for (element = cfg_list_first(addrlist); element != NULL; + element = cfg_list_next(element), i++) + { + const cfg_obj_t *addr; + INSIST(i < count); + addr = cfg_listelt_value(element); + addrs[i] = *cfg_obj_assockaddr(addr); + if (dscpsp != NULL) { + isc_dscp_t innerdscp; + innerdscp = cfg_obj_getdscp(addr); + if (innerdscp == -1) { + innerdscp = dscp; + } + dscps[i] = innerdscp; + } + if (isc_sockaddr_getport(&addrs[i]) == 0) { + isc_sockaddr_setport(&addrs[i], port); + } + } + INSIST(i == count); + + *addrsp = addrs; + *countp = count; + + if (dscpsp != NULL) { + *dscpsp = dscps; + } + + return (ISC_R_SUCCESS); +} + +void +named_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, + isc_dscp_t **dscpsp, uint32_t count) { + INSIST(addrsp != NULL && *addrsp != NULL); + INSIST(dscpsp == NULL || *dscpsp != NULL); + + isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t)); + *addrsp = NULL; + + if (dscpsp != NULL) { + isc_mem_put(mctx, *dscpsp, count * sizeof(isc_dscp_t)); + *dscpsp = NULL; + } +} + +static isc_result_t +getremotesdef(const cfg_obj_t *cctx, const char *list, const char *name, + const cfg_obj_t **ret) { + isc_result_t result; + const cfg_obj_t *obj = NULL; + const cfg_listelt_t *elt; + + REQUIRE(cctx != NULL); + REQUIRE(name != NULL); + REQUIRE(ret != NULL && *ret == NULL); + + result = cfg_map_get(cctx, list, &obj); + if (result != ISC_R_SUCCESS) { + return (result); + } + elt = cfg_list_first(obj); + while (elt != NULL) { + obj = cfg_listelt_value(elt); + if (strcasecmp(cfg_obj_asstring(cfg_tuple_get(obj, "name")), + name) == 0) + { + *ret = obj; + return (ISC_R_SUCCESS); + } + elt = cfg_list_next(elt); + } + return (ISC_R_NOTFOUND); +} + +isc_result_t +named_config_getremotesdef(const cfg_obj_t *cctx, const char *list, + const char *name, const cfg_obj_t **ret) { + isc_result_t result; + + if (strcmp(list, "parental-agents") == 0) { + return (getremotesdef(cctx, list, name, ret)); + } else if (strcmp(list, "primaries") == 0) { + result = getremotesdef(cctx, list, name, ret); + if (result != ISC_R_SUCCESS) { + result = getremotesdef(cctx, "masters", name, ret); + } + return (result); + } + return (ISC_R_NOTFOUND); +} + +isc_result_t +named_config_getipandkeylist(const cfg_obj_t *config, const char *listtype, + const cfg_obj_t *list, isc_mem_t *mctx, + dns_ipkeylist_t *ipkl) { + uint32_t addrcount = 0, dscpcount = 0, keycount = 0, i = 0; + uint32_t listcount = 0, l = 0, j; + uint32_t stackcount = 0, pushed = 0; + isc_result_t result; + const cfg_listelt_t *element; + const cfg_obj_t *addrlist; + const cfg_obj_t *portobj; + const cfg_obj_t *dscpobj; + in_port_t port; + isc_dscp_t dscp = -1; + dns_fixedname_t fname; + isc_sockaddr_t *addrs = NULL; + isc_dscp_t *dscps = NULL; + dns_name_t **keys = NULL; + struct { + const char *name; + } *lists = NULL; + struct { + const cfg_listelt_t *element; + in_port_t port; + isc_dscp_t dscp; + } *stack = NULL; + + REQUIRE(ipkl != NULL); + REQUIRE(ipkl->count == 0); + REQUIRE(ipkl->addrs == NULL); + REQUIRE(ipkl->keys == NULL); + REQUIRE(ipkl->dscps == NULL); + REQUIRE(ipkl->labels == NULL); + REQUIRE(ipkl->allocated == 0); + + /* + * Get system defaults. + */ + result = named_config_getport(config, &port); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = named_config_getdscp(config, &dscp); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + +newlist: + addrlist = cfg_tuple_get(list, "addresses"); + portobj = cfg_tuple_get(list, "port"); + dscpobj = cfg_tuple_get(list, "dscp"); + + if (cfg_obj_isuint32(portobj)) { + uint32_t val = cfg_obj_asuint32(portobj); + if (val > UINT16_MAX) { + cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR, + "port '%u' out of range", val); + result = ISC_R_RANGE; + goto cleanup; + } + port = (in_port_t)val; + } + + if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) { + if (cfg_obj_asuint32(dscpobj) > 63) { + cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR, + "dscp value '%u' is out of range", + cfg_obj_asuint32(dscpobj)); + result = ISC_R_RANGE; + goto cleanup; + } + dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + } + + result = ISC_R_NOMEMORY; + + element = cfg_list_first(addrlist); +resume: + for (; element != NULL; element = cfg_list_next(element)) { + const cfg_obj_t *addr; + const cfg_obj_t *key; + const char *keystr; + isc_buffer_t b; + + addr = cfg_tuple_get(cfg_listelt_value(element), + "remoteselement"); + key = cfg_tuple_get(cfg_listelt_value(element), "key"); + + if (!cfg_obj_issockaddr(addr)) { + const char *listname = cfg_obj_asstring(addr); + isc_result_t tresult; + + /* Grow lists? */ + if (listcount == l) { + void *tmp; + uint32_t newlen = listcount + 16; + size_t newsize, oldsize; + + newsize = newlen * sizeof(*lists); + oldsize = listcount * sizeof(*lists); + tmp = isc_mem_get(mctx, newsize); + if (listcount != 0) { + memmove(tmp, lists, oldsize); + isc_mem_put(mctx, lists, oldsize); + } + lists = tmp; + listcount = newlen; + } + /* Seen? */ + for (j = 0; j < l; j++) { + if (strcasecmp(lists[j].name, listname) == 0) { + break; + } + } + if (j < l) { + continue; + } + list = NULL; + tresult = named_config_getremotesdef(config, listtype, + listname, &list); + if (tresult == ISC_R_NOTFOUND) { + cfg_obj_log(addr, named_g_lctx, ISC_LOG_ERROR, + "%s \"%s\" not found", listtype, + listname); + + result = tresult; + goto cleanup; + } + if (tresult != ISC_R_SUCCESS) { + goto cleanup; + } + lists[l++].name = listname; + /* Grow stack? */ + if (stackcount == pushed) { + void *tmp; + uint32_t newlen = stackcount + 16; + size_t newsize, oldsize; + + newsize = newlen * sizeof(*stack); + oldsize = stackcount * sizeof(*stack); + tmp = isc_mem_get(mctx, newsize); + if (stackcount != 0) { + memmove(tmp, stack, oldsize); + isc_mem_put(mctx, stack, oldsize); + } + stack = tmp; + stackcount = newlen; + } + /* + * We want to resume processing this list on the + * next element. + */ + stack[pushed].element = cfg_list_next(element); + stack[pushed].port = port; + stack[pushed].dscp = dscp; + pushed++; + goto newlist; + } + + if (i == addrcount) { + void *tmp; + uint32_t newlen = addrcount + 16; + size_t newsize, oldsize; + + newsize = newlen * sizeof(isc_sockaddr_t); + oldsize = addrcount * sizeof(isc_sockaddr_t); + tmp = isc_mem_get(mctx, newsize); + if (addrcount != 0) { + memmove(tmp, addrs, oldsize); + isc_mem_put(mctx, addrs, oldsize); + } + addrs = tmp; + addrcount = newlen; + + newsize = newlen * sizeof(isc_dscp_t); + oldsize = dscpcount * sizeof(isc_dscp_t); + tmp = isc_mem_get(mctx, newsize); + if (dscpcount != 0) { + memmove(tmp, dscps, oldsize); + isc_mem_put(mctx, dscps, oldsize); + } + dscps = tmp; + dscpcount = newlen; + + newsize = newlen * sizeof(dns_name_t *); + oldsize = keycount * sizeof(dns_name_t *); + tmp = isc_mem_get(mctx, newsize); + if (keycount != 0) { + memmove(tmp, keys, oldsize); + isc_mem_put(mctx, keys, oldsize); + } + keys = tmp; + keycount = newlen; + } + + addrs[i] = *cfg_obj_assockaddr(addr); + if (isc_sockaddr_getport(&addrs[i]) == 0) { + isc_sockaddr_setport(&addrs[i], port); + } + dscps[i] = cfg_obj_getdscp(addr); + if (dscps[i] == -1) { + dscps[i] = dscp; + } + keys[i] = NULL; + i++; /* Increment here so that cleanup on error works. */ + if (!cfg_obj_isstring(key)) { + continue; + } + keys[i - 1] = isc_mem_get(mctx, sizeof(dns_name_t)); + dns_name_init(keys[i - 1], NULL); + + keystr = cfg_obj_asstring(key); + isc_buffer_constinit(&b, keystr, strlen(keystr)); + isc_buffer_add(&b, strlen(keystr)); + dns_fixedname_init(&fname); + result = dns_name_fromtext(dns_fixedname_name(&fname), &b, + dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + dns_name_dup(dns_fixedname_name(&fname), mctx, keys[i - 1]); + } + if (pushed != 0) { + pushed--; + element = stack[pushed].element; + port = stack[pushed].port; + dscp = stack[pushed].dscp; + goto resume; + } + if (i < addrcount) { + void *tmp; + size_t newsize, oldsize; + + newsize = i * sizeof(isc_sockaddr_t); + oldsize = addrcount * sizeof(isc_sockaddr_t); + if (i != 0) { + tmp = isc_mem_get(mctx, newsize); + memmove(tmp, addrs, newsize); + } else { + tmp = NULL; + } + isc_mem_put(mctx, addrs, oldsize); + addrs = tmp; + addrcount = i; + + newsize = i * sizeof(isc_dscp_t); + oldsize = dscpcount * sizeof(isc_dscp_t); + if (i != 0) { + tmp = isc_mem_get(mctx, newsize); + memmove(tmp, dscps, newsize); + } else { + tmp = NULL; + } + isc_mem_put(mctx, dscps, oldsize); + dscps = tmp; + dscpcount = i; + + newsize = i * sizeof(dns_name_t *); + oldsize = keycount * sizeof(dns_name_t *); + if (i != 0) { + tmp = isc_mem_get(mctx, newsize); + memmove(tmp, keys, newsize); + } else { + tmp = NULL; + } + isc_mem_put(mctx, keys, oldsize); + keys = tmp; + keycount = i; + } + + if (lists != NULL) { + isc_mem_put(mctx, lists, listcount * sizeof(*lists)); + } + if (stack != NULL) { + isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); + } + + INSIST(dscpcount == addrcount); + INSIST(keycount == addrcount); + INSIST(keycount == dscpcount); + + ipkl->addrs = addrs; + ipkl->dscps = dscps; + ipkl->keys = keys; + ipkl->count = addrcount; + ipkl->allocated = addrcount; + + return (ISC_R_SUCCESS); + +cleanup: + if (addrs != NULL) { + isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t)); + } + if (dscps != NULL) { + isc_mem_put(mctx, dscps, dscpcount * sizeof(isc_dscp_t)); + } + if (keys != NULL) { + for (j = 0; j < i; j++) { + if (keys[j] == NULL) { + continue; + } + if (dns_name_dynamic(keys[j])) { + dns_name_free(keys[j], mctx); + } + isc_mem_put(mctx, keys[j], sizeof(dns_name_t)); + } + isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *)); + } + if (lists != NULL) { + isc_mem_put(mctx, lists, listcount * sizeof(*lists)); + } + if (stack != NULL) { + isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); + } + return (result); +} + +isc_result_t +named_config_getport(const cfg_obj_t *config, in_port_t *portp) { + const cfg_obj_t *maps[3]; + const cfg_obj_t *options = NULL; + const cfg_obj_t *portobj = NULL; + isc_result_t result; + int i; + + (void)cfg_map_get(config, "options", &options); + i = 0; + if (options != NULL) { + maps[i++] = options; + } + maps[i++] = named_g_defaults; + maps[i] = NULL; + + result = named_config_get(maps, "port", &portobj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_asuint32(portobj) >= UINT16_MAX) { + cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR, + "port '%u' out of range", + cfg_obj_asuint32(portobj)); + return (ISC_R_RANGE); + } + *portp = (in_port_t)cfg_obj_asuint32(portobj); + return (ISC_R_SUCCESS); +} + +isc_result_t +named_config_getdscp(const cfg_obj_t *config, isc_dscp_t *dscpp) { + const cfg_obj_t *options = NULL; + const cfg_obj_t *dscpobj = NULL; + isc_result_t result; + + (void)cfg_map_get(config, "options", &options); + if (options == NULL) { + return (ISC_R_SUCCESS); + } + + result = cfg_map_get(options, "dscp", &dscpobj); + if (result != ISC_R_SUCCESS || dscpobj == NULL) { + *dscpp = -1; + return (ISC_R_SUCCESS); + } + if (cfg_obj_asuint32(dscpobj) >= 64) { + cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR, + "dscp '%u' out of range", + cfg_obj_asuint32(dscpobj)); + return (ISC_R_RANGE); + } + *dscpp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + return (ISC_R_SUCCESS); +} + +struct keyalgorithms { + const char *str; + enum { + hmacnone, + hmacmd5, + hmacsha1, + hmacsha224, + hmacsha256, + hmacsha384, + hmacsha512 + } hmac; + unsigned int type; + uint16_t size; +} algorithms[] = { { "hmac-md5", hmacmd5, DST_ALG_HMACMD5, 128 }, + { "hmac-md5.sig-alg.reg.int", hmacmd5, DST_ALG_HMACMD5, 0 }, + { "hmac-md5.sig-alg.reg.int.", hmacmd5, DST_ALG_HMACMD5, 0 }, + { "hmac-sha1", hmacsha1, DST_ALG_HMACSHA1, 160 }, + { "hmac-sha224", hmacsha224, DST_ALG_HMACSHA224, 224 }, + { "hmac-sha256", hmacsha256, DST_ALG_HMACSHA256, 256 }, + { "hmac-sha384", hmacsha384, DST_ALG_HMACSHA384, 384 }, + { "hmac-sha512", hmacsha512, DST_ALG_HMACSHA512, 512 }, + { NULL, hmacnone, DST_ALG_UNKNOWN, 0 } }; + +isc_result_t +named_config_getkeyalgorithm(const char *str, const dns_name_t **name, + uint16_t *digestbits) { + return (named_config_getkeyalgorithm2(str, name, NULL, digestbits)); +} + +isc_result_t +named_config_getkeyalgorithm2(const char *str, const dns_name_t **name, + unsigned int *typep, uint16_t *digestbits) { + int i; + size_t len = 0; + uint16_t bits; + isc_result_t result; + + for (i = 0; algorithms[i].str != NULL; i++) { + len = strlen(algorithms[i].str); + if (strncasecmp(algorithms[i].str, str, len) == 0 && + (str[len] == '\0' || + (algorithms[i].size != 0 && str[len] == '-'))) + { + break; + } + } + if (algorithms[i].str == NULL) { + return (ISC_R_NOTFOUND); + } + if (str[len] == '-') { + result = isc_parse_uint16(&bits, str + len + 1, 10); + if (result != ISC_R_SUCCESS) { + return (result); + } + if (bits > algorithms[i].size) { + return (ISC_R_RANGE); + } + } else if (algorithms[i].size == 0) { + bits = 128; + } else { + bits = algorithms[i].size; + } + + if (name != NULL) { + switch (algorithms[i].hmac) { + case hmacmd5: + *name = dns_tsig_hmacmd5_name; + break; + case hmacsha1: + *name = dns_tsig_hmacsha1_name; + break; + case hmacsha224: + *name = dns_tsig_hmacsha224_name; + break; + case hmacsha256: + *name = dns_tsig_hmacsha256_name; + break; + case hmacsha384: + *name = dns_tsig_hmacsha384_name; + break; + case hmacsha512: + *name = dns_tsig_hmacsha512_name; + break; + default: + UNREACHABLE(); + } + } + if (typep != NULL) { + *typep = algorithms[i].type; + } + if (digestbits != NULL) { + *digestbits = bits; + } + return (ISC_R_SUCCESS); +} diff --git a/bin/named/control.c b/bin/named/control.c new file mode 100644 index 0000000..4cd5a5d --- /dev/null +++ b/bin/named/control.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_LIBSCF +#include +#endif /* ifdef HAVE_LIBSCF */ + +static isc_result_t +getcommand(isc_lex_t *lex, char **cmdp) { + isc_result_t result; + isc_token_t token; + + REQUIRE(cmdp != NULL && *cmdp == NULL); + + result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF, &token); + if (result != ISC_R_SUCCESS) { + return (result); + } + + isc_lex_ungettoken(lex, &token); + + if (token.type != isc_tokentype_string) { + return (ISC_R_FAILURE); + } + + *cmdp = token.value.as_textregion.base; + + return (ISC_R_SUCCESS); +} + +static bool +command_compare(const char *str, const char *command) { + return (strcasecmp(str, command) == 0); +} + +/*% + * This function is called to process the incoming command + * when a control channel message is received. + */ +isc_result_t +named_control_docommand(isccc_sexpr_t *message, bool readonly, + isc_buffer_t **text) { + isccc_sexpr_t *data; + char *cmdline = NULL; + char *command = NULL; + isc_result_t result; + int log_level; + isc_buffer_t src; + isc_lex_t *lex = NULL; +#ifdef HAVE_LIBSCF + named_smf_want_disable = 0; +#endif /* ifdef HAVE_LIBSCF */ + + data = isccc_alist_lookup(message, "_data"); + if (!isccc_alist_alistp(data)) { + /* + * No data section. + */ + return (ISC_R_FAILURE); + } + + result = isccc_cc_lookupstring(data, "type", &cmdline); + if (result != ISC_R_SUCCESS) { + /* + * We have no idea what this is. + */ + return (result); + } + + result = isc_lex_create(named_g_mctx, strlen(cmdline), &lex); + if (result != ISC_R_SUCCESS) { + return (result); + } + + isc_buffer_init(&src, cmdline, strlen(cmdline)); + isc_buffer_add(&src, strlen(cmdline)); + result = isc_lex_openbuffer(lex, &src); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = getcommand(lex, &command); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + /* + * Compare the 'command' parameter against all known control commands. + */ + if ((command_compare(command, NAMED_COMMAND_NULL) && + strlen(cmdline) == 4) || + command_compare(command, NAMED_COMMAND_STATUS)) + { + log_level = ISC_LOG_DEBUG(1); + } else { + log_level = ISC_LOG_INFO; + } + + /* + * If this listener should have read-only access, reject + * restricted commands here. rndc nta is handled specially + * below. + */ + if (readonly && !command_compare(command, NAMED_COMMAND_NTA) && + !command_compare(command, NAMED_COMMAND_NULL) && + !command_compare(command, NAMED_COMMAND_STATUS) && + !command_compare(command, NAMED_COMMAND_SHOWZONE) && + !command_compare(command, NAMED_COMMAND_TESTGEN) && + !command_compare(command, NAMED_COMMAND_ZONESTATUS)) + { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, log_level, + "rejecting restricted control channel " + "command '%s'", + cmdline); + result = ISC_R_FAILURE; + goto cleanup; + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, log_level, + "received control channel command '%s'", cmdline); + + /* + * After the lengthy "halt" and "stop", the commands are + * handled in alphabetical order of the NAMED_COMMAND_ macros. + */ + if (command_compare(command, NAMED_COMMAND_HALT)) { +#ifdef HAVE_LIBSCF + /* + * If we are managed by smf(5), AND in chroot, then + * we cannot connect to the smf repository, so just + * return with an appropriate message back to rndc. + */ + if (named_smf_got_instance == 1 && named_smf_chroot == 1) { + result = named_smf_add_message(text); + goto cleanup; + } + /* + * If we are managed by smf(5) but not in chroot, + * try to disable ourselves the smf way. + */ + if (named_smf_got_instance == 1 && named_smf_chroot == 0) { + named_smf_want_disable = 1; + } + /* + * If named_smf_got_instance = 0, named_smf_chroot + * is not relevant and we fall through to + * isc_app_shutdown below. + */ +#endif /* ifdef HAVE_LIBSCF */ + /* Do not flush master files */ + named_server_flushonshutdown(named_g_server, false); + named_os_shutdownmsg(cmdline, *text); + isc_app_shutdown(); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NAMED_COMMAND_STOP)) { + /* + * "stop" is the same as "halt" except it does + * flush master files. + */ +#ifdef HAVE_LIBSCF + if (named_smf_got_instance == 1 && named_smf_chroot == 1) { + result = named_smf_add_message(text); + goto cleanup; + } + if (named_smf_got_instance == 1 && named_smf_chroot == 0) { + named_smf_want_disable = 1; + } +#endif /* ifdef HAVE_LIBSCF */ + named_server_flushonshutdown(named_g_server, true); + named_os_shutdownmsg(cmdline, *text); + isc_app_shutdown(); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NAMED_COMMAND_ADDZONE) || + command_compare(command, NAMED_COMMAND_MODZONE)) + { + result = named_server_changezone(named_g_server, cmdline, text); + } else if (command_compare(command, NAMED_COMMAND_DELZONE)) { + result = named_server_delzone(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_DNSSEC)) { + result = named_server_dnssec(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_DNSTAP) || + command_compare(command, NAMED_COMMAND_DNSTAPREOPEN)) + { + result = named_server_dnstap(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_DUMPDB)) { + named_server_dumpdb(named_g_server, lex, text); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NAMED_COMMAND_DUMPSTATS)) { + result = named_server_dumpstats(named_g_server); + } else if (command_compare(command, NAMED_COMMAND_FLUSH)) { + result = named_server_flushcache(named_g_server, lex); + } else if (command_compare(command, NAMED_COMMAND_FLUSHNAME)) { + result = named_server_flushnode(named_g_server, lex, false); + } else if (command_compare(command, NAMED_COMMAND_FLUSHTREE)) { + result = named_server_flushnode(named_g_server, lex, true); + } else if (command_compare(command, NAMED_COMMAND_FREEZE)) { + result = named_server_freeze(named_g_server, true, lex, text); + } else if (command_compare(command, NAMED_COMMAND_LOADKEYS) || + command_compare(command, NAMED_COMMAND_SIGN)) + { + result = named_server_rekey(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_MKEYS)) { + result = named_server_mkeys(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_NOTIFY)) { + result = named_server_notifycommand(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_NOTRACE)) { + named_g_debuglevel = 0; + isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NAMED_COMMAND_NTA)) { + result = named_server_nta(named_g_server, lex, readonly, text); + } else if (command_compare(command, NAMED_COMMAND_NULL)) { + result = ISC_R_SUCCESS; + } else if (command_compare(command, NAMED_COMMAND_QUERYLOG)) { + result = named_server_togglequerylog(named_g_server, lex); + } else if (command_compare(command, NAMED_COMMAND_RECONFIG)) { + result = named_server_reconfigcommand(named_g_server); + } else if (command_compare(command, NAMED_COMMAND_RECURSING)) { + result = named_server_dumprecursing(named_g_server); + } else if (command_compare(command, NAMED_COMMAND_REFRESH)) { + result = named_server_refreshcommand(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_RELOAD)) { + result = named_server_reloadcommand(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_RETRANSFER)) { + result = named_server_retransfercommand(named_g_server, lex, + text); + } else if (command_compare(command, NAMED_COMMAND_SCAN)) { + named_server_scan_interfaces(named_g_server); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NAMED_COMMAND_SECROOTS)) { + result = named_server_dumpsecroots(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_SERVESTALE)) { + result = named_server_servestale(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_SHOWZONE)) { + result = named_server_showzone(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_SIGNING)) { + result = named_server_signing(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_STATUS)) { + result = named_server_status(named_g_server, text); + } else if (command_compare(command, NAMED_COMMAND_SYNC)) { + result = named_server_sync(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_TCPTIMEOUTS)) { + result = named_server_tcptimeouts(lex, text); + } else if (command_compare(command, NAMED_COMMAND_TESTGEN)) { + result = named_server_testgen(lex, text); + } else if (command_compare(command, NAMED_COMMAND_THAW) || + command_compare(command, NAMED_COMMAND_UNFREEZE)) + { + result = named_server_freeze(named_g_server, false, lex, text); + } else if (command_compare(command, NAMED_COMMAND_TIMERPOKE)) { + isc_timermgr_poke(named_g_timermgr); + result = ISC_R_SUCCESS; + } else if (command_compare(command, NAMED_COMMAND_TRACE)) { + result = named_server_setdebuglevel(named_g_server, lex); + } else if (command_compare(command, NAMED_COMMAND_TSIGDELETE)) { + result = named_server_tsigdelete(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_TSIGLIST)) { + result = named_server_tsiglist(named_g_server, text); + } else if (command_compare(command, NAMED_COMMAND_VALIDATION)) { + result = named_server_validation(named_g_server, lex, text); + } else if (command_compare(command, NAMED_COMMAND_ZONESTATUS)) { + result = named_server_zonestatus(named_g_server, lex, text); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "unknown control channel command '%s'", command); + result = DNS_R_UNKNOWNCOMMAND; + } + +cleanup: + if (lex != NULL) { + isc_lex_destroy(&lex); + } + + return (result); +} diff --git a/bin/named/controlconf.c b/bin/named/controlconf.c new file mode 100644 index 0000000..edb94aa --- /dev/null +++ b/bin/named/controlconf.c @@ -0,0 +1,1563 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +/* + * Note: Listeners and connections are not locked. All event handlers are + * executed by the server task, and all callers of exported routines must + * be running under the server task. + */ + +typedef struct controlkey controlkey_t; +typedef ISC_LIST(controlkey_t) controlkeylist_t; + +typedef struct controlconnection controlconnection_t; +typedef ISC_LIST(controlconnection_t) controlconnectionlist_t; + +typedef struct controllistener controllistener_t; +typedef ISC_LIST(controllistener_t) controllistenerlist_t; + +struct controlkey { + char *keyname; + uint32_t algorithm; + isc_region_t secret; + ISC_LINK(controlkey_t) link; +}; + +struct controlconnection { + isc_socket_t *sock; + isccc_ccmsg_t ccmsg; + bool ccmsg_valid; + bool sending; + isc_timer_t *timer; + isc_buffer_t *buffer; + controllistener_t *listener; + uint32_t nonce; + ISC_LINK(controlconnection_t) link; +}; + +struct controllistener { + named_controls_t *controls; + isc_mem_t *mctx; + isc_task_t *task; + isc_sockaddr_t address; + isc_socket_t *sock; + dns_acl_t *acl; + bool listening; + bool exiting; + controlkeylist_t keys; + controlconnectionlist_t connections; + isc_sockettype_t type; + uint32_t perm; + uint32_t owner; + uint32_t group; + bool readonly; + ISC_LINK(controllistener_t) link; +}; + +struct named_controls { + named_server_t *server; + controllistenerlist_t listeners; + bool shuttingdown; + isc_mutex_t symtab_lock; + isccc_symtab_t *symtab; +}; + +static void +control_newconn(isc_task_t *task, isc_event_t *event); +static void +control_recvmessage(isc_task_t *task, isc_event_t *event); + +#define CLOCKSKEW 300 + +static void +free_controlkey(controlkey_t *key, isc_mem_t *mctx) { + if (key->keyname != NULL) { + isc_mem_free(mctx, key->keyname); + } + if (key->secret.base != NULL) { + isc_mem_put(mctx, key->secret.base, key->secret.length); + } + isc_mem_put(mctx, key, sizeof(*key)); +} + +static void +free_controlkeylist(controlkeylist_t *keylist, isc_mem_t *mctx) { + while (!ISC_LIST_EMPTY(*keylist)) { + controlkey_t *key = ISC_LIST_HEAD(*keylist); + ISC_LIST_UNLINK(*keylist, key, link); + free_controlkey(key, mctx); + } +} + +static void +free_listener(controllistener_t *listener) { + INSIST(listener->exiting); + INSIST(!listener->listening); + INSIST(ISC_LIST_EMPTY(listener->connections)); + + if (listener->sock != NULL) { + isc_socket_detach(&listener->sock); + } + + free_controlkeylist(&listener->keys, listener->mctx); + + if (listener->acl != NULL) { + dns_acl_detach(&listener->acl); + } + + isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); +} + +static void +maybe_free_listener(controllistener_t *listener) { + if (listener->exiting && !listener->listening && + ISC_LIST_EMPTY(listener->connections)) + { + free_listener(listener); + } +} + +static void +maybe_free_connection(controlconnection_t *conn) { + controllistener_t *listener = conn->listener; + + if (conn->buffer != NULL) { + isc_buffer_free(&conn->buffer); + } + + if (conn->timer != NULL) { + isc_timer_destroy(&conn->timer); + } + + if (conn->ccmsg_valid) { + isccc_ccmsg_cancelread(&conn->ccmsg); + return; + } + + if (conn->sending) { + isc_socket_cancel(conn->sock, listener->task, + ISC_SOCKCANCEL_SEND); + return; + } + + ISC_LIST_UNLINK(listener->connections, conn, link); +#ifdef ENABLE_AFL + if (named_g_fuzz_type == isc_fuzz_rndc) { + named_fuzz_notify(); + } +#endif /* ifdef ENABLE_AFL */ + isc_mem_put(listener->mctx, conn, sizeof(*conn)); +} + +static void +shutdown_listener(controllistener_t *listener) { + controlconnection_t *conn; + controlconnection_t *next; + + if (!listener->exiting) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + ISC_LIST_UNLINK(listener->controls->listeners, listener, link); + + isc_sockaddr_format(&listener->address, socktext, + sizeof(socktext)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_NOTICE, + "stopping command channel on %s", socktext); + if (listener->type == isc_sockettype_unix) { + isc_socket_cleanunix(&listener->address, true); + } + listener->exiting = true; + } + + for (conn = ISC_LIST_HEAD(listener->connections); conn != NULL; + conn = next) + { + next = ISC_LIST_NEXT(conn, link); + maybe_free_connection(conn); + } + + if (listener->listening) { + isc_socket_cancel(listener->sock, listener->task, + ISC_SOCKCANCEL_ACCEPT); + return; + } + + maybe_free_listener(listener); +} + +static bool +address_ok(isc_sockaddr_t *sockaddr, dns_acl_t *acl) { + dns_aclenv_t *env = + ns_interfacemgr_getaclenv(named_g_server->interfacemgr); + isc_netaddr_t netaddr; + isc_result_t result; + int match; + + isc_netaddr_fromsockaddr(&netaddr, sockaddr); + + result = dns_acl_match(&netaddr, NULL, acl, env, &match, NULL); + return (result == ISC_R_SUCCESS && match > 0); +} + +static isc_result_t +control_accept(controllistener_t *listener) { + isc_result_t result; + result = isc_socket_accept(listener->sock, listener->task, + control_newconn, listener); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socket_accept() failed: %s", + isc_result_totext(result)); + } else { + listener->listening = true; + } + return (result); +} + +static isc_result_t +control_listen(controllistener_t *listener) { + isc_result_t result; + + result = isc_socket_listen(listener->sock, 0); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socket_listen() failed: %s", + isc_result_totext(result)); + } + return (result); +} + +static void +control_next(controllistener_t *listener) { + (void)control_accept(listener); +} + +static void +control_senddone(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + controlconnection_t *conn = event->ev_arg; + controllistener_t *listener = conn->listener; + isc_socket_t *sock = (isc_socket_t *)sevent->ev_sender; + isc_result_t result; + + REQUIRE(conn->sending); + + UNUSED(task); + + conn->sending = false; + + if (sevent->result != ISC_R_SUCCESS && sevent->result != ISC_R_CANCELED) + { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t peeraddr; + + (void)isc_socket_getpeername(sock, &peeraddr); + isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "error sending command response to %s: %s", + socktext, isc_result_totext(sevent->result)); + } + isc_event_free(&event); + + result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task, + control_recvmessage, conn); + if (result != ISC_R_SUCCESS) { + isc_socket_detach(&conn->sock); + maybe_free_connection(conn); + maybe_free_listener(listener); + } +} + +static void +log_invalid(isccc_ccmsg_t *ccmsg, isc_result_t result) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t peeraddr; + + (void)isc_socket_getpeername(ccmsg->sock, &peeraddr); + isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_ERROR, + "invalid command from %s: %s", socktext, + isc_result_totext(result)); +} + +static void +control_recvmessage(isc_task_t *task, isc_event_t *event) { + controlconnection_t *conn = NULL; + controllistener_t *listener = NULL; + controlkey_t *key = NULL; + isccc_sexpr_t *request = NULL; + isccc_sexpr_t *response = NULL; + uint32_t algorithm; + isccc_region_t secret; + isc_stdtime_t now; + isc_buffer_t b; + isc_region_t r; + isc_buffer_t *text; + isc_result_t result; + isc_result_t eresult; + isccc_sexpr_t *_ctrl = NULL; + isccc_time_t sent; + isccc_time_t exp; + uint32_t nonce; + isccc_sexpr_t *data = NULL; + + REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG); + + conn = event->ev_arg; + listener = conn->listener; + algorithm = DST_ALG_UNKNOWN; + secret.rstart = NULL; + text = NULL; + + /* Is the server shutting down? */ + if (listener->controls->shuttingdown) { + goto cleanup; + } + + if (conn->ccmsg.result != ISC_R_SUCCESS) { + if (conn->ccmsg.result != ISC_R_CANCELED && + conn->ccmsg.result != ISC_R_EOF) + { + log_invalid(&conn->ccmsg, conn->ccmsg.result); + } + goto cleanup; + } + + request = NULL; + + for (key = ISC_LIST_HEAD(listener->keys); key != NULL; + key = ISC_LIST_NEXT(key, link)) + { + isccc_region_t ccregion; + + ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer); + ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer); + secret.rstart = isc_mem_get(listener->mctx, key->secret.length); + memmove(secret.rstart, key->secret.base, key->secret.length); + secret.rend = secret.rstart + key->secret.length; + algorithm = key->algorithm; + result = isccc_cc_fromwire(&ccregion, &request, algorithm, + &secret); + if (result == ISC_R_SUCCESS) { + break; + } + isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); + } + + if (key == NULL) { + log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); + goto cleanup; + } + + /* We shouldn't be getting a reply. */ + if (isccc_cc_isreply(request)) { + log_invalid(&conn->ccmsg, ISC_R_FAILURE); + goto cleanup_request; + } + + isc_stdtime_get(&now); + + /* + * Limit exposure to replay attacks. + */ + _ctrl = isccc_alist_lookup(request, "_ctrl"); + if (!isccc_alist_alistp(_ctrl)) { + log_invalid(&conn->ccmsg, ISC_R_FAILURE); + goto cleanup_request; + } + + if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) { + if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) { + log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW); + goto cleanup_request; + } + } else { + log_invalid(&conn->ccmsg, ISC_R_FAILURE); + goto cleanup_request; + } + + /* + * Expire messages that are too old. + */ + if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS && + now > exp) + { + log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED); + goto cleanup_request; + } + + /* + * Duplicate suppression (required for UDP). + */ + LOCK(&listener->controls->symtab_lock); + isccc_cc_cleansymtab(listener->controls->symtab, now); + result = isccc_cc_checkdup(listener->controls->symtab, request, now); + UNLOCK(&listener->controls->symtab_lock); + if (result != ISC_R_SUCCESS) { + if (result == ISC_R_EXISTS) { + result = ISCCC_R_DUPLICATE; + } + log_invalid(&conn->ccmsg, result); + goto cleanup_request; + } + + if (conn->nonce != 0 && + (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS || + conn->nonce != nonce)) + { + log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); + goto cleanup_request; + } + + isc_buffer_allocate(listener->mctx, &text, 2 * 2048); + + /* + * Establish nonce. + */ + if (conn->nonce == 0) { + while (conn->nonce == 0) { + isc_nonce_buf(&conn->nonce, sizeof(conn->nonce)); + } + eresult = ISC_R_SUCCESS; + } else { + eresult = named_control_docommand(request, listener->readonly, + &text); + } + + result = isccc_cc_createresponse(request, now, now + 60, &response); + if (result != ISC_R_SUCCESS) { + goto cleanup_request; + } + + data = isccc_alist_lookup(response, "_data"); + if (data != NULL) { + if (isccc_cc_defineuint32(data, "result", eresult) == NULL) { + goto cleanup_response; + } + } + + if (eresult != ISC_R_SUCCESS) { + if (data != NULL) { + const char *estr = isc_result_totext(eresult); + if (isccc_cc_definestring(data, "err", estr) == NULL) { + goto cleanup_response; + } + } + } + + if (isc_buffer_usedlength(text) > 0) { + if (data != NULL) { + char *str = (char *)isc_buffer_base(text); + if (isccc_cc_definestring(data, "text", str) == NULL) { + goto cleanup_response; + } + } + } + + _ctrl = isccc_alist_lookup(response, "_ctrl"); + if (_ctrl == NULL || + isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL) + { + goto cleanup_response; + } + + if (conn->buffer == NULL) { + isc_buffer_allocate(listener->mctx, &conn->buffer, 2 * 2048); + } + + isc_buffer_clear(conn->buffer); + /* Skip the length field (4 bytes) */ + isc_buffer_add(conn->buffer, 4); + + result = isccc_cc_towire(response, &conn->buffer, algorithm, &secret); + if (result != ISC_R_SUCCESS) { + goto cleanup_response; + } + + isc_buffer_init(&b, conn->buffer->base, 4); + isc_buffer_putuint32(&b, conn->buffer->used - 4); + + r.base = conn->buffer->base; + r.length = conn->buffer->used; + + result = isc_socket_send(conn->sock, &r, task, control_senddone, conn); + if (result != ISC_R_SUCCESS) { + goto cleanup_response; + } + conn->sending = true; + + isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); + isccc_sexpr_free(&request); + isccc_sexpr_free(&response); + isc_buffer_free(&text); + return; + +cleanup_response: + isccc_sexpr_free(&response); + +cleanup_request: + isccc_sexpr_free(&request); + isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); + if (text != NULL) { + isc_buffer_free(&text); + } + +cleanup: + isc_socket_detach(&conn->sock); + isccc_ccmsg_invalidate(&conn->ccmsg); + conn->ccmsg_valid = false; + maybe_free_connection(conn); + maybe_free_listener(listener); +} + +static void +control_timeout(isc_task_t *task, isc_event_t *event) { + controlconnection_t *conn = event->ev_arg; + + UNUSED(task); + + isc_event_free(&event); + + isc_timer_destroy(&conn->timer); + maybe_free_connection(conn); +} + +static isc_result_t +newconnection(controllistener_t *listener, isc_socket_t *sock) { + controlconnection_t *conn; + isc_interval_t interval; + isc_result_t result; + + conn = isc_mem_get(listener->mctx, sizeof(*conn)); + + conn->sock = sock; + isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg); + + /* Set a 32 KiB upper limit on incoming message. */ + isccc_ccmsg_setmaxsize(&conn->ccmsg, 32768); + + conn->ccmsg_valid = true; + conn->sending = false; + conn->buffer = NULL; + conn->timer = NULL; + isc_interval_set(&interval, 60, 0); + result = isc_timer_create(named_g_timermgr, isc_timertype_once, NULL, + &interval, listener->task, control_timeout, + conn, &conn->timer); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + conn->listener = listener; + conn->nonce = 0; + ISC_LINK_INIT(conn, link); + + result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task, + control_recvmessage, conn); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + ISC_LIST_APPEND(listener->connections, conn, link); + return (ISC_R_SUCCESS); + +cleanup: + if (conn->buffer != NULL) { + isc_buffer_free(&conn->buffer); + } + isccc_ccmsg_invalidate(&conn->ccmsg); + if (conn->timer != NULL) { + isc_timer_destroy(&conn->timer); + } + isc_mem_put(listener->mctx, conn, sizeof(*conn)); +#ifdef ENABLE_AFL + if (named_g_fuzz_type == isc_fuzz_rndc) { + named_fuzz_notify(); + } +#endif /* ifdef ENABLE_AFL */ + return (result); +} + +static void +control_newconn(isc_task_t *task, isc_event_t *event) { + isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; + controllistener_t *listener = event->ev_arg; + isc_socket_t *sock; + isc_sockaddr_t peeraddr; + isc_result_t result; + + UNUSED(task); + + REQUIRE(listener->listening); + + listener->listening = false; + + if (nevent->result != ISC_R_SUCCESS) { + if (nevent->result == ISC_R_CANCELED) { + shutdown_listener(listener); + goto cleanup; + } + goto restart; + } + + sock = nevent->newsocket; + + /* Is the server shutting down? */ + if (listener->controls->shuttingdown) { + isc_socket_detach(&sock); + shutdown_listener(listener); + goto cleanup; + } + + isc_socket_setname(sock, "control", NULL); + (void)isc_socket_getpeername(sock, &peeraddr); + if (listener->type == isc_sockettype_tcp && + !address_ok(&peeraddr, listener->acl)) + { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "rejected command channel message from %s", + socktext); + isc_socket_detach(&sock); + goto restart; + } + + result = newconnection(listener, sock); + if (result != ISC_R_SUCCESS) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "dropped command channel from %s: %s", socktext, + isc_result_totext(result)); + isc_socket_detach(&sock); + goto restart; + } + +restart: + control_next(listener); +cleanup: + isc_event_free(&event); +} + +static void +controls_shutdown(named_controls_t *controls) { + controllistener_t *listener; + controllistener_t *next; + + for (listener = ISC_LIST_HEAD(controls->listeners); listener != NULL; + listener = next) + { + /* + * This is asynchronous. As listeners shut down, they will + * call their callbacks. + */ + next = ISC_LIST_NEXT(listener, link); + shutdown_listener(listener); + } +} + +void +named_controls_shutdown(named_controls_t *controls) { + controls_shutdown(controls); + controls->shuttingdown = true; +} + +static isc_result_t +cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname, + const cfg_obj_t **objp) { + const cfg_listelt_t *element; + const char *str; + const cfg_obj_t *obj; + + for (element = cfg_list_first(keylist); element != NULL; + element = cfg_list_next(element)) + { + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(cfg_map_getname(obj)); + if (strcasecmp(str, keyname) == 0) { + break; + } + } + if (element == NULL) { + return (ISC_R_NOTFOUND); + } + obj = cfg_listelt_value(element); + *objp = obj; + return (ISC_R_SUCCESS); +} + +static void +controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx, + controlkeylist_t *keyids) { + const cfg_listelt_t *element; + char *newstr = NULL; + const char *str; + const cfg_obj_t *obj; + controlkey_t *key; + + for (element = cfg_list_first(keylist); element != NULL; + element = cfg_list_next(element)) + { + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(obj); + newstr = isc_mem_strdup(mctx, str); + key = isc_mem_get(mctx, sizeof(*key)); + key->keyname = newstr; + key->algorithm = DST_ALG_UNKNOWN; + key->secret.base = NULL; + key->secret.length = 0; + ISC_LINK_INIT(key, link); + ISC_LIST_APPEND(*keyids, key, link); + newstr = NULL; + } +} + +static void +register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist, + controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext) { + controlkey_t *keyid, *next; + const cfg_obj_t *keydef; + char secret[1024]; + isc_buffer_t b; + isc_result_t result; + + /* + * Find the keys corresponding to the keyids used by this listener. + */ + for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) { + next = ISC_LIST_NEXT(keyid, link); + + result = cfgkeylist_find(keylist, keyid->keyname, &keydef); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING, + "couldn't find key '%s' for use with " + "command channel %s", + keyid->keyname, socktext); + ISC_LIST_UNLINK(*keyids, keyid, link); + free_controlkey(keyid, mctx); + } else { + const cfg_obj_t *algobj = NULL; + const cfg_obj_t *secretobj = NULL; + const char *algstr = NULL; + const char *secretstr = NULL; + unsigned int algtype; + + (void)cfg_map_get(keydef, "algorithm", &algobj); + (void)cfg_map_get(keydef, "secret", &secretobj); + INSIST(algobj != NULL && secretobj != NULL); + + algstr = cfg_obj_asstring(algobj); + secretstr = cfg_obj_asstring(secretobj); + + if (named_config_getkeyalgorithm2(algstr, NULL, + &algtype, NULL) != + ISC_R_SUCCESS) + { + cfg_obj_log(control, named_g_lctx, + ISC_LOG_WARNING, + "unsupported algorithm '%s' in " + "key '%s' for use with command " + "channel %s", + algstr, keyid->keyname, socktext); + ISC_LIST_UNLINK(*keyids, keyid, link); + free_controlkey(keyid, mctx); + continue; + } + + keyid->algorithm = algtype; + isc_buffer_init(&b, secret, sizeof(secret)); + result = isc_base64_decodestring(secretstr, &b); + + if (result != ISC_R_SUCCESS) { + cfg_obj_log(keydef, named_g_lctx, + ISC_LOG_WARNING, + "secret for key '%s' on " + "command channel %s: %s", + keyid->keyname, socktext, + isc_result_totext(result)); + ISC_LIST_UNLINK(*keyids, keyid, link); + free_controlkey(keyid, mctx); + continue; + } + + keyid->secret.length = isc_buffer_usedlength(&b); + keyid->secret.base = isc_mem_get(mctx, + keyid->secret.length); + memmove(keyid->secret.base, isc_buffer_base(&b), + keyid->secret.length); + } + } +} + +#define CHECK(x) \ + do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +static isc_result_t +get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) { + isc_result_t result; + cfg_parser_t *pctx = NULL; + cfg_obj_t *config = NULL; + const cfg_obj_t *key = NULL; + const cfg_obj_t *algobj = NULL; + const cfg_obj_t *secretobj = NULL; + const char *algstr = NULL; + const char *secretstr = NULL; + controlkey_t *keyid = NULL; + char secret[1024]; + unsigned int algtype; + isc_buffer_t b; + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO, + "configuring command channel from '%s'", named_g_keyfile); + if (!isc_file_exists(named_g_keyfile)) { + return (ISC_R_FILENOTFOUND); + } + + CHECK(cfg_parser_create(mctx, named_g_lctx, &pctx)); + CHECK(cfg_parse_file(pctx, named_g_keyfile, &cfg_type_rndckey, + &config)); + CHECK(cfg_map_get(config, "key", &key)); + + keyid = isc_mem_get(mctx, sizeof(*keyid)); + keyid->keyname = isc_mem_strdup(mctx, + cfg_obj_asstring(cfg_map_getname(key))); + keyid->secret.base = NULL; + keyid->secret.length = 0; + keyid->algorithm = DST_ALG_UNKNOWN; + ISC_LINK_INIT(keyid, link); + if (keyid->keyname == NULL) { + CHECK(ISC_R_NOMEMORY); + } + + CHECK(bind9_check_key(key, named_g_lctx)); + + (void)cfg_map_get(key, "algorithm", &algobj); + (void)cfg_map_get(key, "secret", &secretobj); + INSIST(algobj != NULL && secretobj != NULL); + + algstr = cfg_obj_asstring(algobj); + secretstr = cfg_obj_asstring(secretobj); + + if (named_config_getkeyalgorithm2(algstr, NULL, &algtype, NULL) != + ISC_R_SUCCESS) + { + cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING, + "unsupported algorithm '%s' in " + "key '%s' for use with command " + "channel", + algstr, keyid->keyname); + goto cleanup; + } + + keyid->algorithm = algtype; + isc_buffer_init(&b, secret, sizeof(secret)); + result = isc_base64_decodestring(secretstr, &b); + + if (result != ISC_R_SUCCESS) { + cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING, + "secret for key '%s' on command channel: %s", + keyid->keyname, isc_result_totext(result)); + goto cleanup; + } + + keyid->secret.length = isc_buffer_usedlength(&b); + keyid->secret.base = isc_mem_get(mctx, keyid->secret.length); + memmove(keyid->secret.base, isc_buffer_base(&b), keyid->secret.length); + ISC_LIST_APPEND(*keyids, keyid, link); + keyid = NULL; + result = ISC_R_SUCCESS; + +cleanup: + if (keyid != NULL) { + free_controlkey(keyid, mctx); + } + if (config != NULL) { + cfg_obj_destroy(pctx, &config); + } + if (pctx != NULL) { + cfg_parser_destroy(&pctx); + } + return (result); +} + +/* + * Ensures that both '*global_keylistp' and '*control_keylistp' are + * valid or both are NULL. + */ +static void +get_key_info(const cfg_obj_t *config, const cfg_obj_t *control, + const cfg_obj_t **global_keylistp, + const cfg_obj_t **control_keylistp) { + isc_result_t result; + const cfg_obj_t *control_keylist = NULL; + const cfg_obj_t *global_keylist = NULL; + + REQUIRE(global_keylistp != NULL && *global_keylistp == NULL); + REQUIRE(control_keylistp != NULL && *control_keylistp == NULL); + + control_keylist = cfg_tuple_get(control, "keys"); + + if (!cfg_obj_isvoid(control_keylist) && + cfg_list_first(control_keylist) != NULL) + { + result = cfg_map_get(config, "key", &global_keylist); + + if (result == ISC_R_SUCCESS) { + *global_keylistp = global_keylist; + *control_keylistp = control_keylist; + } + } +} + +static void +update_listener(named_controls_t *cp, controllistener_t **listenerp, + const cfg_obj_t *control, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext, isc_sockettype_t type) { + controllistener_t *listener; + const cfg_obj_t *allow; + const cfg_obj_t *global_keylist = NULL; + const cfg_obj_t *control_keylist = NULL; + dns_acl_t *new_acl = NULL; + controlkeylist_t keys; + isc_result_t result = ISC_R_SUCCESS; + + for (listener = ISC_LIST_HEAD(cp->listeners); listener != NULL; + listener = ISC_LIST_NEXT(listener, link)) + { + if (isc_sockaddr_equal(addr, &listener->address)) { + break; + } + } + + if (listener == NULL) { + *listenerp = NULL; + return; + } + + /* + * There is already a listener for this sockaddr. + * Update the access list and key information. + * + * First try to deal with the key situation. There are a few + * possibilities: + * (a) It had an explicit keylist and still has an explicit keylist. + * (b) It had an automagic key and now has an explicit keylist. + * (c) It had an explicit keylist and now needs an automagic key. + * (d) It has an automagic key and still needs the automagic key. + * + * (c) and (d) are the annoying ones. The caller needs to know + * that it should use the automagic configuration for key information + * in place of the named.conf configuration. + * + * XXXDCL There is one other hazard that has not been dealt with, + * the problem that if a key change is being caused by a control + * channel reload, then the response will be with the new key + * and not able to be decrypted by the client. + */ + if (control != NULL) { + get_key_info(config, control, &global_keylist, + &control_keylist); + } + + if (control_keylist != NULL) { + INSIST(global_keylist != NULL); + + ISC_LIST_INIT(keys); + controlkeylist_fromcfg(control_keylist, listener->mctx, &keys); + free_controlkeylist(&listener->keys, listener->mctx); + listener->keys = keys; + register_keys(control, global_keylist, &listener->keys, + listener->mctx, socktext); + } else { + free_controlkeylist(&listener->keys, listener->mctx); + result = get_rndckey(listener->mctx, &listener->keys); + } + + if (result != ISC_R_SUCCESS && global_keylist != NULL) { + /* + * This message might be a little misleading since the + * "new keys" might in fact be identical to the old ones, + * but tracking whether they are identical just for the + * sake of avoiding this message would be too much trouble. + */ + if (control != NULL) { + cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING, + "couldn't install new keys for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "couldn't install new keys for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + } + } + + /* + * Now, keep the old access list unless a new one can be made. + */ + if (control != NULL && type == isc_sockettype_tcp) { + allow = cfg_tuple_get(control, "allow"); + result = cfg_acl_fromconfig(allow, config, named_g_lctx, + aclconfctx, listener->mctx, 0, + &new_acl); + } else { + result = dns_acl_any(listener->mctx, &new_acl); + } + + if (control != NULL) { + const cfg_obj_t *readonly; + + readonly = cfg_tuple_get(control, "read-only"); + if (!cfg_obj_isvoid(readonly)) { + listener->readonly = cfg_obj_asboolean(readonly); + } + } + + if (result == ISC_R_SUCCESS) { + dns_acl_detach(&listener->acl); + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + /* XXXDCL say the old acl is still used? */ + } else if (control != NULL) { + cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING, + "couldn't install new acl for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING, + "couldn't install new acl for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + } + + if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { + uint32_t perm, owner, group; + perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); + owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); + group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); + result = ISC_R_SUCCESS; + if (listener->perm != perm || listener->owner != owner || + listener->group != group) + { + result = isc_socket_permunix(&listener->address, perm, + owner, group); + } + if (result == ISC_R_SUCCESS) { + listener->perm = perm; + listener->owner = owner; + listener->group = group; + } else if (control != NULL) { + cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING, + "couldn't update ownership/permission for " + "command channel %s", + socktext); + } + } + + *listenerp = listener; +} + +static void +add_listener(named_controls_t *cp, controllistener_t **listenerp, + const cfg_obj_t *control, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext, isc_sockettype_t type) { + isc_mem_t *mctx = cp->server->mctx; + controllistener_t *listener; + const cfg_obj_t *allow; + const cfg_obj_t *global_keylist = NULL; + const cfg_obj_t *control_keylist = NULL; + dns_acl_t *new_acl = NULL; + isc_result_t result = ISC_R_SUCCESS; + + listener = isc_mem_get(mctx, sizeof(*listener)); + + listener->mctx = NULL; + isc_mem_attach(mctx, &listener->mctx); + listener->controls = cp; + listener->task = cp->server->task; + listener->address = *addr; + listener->sock = NULL; + listener->listening = false; + listener->exiting = false; + listener->acl = NULL; + listener->type = type; + listener->perm = 0; + listener->owner = 0; + listener->group = 0; + listener->readonly = false; + ISC_LINK_INIT(listener, link); + ISC_LIST_INIT(listener->keys); + ISC_LIST_INIT(listener->connections); + + /* + * Make the acl. + */ + if (control != NULL && type == isc_sockettype_tcp) { + allow = cfg_tuple_get(control, "allow"); + result = cfg_acl_fromconfig(allow, config, named_g_lctx, + aclconfctx, mctx, 0, &new_acl); + } else { + result = dns_acl_any(mctx, &new_acl); + } + + if ((result == ISC_R_SUCCESS) && (control != NULL)) { + const cfg_obj_t *readonly; + + readonly = cfg_tuple_get(control, "read-only"); + if (!cfg_obj_isvoid(readonly)) { + listener->readonly = cfg_obj_asboolean(readonly); + } + } + + if (result == ISC_R_SUCCESS) { + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + + if (config != NULL) { + get_key_info(config, control, &global_keylist, + &control_keylist); + } + + if (control_keylist != NULL) { + controlkeylist_fromcfg(control_keylist, listener->mctx, + &listener->keys); + register_keys(control, global_keylist, &listener->keys, + listener->mctx, socktext); + } else { + result = get_rndckey(mctx, &listener->keys); + } + + if (result != ISC_R_SUCCESS && control != NULL) { + cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING, + "couldn't install keys for " + "command channel %s: %s", + socktext, isc_result_totext(result)); + } + } + + if (result == ISC_R_SUCCESS) { + int pf = isc_sockaddr_pf(&listener->address); + if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || +#ifdef ISC_PLATFORM_HAVESYSUNH + (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) || +#endif /* ifdef ISC_PLATFORM_HAVESYSUNH */ + (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) + { + result = ISC_R_FAMILYNOSUPPORT; + } + } + + if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { + isc_socket_cleanunix(&listener->address, false); + } + + if (result == ISC_R_SUCCESS) { + result = isc_socket_create(named_g_socketmgr, + isc_sockaddr_pf(&listener->address), + type, &listener->sock); + } + if (result == ISC_R_SUCCESS) { + isc_socket_setname(listener->sock, "control", NULL); + } + +#ifndef ISC_ALLOW_MAPPED + if (result == ISC_R_SUCCESS) { + isc_socket_ipv6only(listener->sock, true); + } +#endif /* ifndef ISC_ALLOW_MAPPED */ + + if (result == ISC_R_SUCCESS) { + result = isc_socket_bind(listener->sock, &listener->address, + ISC_SOCKET_REUSEADDRESS); + } + + if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { + listener->perm = + cfg_obj_asuint32(cfg_tuple_get(control, "perm")); + listener->owner = + cfg_obj_asuint32(cfg_tuple_get(control, "owner")); + listener->group = + cfg_obj_asuint32(cfg_tuple_get(control, "group")); + result = isc_socket_permunix(&listener->address, listener->perm, + listener->owner, listener->group); + } + if (result == ISC_R_SUCCESS) { + result = control_listen(listener); + } + + if (result == ISC_R_SUCCESS) { + result = control_accept(listener); + } + + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_NOTICE, + "command channel listening on %s", socktext); + *listenerp = listener; + } else { + listener->exiting = true; + free_listener(listener); + + if (control != NULL) { + cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING, + "couldn't add command channel %s: %s", + socktext, isc_result_totext(result)); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_NOTICE, + "couldn't add command channel %s: %s", + socktext, isc_result_totext(result)); + } + + *listenerp = NULL; + } + + /* XXXDCL return error results? fail hard? */ +} + +isc_result_t +named_controls_configure(named_controls_t *cp, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx) { + controllistener_t *listener; + controllistenerlist_t new_listeners; + const cfg_obj_t *controlslist = NULL; + const cfg_listelt_t *element, *element2; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + ISC_LIST_INIT(new_listeners); + + /* + * Get the list of named.conf 'controls' statements. + */ + (void)cfg_map_get(config, "controls", &controlslist); + + /* + * Run through the new control channel list, noting sockets that + * are already being listened on and moving them to the new list. + * + * Identifying duplicate addr/port combinations is left to either + * the underlying config code, or to the bind attempt getting an + * address-in-use error. + */ + if (controlslist != NULL) { + for (element = cfg_list_first(controlslist); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *controls; + const cfg_obj_t *inetcontrols = NULL; + + controls = cfg_listelt_value(element); + (void)cfg_map_get(controls, "inet", &inetcontrols); + if (inetcontrols == NULL) { + continue; + } + + for (element2 = cfg_list_first(inetcontrols); + element2 != NULL; + element2 = cfg_list_next(element2)) + { + const cfg_obj_t *control; + const cfg_obj_t *obj; + isc_sockaddr_t addr; + + /* + * The parser handles BIND 8 configuration file + * syntax, so it allows unix phrases as well + * inet phrases with no keys{} clause. + */ + control = cfg_listelt_value(element2); + + obj = cfg_tuple_get(control, "address"); + addr = *cfg_obj_assockaddr(obj); + if (isc_sockaddr_getport(&addr) == 0) { + isc_sockaddr_setport( + &addr, NAMED_CONTROL_PORT); + } + + isc_sockaddr_format(&addr, socktext, + sizeof(socktext)); + + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, + ISC_LOG_DEBUG(9), + "processing control channel %s", + socktext); + + update_listener(cp, &listener, control, config, + &addr, aclconfctx, socktext, + isc_sockettype_tcp); + + if (listener != NULL) { + /* + * Remove the listener from the old + * list, so it won't be shut down. + */ + ISC_LIST_UNLINK(cp->listeners, listener, + link); + } else { + /* + * This is a new listener. + */ + add_listener(cp, &listener, control, + config, &addr, aclconfctx, + socktext, + isc_sockettype_tcp); + } + + if (listener != NULL) { + ISC_LIST_APPEND(new_listeners, listener, + link); + } + } + } + for (element = cfg_list_first(controlslist); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *controls; + const cfg_obj_t *unixcontrols = NULL; + + controls = cfg_listelt_value(element); + (void)cfg_map_get(controls, "unix", &unixcontrols); + if (unixcontrols == NULL) { + continue; + } + + for (element2 = cfg_list_first(unixcontrols); + element2 != NULL; + element2 = cfg_list_next(element2)) + { + const cfg_obj_t *control; + const cfg_obj_t *path; + isc_sockaddr_t addr; + isc_result_t result; + + /* + * The parser handles BIND 8 configuration file + * syntax, so it allows unix phrases as well + * inet phrases with no keys{} clause. + */ + control = cfg_listelt_value(element2); + + path = cfg_tuple_get(control, "path"); + result = isc_sockaddr_frompath( + &addr, cfg_obj_asstring(path)); + if (result != ISC_R_SUCCESS) { + isc_log_write( + named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, + ISC_LOG_DEBUG(9), + "control channel '%s': %s", + cfg_obj_asstring(path), + isc_result_totext(result)); + continue; + } + + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, + ISC_LOG_DEBUG(9), + "processing control channel '%s'", + cfg_obj_asstring(path)); + + update_listener(cp, &listener, control, config, + &addr, aclconfctx, + cfg_obj_asstring(path), + isc_sockettype_unix); + + if (listener != NULL) { + /* + * Remove the listener from the old + * list, so it won't be shut down. + */ + ISC_LIST_UNLINK(cp->listeners, listener, + link); + } else { + /* + * This is a new listener. + */ + add_listener(cp, &listener, control, + config, &addr, aclconfctx, + cfg_obj_asstring(path), + isc_sockettype_unix); + } + + if (listener != NULL) { + ISC_LIST_APPEND(new_listeners, listener, + link); + } + } + } + } else { + int i; + + for (i = 0; i < 2; i++) { + isc_sockaddr_t addr; + + if (i == 0) { + struct in_addr localhost; + + if (isc_net_probeipv4() != ISC_R_SUCCESS) { + continue; + } + localhost.s_addr = htonl(INADDR_LOOPBACK); + isc_sockaddr_fromin(&addr, &localhost, 0); + } else { + if (isc_net_probeipv6() != ISC_R_SUCCESS) { + continue; + } + isc_sockaddr_fromin6(&addr, &in6addr_loopback, + 0); + } + isc_sockaddr_setport(&addr, NAMED_CONTROL_PORT); + + isc_sockaddr_format(&addr, socktext, sizeof(socktext)); + + update_listener(cp, &listener, NULL, NULL, &addr, NULL, + socktext, isc_sockettype_tcp); + + if (listener != NULL) { + /* + * Remove the listener from the old + * list, so it won't be shut down. + */ + ISC_LIST_UNLINK(cp->listeners, listener, link); + } else { + /* + * This is a new listener. + */ + add_listener(cp, &listener, NULL, NULL, &addr, + NULL, socktext, + isc_sockettype_tcp); + } + + if (listener != NULL) { + ISC_LIST_APPEND(new_listeners, listener, link); + } + } + } + + /* + * named_control_shutdown() will stop whatever is on the global + * listeners list, which currently only has whatever sockaddrs + * were in the previous configuration (if any) that do not + * remain in the current configuration. + */ + controls_shutdown(cp); + + /* + * Put all of the valid listeners on the listeners list. + * Anything already on listeners in the process of shutting + * down will be taken care of by listen_done(). + */ + ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link); + return (ISC_R_SUCCESS); +} + +isc_result_t +named_controls_create(named_server_t *server, named_controls_t **ctrlsp) { + isc_mem_t *mctx = server->mctx; + isc_result_t result; + named_controls_t *controls = isc_mem_get(mctx, sizeof(*controls)); + + *controls = (named_controls_t){ + .server = server, + }; + + ISC_LIST_INIT(controls->listeners); + + isc_mutex_init(&controls->symtab_lock); + LOCK(&controls->symtab_lock); + result = isccc_cc_createsymtab(&controls->symtab); + UNLOCK(&controls->symtab_lock); + + if (result != ISC_R_SUCCESS) { + isc_mutex_destroy(&controls->symtab_lock); + isc_mem_put(server->mctx, controls, sizeof(*controls)); + return (result); + } + *ctrlsp = controls; + return (ISC_R_SUCCESS); +} + +void +named_controls_destroy(named_controls_t **ctrlsp) { + named_controls_t *controls = *ctrlsp; + *ctrlsp = NULL; + + REQUIRE(ISC_LIST_EMPTY(controls->listeners)); + + LOCK(&controls->symtab_lock); + isccc_symtab_destroy(&controls->symtab); + UNLOCK(&controls->symtab_lock); + isc_mutex_destroy(&controls->symtab_lock); + isc_mem_put(controls->server->mctx, controls, sizeof(*controls)); +} diff --git a/bin/named/convertxsl.pl b/bin/named/convertxsl.pl new file mode 100755 index 0000000..37c2e15 --- /dev/null +++ b/bin/named/convertxsl.pl @@ -0,0 +1,53 @@ +#!/usr/bin/env perl + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +use strict; +use warnings; + +my $rev = '$Id: convertxsl.pl,v 1.14 2008/07/17 23:43:26 jinmei Exp $'; +$rev =~ s/\$//g; +$rev =~ s/,v//g; +$rev =~ s/Id: //; + +my $xsl = "unknown"; +my $lines = ''; + +while (<>) { + chomp; + # pickout the id for comment. + $xsl = $_ if (//); + # convert Id string to a form not recognisable by cvs. + $_ =~ s///; + s/[\ \t]+/ /g; + s/\>\ \\.*//; +$xsl =~ s/,v//; + +print "/*\n * Generated by $rev \n * From $xsl\n */\n"; +print 'static char xslmsg[] =',"\n"; +print $lines; + +print ';', "\n"; diff --git a/bin/named/fuzz.c b/bin/named/fuzz.c new file mode 100644 index 0000000..fb0d56f --- /dev/null +++ b/bin/named/fuzz.c @@ -0,0 +1,782 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include + +#ifdef ENABLE_AFL +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +/* + * We are using pthreads directly because we might be using it with + * unthreaded version of BIND, where all thread functions are + * mocks. Since AFL for now only works on Linux it's not a problem. + */ +static pthread_cond_t cond; +static pthread_mutex_t mutex; +static bool ready; + +/* + * In "client:" mode, this thread reads fuzzed query messages from AFL + * from standard input and sends it to named's listening port (DNS) that + * is passed in the -A client:
: option. It can be used to + * test named from the client side. + */ +static void * +fuzz_thread_client(void *arg) { + char *host; + char *port; + struct sockaddr_in servaddr; + int sockfd; + void *buf; + + UNUSED(arg); + + /* + * Parse named -A argument in the "address:port" syntax. Due to + * the syntax used, this only supports IPv4 addresses. + */ + host = strdup(named_g_fuzz_addr); + RUNTIME_CHECK(host != NULL); + + port = strchr(host, ':'); + RUNTIME_CHECK(port != NULL); + *port = 0; + ++port; + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + RUNTIME_CHECK(inet_pton(AF_INET, host, &servaddr.sin_addr) == 1); + servaddr.sin_port = htons(atoi(port)); + + free(host); + + /* + * Wait for named to start. This is set in run_server() in the + * named thread. + */ + while (!named_g_run_done) { + usleep(10000); + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + RUNTIME_CHECK(sockfd != -1); + + buf = malloc(65536); + RUNTIME_CHECK(buf != NULL); + + /* + * Processing fuzzed packets 100,000 times before shutting down + * the app. + */ +#ifdef __AFL_LOOP + for (int loop = 0; loop < 100000; loop++) { +#else /* ifdef __AFL_LOOP */ + { +#endif /* ifdef __AFL_LOOP */ + ssize_t length; + ssize_t sent; + + length = read(0, buf, 65536); + if (length <= 0) { + usleep(1000000); + goto next; + } + + /* + * Ignore packets that are larger than 4096 bytes. + */ + if (length > 4096) { + /* + * AFL_CMIN doesn't support persistent mode, so + * shutdown the server. + */ + if (getenv("AFL_CMIN")) { + free(buf); + close(sockfd); + named_server_flushonshutdown(named_g_server, + false); + isc_app_shutdown(); + return (NULL); + } + raise(SIGSTOP); + goto next; + } + + RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0); + + ready = false; + + sent = sendto(sockfd, buf, length, 0, + (struct sockaddr *)&servaddr, sizeof(servaddr)); + RUNTIME_CHECK(sent == length); + + /* + * Read the reply message from named to unclog it. Don't + * bother if there isn't a reply. + */ + (void)recvfrom(sockfd, buf, 65536, MSG_DONTWAIT, NULL, NULL); + + while (!ready) { + pthread_cond_wait(&cond, &mutex); + } + + RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0); + next:; + } + + free(buf); + close(sockfd); + + named_server_flushonshutdown(named_g_server, false); + isc_app_shutdown(); + + return (NULL); +} + +/* + * In "resolver:" mode, this thread reads fuzzed reply messages from AFL + * from standard input. It also sets up a listener as a remote + * authoritative server and sends a driver query to the client side of + * named(resolver). When named(resolver) connects to this authoritative + * server, this thread writes the fuzzed reply message from AFL to it. + * + * -A resolver:::: + * + * Here, : is where named(resolver) is listening on. + * : is where the thread is supposed to setup the + * authoritative server. This address should be configured via the root + * zone to be the authoritiative server for aaaaaaaaaa.example. + * + * named(resolver) when being fuzzed will not cache answers. + */ +static void * +fuzz_thread_resolver(void *arg) { + char *sqtype, *shost, *sport, *rhost, *rport; + struct sockaddr_in servaddr, recaddr, recvaddr; + /* + * Query for aaaaaaaaaa.example./A in wire format with RD=1, + * EDNS and DO=1. 0x88, 0x0c at the start is the ID field which + * will be updated for each query. + */ + char respacket[] = { 0x88, 0x0c, 0x01, 0x20, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x0a, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x07, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }; + /* + * Response for example./DNSKEY in wire format. Note that RRSIGs + * were generated with this DNSKEY that are used as seeds for + * AFL in the DNSSEC fuzzing job. So the DNSKEY content of this + * message must not change, or the corresponding RRSIGs will + * have to be updated. 0x8d, 0xf6 at the start is the ID field + * which will be made to match the query. + */ + const uint8_t dnskey_wf[] = { + 0x8d, 0xf6, 0x84, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x01, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x00, 0x00, 0x30, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x30, 0x00, + 0x01, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x08, 0x01, 0x00, 0x03, + 0x08, 0x03, 0x01, 0x00, 0x01, 0xbd, 0x81, 0xdc, 0x7f, 0x16, + 0xd4, 0x81, 0x7c, 0x1f, 0x9f, 0x6a, 0x68, 0xdd, 0xd4, 0xda, + 0x48, 0xd9, 0x1c, 0xbd, 0xa6, 0x46, 0x1a, 0xf0, 0xb4, 0xb9, + 0xec, 0x3d, 0x6c, 0x0b, 0x57, 0xc7, 0xd6, 0x54, 0x66, 0xe6, + 0x6c, 0xd5, 0x90, 0x3a, 0x78, 0x7d, 0x7f, 0x78, 0x80, 0xa2, + 0x89, 0x61, 0x6d, 0x8a, 0x2b, 0xcd, 0x0a, 0x77, 0x7a, 0xad, + 0xc9, 0x61, 0x53, 0x53, 0x8c, 0x99, 0x72, 0x86, 0x14, 0x74, + 0x9c, 0x49, 0x2a, 0x47, 0x23, 0xf7, 0x02, 0x07, 0x73, 0x1c, + 0x5c, 0x2e, 0xb4, 0x9a, 0xa4, 0xd7, 0x98, 0x42, 0xc3, 0xd2, + 0xfe, 0xbf, 0xf3, 0xb3, 0x6a, 0x52, 0x92, 0xd5, 0xfa, 0x47, + 0x00, 0xe3, 0xd9, 0x59, 0x31, 0x95, 0x48, 0x40, 0xfc, 0x06, + 0x73, 0x90, 0xc6, 0x73, 0x96, 0xba, 0x29, 0x91, 0xe2, 0xac, + 0xa3, 0xa5, 0x6d, 0x91, 0x6d, 0x52, 0xb9, 0x34, 0xba, 0x68, + 0x4f, 0xad, 0xf0, 0xc3, 0xf3, 0x1d, 0x6d, 0x61, 0x76, 0xe5, + 0x3d, 0xa3, 0x9b, 0x2a, 0x0c, 0x92, 0xb3, 0x78, 0x6b, 0xf1, + 0x20, 0xd6, 0x90, 0xb7, 0xac, 0xe2, 0xf8, 0x2b, 0x94, 0x10, + 0x79, 0xce, 0xa8, 0x60, 0x42, 0xea, 0x6a, 0x18, 0x2f, 0xc0, + 0xd8, 0x05, 0x0a, 0x3b, 0x06, 0x0f, 0x02, 0x7e, 0xff, 0x33, + 0x46, 0xee, 0xb6, 0x21, 0x25, 0x90, 0x63, 0x4b, 0x3b, 0x5e, + 0xb2, 0x72, 0x3a, 0xcb, 0x91, 0x41, 0xf4, 0x20, 0x50, 0x78, + 0x1c, 0x93, 0x95, 0xda, 0xfa, 0xae, 0x85, 0xc5, 0xd7, 0x6b, + 0x92, 0x0c, 0x70, 0x6b, 0xe4, 0xb7, 0x29, 0x3a, 0x2e, 0x18, + 0x88, 0x82, 0x33, 0x7c, 0xa8, 0xea, 0xb8, 0x31, 0x8f, 0xaf, + 0x50, 0xc5, 0x9c, 0x08, 0x56, 0x8f, 0x09, 0x76, 0x4e, 0xdf, + 0x97, 0x75, 0x9d, 0x00, 0x52, 0x7f, 0xdb, 0xec, 0x30, 0xcb, + 0x1c, 0x4c, 0x2a, 0x21, 0x93, 0xc4, 0x6d, 0x85, 0xa9, 0x40, + 0x3b, 0xc0, 0x0c, 0x00, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x01, + 0x2c, 0x01, 0x1b, 0x00, 0x30, 0x08, 0x01, 0x00, 0x00, 0x01, + 0x2c, 0x67, 0x74, 0x85, 0x80, 0x58, 0xb3, 0xc5, 0x17, 0x36, + 0x90, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x00, + 0x45, 0xac, 0xd3, 0x82, 0x69, 0xf3, 0x10, 0x3a, 0x97, 0x2c, + 0x6a, 0xa9, 0x78, 0x99, 0xea, 0xb0, 0xcc, 0xf7, 0xaf, 0x33, + 0x51, 0x5b, 0xdf, 0x77, 0x04, 0x18, 0x14, 0x99, 0x61, 0xeb, + 0x8d, 0x76, 0x3f, 0xd1, 0x71, 0x14, 0x43, 0x80, 0x53, 0xc2, + 0x3b, 0x9f, 0x09, 0x4f, 0xb3, 0x51, 0x04, 0x89, 0x0e, 0xc8, + 0x54, 0x12, 0xcd, 0x07, 0x20, 0xbe, 0x94, 0xc2, 0xda, 0x99, + 0xdd, 0x1e, 0xf8, 0xb0, 0x84, 0x2e, 0xf9, 0x19, 0x35, 0x36, + 0xf5, 0xd0, 0x5d, 0x82, 0x18, 0x74, 0xa0, 0x00, 0xb6, 0x15, + 0x57, 0x40, 0x5f, 0x78, 0x2d, 0x27, 0xac, 0xc7, 0x8a, 0x29, + 0x55, 0xa9, 0xcd, 0xbc, 0xf7, 0x3e, 0xff, 0xae, 0x1a, 0x5a, + 0x1d, 0xac, 0x0d, 0x78, 0x0e, 0x08, 0x33, 0x6c, 0x59, 0x70, + 0x40, 0xb9, 0x65, 0xbd, 0x35, 0xbb, 0x9a, 0x70, 0xdc, 0x93, + 0x66, 0xb0, 0xef, 0xfe, 0xf0, 0x32, 0xa6, 0xee, 0xb7, 0x03, + 0x89, 0xa2, 0x4d, 0xe0, 0xf1, 0x20, 0xdf, 0x39, 0xe8, 0xe3, + 0xcc, 0x95, 0xe9, 0x9a, 0xad, 0xbf, 0xbd, 0x7c, 0xf7, 0xd7, + 0xde, 0x47, 0x9e, 0xf6, 0x17, 0xbb, 0x84, 0xa9, 0xed, 0xf2, + 0x45, 0x61, 0x6d, 0x13, 0x0b, 0x06, 0x29, 0x50, 0xde, 0xfd, + 0x42, 0xb0, 0x66, 0x2c, 0x1c, 0x2b, 0x63, 0xcb, 0x4e, 0xb9, + 0x31, 0xc4, 0xea, 0xd2, 0x07, 0x3a, 0x08, 0x79, 0x19, 0x4b, + 0x4c, 0x50, 0x97, 0x02, 0xd7, 0x26, 0x41, 0x2f, 0xdd, 0x57, + 0xaa, 0xb0, 0xa0, 0x21, 0x4e, 0x74, 0xb6, 0x97, 0x4b, 0x8b, + 0x09, 0x9c, 0x3d, 0x29, 0xfb, 0x12, 0x27, 0x47, 0x8f, 0xb8, + 0xc5, 0x8e, 0x65, 0xcd, 0xca, 0x2f, 0xba, 0xf5, 0x3e, 0xec, + 0x56, 0xc3, 0xc9, 0xa1, 0x62, 0x7d, 0xf2, 0x9f, 0x90, 0x16, + 0x1d, 0xbf, 0x97, 0x28, 0xe1, 0x92, 0xb1, 0x53, 0xab, 0xc4, + 0xe0, 0x99, 0xbb, 0x19, 0x90, 0x7c, 0x00, 0x00, 0x29, 0x10, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 + }; + + int sockfd; + int listenfd; + int loop; + uint16_t qtype; + char *buf, *rbuf; + char *nameptr; + unsigned int i; + uint8_t llen; + uint64_t seed; + + UNUSED(arg); + + /* + * Parse named -A argument in the "qtype:saddress:sport:raddress:rport" + * syntax. Due to the syntax used, this only supports IPv4 addresses. + */ + sqtype = strdup(named_g_fuzz_addr); + RUNTIME_CHECK(sqtype != NULL); + + shost = strchr(sqtype, ':'); + RUNTIME_CHECK(shost != NULL); + *shost = 0; + shost++; + + sport = strchr(shost, ':'); + RUNTIME_CHECK(sport != NULL); + *sport = 0; + sport++; + + rhost = strchr(sport, ':'); + RUNTIME_CHECK(rhost != NULL); + *rhost = 0; + rhost++; + + rport = strchr(rhost, ':'); + RUNTIME_CHECK(rport != NULL); + *rport = 0; + rport++; + + /* + * Patch in the qtype into the question section of respacket. + */ + qtype = atoi(sqtype); + respacket[32] = (qtype >> 8) & 0xff; + respacket[33] = qtype & 0xff; + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + RUNTIME_CHECK(inet_pton(AF_INET, shost, &servaddr.sin_addr) == 1); + servaddr.sin_port = htons(atoi(sport)); + + memset(&recaddr, 0, sizeof(recaddr)); + recaddr.sin_family = AF_INET; + RUNTIME_CHECK(inet_pton(AF_INET, rhost, &recaddr.sin_addr) == 1); + recaddr.sin_port = htons(atoi(rport)); + + free(sqtype); + + /* + * Wait for named to start. This is set in run_server() in the + * named thread. + */ + while (!named_g_run_done) { + usleep(10000); + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + RUNTIME_CHECK(sockfd != -1); + + listenfd = socket(AF_INET, SOCK_DGRAM, 0); + RUNTIME_CHECK(listenfd != -1); + + RUNTIME_CHECK(bind(listenfd, (struct sockaddr *)&recaddr, + sizeof(struct sockaddr_in)) == 0); + + buf = malloc(65536); + rbuf = malloc(65536); + RUNTIME_CHECK(buf != NULL); + RUNTIME_CHECK(rbuf != NULL); + + seed = 42; + + /* + * Processing fuzzed packets 100,000 times before shutting down + * the app. + */ + for (loop = 0; loop < 100000; loop++) { + ssize_t length; + ssize_t sent; + unsigned short id; + socklen_t socklen; + + memset(buf, 0, 12); + length = read(0, buf, 65536); + if (length <= 0) { + usleep(1000000); + continue; + } + + if (length > 4096) { + if (getenv("AFL_CMIN")) { + free(buf); + free(rbuf); + close(sockfd); + close(listenfd); + named_server_flushonshutdown(named_g_server, + false); + isc_app_shutdown(); + return (NULL); + } + raise(SIGSTOP); + continue; + } + + if (length < 12) { + length = 12; + } + + RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0); + + ready = false; + + /* Use a unique query ID. */ + seed = 1664525 * seed + 1013904223; + id = seed & 0xffff; + respacket[0] = (id >> 8) & 0xff; + respacket[1] = id & 0xff; + + /* + * Flush any pending data on the authoritative server. + */ + socklen = sizeof(recvaddr); + (void)recvfrom(listenfd, rbuf, 65536, MSG_DONTWAIT, + (struct sockaddr *)&recvaddr, &socklen); + + /* + * Send a fixed client query to named(resolver) of + * aaaaaaaaaa.example./A. This is the starting query + * driver. + */ + sent = sendto(sockfd, respacket, sizeof(respacket), 0, + (struct sockaddr *)&servaddr, sizeof(servaddr)); + RUNTIME_CHECK(sent == sizeof(respacket)); + + /* + * named(resolver) will process the query above and send + * an upstream query to the authoritative server. We + * handle that here as the upstream authoritative server + * on listenfd. + */ + socklen = sizeof(recvaddr); + sent = recvfrom(listenfd, rbuf, 65536, 0, + (struct sockaddr *)&recvaddr, &socklen); + RUNTIME_CHECK(sent > 0); + + /* + * Copy QID and set QR so that response is always + * accepted by named(resolver). + */ + buf[0] = rbuf[0]; + buf[1] = rbuf[1]; + buf[2] |= 0x80; + + /* + * NOTE: We are not copying the QNAME or setting + * rcode=NOERROR each time. So the resolver may fail the + * client query (driver) / wander due to this. AA flag + * may also not be set based on the contents of the AFL + * fuzzed packet. + */ + + /* + * A hack - set QTYPE to the one from query so that we + * can easily share packets between instances. If we + * write over something else we'll get FORMERR anyway. + */ + + /* Skip DNS header to get to the name */ + nameptr = buf + 12; + + /* Skip the name to get to the qtype */ + i = 0; + while (((llen = nameptr[i]) != 0) && (i < 255) && + (((nameptr + i + 1 + llen) - buf) < length)) + { + i += 1 + llen; + } + + if (i <= 255) { + nameptr += 1 + i; + /* Patch the qtype */ + if ((nameptr - buf) < (length - 2)) { + *nameptr++ = (qtype >> 8) & 0xff; + *nameptr++ = qtype & 0xff; + } + /* Patch the qclass */ + if ((nameptr - buf) < (length - 2)) { + *nameptr++ = 0; + *nameptr++ = 1; + } + } + + /* + * Send the reply to named(resolver). + */ + sent = sendto(listenfd, buf, length, 0, + (struct sockaddr *)&recvaddr, sizeof(recvaddr)); + RUNTIME_CHECK(sent == length); + + /* We might get additional questions here (e.g. for CNAME). */ + for (;;) { + fd_set fds; + struct timeval tv; + int rv; + int max; + + FD_ZERO(&fds); + FD_SET(listenfd, &fds); + FD_SET(sockfd, &fds); + tv.tv_sec = 10; + tv.tv_usec = 0; + max = (listenfd > sockfd ? listenfd : sockfd) + 1; + + rv = select(max, &fds, NULL, NULL, &tv); + RUNTIME_CHECK(rv > 0); + + if (FD_ISSET(sockfd, &fds)) { + /* + * It's the reply from named(resolver) + * to the client(query driver), so we're + * done. + */ + (void)recvfrom(sockfd, buf, 65536, 0, NULL, + NULL); + break; + } + + /* + * We've got additional question (eg. due to + * CNAME). Bounce it - setting QR flag and + * NOERROR rcode and sending it back. + */ + length = recvfrom(listenfd, buf, 65536, 0, + (struct sockaddr *)&recvaddr, + &socklen); + + /* + * If this is a DNSKEY query, send the DNSKEY, + * otherwise, bounce the query. + */ + + /* Skip DNS header to get to the name */ + nameptr = buf + 12; + + /* Skip the name to get to the qtype */ + i = 0; + while (((llen = nameptr[i]) != 0) && (i < 255) && + (((nameptr + i + 1 + llen) - buf) < length)) + { + i += 1 + llen; + } + + if (i <= 255) { + nameptr += 1 + i; + /* + * Patch in the DNSKEY reply without + * touching the ID field. Note that we + * don't compare the name in the + * question section in the query, but we + * don't expect to receive any query for + * type DNSKEY but for the name + * "example." + */ + if ((nameptr - buf) < (length - 2)) { + uint8_t hb, lb; + hb = *nameptr++; + lb = *nameptr++; + qtype = (hb << 8) | lb; + + if (qtype == 48) { + memmove(buf + 2, dnskey_wf + 2, + sizeof(dnskey_wf) - 2); + length = sizeof(dnskey_wf); + } + } + } + + buf[2] |= 0x80; + buf[3] &= 0xF0; + sent = sendto(listenfd, buf, length, 0, + (struct sockaddr *)&recvaddr, + sizeof(recvaddr)); + RUNTIME_CHECK(sent == length); + } + + while (!ready) { + pthread_cond_wait(&cond, &mutex); + } + + RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0); + } + + free(buf); + free(rbuf); + close(sockfd); + close(listenfd); + named_server_flushonshutdown(named_g_server, false); + isc_app_shutdown(); + +#ifdef __AFL_LOOP + /* + * This is here just for the signature, that's how AFL detects + * if it's a 'persistent mode' binary. It has to occur somewhere + * in the file, that's all. < wpk_> AFL checks the binary for + * this signature ("##SIG_AFL_PERSISTENT##") and runs the binary + * in persistent mode if it's present. + */ + __AFL_LOOP(0); +#endif /* ifdef __AFL_LOOP */ + + return (NULL); +} + +/* + * In "tcp:", "http:" and "rndc:" modes, this thread reads fuzzed query + * blobs from AFL from standard input and sends it to the corresponding + * TCP listening port of named (port 53 DNS, or the HTTP statistics + * channels listener or the rndc port) that is passed in the -A + * :
: option. It can be used to test named from the + * client side. + */ +static void * +fuzz_thread_tcp(void *arg) { + char *host; + char *port; + struct sockaddr_in servaddr; + int sockfd; + char *buf; + int loop; + + UNUSED(arg); + + /* + * Parse named -A argument in the "address:port" syntax. Due to + * the syntax used, this only supports IPv4 addresses. + */ + host = strdup(named_g_fuzz_addr); + RUNTIME_CHECK(host != NULL); + + port = strchr(host, ':'); + RUNTIME_CHECK(port != NULL); + *port = 0; + ++port; + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + RUNTIME_CHECK(inet_pton(AF_INET, host, &servaddr.sin_addr) == 1); + servaddr.sin_port = htons(atoi(port)); + + free(host); + + /* + * Wait for named to start. This is set in run_server() in the + * named thread. + */ + while (!named_g_run_done) { + usleep(10000); + } + + buf = malloc(65539); + RUNTIME_CHECK(buf != NULL); + + /* + * Processing fuzzed packets 100,000 times before shutting down + * the app. + */ + for (loop = 0; loop < 100000; loop++) { + ssize_t length; + ssize_t sent; + int yes; + int r; + + if (named_g_fuzz_type == isc_fuzz_tcpclient) { + /* + * To fuzz DNS TCP client we have to put 16-bit + * message length preceding the start of packet. + */ + length = read(0, buf + 2, 65535); + buf[0] = (length >> 8) & 0xff; + buf[1] = length & 0xff; + length += 2; + } else { + /* + * Other types of TCP clients such as HTTP, etc. + */ + length = read(0, buf, 65535); + } + if (length <= 0) { + usleep(1000000); + continue; + } + if (named_g_fuzz_type == isc_fuzz_http) { + /* + * This guarantees that the request will be + * processed. + */ + INSIST(length <= 65535); + buf[length++] = '\r'; + buf[length++] = '\n'; + buf[length++] = '\r'; + buf[length++] = '\n'; + } + + RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0); + + ready = false; + yes = 1; + sockfd = socket(AF_INET, SOCK_STREAM, 0); + + RUNTIME_CHECK(sockfd != -1); + RUNTIME_CHECK(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(int)) == 0); + + do { + r = connect(sockfd, (struct sockaddr *)&servaddr, + sizeof(servaddr)); + if (r != 0) { + usleep(10000); + } + } while (r != 0); + + /* + * Send the fuzzed query blob to the target server. + */ + sent = write(sockfd, buf, length); + RUNTIME_CHECK(sent == length); + + close(sockfd); + + while (!ready) { + pthread_cond_wait(&cond, &mutex); + } + + RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0); + } + + free(buf); + close(sockfd); + named_server_flushonshutdown(named_g_server, false); + isc_app_shutdown(); + + return (NULL); +} + +#endif /* ENABLE_AFL */ + +/* + * named has finished processing a message and has sent the + * reply. Signal the fuzz thread using the condition variable, to read + * and process the next item from AFL. + */ +void +named_fuzz_notify(void) { +#ifdef ENABLE_AFL + if (getenv("AFL_CMIN")) { + named_server_flushonshutdown(named_g_server, false); + isc_app_shutdown(); + return; + } + + raise(SIGSTOP); + + RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0); + + ready = true; + + RUNTIME_CHECK(pthread_cond_signal(&cond) == 0); + RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0); +#endif /* ENABLE_AFL */ +} + +void +named_fuzz_setup(void) { +#ifdef ENABLE_AFL + if (getenv("__AFL_PERSISTENT") || getenv("AFL_CMIN")) { + pthread_t thread; + void *(fn) = NULL; + + switch (named_g_fuzz_type) { + case isc_fuzz_client: + fn = fuzz_thread_client; + break; + + case isc_fuzz_http: + case isc_fuzz_tcpclient: + case isc_fuzz_rndc: + fn = fuzz_thread_tcp; + break; + + case isc_fuzz_resolver: + fn = fuzz_thread_resolver; + break; + + default: + RUNTIME_CHECK(fn != NULL); + } + + RUNTIME_CHECK(pthread_mutex_init(&mutex, NULL) == 0); + RUNTIME_CHECK(pthread_cond_init(&cond, NULL) == 0); + RUNTIME_CHECK(pthread_create(&thread, NULL, fn, NULL) == 0); + } +#endif /* ENABLE_AFL */ +} diff --git a/bin/named/geoip.c b/bin/named/geoip.c new file mode 100644 index 0000000..9963ca8 --- /dev/null +++ b/bin/named/geoip.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#if defined(HAVE_GEOIP2) +#include +#endif /* if defined(HAVE_GEOIP2) */ + +#include +#include +#include + +#include + +#include +#include + +static dns_geoip_databases_t geoip_table; + +#if defined(HAVE_GEOIP2) +static MMDB_s geoip_country, geoip_city, geoip_as, geoip_isp, geoip_domain; + +static MMDB_s * +open_geoip2(const char *dir, const char *dbfile, MMDB_s *mmdb) { + char pathbuf[PATH_MAX]; + unsigned int n; + int ret; + + n = snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dir, dbfile); + if (n >= sizeof(pathbuf)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "GeoIP2 database '%s/%s': path too long", dir, + dbfile); + return (NULL); + } + + ret = MMDB_open(pathbuf, MMDB_MODE_MMAP, mmdb); + if (ret == MMDB_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "opened GeoIP2 database '%s'", pathbuf); + return (mmdb); + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), + "unable to open GeoIP2 database '%s' (status %d)", + pathbuf, ret); + + return (NULL); +} +#endif /* HAVE_GEOIP2 */ + +void +named_geoip_init(void) { +#if defined(HAVE_GEOIP2) + if (named_g_geoip == NULL) { + named_g_geoip = &geoip_table; + } +#else /* if defined(HAVE_GEOIP2) */ + return; +#endif /* if defined(HAVE_GEOIP2) */ +} + +void +named_geoip_load(char *dir) { +#if defined(HAVE_GEOIP2) + REQUIRE(dir != NULL); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "looking for GeoIP2 databases in '%s'", dir); + + named_g_geoip->country = open_geoip2(dir, "GeoIP2-Country.mmdb", + &geoip_country); + if (named_g_geoip->country == NULL) { + named_g_geoip->country = open_geoip2( + dir, "GeoLite2-Country.mmdb", &geoip_country); + } + + named_g_geoip->city = open_geoip2(dir, "GeoIP2-City.mmdb", &geoip_city); + if (named_g_geoip->city == NULL) { + named_g_geoip->city = open_geoip2(dir, "GeoLite2-City.mmdb", + &geoip_city); + } + + named_g_geoip->as = open_geoip2(dir, "GeoIP2-ASN.mmdb", &geoip_as); + if (named_g_geoip->as == NULL) { + named_g_geoip->as = open_geoip2(dir, "GeoLite2-ASN.mmdb", + &geoip_as); + } + + named_g_geoip->isp = open_geoip2(dir, "GeoIP2-ISP.mmdb", &geoip_isp); + named_g_geoip->domain = open_geoip2(dir, "GeoIP2-Domain.mmdb", + &geoip_domain); +#else /* if defined(HAVE_GEOIP2) */ + UNUSED(dir); + + return; +#endif /* if defined(HAVE_GEOIP2) */ +} + +void +named_geoip_unload(void) { +#ifdef HAVE_GEOIP2 + if (named_g_geoip->country != NULL) { + MMDB_close(named_g_geoip->country); + named_g_geoip->country = NULL; + } + if (named_g_geoip->city != NULL) { + MMDB_close(named_g_geoip->city); + named_g_geoip->city = NULL; + } + if (named_g_geoip->as != NULL) { + MMDB_close(named_g_geoip->as); + named_g_geoip->as = NULL; + } + if (named_g_geoip->isp != NULL) { + MMDB_close(named_g_geoip->isp); + named_g_geoip->isp = NULL; + } + if (named_g_geoip->domain != NULL) { + MMDB_close(named_g_geoip->domain); + named_g_geoip->domain = NULL; + } +#endif /* ifdef HAVE_GEOIP2 */ +} + +void +named_geoip_shutdown(void) { +#ifdef HAVE_GEOIP2 + named_geoip_unload(); +#endif /* HAVE_GEOIP2 */ +} diff --git a/bin/named/include/.clang-format b/bin/named/include/.clang-format new file mode 120000 index 0000000..0e62f72 --- /dev/null +++ b/bin/named/include/.clang-format @@ -0,0 +1 @@ +../../../.clang-format.headers \ No newline at end of file diff --git a/bin/named/include/dlz/dlz_dlopen_driver.h b/bin/named/include/dlz/dlz_dlopen_driver.h new file mode 100644 index 0000000..7835986 --- /dev/null +++ b/bin/named/include/dlz/dlz_dlopen_driver.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef DLZ_DLOPEN_DRIVER_H +#define DLZ_DLOPEN_DRIVER_H + +isc_result_t +dlz_dlopen_init(isc_mem_t *mctx); + +void +dlz_dlopen_clear(void); +#endif /* ifndef DLZ_DLOPEN_DRIVER_H */ diff --git a/bin/named/include/named/builtin.h b/bin/named/include/named/builtin.h new file mode 100644 index 0000000..9968759 --- /dev/null +++ b/bin/named/include/named/builtin.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_BUILTIN_H +#define NAMED_BUILTIN_H 1 + +/*! \file */ + +#include + +isc_result_t +named_builtin_init(void); + +void +named_builtin_deinit(void); + +#endif /* NAMED_BUILTIN_H */ diff --git a/bin/named/include/named/config.h b/bin/named/include/named/config.h new file mode 100644 index 0000000..e6293ef --- /dev/null +++ b/bin/named/include/named/config.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_CONFIG_H +#define NAMED_CONFIG_H 1 + +/*! \file */ + +#include + +#include +#include + +#include + +#define DEFAULT_IANA_ROOT_ZONE_PRIMARIES "_default_iana_root_zone_primaries" + +isc_result_t +named_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf); + +const char * +named_config_getdefault(void); + +isc_result_t +named_config_get(cfg_obj_t const *const *maps, const char *name, + const cfg_obj_t **obj); + +isc_result_t +named_checknames_get(const cfg_obj_t **maps, const char *const names[], + const cfg_obj_t **obj); + +int +named_config_listcount(const cfg_obj_t *list); + +isc_result_t +named_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass, + dns_rdataclass_t *classp); + +isc_result_t +named_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype, + dns_rdatatype_t *typep); + +dns_zonetype_t +named_config_getzonetype(const cfg_obj_t *zonetypeobj); + +isc_result_t +named_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, + in_port_t defport, isc_mem_t *mctx, + isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp, + uint32_t *countp); + +void +named_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, + isc_dscp_t **dscpsp, uint32_t count); + +isc_result_t +named_config_getremotesdef(const cfg_obj_t *cctx, const char *list, + const char *name, const cfg_obj_t **ret); + +isc_result_t +named_config_getipandkeylist(const cfg_obj_t *config, const char *listtype, + const cfg_obj_t *list, isc_mem_t *mctx, + dns_ipkeylist_t *ipkl); + +isc_result_t +named_config_getport(const cfg_obj_t *config, in_port_t *portp); + +isc_result_t +named_config_getkeyalgorithm(const char *str, const dns_name_t **name, + uint16_t *digestbits); +isc_result_t +named_config_getkeyalgorithm2(const char *str, const dns_name_t **name, + unsigned int *typep, uint16_t *digestbits); + +isc_result_t +named_config_getdscp(const cfg_obj_t *config, isc_dscp_t *dscpp); + +#endif /* NAMED_CONFIG_H */ diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h new file mode 100644 index 0000000..4c0e5f2 --- /dev/null +++ b/bin/named/include/named/control.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_CONTROL_H +#define NAMED_CONTROL_H 1 + +/*! \file + * \brief + * The name server command channel. + */ + +#include + +#include + +#include +#include + +#define NAMED_CONTROL_PORT 953 + +#define NAMED_COMMAND_STOP "stop" +#define NAMED_COMMAND_HALT "halt" +#define NAMED_COMMAND_RELOAD "reload" +#define NAMED_COMMAND_RECONFIG "reconfig" +#define NAMED_COMMAND_REFRESH "refresh" +#define NAMED_COMMAND_RETRANSFER "retransfer" +#define NAMED_COMMAND_DUMPSTATS "stats" +#define NAMED_COMMAND_QUERYLOG "querylog" +#define NAMED_COMMAND_DUMPDB "dumpdb" +#define NAMED_COMMAND_SECROOTS "secroots" +#define NAMED_COMMAND_TRACE "trace" +#define NAMED_COMMAND_NOTRACE "notrace" +#define NAMED_COMMAND_FLUSH "flush" +#define NAMED_COMMAND_FLUSHNAME "flushname" +#define NAMED_COMMAND_FLUSHTREE "flushtree" +#define NAMED_COMMAND_STATUS "status" +#define NAMED_COMMAND_TSIGLIST "tsig-list" +#define NAMED_COMMAND_TSIGDELETE "tsig-delete" +#define NAMED_COMMAND_FREEZE "freeze" +#define NAMED_COMMAND_UNFREEZE "unfreeze" +#define NAMED_COMMAND_THAW "thaw" +#define NAMED_COMMAND_TIMERPOKE "timerpoke" +#define NAMED_COMMAND_RECURSING "recursing" +#define NAMED_COMMAND_NULL "null" +#define NAMED_COMMAND_NOTIFY "notify" +#define NAMED_COMMAND_VALIDATION "validation" +#define NAMED_COMMAND_SCAN "scan" +#define NAMED_COMMAND_SIGN "sign" +#define NAMED_COMMAND_LOADKEYS "loadkeys" +#define NAMED_COMMAND_ADDZONE "addzone" +#define NAMED_COMMAND_MODZONE "modzone" +#define NAMED_COMMAND_DELZONE "delzone" +#define NAMED_COMMAND_SHOWZONE "showzone" +#define NAMED_COMMAND_SYNC "sync" +#define NAMED_COMMAND_SIGNING "signing" +#define NAMED_COMMAND_DNSSEC "dnssec" +#define NAMED_COMMAND_ZONESTATUS "zonestatus" +#define NAMED_COMMAND_NTA "nta" +#define NAMED_COMMAND_TESTGEN "testgen" +#define NAMED_COMMAND_MKEYS "managed-keys" +#define NAMED_COMMAND_DNSTAPREOPEN "dnstap-reopen" +#define NAMED_COMMAND_DNSTAP "dnstap" +#define NAMED_COMMAND_TCPTIMEOUTS "tcp-timeouts" +#define NAMED_COMMAND_SERVESTALE "serve-stale" + +isc_result_t +named_controls_create(named_server_t *server, named_controls_t **ctrlsp); +/*%< + * Create an initial, empty set of command channels for 'server'. + */ + +void +named_controls_destroy(named_controls_t **ctrlsp); +/*%< + * Destroy a set of command channels. + * + * Requires: + * Shutdown of the channels has completed. + */ + +isc_result_t +named_controls_configure(named_controls_t *controls, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx); +/*%< + * Configure zero or more command channels into 'controls' + * as defined in the configuration parse tree 'config'. + * The channels will evaluate ACLs in the context of + * 'aclconfctx'. + */ + +void +named_controls_shutdown(named_controls_t *controls); +/*%< + * Initiate shutdown of all the command channels in 'controls'. + */ + +isc_result_t +named_control_docommand(isccc_sexpr_t *message, bool readonly, + isc_buffer_t **text); + +#endif /* NAMED_CONTROL_H */ diff --git a/bin/named/include/named/fuzz.h b/bin/named/include/named/fuzz.h new file mode 100644 index 0000000..43a13e2 --- /dev/null +++ b/bin/named/include/named/fuzz.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include + +#ifndef NAMED_FUZZ_H +#define NAMED_FUZZ_H + +void +named_fuzz_notify(void); + +void +named_fuzz_setup(void); + +#endif /* NAMED_FUZZ_H */ diff --git a/bin/named/include/named/geoip.h b/bin/named/include/named/geoip.h new file mode 100644 index 0000000..d1852ef --- /dev/null +++ b/bin/named/include/named/geoip.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +extern dns_geoip_databases_t *named_g_geoip; + +void +named_geoip_init(void); + +void +named_geoip_load(char *dir); + +void +named_geoip_unload(void); + +void +named_geoip_shutdown(void); diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h new file mode 100644 index 0000000..82b632e --- /dev/null +++ b/bin/named/include/named/globals.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_GLOBALS_H +#define NAMED_GLOBALS_H 1 + +/*! \file */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#undef EXTERN +#undef INIT +#ifdef NAMED_MAIN +#define EXTERN +#define INIT(v) = (v) +#else /* ifdef NAMED_MAIN */ +#define EXTERN extern +#define INIT(v) +#endif /* ifdef NAMED_MAIN */ + +#ifndef NAMED_RUN_PID_DIR +#define NAMED_RUN_PID_DIR 1 +#endif /* ifndef NAMED_RUN_PID_DIR */ + +EXTERN isc_mem_t *named_g_mctx INIT(NULL); +EXTERN unsigned int named_g_cpus INIT(0); +EXTERN unsigned int named_g_udpdisp INIT(0); +EXTERN isc_taskmgr_t *named_g_taskmgr INIT(NULL); +EXTERN dns_dispatchmgr_t *named_g_dispatchmgr INIT(NULL); +EXTERN unsigned int named_g_cpus_detected INIT(1); + +#ifdef ENABLE_AFL +EXTERN bool named_g_run_done INIT(false); +#endif /* ifdef ENABLE_AFL */ +/* + * XXXRTH We're going to want multiple timer managers eventually. One + * for really short timers, another for client timers, and one + * for zone timers. + */ +EXTERN isc_timermgr_t *named_g_timermgr INIT(NULL); +EXTERN isc_socketmgr_t *named_g_socketmgr INIT(NULL); +EXTERN isc_nm_t *named_g_nm INIT(NULL); +EXTERN cfg_parser_t *named_g_parser INIT(NULL); +EXTERN cfg_parser_t *named_g_addparser INIT(NULL); +EXTERN const char *named_g_version INIT(VERSION); +EXTERN const char *named_g_product INIT(PRODUCT); +EXTERN const char *named_g_description INIT(DESCRIPTION); +EXTERN const char *named_g_srcid INIT(SRCID); +EXTERN const char *named_g_configargs INIT(CONFIGARGS); +EXTERN const char *named_g_builder INIT(BUILDER); +EXTERN in_port_t named_g_port INIT(0); +EXTERN isc_dscp_t named_g_dscp INIT(-1); + +EXTERN named_server_t *named_g_server INIT(NULL); + +/* + * Logging. + */ +EXTERN isc_log_t *named_g_lctx INIT(NULL); +EXTERN isc_logcategory_t *named_g_categories INIT(NULL); +EXTERN isc_logmodule_t *named_g_modules INIT(NULL); +EXTERN unsigned int named_g_debuglevel INIT(0); + +/* + * Current configuration information. + */ +EXTERN cfg_obj_t *named_g_config INIT(NULL); +EXTERN const cfg_obj_t *named_g_defaults INIT(NULL); +EXTERN const char *named_g_conffile INIT(NAMED_SYSCONFDIR "/named.conf"); +EXTERN const char *named_g_defaultbindkeys INIT(NAMED_SYSCONFDIR "/bind.keys"); +EXTERN const char *named_g_keyfile INIT(NAMED_SYSCONFDIR "/rndc.key"); + +EXTERN dns_tsigkey_t *named_g_sessionkey INIT(NULL); +EXTERN dns_name_t named_g_sessionkeyname; +EXTERN bool named_g_conffileset INIT(false); +EXTERN cfg_aclconfctx_t *named_g_aclconfctx INIT(NULL); + +/* + * Initial resource limits. + */ +EXTERN isc_resourcevalue_t named_g_initstacksize INIT(0); +EXTERN isc_resourcevalue_t named_g_initdatasize INIT(0); +EXTERN isc_resourcevalue_t named_g_initcoresize INIT(0); +EXTERN isc_resourcevalue_t named_g_initopenfiles INIT(0); + +/* + * Misc. + */ +EXTERN bool named_g_coreok INIT(true); +EXTERN const char *named_g_chrootdir INIT(NULL); +EXTERN bool named_g_foreground INIT(false); +EXTERN bool named_g_logstderr INIT(false); +EXTERN bool named_g_nosyslog INIT(false); +EXTERN const char *named_g_logfile INIT(NULL); + +EXTERN const char *named_g_defaultsessionkeyfile INIT(NAMED_LOCALSTATEDIR + "/run/named/" + "session.key"); +EXTERN const char *named_g_defaultlockfile INIT(NAMED_LOCALSTATEDIR "/run/" + "named/" + "named." + "lock"); +EXTERN bool named_g_forcelock INIT(false); + +#if NAMED_RUN_PID_DIR +EXTERN const char *named_g_defaultpidfile INIT(NAMED_LOCALSTATEDIR "/run/named/" + "named.pid"); +#else /* if NAMED_RUN_PID_DIR */ +EXTERN const char *named_g_defaultpidfile INIT(NAMED_LOCALSTATEDIR "/run/" + "named.pid"); +#endif /* if NAMED_RUN_PID_DIR */ + +EXTERN const char *named_g_username INIT(NULL); + +EXTERN const char *named_g_engine INIT(NULL); + +EXTERN isc_time_t named_g_boottime; +EXTERN isc_time_t named_g_configtime; +EXTERN bool named_g_memstatistics INIT(false); +EXTERN bool named_g_keepstderr INIT(false); + +EXTERN unsigned int named_g_tat_interval INIT(24 * 3600); +EXTERN unsigned int named_g_maxcachesize INIT(0); + +#if defined(HAVE_GEOIP2) +EXTERN dns_geoip_databases_t *named_g_geoip INIT(NULL); +#endif /* if defined(HAVE_GEOIP2) */ + +EXTERN const char *named_g_fuzz_addr INIT(NULL); +EXTERN isc_fuzztype_t named_g_fuzz_type INIT(isc_fuzz_none); + +EXTERN dns_acl_t *named_g_mapped INIT(NULL); + +#undef EXTERN +#undef INIT + +#endif /* NAMED_GLOBALS_H */ diff --git a/bin/named/include/named/log.h b/bin/named/include/named/log.h new file mode 100644 index 0000000..d54b155 --- /dev/null +++ b/bin/named/include/named/log.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_LOG_H +#define NAMED_LOG_H 1 + +/*! \file */ + +#include +#include + +#include + +#include /* Required for named_g_(categories|modules). */ + +/* Unused slot 0. */ +#define NAMED_LOGCATEGORY_UNMATCHED (&named_g_categories[1]) + +/* + * Backwards compatibility. + */ +#define NAMED_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL + +#define NAMED_LOGMODULE_MAIN (&named_g_modules[0]) +#define NAMED_LOGMODULE_SERVER (&named_g_modules[1]) +#define NAMED_LOGMODULE_CONTROL (&named_g_modules[2]) + +isc_result_t +named_log_init(bool safe); +/*% + * Initialize the logging system and set up an initial default + * logging default configuration that will be used until the + * config file has been read. + * + * If 'safe' is true, use a default configuration that refrains + * from opening files. This is to avoid creating log files + * as root. + */ + +void +named_log_setdefaultchannels(isc_logconfig_t *lcfg); +/*% + * Set up logging channels according to the named defaults, which + * may differ from the logging library defaults. Currently, + * this just means setting up default_debug. + */ + +void +named_log_setsafechannels(isc_logconfig_t *lcfg); +/*% + * Like named_log_setdefaultchannels(), but omits any logging to files. + */ + +isc_result_t +named_log_setdefaultcategory(isc_logconfig_t *lcfg); +/*% + * Set up "category default" to go to the right places. + */ + +isc_result_t +named_log_setunmatchedcategory(isc_logconfig_t *lcfg); +/*% + * Set up "category unmatched" to go to the right places. + */ + +void +named_log_shutdown(void); + +#endif /* NAMED_LOG_H */ diff --git a/bin/named/include/named/logconf.h b/bin/named/include/named/logconf.h new file mode 100644 index 0000000..0fc1d3c --- /dev/null +++ b/bin/named/include/named/logconf.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_LOGCONF_H +#define NAMED_LOGCONF_H 1 + +/*! \file */ + +#include + +isc_result_t +named_logconfig(isc_logconfig_t *logconf, const cfg_obj_t *logstmt); +/*%< + * Set up the logging configuration in '*logconf' according to + * the named.conf data in 'logstmt'. + */ + +#endif /* NAMED_LOGCONF_H */ diff --git a/bin/named/include/named/main.h b/bin/named/include/named/main.h new file mode 100644 index 0000000..ee790b9 --- /dev/null +++ b/bin/named/include/named/main.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_MAIN_H +#define NAMED_MAIN_H 1 + +/*! \file */ + +#ifdef ISC_MAIN_HOOK +#define main(argc, argv) bindmain(argc, argv) +#endif /* ifdef ISC_MAIN_HOOK */ + +/* + * Commandline arguments for named; also referenced in win32/ntservice.c + */ +#define NAMED_MAIN_ARGS "46A:c:Cd:D:E:fFgL:M:m:n:N:p:sS:t:T:U:u:vVx:X:" + +ISC_PLATFORM_NORETURN_PRE void +named_main_earlyfatal(const char *format, ...) + ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; + +void +named_main_earlywarning(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +void +named_main_setmemstats(const char *); + +#endif /* NAMED_MAIN_H */ diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h new file mode 100644 index 0000000..80f839d --- /dev/null +++ b/bin/named/include/named/server.h @@ -0,0 +1,397 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_SERVER_H +#define NAMED_SERVER_H 1 + +/*! \file */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define NAMED_EVENTCLASS ISC_EVENTCLASS(0x4E43) +#define NAMED_EVENT_RELOAD (NAMED_EVENTCLASS + 0) +#define NAMED_EVENT_DELZONE (NAMED_EVENTCLASS + 1) +#define NAMED_EVENT_COMMAND (NAMED_EVENTCLASS + 2) +#define NAMED_EVENT_TATSEND (NAMED_EVENTCLASS + 3) + +/*% + * Name server state. Better here than in lots of separate global variables. + */ +struct named_server { + unsigned int magic; + isc_mem_t *mctx; + + ns_server_t *sctx; + + isc_task_t *task; + + char *statsfile; /*%< Statistics file name */ + char *dumpfile; /*%< Dump file name */ + char *secrootsfile; /*%< Secroots file name */ + char *bindkeysfile; /*%< bind.keys file name + * */ + char *recfile; /*%< Recursive file name */ + bool version_set; /*%< User has set version + * */ + char *version; /*%< User-specified version */ + bool hostname_set; /*%< User has set hostname + * */ + char *hostname; /*%< User-specified hostname + * */ + + /* Server data structures. */ + dns_loadmgr_t *loadmgr; + dns_zonemgr_t *zonemgr; + dns_viewlist_t viewlist; + dns_kasplist_t kasplist; + ns_interfacemgr_t *interfacemgr; + dns_db_t *in_roothints; + + isc_timer_t *interface_timer; + isc_timer_t *heartbeat_timer; + isc_timer_t *pps_timer; + isc_timer_t *tat_timer; + + uint32_t interface_interval; + uint32_t heartbeat_interval; + + isc_mutex_t reload_event_lock; + isc_event_t *reload_event; + atomic_int reload_status; + + bool flushonshutdown; + + named_cachelist_t cachelist; /*%< Possibly shared caches + * */ + isc_stats_t *zonestats; /*% Zone management stats */ + isc_stats_t *resolverstats; /*% Resolver stats */ + isc_stats_t *sockstats; /*%< Socket stats */ + + named_controls_t *controls; /*%< Control channels */ + unsigned int dispatchgen; + named_dispatchlist_t dispatches; + + named_statschannellist_t statschannels; + + dns_tsigkey_t *sessionkey; + char *session_keyfile; + dns_name_t *session_keyname; + unsigned int session_keyalg; + uint16_t session_keybits; + bool interface_auto; + unsigned char secret[32]; /*%< Server Cookie Secret */ + ns_cookiealg_t cookiealg; + + dns_dtenv_t *dtenv; /*%< Dnstap environment */ + + char *lockfile; +}; + +#define NAMED_SERVER_MAGIC ISC_MAGIC('S', 'V', 'E', 'R') +#define NAMED_SERVER_VALID(s) ISC_MAGIC_VALID(s, NAMED_SERVER_MAGIC) + +void +named_server_create(isc_mem_t *mctx, named_server_t **serverp); +/*%< + * Create a server object with default settings. + * This function either succeeds or causes the program to exit + * with a fatal error. + */ + +void +named_server_destroy(named_server_t **serverp); +/*%< + * Destroy a server object, freeing its memory. + */ + +void +named_server_reloadwanted(named_server_t *server); +/*%< + * Inform a server that a reload is wanted. This function + * may be called asynchronously, from outside the server's task. + * If a reload is already scheduled or in progress, the call + * is ignored. + */ + +void +named_server_scan_interfaces(named_server_t *server); +/*%< + * Trigger a interface scan. + * Must only be called when running under server->task. + */ + +void +named_server_flushonshutdown(named_server_t *server, bool flush); +/*%< + * Inform the server that the zones should be flushed to disk on shutdown. + */ + +isc_result_t +named_server_reloadcommand(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); +/*%< + * Act on a "reload" command from the command channel. + */ + +isc_result_t +named_server_reconfigcommand(named_server_t *server); +/*%< + * Act on a "reconfig" command from the command channel. + */ + +isc_result_t +named_server_notifycommand(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); +/*%< + * Act on a "notify" command from the command channel. + */ + +isc_result_t +named_server_refreshcommand(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); +/*%< + * Act on a "refresh" command from the command channel. + */ + +isc_result_t +named_server_retransfercommand(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); +/*%< + * Act on a "retransfer" command from the command channel. + */ + +isc_result_t +named_server_togglequerylog(named_server_t *server, isc_lex_t *lex); +/*%< + * Enable/disable logging of queries. (Takes "yes" or "no" argument, + * but can also be used as a toggle for backward comptibility.) + */ + +/*% + * Save the current NTAs for all views to files. + */ +isc_result_t +named_server_saventa(named_server_t *server); + +/*% + * Load NTAs for all views from files. + */ +isc_result_t +named_server_loadnta(named_server_t *server); + +/*% + * Dump the current statistics to the statistics file. + */ +isc_result_t +named_server_dumpstats(named_server_t *server); + +/*% + * Dump the current cache to the dump file. + */ +isc_result_t +named_server_dumpdb(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Dump the current security roots to the secroots file. + */ +isc_result_t +named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Change or increment the server debug level. + */ +isc_result_t +named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex); + +/*% + * Flush the server's cache(s) + */ +isc_result_t +named_server_flushcache(named_server_t *server, isc_lex_t *lex); + +/*% + * Flush a particular name from the server's cache. If 'tree' is false, + * also flush the name from the ADB and badcache. If 'tree' is true, also + * flush all the names under the specified name. + */ +isc_result_t +named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree); + +/*% + * Report the server's status. + */ +isc_result_t +named_server_status(named_server_t *server, isc_buffer_t **text); + +/*% + * Report a list of dynamic and static tsig keys, per view. + */ +isc_result_t +named_server_tsiglist(named_server_t *server, isc_buffer_t **text); + +/*% + * Delete a specific key (with optional view). + */ +isc_result_t +named_server_tsigdelete(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Enable or disable updates for a zone. + */ +isc_result_t +named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Dump zone updates to disk, optionally removing the journal file + */ +isc_result_t +named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text); + +/*% + * Update a zone's DNSKEY set from the key repository. If + * the command that triggered the call to this function was "sign", + * then force a full signing of the zone. If it was "loadkeys", + * then don't sign the zone; any needed changes to signatures can + * take place incrementally. + */ +isc_result_t +named_server_rekey(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text); + +/*% + * Dump the current recursive queries. + */ +isc_result_t +named_server_dumprecursing(named_server_t *server); + +/*% + * Maintain a list of dispatches that require reserved ports. + */ +void +named_add_reserved_dispatch(named_server_t *server, const isc_sockaddr_t *addr); + +/*% + * Enable or disable dnssec validation. + */ +isc_result_t +named_server_validation(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Add a zone to a running process, or modify an existing zone + */ +isc_result_t +named_server_changezone(named_server_t *server, char *command, + isc_buffer_t **text); + +/*% + * Deletes a zone from a running process + */ +isc_result_t +named_server_delzone(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Show current configuration for a given zone + */ +isc_result_t +named_server_showzone(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Lists the status of the signing records for a given zone. + */ +isc_result_t +named_server_signing(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Lists the DNSSEC status for a given zone. + */ +isc_result_t +named_server_dnssec(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Lists status information for a given zone (e.g., name, type, files, + * load time, expiry, etc). + */ +isc_result_t +named_server_zonestatus(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Adds/updates a Negative Trust Anchor (NTA) for a specified name and + * duration, in a particular view if specified, or in all views. + */ +isc_result_t +named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly, + isc_buffer_t **text); + +/*% + * Generates a test sequence that is only for use in system tests. The + * argument is the size of required output in bytes. + */ +isc_result_t +named_server_testgen(isc_lex_t *lex, isc_buffer_t **text); + +/*% + * Force fefresh or print status for managed keys zones. + */ +isc_result_t +named_server_mkeys(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text); + +/*% + * Close and reopen DNSTAP output file. + */ +isc_result_t +named_server_dnstap(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +/*% + * Display or update tcp-{initial,idle,keepalive,advertised}-timeout options. + */ +isc_result_t +named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text); + +/*% + * Control whether stale answers are served or not when configured in + * named.conf. + */ +isc_result_t +named_server_servestale(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); + +#endif /* NAMED_SERVER_H */ diff --git a/bin/named/include/named/smf_globals.h b/bin/named/include/named/smf_globals.h new file mode 100644 index 0000000..d777c24 --- /dev/null +++ b/bin/named/include/named/smf_globals.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_SMF_GLOBALS_H +#define NAMED_SMF_GLOBALS_H 1 + +#include + +#undef EXTERN +#undef INIT +#ifdef NAMED_MAIN +#define EXTERN +#define INIT(v) = (v) +#else /* ifdef NAMED_MAIN */ +#define EXTERN extern +#define INIT(v) +#endif /* ifdef NAMED_MAIN */ + +EXTERN unsigned int named_smf_got_instance INIT(0); +EXTERN unsigned int named_smf_chroot INIT(0); +EXTERN unsigned int named_smf_want_disable INIT(0); + +isc_result_t +named_smf_add_message(isc_buffer_t **text); +isc_result_t +named_smf_get_instance(char **name, int debug, isc_mem_t *mctx); + +#undef EXTERN +#undef INIT + +#endif /* NAMED_SMF_GLOBALS_H */ diff --git a/bin/named/include/named/statschannel.h b/bin/named/include/named/statschannel.h new file mode 100644 index 0000000..db6fb9d --- /dev/null +++ b/bin/named/include/named/statschannel.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_STATSCHANNEL_H +#define NAMED_STATSCHANNEL_H 1 + +/*! \file + * \brief + * The statistics channels built-in the name server. + */ + +#include + +#include +#include + +#define NAMED_STATSCHANNEL_HTTPPORT 80 + +isc_result_t +named_statschannels_configure(named_server_t *server, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx); +/*%< + * [Re]configure the statistics channels. + * + * If it is no longer there but was previously configured, destroy + * it here. + * + * If the IP address or port has changed, destroy the old server + * and create a new one. + */ + +void +named_statschannels_shutdown(named_server_t *server); +/*%< + * Initiate shutdown of all the statistics channel listeners. + */ + +isc_result_t +named_stats_dump(named_server_t *server, FILE *fp); +/*%< + * Dump statistics counters managed by the server to the file fp. + */ + +#endif /* NAMED_STATSCHANNEL_H */ diff --git a/bin/named/include/named/tkeyconf.h b/bin/named/include/named/tkeyconf.h new file mode 100644 index 0000000..8f42633 --- /dev/null +++ b/bin/named/include/named/tkeyconf.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_TKEYCONF_H +#define NAMED_TKEYCONF_H 1 + +/*! \file */ + +#include +#include + +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +named_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx, + dns_tkeyctx_t **tctxp); +/*%< + * Create a TKEY context and configure it, including the default DH key + * and default domain, according to 'options'. + * + * Requires: + *\li 'cfg' is a valid configuration options object. + *\li 'mctx' is not NULL + *\li 'tctx' is not NULL + *\li '*tctx' is NULL + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOMEMORY + */ + +ISC_LANG_ENDDECLS + +#endif /* NAMED_TKEYCONF_H */ diff --git a/bin/named/include/named/tsigconf.h b/bin/named/include/named/tsigconf.h new file mode 100644 index 0000000..f9f21d9 --- /dev/null +++ b/bin/named/include/named/tsigconf.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_TSIGCONF_H +#define NAMED_TSIGCONF_H 1 + +/*! \file */ + +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +named_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, + isc_mem_t *mctx, dns_tsig_keyring_t **ringp); +/*%< + * Create a TSIG key ring and configure it according to the 'key' + * statements in the global and view configuration objects. + * + * Requires: + * \li 'config' is not NULL. + * \li 'vconfig' is not NULL. + * \li 'mctx' is not NULL + * \li 'ringp' is not NULL, and '*ringp' is NULL + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOMEMORY + */ + +ISC_LANG_ENDDECLS + +#endif /* NAMED_TSIGCONF_H */ diff --git a/bin/named/include/named/types.h b/bin/named/include/named/types.h new file mode 100644 index 0000000..addb76a --- /dev/null +++ b/bin/named/include/named/types.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_TYPES_H +#define NAMED_TYPES_H 1 + +/*! \file */ + +#include + +typedef struct named_cache named_cache_t; +typedef ISC_LIST(named_cache_t) named_cachelist_t; +typedef struct named_server named_server_t; +typedef struct named_xmld named_xmld_t; +typedef struct named_xmldmgr named_xmldmgr_t; +typedef struct named_controls named_controls_t; +typedef struct named_dispatch named_dispatch_t; +typedef ISC_LIST(named_dispatch_t) named_dispatchlist_t; +typedef struct named_statschannel named_statschannel_t; +typedef ISC_LIST(named_statschannel_t) named_statschannellist_t; + +/*% + * Used for server->reload_status as printed by `rndc status` + */ +typedef enum { + NAMED_RELOAD_DONE, + NAMED_RELOAD_IN_PROGRESS, + NAMED_RELOAD_FAILED, +} named_reload_t; + +#endif /* NAMED_TYPES_H */ diff --git a/bin/named/include/named/zoneconf.h b/bin/named/include/named/zoneconf.h new file mode 100644 index 0000000..6f37f61 --- /dev/null +++ b/bin/named/include/named/zoneconf.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_ZONECONF_H +#define NAMED_ZONECONF_H 1 + +/*! \file */ + +#include + +#include +#include + +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, + const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac, + dns_kasplist_t *kasplist, dns_zone_t *zone, + dns_zone_t *raw); +/*%< + * Configure or reconfigure a zone according to the named.conf + * data. + * + * The zone origin is not configured, it is assumed to have been set + * at zone creation time. + * + * Require: + * \li 'ac' to point to an initialized cfg_aclconfctx_t. + * \li 'kasplist' to be initialized. + * \li 'zone' to be initialized. + */ + +bool +named_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig); +/*%< + * If 'zone' can be safely reconfigured according to the configuration + * data in 'zconfig', return true. If the configuration data is so + * different from the current zone state that the zone needs to be destroyed + * and recreated, return false. + */ + +bool +named_zone_inlinesigning(const cfg_obj_t *zconfig); +/*%< + * Determine if zone uses inline-signing. This is true if inline-signing + * is set to yes. + */ + +isc_result_t +named_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone, + dns_rdataclass_t rdclass, dns_name_t *name); +/*%> + * configure a DLZ zone, setting up the database methods and calling + * postload to load the origin values + * + * Require: + * \li 'dlzdatabase' to be a valid dlz database + * \li 'zone' to be initialized. + * \li 'rdclass' to be a valid rdataclass + * \li 'name' to be a valid zone origin name + */ + +ISC_LANG_ENDDECLS + +#endif /* NAMED_ZONECONF_H */ diff --git a/bin/named/log.c b/bin/named/log.c new file mode 100644 index 0000000..b59002d --- /dev/null +++ b/bin/named/log.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include + +#include + +#include + +#include + +#include + +#ifndef ISC_FACILITY +#define ISC_FACILITY LOG_DAEMON +#endif /* ifndef ISC_FACILITY */ + +/*% + * When adding a new category, be sure to add the appropriate + * \#define to and to update the list in + * bin/check/check-tool.c. + */ +static isc_logcategory_t categories[] = { { "", 0 }, + { "unmatched", 0 }, + { NULL, 0 } }; + +/*% + * When adding a new module, be sure to add the appropriate + * \#define to . + */ +static isc_logmodule_t modules[] = { + { "main", 0 }, { "server", 0 }, { "control", 0 }, { NULL, 0 } +}; + +isc_result_t +named_log_init(bool safe) { + isc_result_t result; + isc_logconfig_t *lcfg = NULL; + + named_g_categories = categories; + named_g_modules = modules; + + /* + * Setup a logging context. + */ + isc_log_create(named_g_mctx, &named_g_lctx, &lcfg); + + /* + * named-checktool.c:setup_logging() needs to be kept in sync. + */ + isc_log_registercategories(named_g_lctx, named_g_categories); + isc_log_registermodules(named_g_lctx, named_g_modules); + isc_log_setcontext(named_g_lctx); + dns_log_init(named_g_lctx); + dns_log_setcontext(named_g_lctx); + cfg_log_init(named_g_lctx); + ns_log_init(named_g_lctx); + ns_log_setcontext(named_g_lctx); + + if (safe) { + named_log_setsafechannels(lcfg); + } else { + named_log_setdefaultchannels(lcfg); + } + + result = named_log_setdefaultcategory(lcfg); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + return (ISC_R_SUCCESS); + +cleanup: + isc_log_destroy(&named_g_lctx); + isc_log_setcontext(NULL); + dns_log_setcontext(NULL); + + return (result); +} + +void +named_log_setdefaultchannels(isc_logconfig_t *lcfg) { + isc_logdestination_t destination; + + /* + * By default, the logging library makes "default_debug" log to + * stderr. In BIND, we want to override this and log to named.run + * instead, unless the -g option was given. + */ + if (!named_g_logstderr) { + destination.file.stream = NULL; + destination.file.name = "named.run"; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(lcfg, "default_debug", ISC_LOG_TOFILE, + ISC_LOG_DYNAMIC, &destination, + ISC_LOG_PRINTTIME | ISC_LOG_DEBUGONLY); + } + + if (named_g_logfile != NULL) { + destination.file.stream = NULL; + destination.file.name = named_g_logfile; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(lcfg, "default_logfile", ISC_LOG_TOFILE, + ISC_LOG_DYNAMIC, &destination, + ISC_LOG_PRINTTIME | + ISC_LOG_PRINTCATEGORY | + ISC_LOG_PRINTLEVEL); + } + +#if ISC_FACILITY != LOG_DAEMON + destination.facility = ISC_FACILITY; + isc_log_createchannel(lcfg, "default_syslog", ISC_LOG_TOSYSLOG, + ISC_LOG_INFO, &destination, 0); +#endif /* if ISC_FACILITY != LOG_DAEMON */ + + /* + * Set the initial debug level. + */ + isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel); +} + +void +named_log_setsafechannels(isc_logconfig_t *lcfg) { + isc_logdestination_t destination; + + if (!named_g_logstderr) { + isc_log_createchannel(lcfg, "default_debug", ISC_LOG_TONULL, + ISC_LOG_DYNAMIC, NULL, 0); + + /* + * Setting the debug level to zero should get the output + * discarded a bit faster. + */ + isc_log_setdebuglevel(named_g_lctx, 0); + } else { + isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel); + } + + if (named_g_logfile != NULL) { + destination.file.stream = NULL; + destination.file.name = named_g_logfile; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(lcfg, "default_logfile", ISC_LOG_TOFILE, + ISC_LOG_DYNAMIC, &destination, + ISC_LOG_PRINTTIME | + ISC_LOG_PRINTCATEGORY | + ISC_LOG_PRINTLEVEL); + } + +#if ISC_FACILITY != LOG_DAEMON + destination.facility = ISC_FACILITY; + isc_log_createchannel(lcfg, "default_syslog", ISC_LOG_TOSYSLOG, + ISC_LOG_INFO, &destination, 0); +#endif /* if ISC_FACILITY != LOG_DAEMON */ +} + +isc_result_t +named_log_setdefaultcategory(isc_logconfig_t *lcfg) { + isc_result_t result = ISC_R_SUCCESS; + + result = isc_log_usechannel(lcfg, "default_debug", + ISC_LOGCATEGORY_DEFAULT, NULL); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + if (!named_g_logstderr) { + if (named_g_logfile != NULL) { + result = isc_log_usechannel(lcfg, "default_logfile", + ISC_LOGCATEGORY_DEFAULT, + NULL); + } else if (!named_g_nosyslog) { + result = isc_log_usechannel(lcfg, "default_syslog", + ISC_LOGCATEGORY_DEFAULT, + NULL); + } + } + +cleanup: + return (result); +} + +isc_result_t +named_log_setunmatchedcategory(isc_logconfig_t *lcfg) { + isc_result_t result; + + result = isc_log_usechannel(lcfg, "null", NAMED_LOGCATEGORY_UNMATCHED, + NULL); + return (result); +} + +void +named_log_shutdown(void) { + isc_log_destroy(&named_g_lctx); + isc_log_setcontext(NULL); + dns_log_setcontext(NULL); +} diff --git a/bin/named/logconf.c b/bin/named/logconf.c new file mode 100644 index 0000000..36a19ba --- /dev/null +++ b/bin/named/logconf.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define CHECK(op) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +/*% + * Set up a logging category according to the named.conf data + * in 'ccat' and add it to 'logconfig'. + */ +static isc_result_t +category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *logconfig) { + isc_result_t result; + const char *catname; + isc_logcategory_t *category; + isc_logmodule_t *module; + const cfg_obj_t *destinations = NULL; + const cfg_listelt_t *element = NULL; + + catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name")); + category = isc_log_categorybyname(named_g_lctx, catname); + if (category == NULL) { + cfg_obj_log(ccat, named_g_lctx, ISC_LOG_ERROR, + "unknown logging category '%s' ignored", catname); + /* + * Allow further processing by returning success. + */ + return (ISC_R_SUCCESS); + } + + if (logconfig == NULL) { + return (ISC_R_SUCCESS); + } + + module = NULL; + + destinations = cfg_tuple_get(ccat, "destinations"); + for (element = cfg_list_first(destinations); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *channel = cfg_listelt_value(element); + const char *channelname = cfg_obj_asstring(channel); + + result = isc_log_usechannel(logconfig, channelname, category, + module); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, CFG_LOGCATEGORY_CONFIG, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "logging channel '%s': %s", channelname, + isc_result_totext(result)); + return (result); + } + } + return (ISC_R_SUCCESS); +} + +/*% + * Set up a logging channel according to the named.conf data + * in 'cchan' and add it to 'logconfig'. + */ +static isc_result_t +channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig) { + isc_result_t result = ISC_R_SUCCESS; + isc_logdestination_t dest; + unsigned int type; + unsigned int flags = 0; + int level; + const char *channelname; + const cfg_obj_t *fileobj = NULL; + const cfg_obj_t *syslogobj = NULL; + const cfg_obj_t *nullobj = NULL; + const cfg_obj_t *stderrobj = NULL; + const cfg_obj_t *severity = NULL; + int i; + + channelname = cfg_obj_asstring(cfg_map_getname(channel)); + + (void)cfg_map_get(channel, "file", &fileobj); + (void)cfg_map_get(channel, "syslog", &syslogobj); + (void)cfg_map_get(channel, "null", &nullobj); + (void)cfg_map_get(channel, "stderr", &stderrobj); + + i = 0; + if (fileobj != NULL) { + i++; + } + if (syslogobj != NULL) { + i++; + } + if (nullobj != NULL) { + i++; + } + if (stderrobj != NULL) { + i++; + } + + if (i != 1) { + cfg_obj_log(channel, named_g_lctx, ISC_LOG_ERROR, + "channel '%s': exactly one of file, syslog, " + "null, and stderr must be present", + channelname); + return (ISC_R_FAILURE); + } + + type = ISC_LOG_TONULL; + + if (fileobj != NULL) { + const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file"); + const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size"); + const cfg_obj_t *versionsobj = cfg_tuple_get(fileobj, + "versions"); + const cfg_obj_t *suffixobj = cfg_tuple_get(fileobj, "suffix"); + int32_t versions = ISC_LOG_ROLLNEVER; + isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment; + isc_offset_t size = 0; + uint64_t maxoffset; + + /* + * isc_offset_t is a signed integer type, so the maximum + * value is all 1s except for the MSB. + */ + switch (sizeof(isc_offset_t)) { + case 4: + maxoffset = 0x7fffffffULL; + break; + case 8: + maxoffset = 0x7fffffffffffffffULL; + break; + default: + UNREACHABLE(); + } + + type = ISC_LOG_TOFILE; + + if (versionsobj != NULL && cfg_obj_isuint32(versionsobj)) { + versions = cfg_obj_asuint32(versionsobj); + } else if (versionsobj != NULL && + cfg_obj_isstring(versionsobj) && + strcasecmp(cfg_obj_asstring(versionsobj), + "unlimited") == 0) + { + versions = ISC_LOG_ROLLINFINITE; + } + if (sizeobj != NULL && cfg_obj_isuint64(sizeobj) && + cfg_obj_asuint64(sizeobj) < maxoffset) + { + size = (isc_offset_t)cfg_obj_asuint64(sizeobj); + } + if (suffixobj != NULL && cfg_obj_isstring(suffixobj) && + strcasecmp(cfg_obj_asstring(suffixobj), "timestamp") == 0) + { + suffix = isc_log_rollsuffix_timestamp; + } + + dest.file.stream = NULL; + dest.file.name = cfg_obj_asstring(pathobj); + dest.file.versions = versions; + dest.file.suffix = suffix; + dest.file.maximum_size = size; + } else if (syslogobj != NULL) { + int facility = LOG_DAEMON; + + type = ISC_LOG_TOSYSLOG; + + if (cfg_obj_isstring(syslogobj)) { + const char *facilitystr = cfg_obj_asstring(syslogobj); + (void)isc_syslog_facilityfromstring(facilitystr, + &facility); + } + dest.facility = facility; + } else if (stderrobj != NULL) { + type = ISC_LOG_TOFILEDESC; + dest.file.stream = stderr; + dest.file.name = NULL; + dest.file.versions = ISC_LOG_ROLLNEVER; + dest.file.suffix = isc_log_rollsuffix_increment; + dest.file.maximum_size = 0; + } + + /* + * Munge flags. + */ + { + const cfg_obj_t *printcat = NULL; + const cfg_obj_t *printsev = NULL; + const cfg_obj_t *printtime = NULL; + const cfg_obj_t *buffered = NULL; + + (void)cfg_map_get(channel, "print-category", &printcat); + (void)cfg_map_get(channel, "print-severity", &printsev); + (void)cfg_map_get(channel, "print-time", &printtime); + (void)cfg_map_get(channel, "buffered", &buffered); + + if (printcat != NULL && cfg_obj_asboolean(printcat)) { + flags |= ISC_LOG_PRINTCATEGORY; + } + if (printsev != NULL && cfg_obj_asboolean(printsev)) { + flags |= ISC_LOG_PRINTLEVEL; + } + if (buffered != NULL && cfg_obj_asboolean(buffered)) { + flags |= ISC_LOG_BUFFERED; + } + if (printtime != NULL && cfg_obj_isboolean(printtime)) { + if (cfg_obj_asboolean(printtime)) { + flags |= ISC_LOG_PRINTTIME; + } + } else if (printtime != NULL) { /* local/iso8601/iso8601-utc */ + const char *s = cfg_obj_asstring(printtime); + flags |= ISC_LOG_PRINTTIME; + if (strcasecmp(s, "iso8601") == 0) { + flags |= ISC_LOG_ISO8601; + } else if (strcasecmp(s, "iso8601-utc") == 0) { + flags |= ISC_LOG_ISO8601 | ISC_LOG_UTC; + } + } + } + + level = ISC_LOG_INFO; + if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) { + if (cfg_obj_isstring(severity)) { + const char *str = cfg_obj_asstring(severity); + if (strcasecmp(str, "critical") == 0) { + level = ISC_LOG_CRITICAL; + } else if (strcasecmp(str, "error") == 0) { + level = ISC_LOG_ERROR; + } else if (strcasecmp(str, "warning") == 0) { + level = ISC_LOG_WARNING; + } else if (strcasecmp(str, "notice") == 0) { + level = ISC_LOG_NOTICE; + } else if (strcasecmp(str, "info") == 0) { + level = ISC_LOG_INFO; + } else if (strcasecmp(str, "dynamic") == 0) { + level = ISC_LOG_DYNAMIC; + } + } else { + /* debug */ + level = cfg_obj_asuint32(severity); + } + } + + if (logconfig != NULL) { + isc_log_createchannel(logconfig, channelname, type, level, + &dest, flags); + } + + if (type == ISC_LOG_TOFILE) { + FILE *fp; + + /* + * Test to make sure that file is a plain file. + * Fix defect #22771 + */ + result = isc_file_isplainfile(dest.file.name); + if (result == ISC_R_SUCCESS || result == ISC_R_FILENOTFOUND) { + /* + * Test that the file can be opened, since + * isc_log_open() can't effectively report + * failures when called in isc_log_doit(). + */ + result = isc_stdio_open(dest.file.name, "a", &fp); + if (result != ISC_R_SUCCESS) { + if (logconfig != NULL && !named_g_nosyslog) { + syslog(LOG_ERR, + "isc_stdio_open '%s' failed: " + "%s", + dest.file.name, + isc_result_totext(result)); + } + } else { + (void)isc_stdio_close(fp); + } + goto done; + } + if (logconfig != NULL && !named_g_nosyslog) { + syslog(LOG_ERR, "isc_file_isplainfile '%s' failed: %s", + dest.file.name, isc_result_totext(result)); + } + } + +done: + return (result); +} + +isc_result_t +named_logconfig(isc_logconfig_t *logconfig, const cfg_obj_t *logstmt) { + isc_result_t result; + const cfg_obj_t *channels = NULL; + const cfg_obj_t *categories = NULL; + const cfg_listelt_t *element; + bool default_set = false; + bool unmatched_set = false; + const cfg_obj_t *catname; + + if (logconfig != NULL) { + named_log_setdefaultchannels(logconfig); + } + + (void)cfg_map_get(logstmt, "channel", &channels); + for (element = cfg_list_first(channels); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *channel = cfg_listelt_value(element); + CHECK(channel_fromconf(channel, logconfig)); + } + + (void)cfg_map_get(logstmt, "category", &categories); + for (element = cfg_list_first(categories); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *category = cfg_listelt_value(element); + CHECK(category_fromconf(category, logconfig)); + if (!default_set) { + catname = cfg_tuple_get(category, "name"); + if (strcmp(cfg_obj_asstring(catname), "default") == 0) { + default_set = true; + } + } + if (!unmatched_set) { + catname = cfg_tuple_get(category, "name"); + if (strcmp(cfg_obj_asstring(catname), "unmatched") == 0) + { + unmatched_set = true; + } + } + } + + if (logconfig != NULL && !default_set) { + CHECK(named_log_setdefaultcategory(logconfig)); + } + + if (logconfig != NULL && !unmatched_set) { + CHECK(named_log_setunmatchedcategory(logconfig)); + } + + return (ISC_R_SUCCESS); + +cleanup: + return (result); +} diff --git a/bin/named/main.c b/bin/named/main.c new file mode 100644 index 0000000..074936b --- /dev/null +++ b/bin/named/main.c @@ -0,0 +1,1788 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#if HAVE_LOCALE_H +#include +#endif /* HAVE_LOCALE_H */ + +#ifdef HAVE_DNSTAP +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#if USE_PKCS11 +#include +#endif /* if USE_PKCS11 */ + +#include + +#ifdef HAVE_GPERFTOOLS_PROFILER +#include +#endif /* ifdef HAVE_GPERFTOOLS_PROFILER */ + +#ifdef HAVE_JSON_C +#include +#endif /* HAVE_JSON_C */ + +#ifdef HAVE_GEOIP2 +#include +#endif /* ifdef HAVE_GEOIP2 */ + +/* + * Defining NAMED_MAIN provides storage declarations (rather than extern) + * for variables in named/globals.h. + */ +#define NAMED_MAIN 1 + +#include + +#include +#include +#include +#include +#include /* Explicit, though named/log.h includes it. */ +#include +#include +#include +#include +#ifdef HAVE_LIBSCF +#include +#endif /* ifdef HAVE_LIBSCF */ + +#include +#include +#ifdef HAVE_LIBXML2 +#include +#include +#endif /* ifdef HAVE_LIBXML2 */ +#ifdef HAVE_ZLIB +#include +#endif /* ifdef HAVE_ZLIB */ +/* + * Include header files for database drivers here. + */ +/* #include "xxdb.h" */ + +#ifdef CONTRIB_DLZ +/* + * Include contributed DLZ drivers if appropriate. + */ +#include +#endif /* ifdef CONTRIB_DLZ */ + +/* + * The maximum number of stack frames to dump on assertion failure. + */ +#ifndef BACKTRACE_MAXFRAME +#define BACKTRACE_MAXFRAME 128 +#endif /* ifndef BACKTRACE_MAXFRAME */ + +LIBISC_EXTERNAL_DATA extern int isc_dscp_check_value; +LIBDNS_EXTERNAL_DATA extern unsigned int dns_zone_mkey_hour; +LIBDNS_EXTERNAL_DATA extern unsigned int dns_zone_mkey_day; +LIBDNS_EXTERNAL_DATA extern unsigned int dns_zone_mkey_month; + +static bool want_stats = false; +static char program_name[NAME_MAX] = "named"; +static char absolute_conffile[PATH_MAX]; +static char saved_command_line[4096] = { 0 }; +static char ellipsis[5] = { 0 }; +static char version[512]; +static unsigned int maxsocks = 0; +static int maxudp = 0; + +/* + * -T options: + */ +static bool dropedns = false; +static bool ednsformerr = false; +static bool ednsnotimp = false; +static bool ednsrefused = false; +static bool fixedlocal = false; +static bool noaa = false; +static bool noedns = false; +static bool nonearest = false; +static bool nosoa = false; +static bool notcp = false; +static bool sigvalinsecs = false; + +/* + * -4 and -6 + */ +static bool disable6 = false; +static bool disable4 = false; + +void +named_main_earlywarning(const char *format, ...) { + va_list args; + + va_start(args, format); + if (named_g_lctx != NULL) { + isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_WARNING, format, + args); + } else { + fprintf(stderr, "%s: ", program_name); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + } + va_end(args); +} + +void +named_main_earlyfatal(const char *format, ...) { + va_list args; + + va_start(args, format); + if (named_g_lctx != NULL) { + isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, format, + args); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "exiting (due to early fatal error)"); + } else { + fprintf(stderr, "%s: ", program_name); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + } + va_end(args); + + exit(1); +} + +ISC_PLATFORM_NORETURN_PRE static void +assertion_failed(const char *file, int line, isc_assertiontype_t type, + const char *cond) ISC_PLATFORM_NORETURN_POST; + +static void +assertion_failed(const char *file, int line, isc_assertiontype_t type, + const char *cond) { + void *tracebuf[BACKTRACE_MAXFRAME]; + int i, nframes; + isc_result_t result; + const char *logsuffix = ""; + const char *fname; + + /* + * Handle assertion failures. + */ + + if (named_g_lctx != NULL) { + /* + * Reset the assertion callback in case it is the log + * routines causing the assertion. + */ + isc_assertion_setcallback(NULL); + + result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME, + &nframes); + if (result == ISC_R_SUCCESS && nframes > 0) { + logsuffix = ", back trace"; + } + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "%s:%d: %s(%s) failed%s", file, line, + isc_assertion_typetotext(type), cond, logsuffix); + if (result == ISC_R_SUCCESS) { + for (i = 0; i < nframes; i++) { + unsigned long offset; + + fname = NULL; + result = isc_backtrace_getsymbol( + tracebuf[i], &fname, &offset); + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, + ISC_LOG_CRITICAL, + "#%d %p in %s()+0x%lx", i, + tracebuf[i], fname, + offset); + } else { + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, + ISC_LOG_CRITICAL, + "#%d %p in ??", i, + tracebuf[i]); + } + } + } + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "exiting (due to assertion failure)"); + } else { + fprintf(stderr, "%s:%d: %s(%s) failed\n", file, line, + isc_assertion_typetotext(type), cond); + fflush(stderr); + } + + if (named_g_coreok) { + abort(); + } + exit(1); +} + +ISC_PLATFORM_NORETURN_PRE static void +library_fatal_error(const char *file, int line, const char *format, + va_list args) + ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST; + +static void +library_fatal_error(const char *file, int line, const char *format, + va_list args) { + /* + * Handle isc_error_fatal() calls from our libraries. + */ + + if (named_g_lctx != NULL) { + /* + * Reset the error callback in case it is the log + * routines causing the assertion. + */ + isc_error_setfatal(NULL); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "%s:%d: fatal error:", file, line); + isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, format, + args); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, + "exiting (due to fatal error in library)"); + } else { + fprintf(stderr, "%s:%d: fatal error: ", file, line); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + } + + if (named_g_coreok) { + abort(); + } + exit(1); +} + +static void +library_unexpected_error(const char *file, int line, const char *format, + va_list args) ISC_FORMAT_PRINTF(3, 0); + +static void +library_unexpected_error(const char *file, int line, const char *format, + va_list args) { + /* + * Handle isc_error_unexpected() calls from our libraries. + */ + + if (named_g_lctx != NULL) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR, + "%s:%d: unexpected error:", file, line); + isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR, format, + args); + } else { + fprintf(stderr, "%s:%d: fatal error: ", file, line); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + } +} + +static void +usage(void) { + fprintf(stderr, "usage: named [-4|-6] [-c conffile] [-d debuglevel] " + "[-D comment] [-E engine]\n" + " [-f|-g] [-L logfile] [-n number_of_cpus] " + "[-p port] [-s]\n" + " [-S sockets] [-t chrootdir] [-u " + "username] [-U listeners]\n" + " [-X lockfile] [-m " + "{usage|trace|record|size|mctx}]\n" + " [-M external|internal|fill|nofill]\n" + "usage: named [-v|-V|-C]\n"); +} + +static void +save_command_line(int argc, char *argv[]) { + int i; + char *dst = saved_command_line; + char *eob = saved_command_line + sizeof(saved_command_line) - 1; + char *rollback = dst; + + for (i = 1; i < argc && dst < eob; i++) { + char *src = argv[i]; + bool quoted = false; + + rollback = dst; + *dst++ = ' '; + + while (*src != '\0' && dst < eob) { + if (isalnum(*(unsigned char *)src) || *src == ',' || + *src == '-' || *src == '_' || *src == '.' || + *src == '/') + { + *dst++ = *src++; + } else if (isprint(*(unsigned char *)src)) { + if (dst + 2 >= eob) { + goto add_ellipsis; + } + *dst++ = '\\'; + *dst++ = *src++; + } else { + /* + * Control character found in the input, + * quote the whole arg and restart + */ + if (!quoted) { + dst = rollback; + src = argv[i]; + + if (dst + 3 >= eob) { + goto add_ellipsis; + } + + *dst++ = ' '; + *dst++ = '$'; + *dst++ = '\''; + + quoted = true; + continue; + } else { + char tmp[5]; + int c = snprintf(tmp, sizeof(tmp), + "\\%03o", *src++); + if (dst + c >= eob) { + goto add_ellipsis; + } + memmove(dst, tmp, c); + dst += c; + } + } + } + if (quoted) { + if (dst == eob) { + goto add_ellipsis; + } + *dst++ = '\''; + } + } + + if (dst < eob) { + return; + } +add_ellipsis: + dst = rollback; + *dst = '\0'; + strlcpy(ellipsis, " ...", sizeof(ellipsis)); +} + +static int +parse_int(char *arg, const char *desc) { + char *endp; + int tmp; + long int ltmp; + + ltmp = strtol(arg, &endp, 10); + tmp = (int)ltmp; + if (*endp != '\0') { + named_main_earlyfatal("%s '%s' must be numeric", desc, arg); + } + if (tmp < 0 || tmp != ltmp) { + named_main_earlyfatal("%s '%s' out of range", desc, arg); + } + return (tmp); +} + +static struct flag_def { + const char *name; + unsigned int value; + bool negate; +} mem_debug_flags[] = { { "none", 0, false }, + { "trace", ISC_MEM_DEBUGTRACE, false }, + { "record", ISC_MEM_DEBUGRECORD, false }, + { "usage", ISC_MEM_DEBUGUSAGE, false }, + { "size", ISC_MEM_DEBUGSIZE, false }, + { "mctx", ISC_MEM_DEBUGCTX, false }, + { NULL, 0, false } }, + mem_context_flags[] = { { "external", ISC_MEMFLAG_INTERNAL, true }, + { "internal", ISC_MEMFLAG_INTERNAL, false }, + { "fill", ISC_MEMFLAG_FILL, false }, + { "nofill", ISC_MEMFLAG_FILL, true }, + { NULL, 0, false } }; + +static void +set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) { + bool clear = false; + + for (;;) { + const struct flag_def *def; + const char *end = strchr(arg, ','); + int arglen; + if (end == NULL) { + end = arg + strlen(arg); + } + arglen = (int)(end - arg); + for (def = defs; def->name != NULL; def++) { + if (arglen == (int)strlen(def->name) && + memcmp(arg, def->name, arglen) == 0) + { + if (def->value == 0) { + clear = true; + } + if (def->negate) { + *ret &= ~(def->value); + } else { + *ret |= def->value; + } + goto found; + } + } + named_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg); + found: + if (clear || (*end == '\0')) { + break; + } + arg = end + 1; + } + + if (clear) { + *ret = 0; + } +} + +/*% + * Convert algorithm type to string. + */ +static const char * +dst_hmac_algorithm_totext(dns_secalg_t alg) { + switch (alg) { + case DST_ALG_HMACMD5: + return ("hmac-md5"); + case DST_ALG_HMACSHA1: + return ("hmac-sha1"); + case DST_ALG_HMACSHA224: + return ("hmac-sha224"); + case DST_ALG_HMACSHA256: + return ("hmac-sha256"); + case DST_ALG_HMACSHA384: + return ("hmac-sha384"); + case DST_ALG_HMACSHA512: + return ("hmac-sha512"); + default: + return ("(unknown)"); + } +} + +#define DST_ALG_HMAC_FIRST DST_ALG_HMACMD5 +#define DST_ALG_HMAC_LAST DST_ALG_HMACSHA512 + +static void +list_dnssec_algorithms(isc_buffer_t *b) { + for (size_t i = DST_ALG_UNKNOWN; i < DST_MAX_ALGS; i++) { + if (i == DST_ALG_DH || i == DST_ALG_GSSAPI || + (i >= DST_ALG_HMAC_FIRST && i <= DST_ALG_HMAC_LAST)) + { + continue; + } + if (dst_algorithm_supported(i)) { + isc_buffer_putstr(b, " "); + (void)dns_secalg_totext(i, b); + } + } +} + +static void +list_ds_algorithms(isc_buffer_t *b) { + for (size_t i = 0; i < 256; i++) { + if (dst_ds_digest_supported(i)) { + isc_buffer_putstr(b, " "); + (void)dns_dsdigest_totext(i, b); + } + } +} + +static void +list_hmac_algorithms(isc_buffer_t *b) { + isc_buffer_t sb = *b; + for (size_t i = DST_ALG_HMAC_FIRST; i <= DST_ALG_HMAC_LAST; i++) { + if (i == DST_ALG_GSSAPI) { + continue; + } + if (dst_algorithm_supported(i)) { + isc_buffer_putstr(b, " "); + isc_buffer_putstr(b, dst_hmac_algorithm_totext(i)); + } + } + for (unsigned char *s = isc_buffer_used(&sb); s != isc_buffer_used(b); + s++) + { + *s = toupper(*s); + } +} + +static void +logit(isc_buffer_t *b) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, "%.*s", + (int)isc_buffer_usedlength(b), + (char *)isc_buffer_base(b)); +} + +static void +printit(isc_buffer_t *b) { + printf("%.*s\n", (int)isc_buffer_usedlength(b), + (char *)isc_buffer_base(b)); +} + +static void +format_supported_algorithms(void (*emit)(isc_buffer_t *b)) { + isc_buffer_t b; + char buf[512]; + + isc_buffer_init(&b, buf, sizeof(buf)); + isc_buffer_putstr(&b, "DNSSEC algorithms:"); + list_dnssec_algorithms(&b); + (*emit)(&b); + + isc_buffer_init(&b, buf, sizeof(buf)); + isc_buffer_putstr(&b, "DS algorithms:"); + list_ds_algorithms(&b); + (*emit)(&b); + + isc_buffer_init(&b, buf, sizeof(buf)); + isc_buffer_putstr(&b, "HMAC algorithms:"); + list_hmac_algorithms(&b); + (*emit)(&b); + + isc_buffer_init(&b, buf, sizeof(buf)); + isc_buffer_printf(&b, "TKEY mode 2 support (Diffie-Hellman): %s", + (dst_algorithm_supported(DST_ALG_DH) && + dst_algorithm_supported(DST_ALG_HMACMD5)) + ? "yes" + : "non"); + (*emit)(&b); + + isc_buffer_init(&b, buf, sizeof(buf)); + isc_buffer_printf(&b, "TKEY mode 3 support (GSS-API): %s", + dst_algorithm_supported(DST_ALG_GSSAPI) ? "yes" + : "no"); + (*emit)(&b); +} + +static void +printversion(bool verbose) { + char rndcconf[PATH_MAX], *dot = NULL; + isc_mem_t *mctx = NULL; + isc_result_t result; + isc_buffer_t b; + char buf[512]; +#if defined(HAVE_GEOIP2) + cfg_parser_t *parser = NULL; + cfg_obj_t *config = NULL; + const cfg_obj_t *defaults = NULL, *obj = NULL; +#endif /* if defined(HAVE_GEOIP2) */ + + printf("%s %s%s%s \n", named_g_product, named_g_version, + (*named_g_description != '\0') ? " " : "", named_g_description, + named_g_srcid); + + if (!verbose) { + return; + } + + printf("running on %s\n", named_os_uname()); + printf("built by %s with %s\n", named_g_builder, named_g_configargs); +#ifdef __clang__ + printf("compiled by CLANG %s\n", __VERSION__); +#else /* ifdef __clang__ */ +#if defined(__ICC) || defined(__INTEL_COMPILER) + printf("compiled by ICC %s\n", __VERSION__); +#else /* if defined(__ICC) || defined(__INTEL_COMPILER) */ +#ifdef __GNUC__ + printf("compiled by GCC %s\n", __VERSION__); +#endif /* ifdef __GNUC__ */ +#endif /* if defined(__ICC) || defined(__INTEL_COMPILER) */ +#endif /* ifdef __clang__ */ +#ifdef _MSC_VER + printf("compiled by MSVC %d\n", _MSC_VER); +#endif /* ifdef _MSC_VER */ +#ifdef __SUNPRO_C + printf("compiled by Solaris Studio %x\n", __SUNPRO_C); +#endif /* ifdef __SUNPRO_C */ + printf("compiled with OpenSSL version: %s\n", OPENSSL_VERSION_TEXT); +#if !defined(LIBRESSL_VERSION_NUMBER) && \ + OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 or higher */ + printf("linked to OpenSSL version: %s\n", + OpenSSL_version(OPENSSL_VERSION)); + +#else /* if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= \ + * 0x10100000L */ + printf("linked to OpenSSL version: %s\n", + SSLeay_version(SSLEAY_VERSION)); +#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + printf("compiled with libuv version: %d.%d.%d\n", UV_VERSION_MAJOR, + UV_VERSION_MINOR, UV_VERSION_PATCH); + printf("linked to libuv version: %s\n", uv_version_string()); +#ifdef HAVE_LIBXML2 + printf("compiled with libxml2 version: %s\n", LIBXML_DOTTED_VERSION); + printf("linked to libxml2 version: %s\n", xmlParserVersion); +#endif /* ifdef HAVE_LIBXML2 */ +#if defined(HAVE_JSON_C) + printf("compiled with json-c version: %s\n", JSON_C_VERSION); + printf("linked to json-c version: %s\n", json_c_version()); +#endif /* if defined(HAVE_JSON_C) */ +#if defined(HAVE_ZLIB) && defined(ZLIB_VERSION) + printf("compiled with zlib version: %s\n", ZLIB_VERSION); + printf("linked to zlib version: %s\n", zlibVersion()); +#endif /* if defined(HAVE_ZLIB) && defined(ZLIB_VERSION) */ +#if defined(HAVE_GEOIP2) + /* Unfortunately, no version define on link time */ + printf("linked to maxminddb version: %s\n", MMDB_lib_version()); +#endif /* if defined(HAVE_GEOIP2) */ +#if defined(HAVE_DNSTAP) + printf("compiled with protobuf-c version: %s\n", PROTOBUF_C_VERSION); + printf("linked to protobuf-c version: %s\n", protobuf_c_version()); +#endif /* if defined(HAVE_DNSTAP) */ + printf("threads support is enabled\n"); + + isc_mem_create(&mctx); + result = dst_lib_init(mctx, named_g_engine); + if (result == ISC_R_SUCCESS) { + isc_buffer_init(&b, buf, sizeof(buf)); + format_supported_algorithms(printit); + printf("\n"); + dst_lib_destroy(); + } else { + printf("DST initialization failure: %s\n", + isc_result_totext(result)); + } + + /* + * The default rndc.conf and rndc.key paths are in the same + * directory, but named only has rndc.key defined internally. + * We construct the rndc.conf path from it. (We could use + * NAMED_SYSCONFDIR here but the result would look wrong on + * Windows.) + */ + strlcpy(rndcconf, named_g_keyfile, sizeof(rndcconf)); + dot = strrchr(rndcconf, '.'); + if (dot != NULL) { + size_t len = dot - rndcconf + 1; + snprintf(dot + 1, PATH_MAX - len, "conf"); + } + + /* + * Print default configuration paths. + */ + printf("default paths:\n"); + printf(" named configuration: %s\n", named_g_conffile); + printf(" rndc configuration: %s\n", rndcconf); + printf(" DNSSEC root key: %s\n", named_g_defaultbindkeys); + printf(" nsupdate session key: %s\n", named_g_defaultsessionkeyfile); + printf(" named PID file: %s\n", named_g_defaultpidfile); + printf(" named lock file: %s\n", named_g_defaultlockfile); +#if defined(HAVE_GEOIP2) +#define RTC(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS) + RTC(cfg_parser_create(mctx, named_g_lctx, &parser)); + RTC(named_config_parsedefaults(parser, &config)); + RTC(cfg_map_get(config, "options", &defaults)); + RTC(cfg_map_get(defaults, "geoip-directory", &obj)); + if (cfg_obj_isstring(obj)) { + printf(" geoip-directory: %s\n", cfg_obj_asstring(obj)); + } + cfg_obj_destroy(parser, &config); + cfg_parser_destroy(&parser); + isc_mem_detach(&mctx); +#endif /* HAVE_GEOIP2 */ +} + +static void +parse_fuzz_arg(void) { + if (!strncmp(isc_commandline_argument, "client:", 7)) { + named_g_fuzz_addr = isc_commandline_argument + 7; + named_g_fuzz_type = isc_fuzz_client; + } else if (!strncmp(isc_commandline_argument, "tcp:", 4)) { + named_g_fuzz_addr = isc_commandline_argument + 4; + named_g_fuzz_type = isc_fuzz_tcpclient; + } else if (!strncmp(isc_commandline_argument, "resolver:", 9)) { + named_g_fuzz_addr = isc_commandline_argument + 9; + named_g_fuzz_type = isc_fuzz_resolver; + } else if (!strncmp(isc_commandline_argument, "http:", 5)) { + named_g_fuzz_addr = isc_commandline_argument + 5; + named_g_fuzz_type = isc_fuzz_http; + } else if (!strncmp(isc_commandline_argument, "rndc:", 5)) { + named_g_fuzz_addr = isc_commandline_argument + 5; + named_g_fuzz_type = isc_fuzz_rndc; + } else { + named_main_earlyfatal("unknown fuzzing type '%s'", + isc_commandline_argument); + } +} + +static void +parse_T_opt(char *option) { + const char *p; + char *last = NULL; + /* + * force the server to behave (or misbehave) in + * specified ways for testing purposes. + * dscp=x: check that dscp values are as + * expected and assert otherwise. + */ + if (!strcmp(option, "dropedns")) { + dropedns = true; + } else if (!strncmp(option, "dscp=", 5)) { + isc_dscp_check_value = atoi(option + 5); + } else if (!strcmp(option, "ednsformerr")) { + ednsformerr = true; + } else if (!strcmp(option, "ednsnotimp")) { + ednsnotimp = true; + } else if (!strcmp(option, "ednsrefused")) { + ednsrefused = true; + } else if (!strcmp(option, "fixedlocal")) { + fixedlocal = true; + } else if (!strcmp(option, "keepstderr")) { + named_g_keepstderr = true; + } else if (!strcmp(option, "noaa")) { + noaa = true; + } else if (!strcmp(option, "noedns")) { + noedns = true; + } else if (!strcmp(option, "nonearest")) { + nonearest = true; + } else if (!strcmp(option, "nosoa")) { + nosoa = true; + } else if (!strcmp(option, "nosyslog")) { + named_g_nosyslog = true; + } else if (!strcmp(option, "notcp")) { + notcp = true; + } else if (!strncmp(option, "maxcachesize=", 13)) { + named_g_maxcachesize = atoi(option + 13); + } else if (!strcmp(option, "maxudp512")) { + maxudp = 512; + } else if (!strcmp(option, "maxudp1460")) { + maxudp = 1460; + } else if (!strncmp(option, "maxudp=", 7)) { + maxudp = atoi(option + 7); + if (maxudp <= 0) { + named_main_earlyfatal("bad maxudp"); + } + } else if (!strncmp(option, "mkeytimers=", 11)) { + p = strtok_r(option + 11, "/", &last); + if (p == NULL) { + named_main_earlyfatal("bad mkeytimer"); + } + + dns_zone_mkey_hour = atoi(p); + if (dns_zone_mkey_hour == 0) { + named_main_earlyfatal("bad mkeytimer"); + } + + p = strtok_r(NULL, "/", &last); + if (p == NULL) { + dns_zone_mkey_day = (24 * dns_zone_mkey_hour); + dns_zone_mkey_month = (30 * dns_zone_mkey_day); + return; + } + + dns_zone_mkey_day = atoi(p); + if (dns_zone_mkey_day < dns_zone_mkey_hour) { + named_main_earlyfatal("bad mkeytimer"); + } + + p = strtok_r(NULL, "/", &last); + if (p == NULL) { + dns_zone_mkey_month = (30 * dns_zone_mkey_day); + return; + } + + dns_zone_mkey_month = atoi(p); + if (dns_zone_mkey_month < dns_zone_mkey_day) { + named_main_earlyfatal("bad mkeytimer"); + } + } else if (!strcmp(option, "sigvalinsecs")) { + sigvalinsecs = true; + } else if (!strncmp(option, "tat=", 4)) { + named_g_tat_interval = atoi(option + 4); + } else { + fprintf(stderr, "unknown -T flag '%s'\n", option); + } +} + +static void +parse_command_line(int argc, char *argv[]) { + int ch; + int port; + const char *p; + + save_command_line(argc, argv); + + /* + * NAMED_MAIN_ARGS is defined in main.h, so that it can be used + * both by named and by ntservice hooks. + */ + isc_commandline_errprint = false; + while ((ch = isc_commandline_parse(argc, argv, NAMED_MAIN_ARGS)) != -1) + { + switch (ch) { + case '4': + if (disable4) { + named_main_earlyfatal("cannot specify " + "-4 and -6"); + } + if (isc_net_probeipv4() != ISC_R_SUCCESS) { + named_main_earlyfatal("IPv4 not supported " + "by OS"); + } + isc_net_disableipv6(); + disable6 = true; + break; + case '6': + if (disable6) { + named_main_earlyfatal("cannot specify " + "-4 and -6"); + } + if (isc_net_probeipv6() != ISC_R_SUCCESS) { + named_main_earlyfatal("IPv6 not supported " + "by OS"); + } + isc_net_disableipv4(); + disable4 = true; + break; + case 'A': + parse_fuzz_arg(); + break; + case 'c': + named_g_conffile = isc_commandline_argument; + named_g_conffileset = true; + break; + case 'C': + printf("# Built-in default values. " + "This is NOT the run-time configuration!\n"); + printf("%s", named_config_getdefault()); + exit(0); + case 'd': + named_g_debuglevel = parse_int(isc_commandline_argument, + "debug " + "level"); + break; + case 'D': + /* Descriptive comment for 'ps'. */ + break; + case 'E': + named_g_engine = isc_commandline_argument; + break; + case 'f': + named_g_foreground = true; + break; + case 'g': + named_g_foreground = true; + named_g_logstderr = true; + break; + case 'L': + named_g_logfile = isc_commandline_argument; + break; + case 'M': + set_flags(isc_commandline_argument, mem_context_flags, + &isc_mem_defaultflags); + break; + case 'm': + set_flags(isc_commandline_argument, mem_debug_flags, + &isc_mem_debugging); + break; + case 'N': /* Deprecated. */ + case 'n': + named_g_cpus = parse_int(isc_commandline_argument, + "number of cpus"); + if (named_g_cpus == 0) { + named_g_cpus = 1; + } + break; + case 'p': + port = parse_int(isc_commandline_argument, "port"); + if (port < 1 || port > 65535) { + named_main_earlyfatal("port '%s' out of range", + isc_commandline_argument); + } + named_g_port = port; + break; + case 's': + /* XXXRTH temporary syntax */ + want_stats = true; + break; + case 'S': + maxsocks = parse_int(isc_commandline_argument, + "max number of sockets"); + break; + case 't': + /* XXXJAB should we make a copy? */ + named_g_chrootdir = isc_commandline_argument; + break; + case 'T': /* NOT DOCUMENTED */ + parse_T_opt(isc_commandline_argument); + break; + case 'U': + named_g_udpdisp = parse_int(isc_commandline_argument, + "number of UDP listeners " + "per interface"); + break; + case 'u': + named_g_username = isc_commandline_argument; + break; + case 'v': + printversion(false); + exit(0); + case 'V': + printversion(true); + exit(0); + case 'x': + /* Obsolete. No longer in use. Ignore. */ + break; + case 'X': + named_g_forcelock = true; + if (strcasecmp(isc_commandline_argument, "none") != 0) { + named_g_defaultlockfile = + isc_commandline_argument; + } else { + named_g_defaultlockfile = NULL; + } + break; + case 'F': + /* Reserved for FIPS mode */ + FALLTHROUGH; + case '?': + usage(); + if (isc_commandline_option == '?') { + exit(0); + } + p = strchr(NAMED_MAIN_ARGS, isc_commandline_option); + if (p == NULL || *++p != ':') { + named_main_earlyfatal("unknown option '-%c'", + isc_commandline_option); + } else { + named_main_earlyfatal("option '-%c' requires " + "an argument", + isc_commandline_option); + } + FALLTHROUGH; + default: + named_main_earlyfatal("parsing options returned %d", + ch); + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + POST(argv); + + if (argc > 0) { + usage(); + named_main_earlyfatal("extra command line arguments"); + } +} + +static isc_result_t +create_managers(void) { + isc_result_t result; + unsigned int socks; + + INSIST(named_g_cpus_detected > 0); + + if (named_g_cpus == 0) { + named_g_cpus = named_g_cpus_detected; + } + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, + ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s", + named_g_cpus_detected, named_g_cpus_detected == 1 ? "" : "s", + named_g_cpus, named_g_cpus == 1 ? "" : "s"); +#ifdef WIN32 + named_g_udpdisp = 1; +#else /* ifdef WIN32 */ + if (named_g_udpdisp == 0) { + named_g_udpdisp = named_g_cpus_detected; + } + if (named_g_udpdisp > named_g_cpus) { + named_g_udpdisp = named_g_cpus; + } +#endif /* ifdef WIN32 */ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "using %u UDP listener%s per interface", named_g_udpdisp, + named_g_udpdisp == 1 ? "" : "s"); + + result = isc_managers_create(named_g_mctx, named_g_cpus, 0, &named_g_nm, + &named_g_taskmgr); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_managers_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + + result = isc_timermgr_create(named_g_mctx, &named_g_timermgr); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_timermgr_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + + result = isc_socketmgr_create2(named_g_mctx, &named_g_socketmgr, + maxsocks, named_g_cpus); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socketmgr_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + isc_socketmgr_maxudp(named_g_socketmgr, maxudp); + isc_nm_maxudp(named_g_nm, maxudp); + result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &socks); + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "using up to %u sockets", socks); + } + + return (ISC_R_SUCCESS); +} + +static void +destroy_managers(void) { + isc_managers_destroy(&named_g_nm, &named_g_taskmgr); + isc_timermgr_destroy(&named_g_timermgr); + isc_socketmgr_destroy(&named_g_socketmgr); +} + +static void +dump_symboltable(void) { + int i; + isc_result_t result; + const char *fname; + const void *addr; + + if (isc__backtrace_nsymbols == 0) { + return; + } + + if (!isc_log_wouldlog(named_g_lctx, ISC_LOG_DEBUG(99))) { + return; + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_DEBUG(99), "Symbol table:"); + + for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) { + addr = NULL; + fname = NULL; + result = isc_backtrace_getsymbolfromindex(i, &addr, &fname); + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_DEBUG(99), + "[%d] %p %s", i, addr, fname); + } + } +} + +static void +setup(void) { + isc_result_t result; + isc_resourcevalue_t old_openfiles; + ns_server_t *sctx; +#ifdef HAVE_LIBSCF + char *instance = NULL; +#endif /* ifdef HAVE_LIBSCF */ + + /* + * Get the user and group information before changing the root + * directory, so the administrator does not need to keep a copy + * of the user and group databases in the chroot'ed environment. + */ + named_os_inituserinfo(named_g_username); + + /* + * Initialize time conversion information + */ + named_os_tzset(); + + named_os_opendevnull(); + +#ifdef HAVE_LIBSCF + /* Check if named is under smf control, before chroot. */ + result = named_smf_get_instance(&instance, 0, named_g_mctx); + /* We don't care about instance, just check if we got one. */ + if (result == ISC_R_SUCCESS) { + named_smf_got_instance = 1; + } else { + named_smf_got_instance = 0; + } + if (instance != NULL) { + isc_mem_free(named_g_mctx, instance); + } +#endif /* HAVE_LIBSCF */ + + /* + * Check for the number of cpu's before named_os_chroot(). + */ + named_g_cpus_detected = isc_os_ncpus(); + + named_os_chroot(named_g_chrootdir); + + /* + * For operating systems which have a capability mechanism, now + * is the time to switch to minimal privs and change our user id. + * On traditional UNIX systems, this call will be a no-op, and we + * will change the user ID after reading the config file the first + * time. (We need to read the config file to know which possibly + * privileged ports to bind() to.) + */ + named_os_minprivs(); + + result = named_log_init(named_g_username != NULL); + if (result != ISC_R_SUCCESS) { + named_main_earlyfatal("named_log_init() failed: %s", + isc_result_totext(result)); + } + + /* + * Now is the time to daemonize (if we're not running in the + * foreground). We waited until now because we wanted to get + * a valid logging context setup. We cannot daemonize any later, + * because calling create_managers() will create threads, which + * would be lost after fork(). + */ + if (!named_g_foreground) { + named_os_daemonize(); + } + + /* + * We call isc_app_start() here as some versions of FreeBSD's fork() + * destroys all the signal handling it sets up. + */ + result = isc_app_start(); + if (result != ISC_R_SUCCESS) { + named_main_earlyfatal("isc_app_start() failed: %s", + isc_result_totext(result)); + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "starting %s %s%s%s ", named_g_product, + named_g_version, *named_g_description ? " " : "", + named_g_description, named_g_srcid); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, "running on %s", + named_os_uname()); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, "built with %s", + named_g_configargs); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "running as: %s%s%s", program_name, saved_command_line, + ellipsis); +#ifdef __clang__ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled by CLANG %s", __VERSION__); +#else /* ifdef __clang__ */ +#if defined(__ICC) || defined(__INTEL_COMPILER) + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled by ICC %s", __VERSION__); +#else /* if defined(__ICC) || defined(__INTEL_COMPILER) */ +#ifdef __GNUC__ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled by GCC %s", __VERSION__); +#endif /* ifdef __GNUC__ */ +#endif /* if defined(__ICC) || defined(__INTEL_COMPILER) */ +#endif /* ifdef __clang__ */ +#ifdef _MSC_VER + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled by MSVC %d", _MSC_VER); +#endif /* ifdef _MSC_VER */ +#ifdef __SUNPRO_C + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled by Solaris Studio %x", __SUNPRO_C); +#endif /* ifdef __SUNPRO_C */ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled with OpenSSL version: %s", + OPENSSL_VERSION_TEXT); +#if !defined(LIBRESSL_VERSION_NUMBER) && \ + OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 or higher */ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "linked to OpenSSL version: %s", + OpenSSL_version(OPENSSL_VERSION)); +#else /* if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= \ + * 0x10100000L */ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "linked to OpenSSL version: %s", + SSLeay_version(SSLEAY_VERSION)); +#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled with libuv version: %d.%d.%d", UV_VERSION_MAJOR, + UV_VERSION_MINOR, UV_VERSION_PATCH); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "linked to libuv version: %s", uv_version_string()); +#ifdef HAVE_LIBXML2 + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled with libxml2 version: %s", + LIBXML_DOTTED_VERSION); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "linked to libxml2 version: %s", xmlParserVersion); +#endif /* ifdef HAVE_LIBXML2 */ +#if defined(HAVE_JSON_C) + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled with json-c version: %s", JSON_C_VERSION); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "linked to json-c version: %s", json_c_version()); +#endif /* if defined(HAVE_JSON_C) */ +#if defined(HAVE_ZLIB) && defined(ZLIB_VERSION) + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "compiled with zlib version: %s", ZLIB_VERSION); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "linked to zlib version: %s", zlibVersion()); +#endif /* if defined(HAVE_ZLIB) && defined(ZLIB_VERSION) */ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "----------------------------------------------------"); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "BIND 9 is maintained by Internet Systems Consortium,"); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "Inc. (ISC), a non-profit 501(c)(3) public-benefit "); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "corporation. Support and training for BIND 9 are "); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "available at https://www.isc.org/support"); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "----------------------------------------------------"); + + dump_symboltable(); + + /* + * Get the initial resource limits. + */ +#ifndef WIN32 + RUNTIME_CHECK(isc_resource_getlimit(isc_resource_stacksize, + &named_g_initstacksize) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_resource_getlimit(isc_resource_datasize, + &named_g_initdatasize) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_resource_getlimit(isc_resource_coresize, + &named_g_initcoresize) == + ISC_R_SUCCESS); +#endif /* ifndef WIN32 */ + RUNTIME_CHECK(isc_resource_getlimit(isc_resource_openfiles, + &named_g_initopenfiles) == + ISC_R_SUCCESS); + + /* + * System resources cannot effectively be tuned on some systems. + * Raise the limit in such cases for safety. + */ + old_openfiles = named_g_initopenfiles; + named_os_adjustnofile(); + RUNTIME_CHECK(isc_resource_getlimit(isc_resource_openfiles, + &named_g_initopenfiles) == + ISC_R_SUCCESS); + if (old_openfiles != named_g_initopenfiles) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, + "adjusted limit on open files from " + "%" PRIu64 " to " + "%" PRIu64, + old_openfiles, named_g_initopenfiles); + } + + /* + * If the named configuration filename is relative, prepend the current + * directory's name before possibly changing to another directory. + */ + if (!isc_file_isabsolute(named_g_conffile)) { + result = isc_file_absolutepath(named_g_conffile, + absolute_conffile, + sizeof(absolute_conffile)); + if (result != ISC_R_SUCCESS) { + named_main_earlyfatal("could not construct " + "absolute path " + "of configuration file: %s", + isc_result_totext(result)); + } + named_g_conffile = absolute_conffile; + } + + /* + * Record the server's startup time. + */ + result = isc_time_now(&named_g_boottime); + if (result != ISC_R_SUCCESS) { + named_main_earlyfatal("isc_time_now() failed: %s", + isc_result_totext(result)); + } + + result = create_managers(); + if (result != ISC_R_SUCCESS) { + named_main_earlyfatal("create_managers() failed: %s", + isc_result_totext(result)); + } + + named_builtin_init(); + + /* + * Add calls to register sdb drivers here. + */ + /* xxdb_init(); */ + +#ifdef ISC_DLZ_DLOPEN + /* + * Register the DLZ "dlopen" driver. + */ + result = dlz_dlopen_init(named_g_mctx); + if (result != ISC_R_SUCCESS) { + named_main_earlyfatal("dlz_dlopen_init() failed: %s", + isc_result_totext(result)); + } +#endif /* ifdef ISC_DLZ_DLOPEN */ + +#if CONTRIB_DLZ + /* + * Register any other contributed DLZ drivers. + */ + result = dlz_drivers_init(); + if (result != ISC_R_SUCCESS) { + named_main_earlyfatal("dlz_drivers_init() failed: %s", + isc_result_totext(result)); + } +#endif /* if CONTRIB_DLZ */ + + named_server_create(named_g_mctx, &named_g_server); + ENSURE(named_g_server != NULL); + sctx = named_g_server->sctx; + + /* + * Report supported algorithms now that dst_lib_init() has + * been called via named_server_create(). + */ + format_supported_algorithms(logit); + + /* + * Modify server context according to command line options + */ + if (disable4) { + ns_server_setoption(sctx, NS_SERVER_DISABLE4, true); + } + if (disable6) { + ns_server_setoption(sctx, NS_SERVER_DISABLE6, true); + } + if (dropedns) { + ns_server_setoption(sctx, NS_SERVER_DROPEDNS, true); + } + if (ednsformerr) { /* STD13 server */ + ns_server_setoption(sctx, NS_SERVER_EDNSFORMERR, true); + } + if (ednsnotimp) { + ns_server_setoption(sctx, NS_SERVER_EDNSNOTIMP, true); + } + if (ednsrefused) { + ns_server_setoption(sctx, NS_SERVER_EDNSREFUSED, true); + } + if (fixedlocal) { + ns_server_setoption(sctx, NS_SERVER_FIXEDLOCAL, true); + } + if (noaa) { + ns_server_setoption(sctx, NS_SERVER_NOAA, true); + } + if (noedns) { + ns_server_setoption(sctx, NS_SERVER_NOEDNS, true); + } + if (nonearest) { + ns_server_setoption(sctx, NS_SERVER_NONEAREST, true); + } + if (nosoa) { + ns_server_setoption(sctx, NS_SERVER_NOSOA, true); + } + if (notcp) { + ns_server_setoption(sctx, NS_SERVER_NOTCP, true); + } + if (sigvalinsecs) { + ns_server_setoption(sctx, NS_SERVER_SIGVALINSECS, true); + } +} + +static void +cleanup(void) { + destroy_managers(); + + if (named_g_mapped != NULL) { + dns_acl_detach(&named_g_mapped); + } + + named_server_destroy(&named_g_server); + + named_builtin_deinit(); + + /* + * Add calls to unregister sdb drivers here. + */ + /* xxdb_clear(); */ + +#ifdef CONTRIB_DLZ + /* + * Unregister contributed DLZ drivers. + */ + dlz_drivers_clear(); +#endif /* ifdef CONTRIB_DLZ */ +#ifdef ISC_DLZ_DLOPEN + /* + * Unregister "dlopen" DLZ driver. + */ + dlz_dlopen_clear(); +#endif /* ifdef ISC_DLZ_DLOPEN */ + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, "exiting"); + named_log_shutdown(); +} + +static char *memstats = NULL; + +void +named_main_setmemstats(const char *filename) { + /* + * Caller has to ensure locking. + */ + + if (memstats != NULL) { + free(memstats); + memstats = NULL; + } + + if (filename == NULL) { + return; + } + + memstats = strdup(filename); +} + +#ifdef HAVE_LIBSCF +/* + * Get FMRI for the named process. + */ +isc_result_t +named_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) { + scf_handle_t *h = NULL; + int namelen; + char *instance; + + REQUIRE(ins_name != NULL && *ins_name == NULL); + + if ((h = scf_handle_create(SCF_VERSION)) == NULL) { + if (debug) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "scf_handle_create() failed: %s", + scf_strerror(scf_error())); + } + return (ISC_R_FAILURE); + } + + if (scf_handle_bind(h) == -1) { + if (debug) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "scf_handle_bind() failed: %s", + scf_strerror(scf_error())); + } + scf_handle_destroy(h); + return (ISC_R_FAILURE); + } + + if ((namelen = scf_myname(h, NULL, 0)) == -1) { + if (debug) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "scf_myname() failed: %s", + scf_strerror(scf_error())); + } + scf_handle_destroy(h); + return (ISC_R_FAILURE); + } + + if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "named_smf_get_instance memory " + "allocation failed: %s", + isc_result_totext(ISC_R_NOMEMORY)); + scf_handle_destroy(h); + return (ISC_R_FAILURE); + } + + if (scf_myname(h, instance, namelen + 1) == -1) { + if (debug) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "scf_myname() failed: %s", + scf_strerror(scf_error())); + } + scf_handle_destroy(h); + isc_mem_free(mctx, instance); + return (ISC_R_FAILURE); + } + + scf_handle_destroy(h); + *ins_name = instance; + return (ISC_R_SUCCESS); +} +#endif /* HAVE_LIBSCF */ + +/* main entry point, possibly hooked */ + +int +main(int argc, char *argv[]) { + isc_result_t result; +#ifdef HAVE_LIBSCF + char *instance = NULL; +#endif /* ifdef HAVE_LIBSCF */ + +#ifdef HAVE_GPERFTOOLS_PROFILER + (void)ProfilerStart(NULL); +#endif /* ifdef HAVE_GPERFTOOLS_PROFILER */ + +#ifdef WIN32 + /* + * Prevent unbuffered I/O from crippling named performance on Windows + * when it is logging to stderr (e.g. in system tests). Use full + * buffering (_IOFBF) as line buffering (_IOLBF) is unavailable on + * Windows and fflush() is called anyway after each log message gets + * written to the default stderr logging channels created by libisc. + */ + setvbuf(stderr, NULL, _IOFBF, BUFSIZ); +#endif /* ifdef WIN32 */ + +#ifdef HAVE_LIBXML2 + xmlInitParser(); +#endif /* HAVE_LIBXML2 */ + + /* + * Technically, this call is superfluous because on startup of the main + * program, the portable "C" locale is selected by default. This + * explicit call here is for a reference that the BIND 9 code base is + * not locale aware and the locale MUST be set to "C" (or "POSIX") when + * calling any BIND 9 library code. If you are calling external + * libraries that use locale, such calls must be wrapped into + * setlocale(LC_ALL, ""); before the call and setlocale(LC_ALL, "C"); + * after the call, and no BIND 9 library calls must be made in between. + */ +#if HAVE_SETLOCALE + setlocale(LC_ALL, "C"); +#endif /* HAVE_SETLOCALE */ + + /* + * Record version in core image. + * strings named.core | grep "named version:" + */ + strlcat(version, +#if defined(NO_VERSION_DATE) || !defined(__DATE__) + "named version: BIND " VERSION " <" SRCID ">", +#else /* if defined(NO_VERSION_DATE) || !defined(__DATE__) */ + "named version: BIND " VERSION " <" SRCID "> (" __DATE__ ")", +#endif /* if defined(NO_VERSION_DATE) || !defined(__DATE__) */ + sizeof(version)); + result = isc_file_progname(*argv, program_name, sizeof(program_name)); + if (result != ISC_R_SUCCESS) { + named_main_earlyfatal("program name too long"); + } + + isc_assertion_setcallback(assertion_failed); + isc_error_setfatal(library_fatal_error); + isc_error_setunexpected(library_unexpected_error); + + named_os_init(program_name); + + dns_result_register(); + dst_result_register(); + isccc_result_register(); +#if USE_PKCS11 + pk11_result_register(); +#endif /* if USE_PKCS11 */ + + parse_command_line(argc, argv); + +#ifdef ENABLE_AFL + if (named_g_fuzz_type != isc_fuzz_none) { + named_fuzz_setup(); + } + + if (named_g_fuzz_type == isc_fuzz_resolver) { + dns_resolver_setfuzzing(); + } else if (named_g_fuzz_type == isc_fuzz_http) { + isc_httpd_setfinishhook(named_fuzz_notify); + } +#endif /* ifdef ENABLE_AFL */ + /* + * Warn about common configuration error. + */ + if (named_g_chrootdir != NULL) { + int len = strlen(named_g_chrootdir); + if (strncmp(named_g_chrootdir, named_g_conffile, len) == 0 && + (named_g_conffile[len] == '/' || + named_g_conffile[len] == '\\')) + { + named_main_earlywarning("config filename (-c %s) " + "contains chroot path (-t %s)", + named_g_conffile, + named_g_chrootdir); + } + } + + isc_mem_create(&named_g_mctx); + isc_mem_setname(named_g_mctx, "main", NULL); + + setup(); + INSIST(named_g_server != NULL); + + /* + * Start things running and then wait for a shutdown request + * or reload. + */ + do { + result = isc_app_run(); + + if (result == ISC_R_RELOAD) { + named_server_reloadwanted(named_g_server); + } else if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_run(): %s", + isc_result_totext(result)); + /* + * Force exit. + */ + result = ISC_R_SUCCESS; + } + } while (result != ISC_R_SUCCESS); + +#ifdef HAVE_LIBSCF + if (named_smf_want_disable == 1) { + result = named_smf_get_instance(&instance, 1, named_g_mctx); + if (result == ISC_R_SUCCESS && instance != NULL) { + if (smf_disable_instance(instance, 0) != 0) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "smf_disable_instance() " + "failed for %s : %s", + instance, + scf_strerror(scf_error())); + } + } + if (instance != NULL) { + isc_mem_free(named_g_mctx, instance); + } + } +#endif /* HAVE_LIBSCF */ + + cleanup(); + + if (want_stats) { + isc_mem_stats(named_g_mctx, stdout); + isc_mutex_stats(stdout); + } + + if (named_g_memstatistics && memstats != NULL) { + FILE *fp = NULL; + result = isc_stdio_open(memstats, "w", &fp); + if (result == ISC_R_SUCCESS) { + isc_mem_stats(named_g_mctx, fp); + isc_mutex_stats(fp); + (void)isc_stdio_close(fp); + } + } + isc_mem_destroy(&named_g_mctx); + isc_mem_checkdestroyed(stderr); + + named_main_setmemstats(NULL); + + isc_app_finish(); + + named_os_closedevnull(); + + named_os_shutdown(); + +#ifdef HAVE_LIBXML2 + xmlCleanupParser(); +#endif /* HAVE_LIBXML2 */ + +#ifdef HAVE_GPERFTOOLS_PROFILER + ProfilerStop(); +#endif /* ifdef HAVE_GPERFTOOLS_PROFILER */ + + return (0); +} diff --git a/bin/named/named.conf.rst b/bin/named/named.conf.rst new file mode 100644 index 0000000..4c9f9a7 --- /dev/null +++ b/bin/named/named.conf.rst @@ -0,0 +1,1082 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +named.conf - configuration file for **named** +--------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`named.conf` + +Description +~~~~~~~~~~~ + +``named.conf`` is the configuration file for ``named``. Statements are +enclosed in braces and terminated with a semi-colon. Clauses in the +statements are also semi-colon terminated. The usual comment styles are +supported: + +C style: /\* \*/ + + C++ style: // to end of line + +Unix style: # to end of line + +ACL +^^^ + +:: + + acl string { address_match_element; ... }; + +CONTROLS +^^^^^^^^ + +:: + + controls { + inet ( ipv4_address | ipv6_address | + * ) [ port ( integer | * ) ] allow + { address_match_element; ... } [ + keys { string; ... } ] [ read-only + boolean ]; + unix quoted_string perm integer + owner integer group integer [ + keys { string; ... } ] [ read-only + boolean ]; + }; + +DLZ +^^^ + +:: + + dlz string { + database string; + search boolean; + }; + +DNSSEC-POLICY +^^^^^^^^^^^^^ + +:: + + dnssec-policy string { + dnskey-ttl duration; + keys { ( csk | ksk | zsk ) [ ( key-directory ) ] lifetime + duration_or_unlimited algorithm string [ integer ]; ... }; + max-zone-ttl duration; + nsec3param [ iterations integer ] [ optout boolean ] [ + salt-length integer ]; + parent-ds-ttl duration; + parent-propagation-delay duration; + publish-safety duration; + purge-keys duration; + retire-safety duration; + signatures-refresh duration; + signatures-validity duration; + signatures-validity-dnskey duration; + zone-propagation-delay duration; + }; + +DYNDB +^^^^^ + +:: + + dyndb string quoted_string { + unspecified-text }; + +KEY +^^^ + +:: + + key string { + algorithm string; + secret string; + }; + +LOGGING +^^^^^^^ + +:: + + logging { + category string { string; ... }; + channel string { + buffered boolean; + file quoted_string [ versions ( unlimited | integer ) ] + [ size size ] [ suffix ( increment | timestamp ) ]; + null; + print-category boolean; + print-severity boolean; + print-time ( iso8601 | iso8601-utc | local | boolean ); + severity log_severity; + stderr; + syslog [ syslog_facility ]; + }; + }; + +MANAGED-KEYS +^^^^^^^^^^^^ + +See DNSSEC-KEYS. + +:: + + managed-keys { string ( static-key + | initial-key | static-ds | + initial-ds ) integer integer + integer quoted_string; ... };, deprecated + +MASTERS +^^^^^^^ + +:: + + masters string [ port integer ] [ dscp + integer ] { ( remote-servers | + ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key + string ]; ... }; + +OPTIONS +^^^^^^^ + +:: + + options { + allow-new-zones boolean; + allow-notify { address_match_element; ... }; + allow-query { address_match_element; ... }; + allow-query-cache { address_match_element; ... }; + allow-query-cache-on { address_match_element; ... }; + allow-query-on { address_match_element; ... }; + allow-recursion { address_match_element; ... }; + allow-recursion-on { address_match_element; ... }; + allow-transfer { address_match_element; ... }; + allow-update { address_match_element; ... }; + allow-update-forwarding { address_match_element; ... }; + also-notify [ port integer ] [ dscp integer ] { ( + remote-servers | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; ... }; + alt-transfer-source ( ipv4_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + alt-transfer-source-v6 ( ipv6_address | * ) [ port ( integer | + * ) ] [ dscp integer ]; + answer-cookie boolean; + attach-cache string; + auth-nxdomain boolean; // default changed + auto-dnssec ( allow | maintain | off );// deprecated + automatic-interface-scan boolean; + avoid-v4-udp-ports { portrange; ... }; + avoid-v6-udp-ports { portrange; ... }; + bindkeys-file quoted_string; + blackhole { address_match_element; ... }; + cache-file quoted_string;// deprecated + catalog-zones { zone string [ default-masters [ port integer ] + [ dscp integer ] { ( remote-servers | ipv4_address [ port + integer ] | ipv6_address [ port integer ] ) [ key + string ]; ... } ] [ zone-directory quoted_string ] [ + in-memory boolean ] [ min-update-interval duration ]; ... }; + check-dup-records ( fail | warn | ignore ); + check-integrity boolean; + check-mx ( fail | warn | ignore ); + check-mx-cname ( fail | warn | ignore ); + check-names ( primary | master | + secondary | slave | response ) ( + fail | warn | ignore ); + check-sibling boolean; + check-spf ( warn | ignore ); + check-srv-cname ( fail | warn | ignore ); + check-wildcard boolean; + clients-per-query integer; + cookie-algorithm ( aes | siphash24 ); + cookie-secret string; + coresize ( default | unlimited | sizeval ); + datasize ( default | unlimited | sizeval ); + deny-answer-addresses { address_match_element; ... } [ + except-from { string; ... } ]; + deny-answer-aliases { string; ... } [ except-from { string; ... + } ]; + dialup ( notify | notify-passive | passive | refresh | boolean ); + directory quoted_string; + disable-algorithms string { string; + ... }; + disable-ds-digests string { string; + ... }; + disable-empty-zone string; + dns64 netprefix { + break-dnssec boolean; + clients { address_match_element; ... }; + exclude { address_match_element; ... }; + mapped { address_match_element; ... }; + recursive-only boolean; + suffix ipv6_address; + }; + dns64-contact string; + dns64-server string; + dnskey-sig-validity integer; + dnsrps-enable boolean; + dnsrps-options { unspecified-text }; + dnssec-accept-expired boolean; + dnssec-dnskey-kskonly boolean; + dnssec-loadkeys-interval integer; + dnssec-must-be-secure string boolean; + dnssec-policy string; + dnssec-secure-to-insecure boolean; + dnssec-update-mode ( maintain | no-resign ); + dnssec-validation ( yes | no | auto ); + dnstap { ( all | auth | client | forwarder | resolver | update ) [ + ( query | response ) ]; ... }; + dnstap-identity ( quoted_string | none | hostname ); + dnstap-output ( file | unix ) quoted_string [ size ( unlimited | + size ) ] [ versions ( unlimited | integer ) ] [ suffix ( + increment | timestamp ) ]; + dnstap-version ( quoted_string | none ); + dscp integer; + dual-stack-servers [ port integer ] { ( quoted_string [ port + integer ] [ dscp integer ] | ipv4_address [ port + integer ] [ dscp integer ] | ipv6_address [ port + integer ] [ dscp integer ] ); ... }; + dump-file quoted_string; + edns-udp-size integer; + empty-contact string; + empty-server string; + empty-zones-enable boolean; + fetch-quota-params integer fixedpoint fixedpoint fixedpoint; + fetches-per-server integer [ ( drop | fail ) ]; + fetches-per-zone integer [ ( drop | fail ) ]; + files ( default | unlimited | sizeval ); + flush-zones-on-shutdown boolean; + forward ( first | only ); + forwarders [ port integer ] [ dscp integer ] { ( ipv4_address + | ipv6_address ) [ port integer ] [ dscp integer ]; ... }; + fstrm-set-buffer-hint integer; + fstrm-set-flush-timeout integer; + fstrm-set-input-queue-size integer; + fstrm-set-output-notify-threshold integer; + fstrm-set-output-queue-model ( mpsc | spsc ); + fstrm-set-output-queue-size integer; + fstrm-set-reopen-interval duration; + geoip-directory ( quoted_string | none ); + glue-cache boolean; + heartbeat-interval integer; + hostname ( quoted_string | none ); + interface-interval duration; + ixfr-from-differences ( primary | master | secondary | slave | + boolean ); + keep-response-order { address_match_element; ... }; + key-directory quoted_string; + lame-ttl duration; + listen-on [ port integer ] [ dscp + integer ] { + address_match_element; ... }; + listen-on-v6 [ port integer ] [ dscp + integer ] { + address_match_element; ... }; + lmdb-mapsize sizeval; + lock-file ( quoted_string | none ); + managed-keys-directory quoted_string; + masterfile-format ( map | raw | text ); + masterfile-style ( full | relative ); + match-mapped-addresses boolean; + max-cache-size ( default | unlimited | sizeval | percentage ); + max-cache-ttl duration; + max-clients-per-query integer; + max-ixfr-ratio ( unlimited | percentage ); + max-journal-size ( default | unlimited | sizeval ); + max-ncache-ttl duration; + max-records integer; + max-recursion-depth integer; + max-recursion-queries integer; + max-refresh-time integer; + max-retry-time integer; + max-rsa-exponent-size integer; + max-stale-ttl duration; + max-transfer-idle-in integer; + max-transfer-idle-out integer; + max-transfer-time-in integer; + max-transfer-time-out integer; + max-udp-size integer; + max-zone-ttl ( unlimited | duration ); + memstatistics boolean; + memstatistics-file quoted_string; + message-compression boolean; + min-cache-ttl duration; + min-ncache-ttl duration; + min-refresh-time integer; + min-retry-time integer; + minimal-any boolean; + minimal-responses ( no-auth | no-auth-recursive | boolean ); + multi-master boolean; + new-zones-directory quoted_string; + no-case-compress { address_match_element; ... }; + nocookie-udp-size integer; + notify ( explicit | master-only | primary-only | boolean ); + notify-delay integer; + notify-rate integer; + notify-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ] + [ dscp integer ]; + notify-to-soa boolean; + nta-lifetime duration; + nta-recheck duration; + nxdomain-redirect string; + parental-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + parental-source-v6 ( ipv6_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + pid-file ( quoted_string | none ); + port integer; + preferred-glue string; + prefetch integer [ integer ]; + provide-ixfr boolean; + qname-minimization ( strict | relaxed | disabled | off ); + query-source ( ( [ address ] ( ipv4_address | * ) [ port ( + integer | * ) ] ) | ( [ [ address ] ( ipv4_address | * ) ] + port ( integer | * ) ) ) [ dscp integer ]; + query-source-v6 ( ( [ address ] ( ipv6_address | * ) [ port ( + integer | * ) ] ) | ( [ [ address ] ( ipv6_address | * ) ] + port ( integer | * ) ) ) [ dscp integer ]; + querylog boolean; + random-device ( quoted_string | none ); + rate-limit { + all-per-second integer; + errors-per-second integer; + exempt-clients { address_match_element; ... }; + ipv4-prefix-length integer; + ipv6-prefix-length integer; + log-only boolean; + max-table-size integer; + min-table-size integer; + nodata-per-second integer; + nxdomains-per-second integer; + qps-scale integer; + referrals-per-second integer; + responses-per-second integer; + slip integer; + window integer; + }; + recursing-file quoted_string; + recursion boolean; + recursive-clients integer; + request-expire boolean; + request-ixfr boolean; + request-nsid boolean; + require-server-cookie boolean; + reserved-sockets integer; + resolver-nonbackoff-tries integer; + resolver-query-timeout integer; + resolver-retry-interval integer; + response-padding { address_match_element; ... } block-size + integer; + response-policy { zone string [ add-soa boolean ] [ log + boolean ] [ max-policy-ttl duration ] [ min-update-interval + duration ] [ policy ( cname | disabled | drop | given | no-op + | nodata | nxdomain | passthru | tcp-only quoted_string ) ] [ + recursive-only boolean ] [ nsip-enable boolean ] [ + nsdname-enable boolean ]; ... } [ add-soa boolean ] [ + break-dnssec boolean ] [ max-policy-ttl duration ] [ + min-update-interval duration ] [ min-ns-dots integer ] [ + nsip-wait-recurse boolean ] [ qname-wait-recurse boolean ] + [ recursive-only boolean ] [ nsip-enable boolean ] [ + nsdname-enable boolean ] [ dnsrps-enable boolean ] [ + dnsrps-options { unspecified-text } ]; + reuseport boolean; + root-delegation-only [ exclude { string; ... } ]; + root-key-sentinel boolean; + rrset-order { [ class string ] [ type string ] [ name + quoted_string ] string string; ... }; + secroots-file quoted_string; + send-cookie boolean; + serial-query-rate integer; + serial-update-method ( date | increment | unixtime ); + server-id ( quoted_string | none | hostname ); + servfail-ttl duration; + session-keyalg string; + session-keyfile ( quoted_string | none ); + session-keyname string; + sig-signing-nodes integer; + sig-signing-signatures integer; + sig-signing-type integer; + sig-validity-interval integer [ integer ]; + sortlist { address_match_element; ... }; + stacksize ( default | unlimited | sizeval ); + stale-answer-client-timeout ( disabled | off | integer ); + stale-answer-enable boolean; + stale-answer-ttl duration; + stale-cache-enable boolean; + stale-refresh-time duration; + startup-notify-rate integer; + statistics-file quoted_string; + synth-from-dnssec boolean; + tcp-advertised-timeout integer; + tcp-clients integer; + tcp-idle-timeout integer; + tcp-initial-timeout integer; + tcp-keepalive-timeout integer; + tcp-listen-queue integer; + tkey-dhkey quoted_string integer; + tkey-domain quoted_string; + tkey-gssapi-credential quoted_string; + tkey-gssapi-keytab quoted_string; + transfer-format ( many-answers | one-answer ); + transfer-message-size integer; + transfer-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + transfer-source-v6 ( ipv6_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + transfers-in integer; + transfers-out integer; + transfers-per-ns integer; + trust-anchor-telemetry boolean; // experimental + try-tcp-refresh boolean; + update-check-ksk boolean; + update-quota integer; + use-alt-transfer-source boolean; + use-v4-udp-ports { portrange; ... }; + use-v6-udp-ports { portrange; ... }; + v6-bias integer; + validate-except { string; ... }; + version ( quoted_string | none ); + zero-no-soa-ttl boolean; + zero-no-soa-ttl-cache boolean; + zone-statistics ( full | terse | none | boolean ); + }; + +PARENTAL-AGENTS +^^^^^^^^^^^^^^^ + +:: + + parental-agents string [ port integer ] [ + dscp integer ] { ( remote-servers | + ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key + string ]; ... }; + +PLUGIN +^^^^^^ + +:: + + plugin ( query ) string [ { unspecified-text + } ]; + +PRIMARIES +^^^^^^^^^ + +:: + + primaries string [ port integer ] [ dscp + integer ] { ( remote-servers | + ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key + string ]; ... }; + +SERVER +^^^^^^ + +:: + + server netprefix { + bogus boolean; + edns boolean; + edns-udp-size integer; + edns-version integer; + keys server_key; + max-udp-size integer; + notify-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ] + [ dscp integer ]; + padding integer; + provide-ixfr boolean; + query-source ( ( [ address ] ( ipv4_address | * ) [ port ( + integer | * ) ] ) | ( [ [ address ] ( ipv4_address | * ) ] + port ( integer | * ) ) ) [ dscp integer ]; + query-source-v6 ( ( [ address ] ( ipv6_address | * ) [ port ( + integer | * ) ] ) | ( [ [ address ] ( ipv6_address | * ) ] + port ( integer | * ) ) ) [ dscp integer ]; + request-expire boolean; + request-ixfr boolean; + request-nsid boolean; + send-cookie boolean; + tcp-keepalive boolean; + tcp-only boolean; + transfer-format ( many-answers | one-answer ); + transfer-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + transfer-source-v6 ( ipv6_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + transfers integer; + }; + +STATISTICS-CHANNELS +^^^^^^^^^^^^^^^^^^^ + +:: + + statistics-channels { + inet ( ipv4_address | ipv6_address | + * ) [ port ( integer | * ) ] [ + allow { address_match_element; ... + } ]; + }; + +TRUST-ANCHORS +^^^^^^^^^^^^^ + +:: + + trust-anchors { string ( static-key | + initial-key | static-ds | initial-ds ) + integer integer integer + quoted_string; ... }; + +TRUSTED-KEYS +^^^^^^^^^^^^ + +Deprecated - see DNSSEC-KEYS. + +:: + + trusted-keys { string integer + integer integer + quoted_string; ... };, deprecated + +VIEW +^^^^ + +:: + + view string [ class ] { + allow-new-zones boolean; + allow-notify { address_match_element; ... }; + allow-query { address_match_element; ... }; + allow-query-cache { address_match_element; ... }; + allow-query-cache-on { address_match_element; ... }; + allow-query-on { address_match_element; ... }; + allow-recursion { address_match_element; ... }; + allow-recursion-on { address_match_element; ... }; + allow-transfer { address_match_element; ... }; + allow-update { address_match_element; ... }; + allow-update-forwarding { address_match_element; ... }; + also-notify [ port integer ] [ dscp integer ] { ( + remote-servers | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; ... }; + alt-transfer-source ( ipv4_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + alt-transfer-source-v6 ( ipv6_address | * ) [ port ( integer | + * ) ] [ dscp integer ]; + attach-cache string; + auth-nxdomain boolean; // default changed + auto-dnssec ( allow | maintain | off );// deprecated + cache-file quoted_string;// deprecated + catalog-zones { zone string [ default-masters [ port integer ] + [ dscp integer ] { ( remote-servers | ipv4_address [ port + integer ] | ipv6_address [ port integer ] ) [ key + string ]; ... } ] [ zone-directory quoted_string ] [ + in-memory boolean ] [ min-update-interval duration ]; ... }; + check-dup-records ( fail | warn | ignore ); + check-integrity boolean; + check-mx ( fail | warn | ignore ); + check-mx-cname ( fail | warn | ignore ); + check-names ( primary | master | + secondary | slave | response ) ( + fail | warn | ignore ); + check-sibling boolean; + check-spf ( warn | ignore ); + check-srv-cname ( fail | warn | ignore ); + check-wildcard boolean; + clients-per-query integer; + deny-answer-addresses { address_match_element; ... } [ + except-from { string; ... } ]; + deny-answer-aliases { string; ... } [ except-from { string; ... + } ]; + dialup ( notify | notify-passive | passive | refresh | boolean ); + disable-algorithms string { string; + ... }; + disable-ds-digests string { string; + ... }; + disable-empty-zone string; + dlz string { + database string; + search boolean; + }; + dns64 netprefix { + break-dnssec boolean; + clients { address_match_element; ... }; + exclude { address_match_element; ... }; + mapped { address_match_element; ... }; + recursive-only boolean; + suffix ipv6_address; + }; + dns64-contact string; + dns64-server string; + dnskey-sig-validity integer; + dnsrps-enable boolean; + dnsrps-options { unspecified-text }; + dnssec-accept-expired boolean; + dnssec-dnskey-kskonly boolean; + dnssec-loadkeys-interval integer; + dnssec-must-be-secure string boolean; + dnssec-policy string; + dnssec-secure-to-insecure boolean; + dnssec-update-mode ( maintain | no-resign ); + dnssec-validation ( yes | no | auto ); + dnstap { ( all | auth | client | forwarder | resolver | update ) [ + ( query | response ) ]; ... }; + dual-stack-servers [ port integer ] { ( quoted_string [ port + integer ] [ dscp integer ] | ipv4_address [ port + integer ] [ dscp integer ] | ipv6_address [ port + integer ] [ dscp integer ] ); ... }; + dyndb string quoted_string { + unspecified-text }; + edns-udp-size integer; + empty-contact string; + empty-server string; + empty-zones-enable boolean; + fetch-quota-params integer fixedpoint fixedpoint fixedpoint; + fetches-per-server integer [ ( drop | fail ) ]; + fetches-per-zone integer [ ( drop | fail ) ]; + forward ( first | only ); + forwarders [ port integer ] [ dscp integer ] { ( ipv4_address + | ipv6_address ) [ port integer ] [ dscp integer ]; ... }; + glue-cache boolean; + ixfr-from-differences ( primary | master | secondary | slave | + boolean ); + key string { + algorithm string; + secret string; + }; + key-directory quoted_string; + lame-ttl duration; + lmdb-mapsize sizeval; + managed-keys { string ( + static-key | initial-key + | static-ds | initial-ds + ) integer integer + integer + quoted_string; ... };, deprecated + masterfile-format ( map | raw | text ); + masterfile-style ( full | relative ); + match-clients { address_match_element; ... }; + match-destinations { address_match_element; ... }; + match-recursive-only boolean; + max-cache-size ( default | unlimited | sizeval | percentage ); + max-cache-ttl duration; + max-clients-per-query integer; + max-ixfr-ratio ( unlimited | percentage ); + max-journal-size ( default | unlimited | sizeval ); + max-ncache-ttl duration; + max-records integer; + max-recursion-depth integer; + max-recursion-queries integer; + max-refresh-time integer; + max-retry-time integer; + max-stale-ttl duration; + max-transfer-idle-in integer; + max-transfer-idle-out integer; + max-transfer-time-in integer; + max-transfer-time-out integer; + max-udp-size integer; + max-zone-ttl ( unlimited | duration ); + message-compression boolean; + min-cache-ttl duration; + min-ncache-ttl duration; + min-refresh-time integer; + min-retry-time integer; + minimal-any boolean; + minimal-responses ( no-auth | no-auth-recursive | boolean ); + multi-master boolean; + new-zones-directory quoted_string; + no-case-compress { address_match_element; ... }; + nocookie-udp-size integer; + notify ( explicit | master-only | primary-only | boolean ); + notify-delay integer; + notify-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ] + [ dscp integer ]; + notify-to-soa boolean; + nta-lifetime duration; + nta-recheck duration; + nxdomain-redirect string; + parental-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + parental-source-v6 ( ipv6_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + plugin ( query ) string [ { + unspecified-text } ]; + preferred-glue string; + prefetch integer [ integer ]; + provide-ixfr boolean; + qname-minimization ( strict | relaxed | disabled | off ); + query-source ( ( [ address ] ( ipv4_address | * ) [ port ( + integer | * ) ] ) | ( [ [ address ] ( ipv4_address | * ) ] + port ( integer | * ) ) ) [ dscp integer ]; + query-source-v6 ( ( [ address ] ( ipv6_address | * ) [ port ( + integer | * ) ] ) | ( [ [ address ] ( ipv6_address | * ) ] + port ( integer | * ) ) ) [ dscp integer ]; + rate-limit { + all-per-second integer; + errors-per-second integer; + exempt-clients { address_match_element; ... }; + ipv4-prefix-length integer; + ipv6-prefix-length integer; + log-only boolean; + max-table-size integer; + min-table-size integer; + nodata-per-second integer; + nxdomains-per-second integer; + qps-scale integer; + referrals-per-second integer; + responses-per-second integer; + slip integer; + window integer; + }; + recursion boolean; + request-expire boolean; + request-ixfr boolean; + request-nsid boolean; + require-server-cookie boolean; + resolver-nonbackoff-tries integer; + resolver-query-timeout integer; + resolver-retry-interval integer; + response-padding { address_match_element; ... } block-size + integer; + response-policy { zone string [ add-soa boolean ] [ log + boolean ] [ max-policy-ttl duration ] [ min-update-interval + duration ] [ policy ( cname | disabled | drop | given | no-op + | nodata | nxdomain | passthru | tcp-only quoted_string ) ] [ + recursive-only boolean ] [ nsip-enable boolean ] [ + nsdname-enable boolean ]; ... } [ add-soa boolean ] [ + break-dnssec boolean ] [ max-policy-ttl duration ] [ + min-update-interval duration ] [ min-ns-dots integer ] [ + nsip-wait-recurse boolean ] [ qname-wait-recurse boolean ] + [ recursive-only boolean ] [ nsip-enable boolean ] [ + nsdname-enable boolean ] [ dnsrps-enable boolean ] [ + dnsrps-options { unspecified-text } ]; + root-delegation-only [ exclude { string; ... } ]; + root-key-sentinel boolean; + rrset-order { [ class string ] [ type string ] [ name + quoted_string ] string string; ... }; + send-cookie boolean; + serial-update-method ( date | increment | unixtime ); + server netprefix { + bogus boolean; + edns boolean; + edns-udp-size integer; + edns-version integer; + keys server_key; + max-udp-size integer; + notify-source ( ipv4_address | * ) [ port ( integer | * + ) ] [ dscp integer ]; + notify-source-v6 ( ipv6_address | * ) [ port ( integer + | * ) ] [ dscp integer ]; + padding integer; + provide-ixfr boolean; + query-source ( ( [ address ] ( ipv4_address | * ) [ port + ( integer | * ) ] ) | ( [ [ address ] ( + ipv4_address | * ) ] port ( integer | * ) ) ) [ + dscp integer ]; + query-source-v6 ( ( [ address ] ( ipv6_address | * ) [ + port ( integer | * ) ] ) | ( [ [ address ] ( + ipv6_address | * ) ] port ( integer | * ) ) ) [ + dscp integer ]; + request-expire boolean; + request-ixfr boolean; + request-nsid boolean; + send-cookie boolean; + tcp-keepalive boolean; + tcp-only boolean; + transfer-format ( many-answers | one-answer ); + transfer-source ( ipv4_address | * ) [ port ( integer | + * ) ] [ dscp integer ]; + transfer-source-v6 ( ipv6_address | * ) [ port ( + integer | * ) ] [ dscp integer ]; + transfers integer; + }; + servfail-ttl duration; + sig-signing-nodes integer; + sig-signing-signatures integer; + sig-signing-type integer; + sig-validity-interval integer [ integer ]; + sortlist { address_match_element; ... }; + stale-answer-client-timeout ( disabled | off | integer ); + stale-answer-enable boolean; + stale-answer-ttl duration; + stale-cache-enable boolean; + stale-refresh-time duration; + synth-from-dnssec boolean; + transfer-format ( many-answers | one-answer ); + transfer-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + transfer-source-v6 ( ipv6_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + trust-anchor-telemetry boolean; // experimental + trust-anchors { string ( static-key | + initial-key | static-ds | initial-ds + ) integer integer integer + quoted_string; ... }; + trusted-keys { string + integer integer + integer + quoted_string; ... };, deprecated + try-tcp-refresh boolean; + update-check-ksk boolean; + use-alt-transfer-source boolean; + v6-bias integer; + validate-except { string; ... }; + zero-no-soa-ttl boolean; + zero-no-soa-ttl-cache boolean; + zone string [ class ] { + allow-notify { address_match_element; ... }; + allow-query { address_match_element; ... }; + allow-query-on { address_match_element; ... }; + allow-transfer { address_match_element; ... }; + allow-update { address_match_element; ... }; + allow-update-forwarding { address_match_element; ... }; + also-notify [ port integer ] [ dscp integer ] { ( + remote-servers | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; + ... }; + alt-transfer-source ( ipv4_address | * ) [ port ( + integer | * ) ] [ dscp integer ]; + alt-transfer-source-v6 ( ipv6_address | * ) [ port ( + integer | * ) ] [ dscp integer ]; + auto-dnssec ( allow | maintain | off );// deprecated + check-dup-records ( fail | warn | ignore ); + check-integrity boolean; + check-mx ( fail | warn | ignore ); + check-mx-cname ( fail | warn | ignore ); + check-names ( fail | warn | ignore ); + check-sibling boolean; + check-spf ( warn | ignore ); + check-srv-cname ( fail | warn | ignore ); + check-wildcard boolean; + database string; + delegation-only boolean; + dialup ( notify | notify-passive | passive | refresh | + boolean ); + dlz string; + dnskey-sig-validity integer; + dnssec-dnskey-kskonly boolean; + dnssec-loadkeys-interval integer; + dnssec-policy string; + dnssec-secure-to-insecure boolean; + dnssec-update-mode ( maintain | no-resign ); + file quoted_string; + forward ( first | only ); + forwarders [ port integer ] [ dscp integer ] { ( + ipv4_address | ipv6_address ) [ port integer ] [ + dscp integer ]; ... }; + in-view string; + inline-signing boolean; + ixfr-from-differences boolean; + journal quoted_string; + key-directory quoted_string; + masterfile-format ( map | raw | text ); + masterfile-style ( full | relative ); + masters [ port integer ] [ dscp integer ] { ( + remote-servers | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; + ... }; + max-ixfr-ratio ( unlimited | percentage ); + max-journal-size ( default | unlimited | sizeval ); + max-records integer; + max-refresh-time integer; + max-retry-time integer; + max-transfer-idle-in integer; + max-transfer-idle-out integer; + max-transfer-time-in integer; + max-transfer-time-out integer; + max-zone-ttl ( unlimited | duration ); + min-refresh-time integer; + min-retry-time integer; + multi-master boolean; + notify ( explicit | master-only | primary-only | boolean ); + notify-delay integer; + notify-source ( ipv4_address | * ) [ port ( integer | * + ) ] [ dscp integer ]; + notify-source-v6 ( ipv6_address | * ) [ port ( integer + | * ) ] [ dscp integer ]; + notify-to-soa boolean; + parental-agents [ port integer ] [ dscp integer ] { ( + remote-servers | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; + ... }; + parental-source ( ipv4_address | * ) [ port ( integer | + * ) ] [ dscp integer ]; + parental-source-v6 ( ipv6_address | * ) [ port ( + integer | * ) ] [ dscp integer ]; + primaries [ port integer ] [ dscp integer ] { ( + remote-servers | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; + ... }; + request-expire boolean; + request-ixfr boolean; + serial-update-method ( date | increment | unixtime ); + server-addresses { ( ipv4_address | ipv6_address ); ... }; + server-names { string; ... }; + sig-signing-nodes integer; + sig-signing-signatures integer; + sig-signing-type integer; + sig-validity-interval integer [ integer ]; + transfer-source ( ipv4_address | * ) [ port ( integer | + * ) ] [ dscp integer ]; + transfer-source-v6 ( ipv6_address | * ) [ port ( + integer | * ) ] [ dscp integer ]; + try-tcp-refresh boolean; + type ( primary | master | secondary | slave | mirror | + delegation-only | forward | hint | redirect | + static-stub | stub ); + update-check-ksk boolean; + update-policy ( local | { ( deny | grant ) string ( + 6to4-self | external | krb5-self | krb5-selfsub | + krb5-subdomain | ms-self | ms-selfsub | ms-subdomain | + name | self | selfsub | selfwild | subdomain | tcp-self + | wildcard | zonesub ) [ string ] rrtypelist; ... } ); + use-alt-transfer-source boolean; + zero-no-soa-ttl boolean; + zone-statistics ( full | terse | none | boolean ); + }; + zone-statistics ( full | terse | none | boolean ); + }; + +ZONE +^^^^ + +:: + + zone string [ class ] { + allow-notify { address_match_element; ... }; + allow-query { address_match_element; ... }; + allow-query-on { address_match_element; ... }; + allow-transfer { address_match_element; ... }; + allow-update { address_match_element; ... }; + allow-update-forwarding { address_match_element; ... }; + also-notify [ port integer ] [ dscp integer ] { ( + remote-servers | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; ... }; + alt-transfer-source ( ipv4_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + alt-transfer-source-v6 ( ipv6_address | * ) [ port ( integer | + * ) ] [ dscp integer ]; + auto-dnssec ( allow | maintain | off );// deprecated + check-dup-records ( fail | warn | ignore ); + check-integrity boolean; + check-mx ( fail | warn | ignore ); + check-mx-cname ( fail | warn | ignore ); + check-names ( fail | warn | ignore ); + check-sibling boolean; + check-spf ( warn | ignore ); + check-srv-cname ( fail | warn | ignore ); + check-wildcard boolean; + database string; + delegation-only boolean; + dialup ( notify | notify-passive | passive | refresh | boolean ); + dlz string; + dnskey-sig-validity integer; + dnssec-dnskey-kskonly boolean; + dnssec-loadkeys-interval integer; + dnssec-policy string; + dnssec-secure-to-insecure boolean; + dnssec-update-mode ( maintain | no-resign ); + file quoted_string; + forward ( first | only ); + forwarders [ port integer ] [ dscp integer ] { ( ipv4_address + | ipv6_address ) [ port integer ] [ dscp integer ]; ... }; + in-view string; + inline-signing boolean; + ixfr-from-differences boolean; + journal quoted_string; + key-directory quoted_string; + masterfile-format ( map | raw | text ); + masterfile-style ( full | relative ); + masters [ port integer ] [ dscp integer ] { ( remote-servers + | ipv4_address [ port integer ] | ipv6_address [ port + integer ] ) [ key string ]; ... }; + max-ixfr-ratio ( unlimited | percentage ); + max-journal-size ( default | unlimited | sizeval ); + max-records integer; + max-refresh-time integer; + max-retry-time integer; + max-transfer-idle-in integer; + max-transfer-idle-out integer; + max-transfer-time-in integer; + max-transfer-time-out integer; + max-zone-ttl ( unlimited | duration ); + min-refresh-time integer; + min-retry-time integer; + multi-master boolean; + notify ( explicit | master-only | primary-only | boolean ); + notify-delay integer; + notify-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ] + [ dscp integer ]; + notify-to-soa boolean; + parental-agents [ port integer ] [ dscp integer ] { ( + remote-servers | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; ... }; + parental-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + parental-source-v6 ( ipv6_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + primaries [ port integer ] [ dscp integer ] { ( + remote-servers | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; ... }; + request-expire boolean; + request-ixfr boolean; + serial-update-method ( date | increment | unixtime ); + server-addresses { ( ipv4_address | ipv6_address ); ... }; + server-names { string; ... }; + sig-signing-nodes integer; + sig-signing-signatures integer; + sig-signing-type integer; + sig-validity-interval integer [ integer ]; + transfer-source ( ipv4_address | * ) [ port ( integer | * ) ] [ + dscp integer ]; + transfer-source-v6 ( ipv6_address | * ) [ port ( integer | * ) + ] [ dscp integer ]; + try-tcp-refresh boolean; + type ( primary | master | secondary | slave | mirror | + delegation-only | forward | hint | redirect | static-stub | + stub ); + update-check-ksk boolean; + update-policy ( local | { ( deny | grant ) string ( 6to4-self | + external | krb5-self | krb5-selfsub | krb5-subdomain | ms-self + | ms-selfsub | ms-subdomain | name | self | selfsub | selfwild + | subdomain | tcp-self | wildcard | zonesub ) [ string ] + rrtypelist; ... } ); + use-alt-transfer-source boolean; + zero-no-soa-ttl boolean; + zone-statistics ( full | terse | none | boolean ); + }; + +Files +~~~~~ + +``/etc/named.conf`` + +See Also +~~~~~~~~ + +:manpage:`ddns-confgen(8)`, :manpage:`named(8)`, :manpage:`named-checkconf(8)`, :manpage:`rndc(8)`, :manpage:`rndc-confgen(8)`, BIND 9 Administrator Reference Manual. + diff --git a/bin/named/named.rst b/bin/named/named.rst new file mode 100644 index 0000000..449761c --- /dev/null +++ b/bin/named/named.rst @@ -0,0 +1,248 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_named: + +named - Internet domain name server +----------------------------------- + +Synopsis +~~~~~~~~ + +:program:`named` [ [**-4**] | [**-6**] ] [**-c** config-file] [**-C**] [**-d** debug-level] [**-D** string] [**-E** engine-name] [**-f**] [**-g**] [**-L** logfile] [**-M** option] [**-m** flag] [**-n** #cpus] [**-p** port] [**-s**] [**-S** #max-socks] [**-t** directory] [**-U** #listeners] [**-u** user] [**-v**] [**-V**] [**-X** lock-file] [**-x** cache-file] + +Description +~~~~~~~~~~~ + +``named`` is a Domain Name System (DNS) server, part of the BIND 9 +distribution from ISC. For more information on the DNS, see :rfc:`1033`, +:rfc:`1034`, and :rfc:`1035`. + +When invoked without arguments, ``named`` reads the default +configuration file ``/etc/named.conf``, reads any initial data, and +listens for queries. + +Options +~~~~~~~ + +``-4`` + This option tells ``named`` to use only IPv4, even if the host machine is capable of IPv6. ``-4`` and + ``-6`` are mutually exclusive. + +``-6`` + This option tells ``named`` to use only IPv6, even if the host machine is capable of IPv4. ``-4`` and + ``-6`` are mutually exclusive. + +``-c config-file`` + This option tells ``named`` to use ``config-file`` as its configuration file instead of the default, + ``/etc/named.conf``. To ensure that the configuration file + can be reloaded after the server has changed its working directory + due to to a possible ``directory`` option in the configuration file, + ``config-file`` should be an absolute pathname. + +``-C`` + + This option prints out the default built-in configuration and exits. + + NOTE: This is for debugging purposes only and is not an + accurate representation of the actual configuration used by :iscman:`named` + at runtime. + +``-d debug-level`` + This option sets the daemon's debug level to ``debug-level``. Debugging traces from + ``named`` become more verbose as the debug level increases. + +``-D string`` + This option specifies a string that is used to identify a instance of ``named`` + in a process listing. The contents of ``string`` are not examined. + +``-E engine-name`` + When applicable, this option specifies the hardware to use for cryptographic + operations, such as a secure key store used for signing. + + When BIND 9 is built with OpenSSL, this needs to be set to the OpenSSL + engine identifier that drives the cryptographic accelerator or + hardware service module (usually ``pkcs11``). When BIND is + built with native PKCS#11 cryptography (``--enable-native-pkcs11``), it + defaults to the path of the PKCS#11 provider library specified via + ``--with-pkcs11``. + +``-f`` + This option runs the server in the foreground (i.e., do not daemonize). + +``-g`` + This option runs the server in the foreground and forces all logging to ``stderr``. + +``-L logfile`` + This option sets the log to the file ``logfile`` by default, instead of the system log. + +``-M option`` + + This option sets the default (comma-separated) memory context + options. The possible flags are: + + - ``external``: use system-provided memory allocation functions; this + is the implicit default. + + - ``internal``: use the internal memory manager. + + - ``fill``: fill blocks of memory with tag values when they are + allocated or freed, to assist debugging of memory problems; this is + the implicit default if ``named`` has been compiled with + ``--enable-developer``. + + - ``nofill``: disable the behavior enabled by ``fill``; this is the + implicit default unless ``named`` has been compiled with + ``--enable-developer``. + +``-m flag`` + This option turns on memory usage debugging flags. Possible flags are ``usage``, + ``trace``, ``record``, ``size``, and ``mctx``. These correspond to the + ``ISC_MEM_DEBUGXXXX`` flags described in ````. + +``-n #cpus`` + This option controls the number of CPUs that ``named`` assumes the + presence of. If not specified, ``named`` tries to determine the + number of CPUs present automatically; if it fails, a single CPU is + assumed to be present. + + ``named`` creates two threads per each CPU present (one thread for + receiving and sending client traffic and another thread for sending + and receiving resolver traffic) and then on top of that a single + thread for handling time-based events. + +``-p port`` + This option listens for queries on ``port``. If not specified, the default is + port 53. + +``-s`` + This option writes memory usage statistics to ``stdout`` on exit. + +.. note:: + + This option is mainly of interest to BIND 9 developers and may be + removed or changed in a future release. + +``-S #max-socks`` + This option allows ``named`` to use up to ``#max-socks`` sockets. The default value is + 21000 on systems built with default configuration options, and 4096 + on systems built with ``configure --with-tuning=small``. + +.. warning:: + + This option should be unnecessary for the vast majority of users. + The use of this option could even be harmful, because the specified + value may exceed the limitation of the underlying system API. It + is therefore set only when the default configuration causes + exhaustion of file descriptors and the operational environment is + known to support the specified number of sockets. Note also that + the actual maximum number is normally slightly fewer than the + specified value, because ``named`` reserves some file descriptors + for its internal use. + +``-t directory`` + This option tells ``named`` to chroot to ``directory`` after processing the command-line arguments, but + before reading the configuration file. + +.. warning:: + + This option should be used in conjunction with the ``-u`` option, + as chrooting a process running as root doesn't enhance security on + most systems; the way ``chroot`` is defined allows a process + with root privileges to escape a chroot jail. + +``-U #listeners`` + This option tells ``named`` the number of ``#listeners`` worker threads to listen on, for incoming UDP packets on + each address. If not specified, ``named`` calculates a default + value based on the number of detected CPUs: 1 for 1 CPU, and the + number of detected CPUs minus one for machines with more than 1 CPU. + This cannot be increased to a value higher than the number of CPUs. + If ``-n`` has been set to a higher value than the number of detected + CPUs, then ``-U`` may be increased as high as that value, but no + higher. On Windows, the number of UDP listeners is hardwired to 1 and + this option has no effect. + +``-u user`` + This option sets the setuid to ``user`` after completing privileged operations, such as + creating sockets that listen on privileged ports. + +.. note:: + + On Linux, ``named`` uses the kernel's capability mechanism to drop + all root privileges except the ability to ``bind`` to a + privileged port and set process resource limits. Unfortunately, + this means that the ``-u`` option only works when ``named`` is run + on kernel 2.2.18 or later, or kernel 2.3.99-pre3 or later, since + previous kernels did not allow privileges to be retained after + ``setuid``. + +``-v`` + This option reports the version number and exits. + +``-V`` + This option reports the version number, build options, supported + cryptographics algorithms, and exits. + +``-X lock-file`` + This option acquires a lock on the specified file at runtime; this helps to + prevent duplicate ``named`` instances from running simultaneously. + Use of this option overrides the ``lock-file`` option in + ``named.conf``. If set to ``none``, the lock file check is disabled. + +``-x cache-file`` + This option loads data from ``cache-file`` into the cache of the default view. + +.. warning:: + + This option must not be used in normal operations. It is only of interest to BIND 9 + developers and may be removed or changed in a future release. + +Signals +~~~~~~~ + +In routine operation, signals should not be used to control the +nameserver; ``rndc`` should be used instead. + +SIGHUP + This signal forces a reload of the server. + +SIGINT, SIGTERM + These signals shut down the server. + +The result of sending any other signals to the server is undefined. + +Configuration +~~~~~~~~~~~~~ + +The ``named`` configuration file is too complex to describe in detail +here. A complete description is provided in the BIND 9 Administrator +Reference Manual. + +``named`` inherits the ``umask`` (file creation mode mask) from the +parent process. If files created by ``named``, such as journal files, +need to have custom permissions, the ``umask`` should be set explicitly +in the script used to start the ``named`` process. + +Files +~~~~~ + +``/etc/named.conf`` + The default configuration file. + +``/var/run/named/named.pid`` + The default process-id file. + +See Also +~~~~~~~~ + +:rfc:`1033`, :rfc:`1034`, :rfc:`1035`, :manpage:`named-checkconf(8)`, :manpage:`named-checkzone(8)`, :manpage:`rndc(8)`, :manpage:`named.conf(5)`, BIND 9 Administrator Reference Manual. diff --git a/bin/named/server.c b/bin/named/server.c new file mode 100644 index 0000000..7306e0a --- /dev/null +++ b/bin/named/server.c @@ -0,0 +1,16272 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_DNSTAP +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#if defined(HAVE_GEOIP2) +#include +#endif /* HAVE_GEOIP2 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBSCF +#include + +#include +#endif /* ifdef HAVE_LIBSCF */ + +#ifdef HAVE_LMDB +#include + +#include +#define count_newzones count_newzones_db +#define configure_newzones configure_newzones_db +#define dumpzone dumpzone_db +#else /* HAVE_LMDB */ +#define count_newzones count_newzones_file +#define configure_newzones configure_newzones_file +#define dumpzone dumpzone_file +#endif /* HAVE_LMDB */ + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t)-1) +#endif /* ifndef SIZE_MAX */ + +#ifndef SIZE_AS_PERCENT +#define SIZE_AS_PERCENT ((size_t)-2) +#endif /* ifndef SIZE_AS_PERCENT */ + +#ifdef TUNE_LARGE +#define RESOLVER_NTASKS_PERCPU 32 +#define UDPBUFFERS 32768 +#define EXCLBUFFERS 32768 +#else +#define RESOLVER_NTASKS_PERCPU 8 +#define UDPBUFFERS 1000 +#define EXCLBUFFERS 4096 +#endif /* TUNE_LARGE */ + +/* RFC7828 defines timeout as 16-bit value specified in units of 100 + * milliseconds, so the maximum and minimum advertised and keepalive + * timeouts are capped by the data type (it's ~109 minutes) + */ +#define MIN_INITIAL_TIMEOUT UINT32_C(2500) /* 2.5 seconds */ +#define MAX_INITIAL_TIMEOUT UINT32_C(120000) /* 2 minutes */ +#define MIN_IDLE_TIMEOUT UINT32_C(100) /* 0.1 seconds */ +#define MAX_IDLE_TIMEOUT UINT32_C(120000) /* 2 minutes */ +#define MIN_KEEPALIVE_TIMEOUT UINT32_C(100) /* 0.1 seconds */ +#define MAX_KEEPALIVE_TIMEOUT UINT32_C(UINT16_MAX * 100) +#define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */ +#define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100) + +/*% + * Check an operation for failure. Assumes that the function + * using it has a 'result' variable and a 'cleanup' label. + */ +#define CHECK(op) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +#define TCHECK(op) \ + do { \ + tresult = (op); \ + if (tresult != ISC_R_SUCCESS) { \ + isc_buffer_clear(*text); \ + goto cleanup; \ + } \ + } while (0) + +#define CHECKM(op, msg) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) { \ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \ + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, \ + "%s: %s", msg, \ + isc_result_totext(result)); \ + goto cleanup; \ + } \ + } while (0) + +#define CHECKMF(op, msg, file) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) { \ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \ + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, \ + "%s '%s': %s", msg, file, \ + isc_result_totext(result)); \ + goto cleanup; \ + } \ + } while (0) + +#define CHECKFATAL(op, msg) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) \ + fatal(server, msg, result); \ + } while (0) + +/*% + * Maximum ADB size for views that share a cache. Use this limit to suppress + * the total of memory footprint, which should be the main reason for sharing + * a cache. Only effective when a finite max-cache-size is specified. + * This is currently defined to be 8MB. + */ +#define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U + +struct named_dispatch { + isc_sockaddr_t addr; + unsigned int dispatchgen; + dns_dispatch_t *dispatch; + ISC_LINK(struct named_dispatch) link; +}; + +struct named_cache { + dns_cache_t *cache; + dns_view_t *primaryview; + bool needflush; + bool adbsizeadjusted; + dns_rdataclass_t rdclass; + ISC_LINK(named_cache_t) link; +}; + +struct dumpcontext { + isc_mem_t *mctx; + bool dumpcache; + bool dumpzones; + bool dumpadb; + bool dumpbad; + bool dumpexpired; + bool dumpfail; + FILE *fp; + ISC_LIST(struct viewlistentry) viewlist; + struct viewlistentry *view; + struct zonelistentry *zone; + dns_dumpctx_t *mdctx; + dns_db_t *db; + dns_db_t *cache; + isc_task_t *task; + dns_dbversion_t *version; +}; + +struct viewlistentry { + dns_view_t *view; + ISC_LINK(struct viewlistentry) link; + ISC_LIST(struct zonelistentry) zonelist; +}; + +struct zonelistentry { + dns_zone_t *zone; + ISC_LINK(struct zonelistentry) link; +}; + +/*% + * Configuration context to retain for each view that allows + * new zones to be added at runtime. + */ +typedef struct ns_cfgctx { + isc_mem_t *mctx; + cfg_parser_t *conf_parser; + cfg_parser_t *add_parser; + cfg_obj_t *config; + cfg_obj_t *vconfig; + cfg_obj_t *nzf_config; + cfg_aclconfctx_t *actx; +} ns_cfgctx_t; + +/*% + * A function to write out added-zone configuration to the new_zone_file + * specified in 'view'. Maybe called by delete_zoneconf(). + */ +typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view); + +/*% + * Holds state information for the initial zone loading process. + * Uses the isc_refcount structure to count the number of views + * with pending zone loads, dereferencing as each view finishes. + */ +typedef struct { + named_server_t *server; + bool reconfig; + isc_refcount_t refs; +} ns_zoneload_t; + +typedef struct { + named_server_t *server; +} catz_cb_data_t; + +typedef struct catz_chgzone_event { + ISC_EVENT_COMMON(struct catz_chgzone_event); + dns_catz_entry_t *entry; + dns_catz_zone_t *origin; + dns_view_t *view; + catz_cb_data_t *cbd; + bool mod; +} catz_chgzone_event_t; + +typedef struct { + unsigned int magic; +#define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r') + isc_buffer_t **text; + isc_result_t result; +} ns_dzarg_t; + +/* + * These zones should not leak onto the Internet. + */ +const char *empty_zones[] = { + /* RFC 1918 */ + "10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA", + "18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA", + "21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA", + "24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA", + "27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA", + "30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA", + + /* RFC 6598 */ + "64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA", + "67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA", + "70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA", + "73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA", + "76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA", + "79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA", + "82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA", + "85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA", + "88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA", + "91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA", + "94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA", + "97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA", + "100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA", "102.100.IN-ADDR.ARPA", + "103.100.IN-ADDR.ARPA", "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA", + "106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA", "108.100.IN-ADDR.ARPA", + "109.100.IN-ADDR.ARPA", "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA", + "112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA", "114.100.IN-ADDR.ARPA", + "115.100.IN-ADDR.ARPA", "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA", + "118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA", "120.100.IN-ADDR.ARPA", + "121.100.IN-ADDR.ARPA", "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA", + "124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA", "126.100.IN-ADDR.ARPA", + "127.100.IN-ADDR.ARPA", + + /* RFC 5735 and RFC 5737 */ + "0.IN-ADDR.ARPA", /* THIS NETWORK */ + "127.IN-ADDR.ARPA", /* LOOPBACK */ + "254.169.IN-ADDR.ARPA", /* LINK LOCAL */ + "2.0.192.IN-ADDR.ARPA", /* TEST NET */ + "100.51.198.IN-ADDR.ARPA", /* TEST NET 2 */ + "113.0.203.IN-ADDR.ARPA", /* TEST NET 3 */ + "255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */ + + /* Local IPv6 Unicast Addresses */ + "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6." + "ARPA", + "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6." + "ARPA", + /* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */ + "D.F.IP6.ARPA", "8.E.F.IP6.ARPA", /* LINK LOCAL */ + "9.E.F.IP6.ARPA", /* LINK LOCAL */ + "A.E.F.IP6.ARPA", /* LINK LOCAL */ + "B.E.F.IP6.ARPA", /* LINK LOCAL */ + + /* Example Prefix, RFC 3849. */ + "8.B.D.0.1.0.0.2.IP6.ARPA", + + /* RFC 7534 */ + "EMPTY.AS112.ARPA", + + /* RFC 8375 */ + "HOME.ARPA", + + NULL +}; + +ISC_PLATFORM_NORETURN_PRE static void +fatal(named_server_t *server, const char *msg, + isc_result_t result) ISC_PLATFORM_NORETURN_POST; + +static void +named_server_reload(isc_task_t *task, isc_event_t *event); + +static isc_result_t +ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, + uint16_t family, ns_listenelt_t **target); +static isc_result_t +ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, + uint16_t family, ns_listenlist_t **target); + +static isc_result_t +configure_forward(const cfg_obj_t *config, dns_view_t *view, + const dns_name_t *origin, const cfg_obj_t *forwarders, + const cfg_obj_t *forwardtype); + +static isc_result_t +configure_alternates(const cfg_obj_t *config, dns_view_t *view, + const cfg_obj_t *alternates); + +static isc_result_t +configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, + const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, + dns_viewlist_t *viewlist, dns_kasplist_t *kasplist, + cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok, + bool modify); + +static void +configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig, + dns_view_t *view); + +static isc_result_t +configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, + isc_mem_t *mctx, cfg_aclconfctx_t *actx); + +static isc_result_t +add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx); + +static void +end_reserved_dispatches(named_server_t *server, bool all); + +static void +newzone_cfgctx_destroy(void **cfgp); + +static isc_result_t +putstr(isc_buffer_t **b, const char *str); + +static isc_result_t +putmem(isc_buffer_t **b, const char *str, size_t len); + +static isc_result_t +putuint8(isc_buffer_t **b, uint8_t val); + +static isc_result_t +putnull(isc_buffer_t **b); + +static int +count_zones(const cfg_obj_t *conf); + +#ifdef HAVE_LMDB +static isc_result_t +migrate_nzf(dns_view_t *view); + +static isc_result_t +nzd_writable(dns_view_t *view); + +static isc_result_t +nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi); + +static isc_result_t +nzd_env_reopen(dns_view_t *view); + +static void +nzd_env_close(dns_view_t *view); + +static isc_result_t +nzd_close(MDB_txn **txnp, bool commit); + +static isc_result_t +nzd_count(dns_view_t *view, int *countp); +#else /* ifdef HAVE_LMDB */ +static isc_result_t +nzf_append(dns_view_t *view, const cfg_obj_t *zconfig); +#endif /* ifdef HAVE_LMDB */ + +/*% + * Configure a single view ACL at '*aclp'. Get its configuration from + * 'vconfig' (for per-view configuration) and maybe from 'config' + */ +static isc_result_t +configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, + const cfg_obj_t *gconfig, const char *aclname, + const char *acltuplename, cfg_aclconfctx_t *actx, + isc_mem_t *mctx, dns_acl_t **aclp) { + isc_result_t result; + const cfg_obj_t *maps[4]; + const cfg_obj_t *aclobj = NULL; + int i = 0; + + if (*aclp != NULL) { + dns_acl_detach(aclp); + } + if (vconfig != NULL) { + maps[i++] = cfg_tuple_get(vconfig, "options"); + } + if (config != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) { + maps[i++] = options; + } + } + if (gconfig != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(gconfig, "options", &options); + if (options != NULL) { + maps[i++] = options; + } + } + maps[i] = NULL; + + (void)named_config_get(maps, aclname, &aclobj); + if (aclobj == NULL) { + /* + * No value available. *aclp == NULL. + */ + return (ISC_R_SUCCESS); + } + + if (acltuplename != NULL) { + /* + * If the ACL is given in an optional tuple, retrieve it. + * The parser should have ensured that a valid object be + * returned. + */ + aclobj = cfg_tuple_get(aclobj, acltuplename); + } + + result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0, + aclp); + + return (result); +} + +/*% + * Configure a sortlist at '*aclp'. Essentially the same as + * configure_view_acl() except it calls cfg_acl_fromconfig with a + * nest_level value of 2. + */ +static isc_result_t +configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, + dns_acl_t **aclp) { + isc_result_t result; + const cfg_obj_t *maps[3]; + const cfg_obj_t *aclobj = NULL; + int i = 0; + + if (*aclp != NULL) { + dns_acl_detach(aclp); + } + if (vconfig != NULL) { + maps[i++] = cfg_tuple_get(vconfig, "options"); + } + if (config != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) { + maps[i++] = options; + } + } + maps[i] = NULL; + + (void)named_config_get(maps, "sortlist", &aclobj); + if (aclobj == NULL) { + return (ISC_R_SUCCESS); + } + + /* + * Use a nest level of 3 for the "top level" of the sortlist; + * this means each entry in the top three levels will be stored + * as lists of separate, nested ACLs, rather than merged together + * into IP tables as is usually done with ACLs. + */ + result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3, + aclp); + + return (result); +} + +static isc_result_t +configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config, + const char *confname, const char *conftuplename, + isc_mem_t *mctx, dns_rbt_t **rbtp) { + isc_result_t result; + const cfg_obj_t *maps[3]; + const cfg_obj_t *obj = NULL; + const cfg_listelt_t *element; + int i = 0; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t b; + const char *str; + const cfg_obj_t *nameobj; + + if (*rbtp != NULL) { + dns_rbt_destroy(rbtp); + } + if (vconfig != NULL) { + maps[i++] = cfg_tuple_get(vconfig, "options"); + } + if (config != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) { + maps[i++] = options; + } + } + maps[i] = NULL; + + (void)named_config_get(maps, confname, &obj); + if (obj == NULL) { + /* + * No value available. *rbtp == NULL. + */ + return (ISC_R_SUCCESS); + } + + if (conftuplename != NULL) { + obj = cfg_tuple_get(obj, conftuplename); + if (cfg_obj_isvoid(obj)) { + return (ISC_R_SUCCESS); + } + } + + result = dns_rbt_create(mctx, NULL, NULL, rbtp); + if (result != ISC_R_SUCCESS) { + return (result); + } + + name = dns_fixedname_initname(&fixed); + for (element = cfg_list_first(obj); element != NULL; + element = cfg_list_next(element)) + { + nameobj = cfg_listelt_value(element); + str = cfg_obj_asstring(nameobj); + isc_buffer_constinit(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + /* + * We don't need the node data, but need to set dummy data to + * avoid a partial match with an empty node. For example, if + * we have foo.example.com and bar.example.com, we'd get a match + * for baz.example.com, which is not the expected result. + * We simply use (void *)1 as the dummy data. + */ + result = dns_rbt_addname(*rbtp, name, (void *)1); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR, + "failed to add %s for %s: %s", str, + confname, isc_result_totext(result)); + goto cleanup; + } + } + + return (result); + +cleanup: + dns_rbt_destroy(rbtp); + return (result); +} + +static isc_result_t +ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp, + unsigned char *digest, dns_rdata_ds_t *ds) { + isc_result_t result; + dns_rdata_dnskey_t keystruct; + dns_rdata_t rdata = DNS_RDATA_INIT; + uint32_t rdata1, rdata2, rdata3; + const char *datastr = NULL, *namestr = NULL; + unsigned char data[4096]; + isc_buffer_t databuf; + unsigned char rrdata[4096]; + isc_buffer_t rrdatabuf; + isc_region_t r; + dns_fixedname_t fname; + dns_name_t *name = NULL; + isc_buffer_t namebuf; + const char *atstr = NULL; + enum { + INIT_DNSKEY, + STATIC_DNSKEY, + INIT_DS, + STATIC_DS, + TRUSTED + } anchortype; + + REQUIRE(namestrp != NULL && *namestrp == NULL); + REQUIRE(ds != NULL); + + /* if DNSKEY, flags; if DS, key tag */ + rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1")); + + /* if DNSKEY, protocol; if DS, algorithm */ + rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2")); + + /* if DNSKEY, algorithm; if DS, digest type */ + rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3")); + + namestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); + *namestrp = namestr; + + name = dns_fixedname_initname(&fname); + isc_buffer_constinit(&namebuf, namestr, strlen(namestr)); + isc_buffer_add(&namebuf, strlen(namestr)); + CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL)); + + if (*initialp) { + atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype")); + + if (strcasecmp(atstr, "static-key") == 0) { + *initialp = false; + anchortype = STATIC_DNSKEY; + } else if (strcasecmp(atstr, "static-ds") == 0) { + *initialp = false; + anchortype = STATIC_DS; + } else if (strcasecmp(atstr, "initial-key") == 0) { + anchortype = INIT_DNSKEY; + } else if (strcasecmp(atstr, "initial-ds") == 0) { + anchortype = INIT_DS; + } else { + cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR, + "key '%s': " + "invalid initialization method '%s'", + namestr, atstr); + result = ISC_R_FAILURE; + goto cleanup; + } + } else { + anchortype = TRUSTED; + } + + isc_buffer_init(&databuf, data, sizeof(data)); + isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); + + *ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in, + .common.rdtype = dns_rdatatype_ds }; + + ISC_LINK_INIT(&ds->common, link); + + switch (anchortype) { + case INIT_DNSKEY: + case STATIC_DNSKEY: + case TRUSTED: + /* + * This function should never be reached for view + * class other than IN + */ + keystruct.common.rdclass = dns_rdataclass_in; + keystruct.common.rdtype = dns_rdatatype_dnskey; + + /* + * The key data in keystruct is not dynamically allocated. + */ + keystruct.mctx = NULL; + + ISC_LINK_INIT(&keystruct.common, link); + + if (rdata1 > 0xffff) { + CHECKM(ISC_R_RANGE, "key flags"); + } + if (rdata1 & DNS_KEYFLAG_REVOKE) { + CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set"); + } + if (rdata2 > 0xff) { + CHECKM(ISC_R_RANGE, "key protocol"); + } + if (rdata3 > 0xff) { + CHECKM(ISC_R_RANGE, "key algorithm"); + } + + keystruct.flags = (uint16_t)rdata1; + keystruct.protocol = (uint8_t)rdata2; + keystruct.algorithm = (uint8_t)rdata3; + + if (!dst_algorithm_supported(keystruct.algorithm)) { + CHECK(DST_R_UNSUPPORTEDALG); + } + + datastr = cfg_obj_asstring(cfg_tuple_get(key, "data")); + CHECK(isc_base64_decodestring(datastr, &databuf)); + isc_buffer_usedregion(&databuf, &r); + keystruct.datalen = r.length; + keystruct.data = r.base; + + CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass, + keystruct.common.rdtype, &keystruct, + &rrdatabuf)); + CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, + digest, ds)); + break; + + case INIT_DS: + case STATIC_DS: + if (rdata1 > 0xffff) { + CHECKM(ISC_R_RANGE, "key tag"); + } + if (rdata2 > 0xff) { + CHECKM(ISC_R_RANGE, "key algorithm"); + } + if (rdata3 > 0xff) { + CHECKM(ISC_R_RANGE, "digest type"); + } + + ds->key_tag = (uint16_t)rdata1; + ds->algorithm = (uint8_t)rdata2; + ds->digest_type = (uint8_t)rdata3; + + datastr = cfg_obj_asstring(cfg_tuple_get(key, "data")); + CHECK(isc_hex_decodestring(datastr, &databuf)); + isc_buffer_usedregion(&databuf, &r); + + switch (ds->digest_type) { + case DNS_DSDIGEST_SHA1: + if (r.length != ISC_SHA1_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; + case DNS_DSDIGEST_SHA256: + if (r.length != ISC_SHA256_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; + case DNS_DSDIGEST_SHA384: + if (r.length != ISC_SHA384_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; + default: + cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR, + "key '%s': " + "unknown ds digest type %u", + namestr, ds->digest_type); + result = ISC_R_FAILURE; + goto cleanup; + break; + } + + ds->length = r.length; + ds->digest = digest; + memmove(ds->digest, r.base, r.length); + + break; + + default: + UNREACHABLE(); + } + + return (ISC_R_SUCCESS); + +cleanup: + return (result); +} + +/*% + * Parse 'key' in the context of view configuration 'vconfig'. If successful, + * add the key to 'secroots' if both of the following conditions are true: + * + * - 'keyname_match' is NULL or it matches the owner name of 'key', + * - support for the algorithm used by 'key' is not disabled by 'resolver' + * for the owner name of 'key'. + * + * 'managed' is true for managed keys and false for trusted keys. 'mctx' is + * the memory context to use for allocating memory. + */ +static isc_result_t +process_key(const cfg_obj_t *key, dns_keytable_t *secroots, + const dns_name_t *keyname_match, dns_resolver_t *resolver, + bool managed) { + dns_fixedname_t fkeyname; + dns_name_t *keyname = NULL; + const char *namestr = NULL; + dns_rdata_ds_t ds; + isc_result_t result; + bool initializing = managed; + unsigned char digest[ISC_MAX_MD_SIZE]; + isc_buffer_t b; + + result = ta_fromconfig(key, &initializing, &namestr, digest, &ds); + + switch (result) { + case ISC_R_SUCCESS: + /* + * Trust anchor was parsed correctly. + */ + isc_buffer_constinit(&b, namestr, strlen(namestr)); + isc_buffer_add(&b, strlen(namestr)); + keyname = dns_fixedname_initname(&fkeyname); + result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + return (result); + } + break; + case DST_R_UNSUPPORTEDALG: + case DST_R_BADKEYTYPE: + /* + * Key was parsed correctly, but it cannot be used; this is not + * a fatal error - log a warning about this key being ignored, + * but do not prevent any further ones from being processed. + */ + cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING, + "ignoring %s for '%s': %s", + initializing ? "initial-key" : "static-key", + namestr, isc_result_totext(result)); + return (ISC_R_SUCCESS); + case DST_R_NOCRYPTO: + /* + * Crypto support is not available. + */ + cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR, + "ignoring %s for '%s': no crypto support", + initializing ? "initial-key" : "static-key", + namestr); + return (result); + default: + /* + * Something unexpected happened; we have no choice but to + * indicate an error so that the configuration loading process + * is interrupted. + */ + cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR, + "configuring %s for '%s': %s", + initializing ? "initial-key" : "static-key", + namestr, isc_result_totext(result)); + return (ISC_R_FAILURE); + } + + /* + * If the caller requested to only load keys for a specific name and + * the owner name of this key does not match the requested name, do not + * load it. + */ + if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) { + goto done; + } + + /* + * Ensure that 'resolver' allows using the algorithm of this key for + * its owner name. If it does not, do not load the key and log a + * warning, but do not prevent further keys from being processed. + */ + if (!dns_resolver_algorithm_supported(resolver, keyname, ds.algorithm)) + { + cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING, + "ignoring %s for '%s': algorithm is disabled", + initializing ? "initial-key" : "static-key", + namestr); + goto done; + } + + /* + * Add the key to 'secroots'. Keys from a "trust-anchors" or + * "managed-keys" statement may be either static or initializing + * keys. If it's not initializing, we don't want to treat it as + * managed, so we use 'initializing' twice here, for both the + * 'managed' and 'initializing' arguments to dns_keytable_add(). + */ + result = dns_keytable_add(secroots, initializing, initializing, keyname, + &ds); + +done: + return (result); +} + +/* + * Load keys from configuration into key table. If 'keyname' is specified, + * only load keys matching that name. If 'managed' is true, load the key as + * an initializing key. + */ +static isc_result_t +load_view_keys(const cfg_obj_t *keys, dns_view_t *view, bool managed, + const dns_name_t *keyname) { + const cfg_listelt_t *elt, *elt2; + const cfg_obj_t *keylist; + isc_result_t result; + dns_keytable_t *secroots = NULL; + + CHECK(dns_view_getsecroots(view, &secroots)); + + for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt)) + { + keylist = cfg_listelt_value(elt); + + for (elt2 = cfg_list_first(keylist); elt2 != NULL; + elt2 = cfg_list_next(elt2)) + { + CHECK(process_key(cfg_listelt_value(elt2), secroots, + keyname, view->resolver, managed)); + } + } + +cleanup: + if (secroots != NULL) { + dns_keytable_detach(&secroots); + } + if (result == DST_R_NOCRYPTO) { + result = ISC_R_SUCCESS; + } + return (result); +} + +/*% + * Check whether a key has been successfully loaded. + */ +static bool +keyloaded(dns_view_t *view, const dns_name_t *name) { + isc_result_t result; + dns_keytable_t *secroots = NULL; + dns_keynode_t *keynode = NULL; + + result = dns_view_getsecroots(view, &secroots); + if (result != ISC_R_SUCCESS) { + return (false); + } + + result = dns_keytable_find(secroots, name, &keynode); + + if (keynode != NULL) { + dns_keytable_detachkeynode(secroots, &keynode); + } + if (secroots != NULL) { + dns_keytable_detach(&secroots); + } + + return (result == ISC_R_SUCCESS); +} + +/*% + * Configure DNSSEC keys for a view. + * + * The per-view configuration values and the server-global defaults are read + * from 'vconfig' and 'config'. + */ +static isc_result_t +configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig, + const cfg_obj_t *config, const cfg_obj_t *bindkeys, + bool auto_root, isc_mem_t *mctx) { + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *view_keys = NULL; + const cfg_obj_t *global_keys = NULL; + const cfg_obj_t *view_managed_keys = NULL; + const cfg_obj_t *view_trust_anchors = NULL; + const cfg_obj_t *global_managed_keys = NULL; + const cfg_obj_t *global_trust_anchors = NULL; + const cfg_obj_t *maps[4]; + const cfg_obj_t *voptions = NULL; + const cfg_obj_t *options = NULL; + const cfg_obj_t *obj = NULL; + const char *directory; + int i = 0; + + /* We don't need trust anchors for the _bind view */ + if (strcmp(view->name, "_bind") == 0 && + view->rdclass == dns_rdataclass_chaos) + { + return (ISC_R_SUCCESS); + } + + if (vconfig != NULL) { + voptions = cfg_tuple_get(vconfig, "options"); + if (voptions != NULL) { + (void)cfg_map_get(voptions, "trusted-keys", &view_keys); + + /* managed-keys and trust-anchors are synonyms. */ + (void)cfg_map_get(voptions, "managed-keys", + &view_managed_keys); + (void)cfg_map_get(voptions, "trust-anchors", + &view_trust_anchors); + + maps[i++] = voptions; + } + } + + if (config != NULL) { + (void)cfg_map_get(config, "trusted-keys", &global_keys); + + /* managed-keys and trust-anchors are synonyms. */ + (void)cfg_map_get(config, "managed-keys", &global_managed_keys); + (void)cfg_map_get(config, "trust-anchors", + &global_trust_anchors); + + (void)cfg_map_get(config, "options", &options); + if (options != NULL) { + maps[i++] = options; + } + } + + maps[i++] = named_g_defaults; + maps[i] = NULL; + + result = dns_view_initsecroots(view, mctx); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "couldn't create keytable"); + return (ISC_R_UNEXPECTED); + } + + result = dns_view_initntatable(view, named_g_taskmgr, named_g_timermgr); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "couldn't create NTA table"); + return (ISC_R_UNEXPECTED); + } + + if (auto_root && view->rdclass == dns_rdataclass_in) { + const cfg_obj_t *builtin_keys = NULL; + + /* + * If bind.keys exists and is populated, it overrides + * the trust-anchors clause hard-coded in named_g_config. + */ + if (bindkeys != NULL) { + isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "obtaining root key for view %s " + "from '%s'", + view->name, named_g_server->bindkeysfile); + + (void)cfg_map_get(bindkeys, "trust-anchors", + &builtin_keys); + + if (builtin_keys == NULL) { + isc_log_write( + named_g_lctx, DNS_LOGCATEGORY_SECURITY, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "dnssec-validation auto: " + "WARNING: root zone key " + "not found"); + } + } + + if (builtin_keys == NULL) { + isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "using built-in root key for view %s", + view->name); + + (void)cfg_map_get(named_g_config, "trust-anchors", + &builtin_keys); + } + + if (builtin_keys != NULL) { + CHECK(load_view_keys(builtin_keys, view, true, + dns_rootname)); + } + + if (!keyloaded(view, dns_rootname)) { + isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "root key not loaded"); + result = ISC_R_FAILURE; + goto cleanup; + } + } + + if (view->rdclass == dns_rdataclass_in) { + CHECK(load_view_keys(view_keys, view, false, NULL)); + CHECK(load_view_keys(view_trust_anchors, view, true, NULL)); + CHECK(load_view_keys(view_managed_keys, view, true, NULL)); + + CHECK(load_view_keys(global_keys, view, false, NULL)); + CHECK(load_view_keys(global_trust_anchors, view, true, NULL)); + CHECK(load_view_keys(global_managed_keys, view, true, NULL)); + } + + /* + * Add key zone for managed keys. + */ + obj = NULL; + (void)named_config_get(maps, "managed-keys-directory", &obj); + directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL); + if (directory != NULL) { + result = isc_file_isdirectory(directory); + } + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "invalid managed-keys-directory %s: %s", + directory, isc_result_totext(result)); + goto cleanup; + } else if (directory != NULL) { + if (!isc_file_isdirwritable(directory)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "managed-keys-directory '%s' " + "is not writable", + directory); + result = ISC_R_NOPERM; + goto cleanup; + } + } + + CHECK(add_keydata_zone(view, directory, named_g_mctx)); + +cleanup: + return (result); +} + +static isc_result_t +mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) { + const cfg_listelt_t *element; + const cfg_obj_t *obj; + const char *str; + dns_fixedname_t fixed; + dns_name_t *name; + bool value; + isc_result_t result; + isc_buffer_t b; + + name = dns_fixedname_initname(&fixed); + for (element = cfg_list_first(mbs); element != NULL; + element = cfg_list_next(element)) + { + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); + isc_buffer_constinit(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + value = cfg_obj_asboolean(cfg_tuple_get(obj, "value")); + CHECK(dns_resolver_setmustbesecure(resolver, name, value)); + } + + result = ISC_R_SUCCESS; + +cleanup: + return (result); +} + +/*% + * Get a dispatch appropriate for the resolver of a given view. + */ +static isc_result_t +get_view_querysource_dispatch(const cfg_obj_t **maps, int af, + dns_dispatch_t **dispatchp, isc_dscp_t *dscpp, + bool is_firstview) { + isc_result_t result = ISC_R_FAILURE; + dns_dispatch_t *disp; + isc_sockaddr_t sa; + unsigned int attrs, attrmask; + const cfg_obj_t *obj = NULL; + unsigned int maxdispatchbuffers = UDPBUFFERS; + isc_dscp_t dscp = -1; + + switch (af) { + case AF_INET: + result = named_config_get(maps, "query-source", &obj); + INSIST(result == ISC_R_SUCCESS); + break; + case AF_INET6: + result = named_config_get(maps, "query-source-v6", &obj); + INSIST(result == ISC_R_SUCCESS); + break; + default: + UNREACHABLE(); + } + + sa = *(cfg_obj_assockaddr(obj)); + INSIST(isc_sockaddr_pf(&sa) == af); + + dscp = cfg_obj_getdscp(obj); + if (dscp != -1 && dscpp != NULL) { + *dscpp = dscp; + } + + /* + * If we don't support this address family, we're done! + */ + switch (af) { + case AF_INET: + result = isc_net_probeipv4(); + break; + case AF_INET6: + result = isc_net_probeipv6(); + break; + default: + UNREACHABLE(); + } + if (result != ISC_R_SUCCESS) { + return (ISC_R_SUCCESS); + } + + /* + * Try to find a dispatcher that we can share. + */ + attrs = 0; + attrs |= DNS_DISPATCHATTR_UDP; + switch (af) { + case AF_INET: + attrs |= DNS_DISPATCHATTR_IPV4; + break; + case AF_INET6: + attrs |= DNS_DISPATCHATTR_IPV6; + break; + } + if (isc_sockaddr_getport(&sa) == 0) { + attrs |= DNS_DISPATCHATTR_EXCLUSIVE; + maxdispatchbuffers = EXCLBUFFERS; + } else { + INSIST(obj != NULL); + if (is_firstview) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO, + "using specific query-source port " + "suppresses port randomization and can be " + "insecure."); + } + } + + attrmask = 0; + attrmask |= DNS_DISPATCHATTR_UDP; + attrmask |= DNS_DISPATCHATTR_TCP; + attrmask |= DNS_DISPATCHATTR_IPV4; + attrmask |= DNS_DISPATCHATTR_IPV6; + + disp = NULL; + result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr, + named_g_taskmgr, &sa, 4096, + maxdispatchbuffers, 32768, 16411, 16433, + attrs, attrmask, &disp); + if (result != ISC_R_SUCCESS) { + isc_sockaddr_t any; + char buf[ISC_SOCKADDR_FORMATSIZE]; + + switch (af) { + case AF_INET: + isc_sockaddr_any(&any); + break; + case AF_INET6: + isc_sockaddr_any6(&any); + break; + } + if (isc_sockaddr_equal(&sa, &any)) { + return (ISC_R_SUCCESS); + } + isc_sockaddr_format(&sa, buf, sizeof(buf)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "could not get query source dispatcher (%s)", + buf); + return (result); + } + + *dispatchp = disp; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +configure_order(dns_order_t *order, const cfg_obj_t *ent) { + dns_rdataclass_t rdclass; + dns_rdatatype_t rdtype; + const cfg_obj_t *obj; + dns_fixedname_t fixed; + unsigned int mode = 0; + const char *str; + isc_buffer_t b; + isc_result_t result; + bool addroot; + + result = named_config_getclass(cfg_tuple_get(ent, "class"), + dns_rdataclass_any, &rdclass); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = named_config_gettype(cfg_tuple_get(ent, "type"), + dns_rdatatype_any, &rdtype); + if (result != ISC_R_SUCCESS) { + return (result); + } + + obj = cfg_tuple_get(ent, "name"); + if (cfg_obj_isstring(obj)) { + str = cfg_obj_asstring(obj); + } else { + str = "*"; + } + addroot = (strcmp(str, "*") == 0); + isc_buffer_constinit(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + dns_fixedname_init(&fixed); + result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, dns_rootname, + 0, NULL); + if (result != ISC_R_SUCCESS) { + return (result); + } + + obj = cfg_tuple_get(ent, "ordering"); + INSIST(cfg_obj_isstring(obj)); + str = cfg_obj_asstring(obj); + if (!strcasecmp(str, "fixed")) { +#if DNS_RDATASET_FIXED + mode = DNS_RDATASETATTR_FIXEDORDER; +#else /* if DNS_RDATASET_FIXED */ + mode = DNS_RDATASETATTR_CYCLIC; +#endif /* DNS_RDATASET_FIXED */ + } else if (!strcasecmp(str, "random")) { + mode = DNS_RDATASETATTR_RANDOMIZE; + } else if (!strcasecmp(str, "cyclic")) { + mode = DNS_RDATASETATTR_CYCLIC; + } else if (!strcasecmp(str, "none")) { + mode = DNS_RDATASETATTR_NONE; + } else { + UNREACHABLE(); + } + + /* + * "*" should match everything including the root (BIND 8 compat). + * As dns_name_matcheswildcard(".", "*.") returns FALSE add a + * explicit entry for "." when the name is "*". + */ + if (addroot) { + result = dns_order_add(order, dns_rootname, rdtype, rdclass, + mode); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + + return (dns_order_add(order, dns_fixedname_name(&fixed), rdtype, + rdclass, mode)); +} + +static isc_result_t +configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { + isc_netaddr_t na; + dns_peer_t *peer; + const cfg_obj_t *obj; + const char *str; + isc_result_t result; + unsigned int prefixlen; + + cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen); + + peer = NULL; + result = dns_peer_newprefix(mctx, &na, prefixlen, &peer); + if (result != ISC_R_SUCCESS) { + return (result); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "bogus", &obj); + if (obj != NULL) { + CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "provide-ixfr", &obj); + if (obj != NULL) { + CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "request-expire", &obj); + if (obj != NULL) { + CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "request-ixfr", &obj); + if (obj != NULL) { + CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "request-nsid", &obj); + if (obj != NULL) { + CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "send-cookie", &obj); + if (obj != NULL) { + CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "edns", &obj); + if (obj != NULL) { + CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "edns-udp-size", &obj); + if (obj != NULL) { + uint32_t udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512U) { + udpsize = 512U; + } + if (udpsize > 4096U) { + udpsize = 4096U; + } + CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize)); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "edns-version", &obj); + if (obj != NULL) { + uint32_t ednsversion = cfg_obj_asuint32(obj); + if (ednsversion > 255U) { + ednsversion = 255U; + } + CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion)); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "max-udp-size", &obj); + if (obj != NULL) { + uint32_t udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512U) { + udpsize = 512U; + } + if (udpsize > 4096U) { + udpsize = 4096U; + } + CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize)); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "padding", &obj); + if (obj != NULL) { + uint32_t padding = cfg_obj_asuint32(obj); + if (padding > 512U) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "server padding value cannot " + "exceed 512: lowering"); + padding = 512U; + } + CHECK(dns_peer_setpadding(peer, (uint16_t)padding)); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "tcp-only", &obj); + if (obj != NULL) { + CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "tcp-keepalive", &obj); + if (obj != NULL) { + CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "transfers", &obj); + if (obj != NULL) { + CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj))); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "transfer-format", &obj); + if (obj != NULL) { + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "many-answers") == 0) { + CHECK(dns_peer_settransferformat(peer, + dns_many_answers)); + } else if (strcasecmp(str, "one-answer") == 0) { + CHECK(dns_peer_settransferformat(peer, dns_one_answer)); + } else { + UNREACHABLE(); + } + } + + obj = NULL; + (void)cfg_map_get(cpeer, "keys", &obj); + if (obj != NULL) { + result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj)); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } + + obj = NULL; + if (na.family == AF_INET) { + (void)cfg_map_get(cpeer, "transfer-source", &obj); + } else { + (void)cfg_map_get(cpeer, "transfer-source-v6", &obj); + } + if (obj != NULL) { + result = dns_peer_settransfersource(peer, + cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + result = dns_peer_settransferdscp(peer, cfg_obj_getdscp(obj)); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + named_add_reserved_dispatch(named_g_server, + cfg_obj_assockaddr(obj)); + } + + obj = NULL; + if (na.family == AF_INET) { + (void)cfg_map_get(cpeer, "notify-source", &obj); + } else { + (void)cfg_map_get(cpeer, "notify-source-v6", &obj); + } + if (obj != NULL) { + result = dns_peer_setnotifysource(peer, + cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + result = dns_peer_setnotifydscp(peer, cfg_obj_getdscp(obj)); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + named_add_reserved_dispatch(named_g_server, + cfg_obj_assockaddr(obj)); + } + + obj = NULL; + if (na.family == AF_INET) { + (void)cfg_map_get(cpeer, "query-source", &obj); + } else { + (void)cfg_map_get(cpeer, "query-source-v6", &obj); + } + if (obj != NULL) { + result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + result = dns_peer_setquerydscp(peer, cfg_obj_getdscp(obj)); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + named_add_reserved_dispatch(named_g_server, + cfg_obj_assockaddr(obj)); + } + + *peerp = peer; + return (ISC_R_SUCCESS); + +cleanup: + dns_peer_detach(&peer); + return (result); +} + +#ifdef HAVE_DLOPEN +static isc_result_t +configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, + const dns_dyndbctx_t *dctx) { + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *obj; + const char *name, *library; + + /* Get the name of the dyndb instance and the library path . */ + name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name")); + library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library")); + + obj = cfg_tuple_get(dyndb, "parameters"); + if (obj != NULL) { + result = dns_dyndb_load(library, name, cfg_obj_asstring(obj), + cfg_obj_file(obj), cfg_obj_line(obj), + mctx, dctx); + } + + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dynamic database '%s' configuration failed: %s", + name, isc_result_totext(result)); + } + return (result); +} +#endif /* ifdef HAVE_DLOPEN */ + +static isc_result_t +disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { + isc_result_t result; + const cfg_obj_t *algorithms; + const cfg_listelt_t *element; + const char *str; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t b; + + name = dns_fixedname_initname(&fixed); + str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); + isc_buffer_constinit(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + + algorithms = cfg_tuple_get(disabled, "algorithms"); + for (element = cfg_list_first(algorithms); element != NULL; + element = cfg_list_next(element)) + { + isc_textregion_t r; + dns_secalg_t alg; + + DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); + r.length = strlen(r.base); + + result = dns_secalg_fromtext(&alg, &r); + if (result != ISC_R_SUCCESS) { + uint8_t ui; + result = isc_parse_uint8(&ui, r.base, 10); + alg = ui; + } + if (result != ISC_R_SUCCESS) { + cfg_obj_log(cfg_listelt_value(element), named_g_lctx, + ISC_LOG_ERROR, "invalid algorithm"); + CHECK(result); + } + CHECK(dns_resolver_disable_algorithm(resolver, name, alg)); + } +cleanup: + return (result); +} + +static isc_result_t +disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) { + isc_result_t result; + const cfg_obj_t *digests; + const cfg_listelt_t *element; + const char *str; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t b; + + name = dns_fixedname_initname(&fixed); + str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); + isc_buffer_constinit(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + + digests = cfg_tuple_get(disabled, "digests"); + for (element = cfg_list_first(digests); element != NULL; + element = cfg_list_next(element)) + { + isc_textregion_t r; + dns_dsdigest_t digest; + + DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); + r.length = strlen(r.base); + + /* disable_ds_digests handles numeric values. */ + result = dns_dsdigest_fromtext(&digest, &r); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(cfg_listelt_value(element), named_g_lctx, + ISC_LOG_ERROR, "invalid algorithm"); + CHECK(result); + } + CHECK(dns_resolver_disable_ds_digest(resolver, name, digest)); + } +cleanup: + return (result); +} + +static bool +on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) { + const cfg_listelt_t *element; + dns_fixedname_t fixed; + dns_name_t *name; + isc_result_t result; + const cfg_obj_t *value; + const char *str; + isc_buffer_t b; + + name = dns_fixedname_initname(&fixed); + + for (element = cfg_list_first(disablelist); element != NULL; + element = cfg_list_next(element)) + { + value = cfg_listelt_value(element); + str = cfg_obj_asstring(value); + isc_buffer_constinit(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (dns_name_equal(name, zonename)) { + return (true); + } + } + return (false); +} + +static isc_result_t +check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv, + isc_mem_t *mctx) { + char **argv = NULL; + unsigned int i; + isc_result_t result = ISC_R_SUCCESS; + + CHECK(dns_zone_getdbtype(zone, &argv, mctx)); + + /* + * Check that all the arguments match. + */ + for (i = 0; i < dbtypec; i++) { + if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) { + CHECK(ISC_R_FAILURE); + + /* + * Check that there are not extra arguments. + */ + } + } + + /* + * Check that there are not extra arguments. + */ + if (i == dbtypec && argv[i] != NULL) { + result = ISC_R_FAILURE; + } + +cleanup: + isc_mem_free(mctx, argv); + return (result); +} + +static isc_result_t +setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) { + isc_result_t result; + isc_stats_t *zoneqrystats; + + dns_zone_setstatlevel(zone, level); + + zoneqrystats = NULL; + if (level == dns_zonestat_full) { + result = isc_stats_create(mctx, &zoneqrystats, + ns_statscounter_max); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + dns_zone_setrequeststats(zone, zoneqrystats); + if (zoneqrystats != NULL) { + isc_stats_detach(&zoneqrystats); + } + + return (ISC_R_SUCCESS); +} + +static named_cache_t * +cachelist_find(named_cachelist_t *cachelist, const char *cachename, + dns_rdataclass_t rdclass) { + named_cache_t *nsc; + + for (nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL; + nsc = ISC_LIST_NEXT(nsc, link)) + { + if (nsc->rdclass == rdclass && + strcmp(dns_cache_getname(nsc->cache), cachename) == 0) + { + return (nsc); + } + } + + return (NULL); +} + +static bool +cache_reusable(dns_view_t *originview, dns_view_t *view, + bool new_zero_no_soattl) { + if (originview->rdclass != view->rdclass || + originview->checknames != view->checknames || + dns_resolver_getzeronosoattl(originview->resolver) != + new_zero_no_soattl || + originview->acceptexpired != view->acceptexpired || + originview->enablevalidation != view->enablevalidation || + originview->maxcachettl != view->maxcachettl || + originview->maxncachettl != view->maxncachettl) + { + return (false); + } + + return (true); +} + +static bool +cache_sharable(dns_view_t *originview, dns_view_t *view, + bool new_zero_no_soattl, uint64_t new_max_cache_size, + uint32_t new_stale_ttl, uint32_t new_stale_refresh_time) { + /* + * If the cache cannot even reused for the same view, it cannot be + * shared with other views. + */ + if (!cache_reusable(originview, view, new_zero_no_soattl)) { + return (false); + } + + /* + * Check other cache related parameters that must be consistent among + * the sharing views. + */ + if (dns_cache_getservestalettl(originview->cache) != new_stale_ttl || + dns_cache_getservestalerefresh(originview->cache) != + new_stale_refresh_time || + dns_cache_getcachesize(originview->cache) != new_max_cache_size) + { + return (false); + } + + return (true); +} + +/* + * Callback from DLZ configure when the driver sets up a writeable zone + */ +static isc_result_t +dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) { + dns_name_t *origin = dns_zone_getorigin(zone); + dns_rdataclass_t zclass = view->rdclass; + isc_result_t result; + + result = dns_zonemgr_managezone(named_g_server->zonemgr, zone); + if (result != ISC_R_SUCCESS) { + return (result); + } + dns_zone_setstats(zone, named_g_server->zonestats); + + return (named_zone_configure_writeable_dlz(dlzdb, zone, zclass, + origin)); +} + +static isc_result_t +dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na, + unsigned int prefixlen, const char *server, const char *contact) { + char reverse[48 + sizeof("ip6.arpa.")] = { 0 }; + char buf[sizeof("x.x.")]; + const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." }; + const char *sep = ": view "; + const char *viewname = view->name; + const unsigned char *s6; + dns_fixedname_t fixed; + dns_name_t *name; + dns_zone_t *zone = NULL; + int dns64_dbtypec = 4; + isc_buffer_t b; + isc_result_t result; + + REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 || + prefixlen == 56 || prefixlen == 64 || prefixlen == 96); + + if (!strcmp(viewname, "_default")) { + sep = ""; + viewname = ""; + } + + /* + * Construct the reverse name of the zone. + */ + s6 = na->type.in6.s6_addr; + while (prefixlen > 0) { + prefixlen -= 8; + snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen / 8] & 0xf, + (s6[prefixlen / 8] >> 4) & 0xf); + strlcat(reverse, buf, sizeof(reverse)); + } + strlcat(reverse, "ip6.arpa.", sizeof(reverse)); + + /* + * Create the actual zone. + */ + if (server != NULL) { + dns64_dbtype[2] = server; + } + if (contact != NULL) { + dns64_dbtype[3] = contact; + } + name = dns_fixedname_initname(&fixed); + isc_buffer_constinit(&b, reverse, strlen(reverse)); + isc_buffer_add(&b, strlen(reverse)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + CHECK(dns_zone_create(&zone, mctx)); + CHECK(dns_zone_setorigin(zone, name)); + dns_zone_setview(zone, view); + CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone)); + dns_zone_setclass(zone, view->rdclass); + dns_zone_settype(zone, dns_zone_primary); + dns_zone_setstats(zone, named_g_server->zonestats); + dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype); + if (view->queryacl != NULL) { + dns_zone_setqueryacl(zone, view->queryacl); + } + if (view->queryonacl != NULL) { + dns_zone_setqueryonacl(zone, view->queryonacl); + } + dns_zone_setdialup(zone, dns_dialuptype_no); + dns_zone_setnotifytype(zone, dns_notifytype_no); + dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true); + CHECK(setquerystats(zone, mctx, dns_zonestat_none)); /* XXXMPA */ + CHECK(dns_view_addzone(view, zone)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "dns64 reverse zone%s%s: %s", sep, viewname, reverse); + +cleanup: + if (zone != NULL) { + dns_zone_detach(&zone); + } + return (result); +} + +#ifdef USE_DNSRPS +typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t; +struct conf_dnsrps_ctx { + isc_result_t result; + char *cstr; + size_t cstr_size; + isc_mem_t *mctx; +}; + +/* + * Add to the DNSRPS configuration string. + */ +static bool +conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) { + size_t new_len, cur_len, new_cstr_size; + char *new_cstr; + va_list args; + + if (ctx->cstr == NULL) { + ctx->cstr = isc_mem_get(ctx->mctx, 256); + ctx->cstr[0] = '\0'; + ctx->cstr_size = 256; + } + + cur_len = strlen(ctx->cstr); + va_start(args, p); + new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, + args) + + 1; + va_end(args); + + if (cur_len + new_len <= ctx->cstr_size) { + return (true); + } + + new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256; + new_cstr = isc_mem_get(ctx->mctx, new_cstr_size); + + memmove(new_cstr, ctx->cstr, cur_len); + isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size); + ctx->cstr_size = new_cstr_size; + ctx->cstr = new_cstr; + + /* cannot use args twice after a single va_start()on some systems */ + va_start(args, p); + vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args); + va_end(args); + return (true); +} + +/* + * Get an DNSRPS configuration value using the global and view options + * for the default. Return false upon failure. + */ +static bool +conf_dnsrps_get(const cfg_obj_t **sub_obj, const cfg_obj_t **maps, + const cfg_obj_t *obj, const char *name, + conf_dnsrps_ctx_t *ctx) { + if (ctx != NULL && ctx->result != ISC_R_SUCCESS) { + *sub_obj = NULL; + return (false); + } + + *sub_obj = cfg_tuple_get(obj, name); + if (cfg_obj_isvoid(*sub_obj)) { + *sub_obj = NULL; + if (maps != NULL && + ISC_R_SUCCESS != named_config_get(maps, name, sub_obj)) + { + *sub_obj = NULL; + } + } + return (true); +} + +/* + * Handle a DNSRPS boolean configuration value with the global and view + * options providing the default. + */ +static void +conf_dnsrps_yes_no(const cfg_obj_t *obj, const char *name, + conf_dnsrps_ctx_t *ctx) { + const cfg_obj_t *sub_obj; + + if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) { + return; + } + if (sub_obj == NULL) { + return; + } + if (ctx == NULL) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "\"%s\" without \"dnsrps-enable yes\"", name); + return; + } + + conf_dnsrps_sadd(ctx, " %s %s", name, + cfg_obj_asboolean(sub_obj) ? "yes" : "no"); +} + +static void +conf_dnsrps_num(const cfg_obj_t *obj, const char *name, + conf_dnsrps_ctx_t *ctx) { + const cfg_obj_t *sub_obj; + + if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) { + return; + } + if (sub_obj == NULL) { + return; + } + if (ctx == NULL) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "\"%s\" without \"dnsrps-enable yes\"", name); + return; + } + + if (cfg_obj_isduration(sub_obj)) { + conf_dnsrps_sadd(ctx, " %s %d", name, + cfg_obj_asduration(sub_obj)); + } else { + conf_dnsrps_sadd(ctx, " %s %d", name, + cfg_obj_asuint32(sub_obj)); + } +} + +/* + * Convert the parsed RPZ configuration statement to a string for + * dns_rpz_new_zones(). + */ +static isc_result_t +conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps, bool nsip_enabled, + bool nsdname_enabled, dns_rpz_zbits_t *nsip_on, + dns_rpz_zbits_t *nsdname_on, char **rps_cstr, size_t *rps_cstr_size, + const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element) { + conf_dnsrps_ctx_t ctx; + const cfg_obj_t *zone_obj, *obj; + dns_rpz_num_t rpz_num; + bool on; + const char *s; + + memset(&ctx, 0, sizeof(ctx)); + ctx.result = ISC_R_SUCCESS; + ctx.mctx = view->mctx; + + for (rpz_num = 0; zone_element != NULL && ctx.result == ISC_R_SUCCESS; + ++rpz_num) + { + zone_obj = cfg_listelt_value(zone_element); + + s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name")); + conf_dnsrps_sadd(&ctx, "zone \"%s\"", s); + + obj = cfg_tuple_get(zone_obj, "policy"); + if (!cfg_obj_isvoid(obj)) { + s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name")); + conf_dnsrps_sadd(&ctx, " policy %s", s); + if (strcasecmp(s, "cname") == 0) { + s = cfg_obj_asstring( + cfg_tuple_get(obj, "cname")); + conf_dnsrps_sadd(&ctx, " %s", s); + } + } + + conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx); + conf_dnsrps_yes_no(zone_obj, "log", &ctx); + conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx); + obj = cfg_tuple_get(rpz_obj, "nsip-enable"); + if (!cfg_obj_isvoid(obj)) { + if (cfg_obj_asboolean(obj)) { + *nsip_on |= DNS_RPZ_ZBIT(rpz_num); + } else { + *nsip_on &= ~DNS_RPZ_ZBIT(rpz_num); + } + } + on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0); + if (nsip_enabled != on) { + conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes " + : " nsip-enable no "); + } + obj = cfg_tuple_get(rpz_obj, "nsdname-enable"); + if (!cfg_obj_isvoid(obj)) { + if (cfg_obj_asboolean(obj)) { + *nsdname_on |= DNS_RPZ_ZBIT(rpz_num); + } else { + *nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num); + } + } + on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0); + if (nsdname_enabled != on) { + conf_dnsrps_sadd(&ctx, on ? " nsdname-enable yes " + : " nsdname-enable no "); + } + conf_dnsrps_sadd(&ctx, ";\n"); + zone_element = cfg_list_next(zone_element); + } + + conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx); + conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx); + conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx); + conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx); + conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx); + if (!nsip_enabled) { + conf_dnsrps_sadd(&ctx, " nsip-enable no "); + } + if (!nsdname_enabled) { + conf_dnsrps_sadd(&ctx, " nsdname-enable no "); + } + + /* + * Get the general dnsrpzd parameters from the response-policy + * statement in the view and the general options. + */ + if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) && + obj != NULL) + { + conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj)); + } + + if (ctx.result == ISC_R_SUCCESS) { + *rps_cstr = ctx.cstr; + *rps_cstr_size = ctx.cstr_size; + } else { + if (ctx.cstr != NULL) { + isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size); + } + *rps_cstr = NULL; + *rps_cstr_size = 0; + } + return (ctx.result); +} +#endif /* ifdef USE_DNSRPS */ + +static isc_result_t +configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name, + const char *str, const char *msg) { + isc_result_t result; + + result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL, + "invalid %s '%s'", msg, str); + } + return (result); +} + +static isc_result_t +configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name, + const char *str, const dns_name_t *origin) { + isc_result_t result; + + result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE, + view->mctx); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL, + "invalid zone '%s'", str); + } + return (result); +} + +static isc_result_t +configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element, + bool recursive_only_default, bool add_soa_default, + dns_ttl_t ttl_default, uint32_t minupdateinterval_default, + const dns_rpz_zone_t *old, bool *old_rpz_okp) { + const cfg_obj_t *rpz_obj, *obj; + const char *str; + dns_rpz_zone_t *zone = NULL; + isc_result_t result; + dns_rpz_num_t rpz_num; + + REQUIRE(old != NULL || !*old_rpz_okp); + + rpz_obj = cfg_listelt_value(element); + + if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) { + cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL, + "limit of %d response policy zones exceeded", + DNS_RPZ_MAX_ZONES); + return (ISC_R_FAILURE); + } + + result = dns_rpz_new_zone(view->rpzs, &zone); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL, + "Error creating new RPZ zone : %s", + isc_result_totext(result)); + return (result); + } + + obj = cfg_tuple_get(rpz_obj, "recursive-only"); + if (cfg_obj_isvoid(obj) ? recursive_only_default + : cfg_obj_asboolean(obj)) + { + view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num); + } else { + view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num); + } + + obj = cfg_tuple_get(rpz_obj, "log"); + if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) { + view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num); + } else { + view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num); + } + + obj = cfg_tuple_get(rpz_obj, "max-policy-ttl"); + if (cfg_obj_isduration(obj)) { + zone->max_policy_ttl = cfg_obj_asduration(obj); + } else { + zone->max_policy_ttl = ttl_default; + } + if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl) { + *old_rpz_okp = false; + } + + obj = cfg_tuple_get(rpz_obj, "min-update-interval"); + if (cfg_obj_isduration(obj)) { + zone->min_update_interval = cfg_obj_asduration(obj); + } else { + zone->min_update_interval = minupdateinterval_default; + } + if (*old_rpz_okp && + zone->min_update_interval != old->min_update_interval) + { + *old_rpz_okp = false; + } + + str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name")); + result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone"); + if (result != ISC_R_SUCCESS) { + return (result); + } + if (dns_name_equal(&zone->origin, dns_rootname)) { + cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL, + "invalid zone name '%s'", str); + return (DNS_R_EMPTYLABEL); + } + if (!view->rpzs->p.dnsrps_enabled) { + for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1; + ++rpz_num) + { + if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, + &zone->origin)) + { + cfg_obj_log(rpz_obj, named_g_lctx, + DNS_RPZ_ERROR_LEVEL, + "duplicate '%s'", str); + result = DNS_R_DUPLICATE; + return (result); + } + } + } + if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) { + *old_rpz_okp = false; + } + + result = configure_rpz_name2(view, rpz_obj, &zone->client_ip, + DNS_RPZ_CLIENT_IP_ZONE, &zone->origin); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = configure_rpz_name2(view, rpz_obj, &zone->ip, DNS_RPZ_IP_ZONE, + &zone->origin); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = configure_rpz_name2(view, rpz_obj, &zone->nsdname, + DNS_RPZ_NSDNAME_ZONE, &zone->origin); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = configure_rpz_name2(view, rpz_obj, &zone->nsip, + DNS_RPZ_NSIP_ZONE, &zone->origin); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = configure_rpz_name(view, rpz_obj, &zone->passthru, + DNS_RPZ_PASSTHRU_NAME, "name"); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = configure_rpz_name(view, rpz_obj, &zone->drop, + DNS_RPZ_DROP_NAME, "name"); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = configure_rpz_name(view, rpz_obj, &zone->tcp_only, + DNS_RPZ_TCP_ONLY_NAME, "name"); + if (result != ISC_R_SUCCESS) { + return (result); + } + + obj = cfg_tuple_get(rpz_obj, "policy"); + if (cfg_obj_isvoid(obj)) { + zone->policy = DNS_RPZ_POLICY_GIVEN; + } else { + str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name")); + zone->policy = dns_rpz_str2policy(str); + INSIST(zone->policy != DNS_RPZ_POLICY_ERROR); + if (zone->policy == DNS_RPZ_POLICY_CNAME) { + str = cfg_obj_asstring(cfg_tuple_get(obj, "cname")); + result = configure_rpz_name(view, rpz_obj, &zone->cname, + str, "cname"); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + } + if (*old_rpz_okp && (zone->policy != old->policy || + !dns_name_equal(&old->cname, &zone->cname))) + { + *old_rpz_okp = false; + } + + obj = cfg_tuple_get(rpz_obj, "add-soa"); + if (cfg_obj_isvoid(obj)) { + zone->addsoa = add_soa_default; + } else { + zone->addsoa = cfg_obj_asboolean(obj); + } + if (*old_rpz_okp && zone->addsoa != old->addsoa) { + *old_rpz_okp = false; + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps, + const cfg_obj_t *rpz_obj, bool *old_rpz_okp) { + bool dnsrps_enabled; + const cfg_listelt_t *zone_element; + char *rps_cstr; + size_t rps_cstr_size; + const cfg_obj_t *sub_obj; + bool recursive_only_default, add_soa_default; + bool nsip_enabled, nsdname_enabled; + dns_rpz_zbits_t nsip_on, nsdname_on; + dns_ttl_t ttl_default; + uint32_t minupdateinterval_default; + dns_rpz_zones_t *zones; + const dns_rpz_zones_t *old; + bool pview_must_detach = false; + const dns_rpz_zone_t *old_zone; + isc_result_t result; + int i; + + *old_rpz_okp = false; + + zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list")); + if (zone_element == NULL) { + return (ISC_R_SUCCESS); + } + + nsip_enabled = true; + sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable"); + if (!cfg_obj_isvoid(sub_obj)) { + nsip_enabled = cfg_obj_asboolean(sub_obj); + } + nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0; + + nsdname_enabled = true; + sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable"); + if (!cfg_obj_isvoid(sub_obj)) { + nsdname_enabled = cfg_obj_asboolean(sub_obj); + } + nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0; + + /* + * "dnsrps-enable yes|no" can be either a global or response-policy + * clause. + */ + dnsrps_enabled = false; + rps_cstr = NULL; + rps_cstr_size = 0; + sub_obj = NULL; + (void)named_config_get(maps, "dnsrps-enable", &sub_obj); + if (sub_obj != NULL) { + dnsrps_enabled = cfg_obj_asboolean(sub_obj); + } + sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable"); + if (!cfg_obj_isvoid(sub_obj)) { + dnsrps_enabled = cfg_obj_asboolean(sub_obj); + } +#ifndef USE_DNSRPS + if (dnsrps_enabled) { + cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL, + "\"dnsrps-enable yes\" but" + " without `./configure --enable-dnsrps`"); + return (ISC_R_FAILURE); + } +#else /* ifndef USE_DNSRPS */ + if (dnsrps_enabled) { + if (librpz == NULL) { + cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL, + "\"dnsrps-enable yes\" but %s", + librpz_lib_open_emsg.c); + return (ISC_R_FAILURE); + } + + /* + * Generate the DNS Response Policy Service + * configuration string. + */ + result = conf_dnsrps(view, maps, nsip_enabled, nsdname_enabled, + &nsip_on, &nsdname_on, &rps_cstr, + &rps_cstr_size, rpz_obj, zone_element); + if (result != ISC_R_SUCCESS) { + return (result); + } + } +#endif /* ifndef USE_DNSRPS */ + + result = dns_rpz_new_zones(&view->rpzs, rps_cstr, rps_cstr_size, + view->mctx, named_g_taskmgr, + named_g_timermgr); + if (result != ISC_R_SUCCESS) { + return (result); + } + + zones = view->rpzs; + + zones->p.nsip_on = nsip_on; + zones->p.nsdname_on = nsdname_on; + + sub_obj = cfg_tuple_get(rpz_obj, "recursive-only"); + if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) { + recursive_only_default = false; + } else { + recursive_only_default = true; + } + + sub_obj = cfg_tuple_get(rpz_obj, "add-soa"); + if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) { + add_soa_default = false; + } else { + add_soa_default = true; + } + + sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec"); + if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) { + zones->p.break_dnssec = true; + } else { + zones->p.break_dnssec = false; + } + + sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl"); + if (cfg_obj_isduration(sub_obj)) { + ttl_default = cfg_obj_asduration(sub_obj); + } else { + ttl_default = DNS_RPZ_MAX_TTL_DEFAULT; + } + + sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval"); + if (cfg_obj_isduration(sub_obj)) { + minupdateinterval_default = cfg_obj_asduration(sub_obj); + } else { + minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT; + } + + sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots"); + if (cfg_obj_isuint32(sub_obj)) { + zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1; + } else { + zones->p.min_ns_labels = 2; + } + + sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse"); + if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) { + zones->p.qname_wait_recurse = true; + } else { + zones->p.qname_wait_recurse = false; + } + + sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse"); + if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) { + zones->p.nsip_wait_recurse = true; + } else { + zones->p.nsip_wait_recurse = false; + } + + if (pview != NULL) { + old = pview->rpzs; + } else { + result = dns_viewlist_find(&named_g_server->viewlist, + view->name, view->rdclass, &pview); + if (result == ISC_R_SUCCESS) { + pview_must_detach = true; + old = pview->rpzs; + } else { + old = NULL; + } + } + + if (old == NULL) { + *old_rpz_okp = false; + } else { + *old_rpz_okp = true; + } + + for (i = 0; zone_element != NULL; + ++i, zone_element = cfg_list_next(zone_element)) + { + INSIST(!*old_rpz_okp || old != NULL); + if (*old_rpz_okp && i < old->p.num_zones) { + old_zone = old->zones[i]; + } else { + *old_rpz_okp = false; + old_zone = NULL; + } + result = configure_rpz_zone( + view, zone_element, recursive_only_default, + add_soa_default, ttl_default, minupdateinterval_default, + old_zone, old_rpz_okp); + if (result != ISC_R_SUCCESS) { + if (pview_must_detach) { + dns_view_detach(&pview); + } + return (result); + } + } + + /* + * If this is a reloading and the parameters and list of policy + * zones are unchanged, then use the same policy data. + * Data for individual zones that must be reloaded will be merged. + */ + if (*old_rpz_okp) { + if (old != NULL && + memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0) + { + *old_rpz_okp = false; + } else if ((old == NULL || old->rps_cstr == NULL) != + (zones->rps_cstr == NULL)) + { + *old_rpz_okp = false; + } else if (old != NULL && zones->rps_cstr != NULL && + strcmp(old->rps_cstr, zones->rps_cstr) != 0) + { + *old_rpz_okp = false; + } + } + + if (*old_rpz_okp) { + dns_rpz_detach_rpzs(&view->rpzs); + dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs); + dns_rpz_detach_rpzs(&pview->rpzs); + } else if (old != NULL && pview != NULL) { + ++pview->rpzs->rpz_ver; + view->rpzs->rpz_ver = pview->rpzs->rpz_ver; + cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1, + "updated RPZ policy: version %d", + view->rpzs->rpz_ver); + } + + if (pview_must_detach) { + dns_view_detach(&pview); + } + + return (ISC_R_SUCCESS); +} + +static void +catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) { + catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0; + isc_result_t result; + isc_buffer_t namebuf; + isc_buffer_t *confbuf; + char nameb[DNS_NAME_FORMATSIZE]; + const cfg_obj_t *zlist = NULL; + cfg_obj_t *zoneconf = NULL; + cfg_obj_t *zoneobj = NULL; + ns_cfgctx_t *cfg; + dns_zone_t *zone = NULL; + + cfg = (ns_cfgctx_t *)ev->view->new_zone_config; + if (cfg == NULL) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "catz: allow-new-zones statement missing from " + "config; cannot add zone from the catalog"); + goto cleanup; + } + + isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE); + dns_name_totext(dns_catz_entry_getname(ev->entry), true, &namebuf); + isc_buffer_putuint8(&namebuf, 0); + + /* Zone shouldn't already exist */ + result = dns_zt_find(ev->view->zonetable, + dns_catz_entry_getname(ev->entry), 0, NULL, &zone); + + if (ev->mod) { + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "catz: error \"%s\" while trying to " + "modify zone \"%s\"", + isc_result_totext(result), nameb); + goto cleanup; + } else { + if (!dns_zone_getadded(zone)) { + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "catz: " + "catz_addmodzone_taskaction: " + "zone '%s' is not a dynamically " + "added zone", + nameb); + goto cleanup; + } + if (dns_zone_get_parentcatz(zone) != ev->origin) { + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "catz: catz_delzone_taskaction: " + "zone '%s' exists in multiple " + "catalog zones", + nameb); + goto cleanup; + } + dns_zone_detach(&zone); + } + } else { + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "catz: zone \"%s\" is overridden " + "by explicitly configured zone", + nameb); + goto cleanup; + } else if (result != ISC_R_NOTFOUND && + result != DNS_R_PARTIALMATCH) + { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "catz: error \"%s\" while trying to " + "add zone \"%s\"", + isc_result_totext(result), nameb); + goto cleanup; + } else { /* this can happen in case of DNS_R_PARTIALMATCH */ + if (zone != NULL) { + dns_zone_detach(&zone); + } + } + } + RUNTIME_CHECK(zone == NULL); + /* Create a config for new zone */ + confbuf = NULL; + result = dns_catz_generate_zonecfg(ev->origin, ev->entry, &confbuf); + if (result == ISC_R_SUCCESS) { + cfg_parser_reset(cfg->add_parser); + result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0, + &cfg_type_addzoneconf, 0, &zoneconf); + isc_buffer_free(&confbuf); + } + /* + * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer3() + * failed. + */ + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "catz: error \"%s\" while trying to generate " + "config for zone \"%s\"", + isc_result_totext(result), nameb); + goto cleanup; + } + CHECK(cfg_map_get(zoneconf, "zone", &zlist)); + if (!cfg_obj_islist(zlist)) { + CHECK(ISC_R_FAILURE); + } + + /* For now we only support adding one zone at a time */ + zoneobj = cfg_listelt_value(cfg_list_first(zlist)); + + /* Mark view unfrozen so that zone can be added */ + + result = isc_task_beginexclusive(task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_view_thaw(ev->view); + result = configure_zone( + cfg->config, zoneobj, cfg->vconfig, ev->cbd->server->mctx, + ev->view, &ev->cbd->server->viewlist, + &ev->cbd->server->kasplist, cfg->actx, true, false, ev->mod); + dns_view_freeze(ev->view); + isc_task_endexclusive(task); + + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "catz: failed to configure zone \"%s\" - %d", + nameb, result); + goto cleanup; + } + + /* Is it there yet? */ + CHECK(dns_zt_find(ev->view->zonetable, + dns_catz_entry_getname(ev->entry), 0, NULL, &zone)); + + /* + * Load the zone from the master file. If this fails, we'll + * need to undo the configuration we've done already. + */ + result = dns_zone_load(zone, true); + if (result != ISC_R_SUCCESS) { + dns_db_t *dbp = NULL; + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "catz: dns_zone_load() failed " + "with %s; reverting.", + isc_result_totext(result)); + + /* If the zone loaded partially, unload it */ + if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { + dns_db_detach(&dbp); + dns_zone_unload(zone); + } + + /* Remove the zone from the zone table */ + dns_zt_unmount(ev->view->zonetable, zone); + goto cleanup; + } + + /* Flag the zone as having been added at runtime */ + dns_zone_setadded(zone, true); + dns_zone_set_parentcatz(zone, ev->origin); + +cleanup: + if (zone != NULL) { + dns_zone_detach(&zone); + } + if (zoneconf != NULL) { + cfg_obj_destroy(cfg->add_parser, &zoneconf); + } + dns_catz_entry_detach(ev->origin, &ev->entry); + dns_catz_zone_detach(&ev->origin); + dns_view_detach(&ev->view); + isc_event_free(ISC_EVENT_PTR(&ev)); +} + +static void +catz_delzone_taskaction(isc_task_t *task, isc_event_t *event0) { + catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0; + isc_result_t result; + dns_zone_t *zone = NULL; + dns_db_t *dbp = NULL; + char cname[DNS_NAME_FORMATSIZE]; + const char *file; + + result = isc_task_beginexclusive(task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + dns_name_format(dns_catz_entry_getname(ev->entry), cname, + DNS_NAME_FORMATSIZE); + result = dns_zt_find(ev->view->zonetable, + dns_catz_entry_getname(ev->entry), 0, NULL, &zone); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "catz: catz_delzone_taskaction: " + "zone '%s' not found", + cname); + goto cleanup; + } + + if (!dns_zone_getadded(zone)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "catz: catz_delzone_taskaction: " + "zone '%s' is not a dynamically added zone", + cname); + goto cleanup; + } + + if (dns_zone_get_parentcatz(zone) != ev->origin) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "catz: catz_delzone_taskaction: zone " + "'%s' exists in multiple catalog zones", + cname); + goto cleanup; + } + + /* Stop answering for this zone */ + if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { + dns_db_detach(&dbp); + dns_zone_unload(zone); + } + + CHECK(dns_zt_unmount(ev->view->zonetable, zone)); + file = dns_zone_getfile(zone); + if (file != NULL) { + isc_file_remove(file); + file = dns_zone_getjournal(zone); + if (file != NULL) { + isc_file_remove(file); + } + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "catz: catz_delzone_taskaction: " + "zone '%s' deleted", + cname); +cleanup: + isc_task_endexclusive(task); + if (zone != NULL) { + dns_zone_detach(&zone); + } + dns_catz_entry_detach(ev->origin, &ev->entry); + dns_catz_zone_detach(&ev->origin); + dns_view_detach(&ev->view); + isc_event_free(ISC_EVENT_PTR(&ev)); +} + +static isc_result_t +catz_create_chg_task(dns_catz_entry_t *entry, dns_catz_zone_t *origin, + dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata, + isc_eventtype_t type) { + catz_chgzone_event_t *event = NULL; + isc_task_t *task = NULL; + isc_result_t result; + isc_taskaction_t action = NULL; + + result = isc_taskmgr_excltask(taskmgr, &task); + if (result != ISC_R_SUCCESS) { + return (result); + } + + switch (type) { + case DNS_EVENT_CATZADDZONE: + case DNS_EVENT_CATZMODZONE: + action = catz_addmodzone_taskaction; + break; + case DNS_EVENT_CATZDELZONE: + action = catz_delzone_taskaction; + break; + default: + REQUIRE(0); + UNREACHABLE(); + } + + event = (catz_chgzone_event_t *)isc_event_allocate( + view->mctx, origin, type, action, NULL, sizeof(*event)); + + event->cbd = (catz_cb_data_t *)udata; + event->entry = NULL; + event->origin = NULL; + event->view = NULL; + event->mod = (type == DNS_EVENT_CATZMODZONE); + + dns_catz_entry_attach(entry, &event->entry); + dns_catz_zone_attach(origin, &event->origin); + dns_view_attach(view, &event->view); + + isc_task_send(task, ISC_EVENT_PTR(&event)); + isc_task_detach(&task); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view, + isc_taskmgr_t *taskmgr, void *udata) { + return (catz_create_chg_task(entry, origin, view, taskmgr, udata, + DNS_EVENT_CATZADDZONE)); +} + +static isc_result_t +catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view, + isc_taskmgr_t *taskmgr, void *udata) { + return (catz_create_chg_task(entry, origin, view, taskmgr, udata, + DNS_EVENT_CATZDELZONE)); +} + +static isc_result_t +catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view, + isc_taskmgr_t *taskmgr, void *udata) { + return (catz_create_chg_task(entry, origin, view, taskmgr, udata, + DNS_EVENT_CATZMODZONE)); +} + +static isc_result_t +configure_catz_zone(dns_view_t *view, dns_view_t *pview, + const cfg_obj_t *config, const cfg_listelt_t *element) { + const cfg_obj_t *catz_obj, *obj; + dns_catz_zone_t *zone = NULL; + const char *str; + isc_result_t result; + dns_name_t origin; + dns_catz_options_t *opts; + + dns_name_init(&origin, NULL); + catz_obj = cfg_listelt_value(element); + + str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name")); + + result = dns_name_fromstring(&origin, str, DNS_NAME_DOWNCASE, + view->mctx); + if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname)) { + result = DNS_R_EMPTYLABEL; + } + + if (result != ISC_R_SUCCESS) { + cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL, + "catz: invalid zone name '%s'", str); + goto cleanup; + } + + result = dns_catz_add_zone(view->catzs, &origin, &zone); + if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) { + cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL, + "catz: unable to create catalog zone '%s', " + "error %s", + str, isc_result_totext(result)); + goto cleanup; + } + + if (result == ISC_R_EXISTS) { + isc_ht_iter_t *it = NULL; + + RUNTIME_CHECK(pview != NULL); + + /* + * xxxwpk todo: reconfigure the zone!!!! + */ + cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL, + "catz: catalog zone '%s' will not be reconfigured", + str); + /* + * We have to walk through all the member zones and attach + * them to current view + */ + dns_catz_get_iterator(zone, &it); + + for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS; + result = isc_ht_iter_next(it)) + { + dns_name_t *name = NULL; + dns_zone_t *dnszone = NULL; + dns_catz_entry_t *entry = NULL; + isc_result_t tresult; + + isc_ht_iter_current(it, (void **)&entry); + name = dns_catz_entry_getname(entry); + + tresult = dns_view_findzone(pview, name, &dnszone); + if (tresult != ISC_R_SUCCESS) { + continue; + } + + dns_zone_setview(dnszone, view); + dns_view_addzone(view, dnszone); + + /* + * The dns_view_findzone() call above increments the + * zone's reference count, which we need to decrement + * back. However, as dns_zone_detach() sets the + * supplied pointer to NULL, calling it is deferred + * until the dnszone variable is no longer used. + */ + dns_zone_detach(&dnszone); + } + + isc_ht_iter_destroy(&it); + + result = ISC_R_SUCCESS; + } + + dns_catz_zone_resetdefoptions(zone); + opts = dns_catz_zone_getdefoptions(zone); + + obj = cfg_tuple_get(catz_obj, "default-masters"); + if (obj != NULL && cfg_obj_istuple(obj)) { + result = named_config_getipandkeylist( + config, "primaries", obj, view->mctx, &opts->masters); + } + + obj = cfg_tuple_get(catz_obj, "in-memory"); + if (obj != NULL && cfg_obj_isboolean(obj)) { + opts->in_memory = cfg_obj_asboolean(obj); + } + + obj = cfg_tuple_get(catz_obj, "zone-directory"); + if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) { + opts->zonedir = isc_mem_strdup(view->mctx, + cfg_obj_asstring(obj)); + if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) { + cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL, + "catz: zone-directory '%s' " + "not found; zone files will not be " + "saved", + opts->zonedir); + opts->in_memory = true; + } + } + + obj = cfg_tuple_get(catz_obj, "min-update-interval"); + if (obj != NULL && cfg_obj_isduration(obj)) { + opts->min_update_interval = cfg_obj_asduration(obj); + } + +cleanup: + dns_name_free(&origin, view->mctx); + + return (result); +} + +static catz_cb_data_t ns_catz_cbdata; +static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = { + catz_addzone, catz_modzone, catz_delzone, &ns_catz_cbdata +}; + +static isc_result_t +configure_catz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t *config, + const cfg_obj_t *catz_obj) { + const cfg_listelt_t *zone_element; + const dns_catz_zones_t *old = NULL; + bool pview_must_detach = false; + isc_result_t result; + + /* xxxwpk TODO do it cleaner, once, somewhere */ + ns_catz_cbdata.server = named_g_server; + + zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list")); + if (zone_element == NULL) { + return (ISC_R_SUCCESS); + } + + CHECK(dns_catz_new_zones(&view->catzs, &ns_catz_zonemodmethods, + view->mctx, named_g_taskmgr, + named_g_timermgr)); + + if (pview != NULL) { + old = pview->catzs; + } else { + result = dns_viewlist_find(&named_g_server->viewlist, + view->name, view->rdclass, &pview); + if (result == ISC_R_SUCCESS) { + pview_must_detach = true; + old = pview->catzs; + } + } + + if (old != NULL) { + dns_catz_catzs_detach(&view->catzs); + dns_catz_catzs_attach(pview->catzs, &view->catzs); + dns_catz_catzs_detach(&pview->catzs); + dns_catz_prereconfig(view->catzs); + } + + while (zone_element != NULL) { + CHECK(configure_catz_zone(view, pview, config, zone_element)); + zone_element = cfg_list_next(zone_element); + } + + if (old != NULL) { + dns_catz_postreconfig(view->catzs); + } + + result = ISC_R_SUCCESS; + +cleanup: + if (pview_must_detach) { + dns_view_detach(&pview); + } + + return (result); +} + +#define CHECK_RRL(cond, pat, val1, val2) \ + do { \ + if (!(cond)) { \ + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, pat, \ + val1, val2); \ + result = ISC_R_RANGE; \ + goto cleanup; \ + } \ + } while (0) + +#define CHECK_RRL_RATE(rate, def, max_rate, name) \ + do { \ + obj = NULL; \ + rrl->rate.str = name; \ + result = cfg_map_get(map, name, &obj); \ + if (result == ISC_R_SUCCESS) { \ + rrl->rate.r = cfg_obj_asuint32(obj); \ + CHECK_RRL(rrl->rate.r <= max_rate, name " %d > %d", \ + rrl->rate.r, max_rate); \ + } else { \ + rrl->rate.r = def; \ + } \ + rrl->rate.scaled = rrl->rate.r; \ + } while (0) + +static isc_result_t +configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) { + const cfg_obj_t *obj; + dns_rrl_t *rrl; + isc_result_t result; + int min_entries, i, j; + + /* + * Most DNS servers have few clients, but intentinally open + * recursive and authoritative servers often have many. + * So start with a small number of entries unless told otherwise + * to reduce cold-start costs. + */ + min_entries = 500; + obj = NULL; + result = cfg_map_get(map, "min-table-size", &obj); + if (result == ISC_R_SUCCESS) { + min_entries = cfg_obj_asuint32(obj); + if (min_entries < 1) { + min_entries = 1; + } + } + result = dns_rrl_init(&rrl, view, min_entries); + if (result != ISC_R_SUCCESS) { + return (result); + } + + i = ISC_MAX(20000, min_entries); + obj = NULL; + result = cfg_map_get(map, "max-table-size", &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + CHECK_RRL(i >= min_entries, + "max-table-size %d < min-table-size %d", i, + min_entries); + } + rrl->max_entries = i; + + CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE, + "responses-per-second"); + CHECK_RRL_RATE(referrals_per_second, rrl->responses_per_second.r, + DNS_RRL_MAX_RATE, "referrals-per-second"); + CHECK_RRL_RATE(nodata_per_second, rrl->responses_per_second.r, + DNS_RRL_MAX_RATE, "nodata-per-second"); + CHECK_RRL_RATE(nxdomains_per_second, rrl->responses_per_second.r, + DNS_RRL_MAX_RATE, "nxdomains-per-second"); + CHECK_RRL_RATE(errors_per_second, rrl->responses_per_second.r, + DNS_RRL_MAX_RATE, "errors-per-second"); + + CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second"); + + CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip"); + + i = 15; + obj = NULL; + result = cfg_map_get(map, "window", &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW, + "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW); + } + rrl->window = i; + + i = 0; + obj = NULL; + result = cfg_map_get(map, "qps-scale", &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, ""); + } + rrl->qps_scale = i; + rrl->qps = 1.0; + + i = 24; + obj = NULL; + result = cfg_map_get(map, "ipv4-prefix-length", &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + CHECK_RRL(i >= 8 && i <= 32, + "invalid 'ipv4-prefix-length %d'%s", i, ""); + } + rrl->ipv4_prefixlen = i; + if (i == 32) { + rrl->ipv4_mask = 0xffffffff; + } else { + rrl->ipv4_mask = htonl(0xffffffff << (32 - i)); + } + + i = 56; + obj = NULL; + result = cfg_map_get(map, "ipv6-prefix-length", &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX, + "ipv6-prefix-length %d < 16 or > %d", i, + DNS_RRL_MAX_PREFIX); + } + rrl->ipv6_prefixlen = i; + for (j = 0; j < 4; ++j) { + if (i <= 0) { + rrl->ipv6_mask[j] = 0; + } else if (i < 32) { + rrl->ipv6_mask[j] = htonl(0xffffffff << (32 - i)); + } else { + rrl->ipv6_mask[j] = 0xffffffff; + } + i -= 32; + } + + obj = NULL; + result = cfg_map_get(map, "exempt-clients", &obj); + if (result == ISC_R_SUCCESS) { + result = cfg_acl_fromconfig(obj, config, named_g_lctx, + named_g_aclconfctx, named_g_mctx, 0, + &rrl->exempt); + CHECK_RRL(result == ISC_R_SUCCESS, "invalid %s%s", + "address match list", ""); + } + + obj = NULL; + result = cfg_map_get(map, "log-only", &obj); + if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) { + rrl->log_only = true; + } else { + rrl->log_only = false; + } + + return (ISC_R_SUCCESS); + +cleanup: + dns_rrl_view_destroy(view); + return (result); +} + +static isc_result_t +add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name, + const dns_name_t *origin, const dns_name_t *contact) { + dns_dbnode_t *node = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdatalist_t rdatalist; + dns_rdataset_t rdataset; + isc_result_t result; + unsigned char buf[DNS_SOA_BUFFERSIZE]; + + CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 0, 28800, + 7200, 604800, 86400, buf, &rdata)); + + dns_rdatalist_init(&rdatalist); + rdatalist.type = rdata.type; + rdatalist.rdclass = rdata.rdclass; + rdatalist.ttl = 86400; + ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); + + dns_rdataset_init(&rdataset); + CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)); + CHECK(dns_db_findnode(db, name, true, &node)); + CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL)); + +cleanup: + if (node != NULL) { + dns_db_detachnode(db, &node); + } + return (result); +} + +static isc_result_t +add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name, + const dns_name_t *nsname) { + dns_dbnode_t *node = NULL; + dns_rdata_ns_t ns; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdatalist_t rdatalist; + dns_rdataset_t rdataset; + isc_result_t result; + isc_buffer_t b; + unsigned char buf[DNS_NAME_MAXWIRE]; + + isc_buffer_init(&b, buf, sizeof(buf)); + + ns.common.rdtype = dns_rdatatype_ns; + ns.common.rdclass = dns_db_class(db); + ns.mctx = NULL; + dns_name_init(&ns.name, NULL); + dns_name_clone(nsname, &ns.name); + CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns, + &ns, &b)); + + dns_rdatalist_init(&rdatalist); + rdatalist.type = rdata.type; + rdatalist.rdclass = rdata.rdclass; + rdatalist.ttl = 86400; + ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); + + dns_rdataset_init(&rdataset); + CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)); + CHECK(dns_db_findnode(db, name, true, &node)); + CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL)); + +cleanup: + if (node != NULL) { + dns_db_detachnode(db, &node); + } + return (result); +} + +static isc_result_t +create_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view, + const cfg_obj_t *zonelist, const char **empty_dbtype, + int empty_dbtypec, dns_zonestat_level_t statlevel) { + char namebuf[DNS_NAME_FORMATSIZE]; + const cfg_listelt_t *element; + const cfg_obj_t *obj; + const cfg_obj_t *zconfig; + const cfg_obj_t *zoptions; + const char *rbt_dbtype[4] = { "rbt" }; + const char *sep = ": view "; + const char *str; + const char *viewname = view->name; + dns_db_t *db = NULL; + dns_dbversion_t *version = NULL; + dns_fixedname_t cfixed; + dns_fixedname_t fixed; + dns_fixedname_t nsfixed; + dns_name_t *contact; + dns_name_t *ns; + dns_name_t *zname; + dns_zone_t *myzone = NULL; + int rbt_dbtypec = 1; + isc_result_t result; + dns_namereln_t namereln; + int order; + unsigned int nlabels; + + zname = dns_fixedname_initname(&fixed); + ns = dns_fixedname_initname(&nsfixed); + contact = dns_fixedname_initname(&cfixed); + + /* + * Look for forward "zones" beneath this empty zone and if so + * create a custom db for the empty zone. + */ + for (element = cfg_list_first(zonelist); element != NULL; + element = cfg_list_next(element)) + { + zconfig = cfg_listelt_value(element); + str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + CHECK(dns_name_fromstring(zname, str, 0, NULL)); + namereln = dns_name_fullcompare(zname, name, &order, &nlabels); + if (namereln != dns_namereln_subdomain) { + continue; + } + + zoptions = cfg_tuple_get(zconfig, "options"); + + obj = NULL; + (void)cfg_map_get(zoptions, "type", &obj); + if (obj != NULL && + strcasecmp(cfg_obj_asstring(obj), "forward") == 0) + { + obj = NULL; + (void)cfg_map_get(zoptions, "forward", &obj); + if (obj == NULL) { + continue; + } + if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) { + continue; + } + } + if (db == NULL) { + CHECK(dns_db_create(view->mctx, "rbt", name, + dns_dbtype_zone, view->rdclass, 0, + NULL, &db)); + CHECK(dns_db_newversion(db, &version)); + if (strcmp(empty_dbtype[2], "@") == 0) { + dns_name_clone(name, ns); + } else { + CHECK(dns_name_fromstring(ns, empty_dbtype[2], + 0, NULL)); + } + CHECK(dns_name_fromstring(contact, empty_dbtype[3], 0, + NULL)); + CHECK(add_soa(db, version, name, ns, contact)); + CHECK(add_ns(db, version, name, ns)); + } + CHECK(add_ns(db, version, zname, dns_rootname)); + } + + /* + * Is the existing zone the ok to use? + */ + if (zone != NULL) { + unsigned int typec; + const char **dbargv; + + if (db != NULL) { + typec = rbt_dbtypec; + dbargv = rbt_dbtype; + } else { + typec = empty_dbtypec; + dbargv = empty_dbtype; + } + + result = check_dbtype(zone, typec, dbargv, view->mctx); + if (result != ISC_R_SUCCESS) { + zone = NULL; + } + + if (zone != NULL && dns_zone_gettype(zone) != dns_zone_primary) + { + zone = NULL; + } + if (zone != NULL && dns_zone_getfile(zone) != NULL) { + zone = NULL; + } + if (zone != NULL) { + dns_zone_getraw(zone, &myzone); + if (myzone != NULL) { + dns_zone_detach(&myzone); + zone = NULL; + } + } + } + + if (zone == NULL) { + CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &myzone)); + zone = myzone; + CHECK(dns_zone_setorigin(zone, name)); + CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone)); + if (db == NULL) { + dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype); + } + dns_zone_setclass(zone, view->rdclass); + dns_zone_settype(zone, dns_zone_primary); + dns_zone_setstats(zone, named_g_server->zonestats); + } + + dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false); + dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true); + dns_zone_setnotifytype(zone, dns_notifytype_no); + dns_zone_setdialup(zone, dns_dialuptype_no); + dns_zone_setautomatic(zone, true); + if (view->queryacl != NULL) { + dns_zone_setqueryacl(zone, view->queryacl); + } else { + dns_zone_clearqueryacl(zone); + } + if (view->queryonacl != NULL) { + dns_zone_setqueryonacl(zone, view->queryonacl); + } else { + dns_zone_clearqueryonacl(zone); + } + dns_zone_clearupdateacl(zone); + if (view->transferacl != NULL) { + dns_zone_setxfracl(zone, view->transferacl); + } else { + dns_zone_clearxfracl(zone); + } + + CHECK(setquerystats(zone, view->mctx, statlevel)); + if (db != NULL) { + dns_db_closeversion(db, &version, true); + CHECK(dns_zone_replacedb(zone, db, false)); + } + dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true); + dns_zone_setview(zone, view); + CHECK(dns_view_addzone(view, zone)); + + if (!strcmp(viewname, "_default")) { + sep = ""; + viewname = ""; + } + dns_name_format(name, namebuf, sizeof(namebuf)); + isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "automatic empty zone%s%s: %s", sep, viewname, namebuf); + +cleanup: + if (myzone != NULL) { + dns_zone_detach(&myzone); + } + if (version != NULL) { + dns_db_closeversion(db, &version, false); + } + if (db != NULL) { + dns_db_detach(&db); + } + + INSIST(version == NULL); + + return (result); +} + +#ifdef HAVE_DNSTAP +static isc_result_t +configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) { + isc_result_t result; + const cfg_obj_t *obj, *obj2; + const cfg_listelt_t *element; + const char *dpath; + const cfg_obj_t *dlist = NULL; + dns_dtmsgtype_t dttypes = 0; + unsigned int i; + struct fstrm_iothr_options *fopt = NULL; + + result = named_config_get(maps, "dnstap", &dlist); + if (result != ISC_R_SUCCESS) { + return (ISC_R_SUCCESS); + } + + for (element = cfg_list_first(dlist); element != NULL; + element = cfg_list_next(element)) + { + const char *str; + dns_dtmsgtype_t dt = 0; + + obj = cfg_listelt_value(element); + obj2 = cfg_tuple_get(obj, "type"); + str = cfg_obj_asstring(obj2); + if (strcasecmp(str, "client") == 0) { + dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR; + } else if (strcasecmp(str, "auth") == 0) { + dt |= DNS_DTTYPE_AQ | DNS_DTTYPE_AR; + } else if (strcasecmp(str, "resolver") == 0) { + dt |= DNS_DTTYPE_RQ | DNS_DTTYPE_RR; + } else if (strcasecmp(str, "forwarder") == 0) { + dt |= DNS_DTTYPE_FQ | DNS_DTTYPE_FR; + } else if (strcasecmp(str, "update") == 0) { + dt |= DNS_DTTYPE_UQ | DNS_DTTYPE_UR; + } else if (strcasecmp(str, "all") == 0) { + dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR | DNS_DTTYPE_AQ | + DNS_DTTYPE_AR | DNS_DTTYPE_RQ | DNS_DTTYPE_RR | + DNS_DTTYPE_FQ | DNS_DTTYPE_FR | DNS_DTTYPE_UQ | + DNS_DTTYPE_UR; + } + + obj2 = cfg_tuple_get(obj, "mode"); + if (obj2 == NULL || cfg_obj_isvoid(obj2)) { + dttypes |= dt; + continue; + } + + str = cfg_obj_asstring(obj2); + if (strcasecmp(str, "query") == 0) { + dt &= ~DNS_DTTYPE_RESPONSE; + } else if (strcasecmp(str, "response") == 0) { + dt &= ~DNS_DTTYPE_QUERY; + } + + dttypes |= dt; + } + + if (named_g_server->dtenv == NULL && dttypes != 0) { + dns_dtmode_t dmode; + uint64_t max_size = 0; + uint32_t rolls = 0; + isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment; + + obj = NULL; + CHECKM(named_config_get(maps, "dnstap-output", &obj), + "'dnstap-output' must be set if 'dnstap' is set"); + + obj2 = cfg_tuple_get(obj, "mode"); + if (obj2 == NULL) { + CHECKM(ISC_R_FAILURE, "dnstap-output mode not found"); + } + if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) { + dmode = dns_dtmode_file; + } else { + dmode = dns_dtmode_unix; + } + + obj2 = cfg_tuple_get(obj, "path"); + if (obj2 == NULL) { + CHECKM(ISC_R_FAILURE, "dnstap-output path not found"); + } + + dpath = cfg_obj_asstring(obj2); + + obj2 = cfg_tuple_get(obj, "size"); + if (obj2 != NULL && cfg_obj_isuint64(obj2)) { + max_size = cfg_obj_asuint64(obj2); + if (max_size > SIZE_MAX) { + cfg_obj_log(obj2, named_g_lctx, ISC_LOG_WARNING, + "'dnstap-output size " + "%" PRIu64 "' " + "is too large for this " + "system; reducing to %lu", + max_size, (unsigned long)SIZE_MAX); + max_size = SIZE_MAX; + } + } + + obj2 = cfg_tuple_get(obj, "versions"); + if (obj2 != NULL && cfg_obj_isuint32(obj2)) { + rolls = cfg_obj_asuint32(obj2); + } else { + rolls = ISC_LOG_ROLLINFINITE; + } + + obj2 = cfg_tuple_get(obj, "suffix"); + if (obj2 != NULL && cfg_obj_isstring(obj2) && + strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0) + { + suffix = isc_log_rollsuffix_timestamp; + } + + fopt = fstrm_iothr_options_init(); + /* + * Both network threads and worker threads may log dnstap data. + */ + fstrm_iothr_options_set_num_input_queues(fopt, + 2 * named_g_cpus); + fstrm_iothr_options_set_queue_model( + fopt, FSTRM_IOTHR_QUEUE_MODEL_MPSC); + + obj = NULL; + result = named_config_get(maps, "fstrm-set-buffer-hint", &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + fstrm_iothr_options_set_buffer_hint(fopt, i); + } + + obj = NULL; + result = named_config_get(maps, "fstrm-set-flush-timeout", + &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + fstrm_iothr_options_set_flush_timeout(fopt, i); + } + + obj = NULL; + result = named_config_get(maps, "fstrm-set-input-queue-size", + &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + fstrm_iothr_options_set_input_queue_size(fopt, i); + } + + obj = NULL; + result = named_config_get( + maps, "fstrm-set-output-notify-threshold", &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + fstrm_iothr_options_set_queue_notify_threshold(fopt, i); + } + + obj = NULL; + result = named_config_get(maps, "fstrm-set-output-queue-model", + &obj); + if (result == ISC_R_SUCCESS) { + if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0) { + i = FSTRM_IOTHR_QUEUE_MODEL_SPSC; + } else { + i = FSTRM_IOTHR_QUEUE_MODEL_MPSC; + } + fstrm_iothr_options_set_queue_model(fopt, i); + } + + obj = NULL; + result = named_config_get(maps, "fstrm-set-output-queue-size", + &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asuint32(obj); + fstrm_iothr_options_set_output_queue_size(fopt, i); + } + + obj = NULL; + result = named_config_get(maps, "fstrm-set-reopen-interval", + &obj); + if (result == ISC_R_SUCCESS) { + i = cfg_obj_asduration(obj); + fstrm_iothr_options_set_reopen_interval(fopt, i); + } + + CHECKM(dns_dt_create(named_g_mctx, dmode, dpath, &fopt, + named_g_server->task, + &named_g_server->dtenv), + "unable to create dnstap environment"); + + CHECKM(dns_dt_setupfile(named_g_server->dtenv, max_size, rolls, + suffix), + "unable to set up dnstap logfile"); + } + + if (named_g_server->dtenv == NULL) { + return (ISC_R_SUCCESS); + } + + obj = NULL; + result = named_config_get(maps, "dnstap-version", &obj); + if (result != ISC_R_SUCCESS) { + /* not specified; use the product and version */ + dns_dt_setversion(named_g_server->dtenv, PRODUCT " " VERSION); + } else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) { + /* Quoted string */ + dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj)); + } + + obj = NULL; + result = named_config_get(maps, "dnstap-identity", &obj); + if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { + /* "hostname" is interpreted as boolean true */ + char buf[256]; + result = named_os_gethostname(buf, sizeof(buf)); + if (result == ISC_R_SUCCESS) { + dns_dt_setidentity(named_g_server->dtenv, buf); + } + } else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) { + /* Quoted string */ + dns_dt_setidentity(named_g_server->dtenv, + cfg_obj_asstring(obj)); + } + + dns_dt_attach(named_g_server->dtenv, &view->dtenv); + view->dttypes = dttypes; + + result = ISC_R_SUCCESS; + +cleanup: + if (fopt != NULL) { + fstrm_iothr_options_destroy(&fopt); + } + + return (result); +} +#endif /* HAVE_DNSTAP */ + +static isc_result_t +create_mapped_acl(void) { + isc_result_t result; + dns_acl_t *acl = NULL; + struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT; + isc_netaddr_t addr; + + isc_netaddr_fromin6(&addr, &in6); + + result = dns_acl_create(named_g_mctx, 1, &acl); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = dns_iptable_addprefix(acl->iptable, &addr, 96, true); + if (result == ISC_R_SUCCESS) { + dns_acl_attach(acl, &named_g_mapped); + } + dns_acl_detach(&acl); + return (result); +} + +#ifdef HAVE_DLOPEN +/*% + * A callback for the cfg_pluginlist_foreach() call in configure_view() below. + * If registering any plugin fails, registering subsequent ones is not + * attempted. + */ +static isc_result_t +register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj, + const char *plugin_path, const char *parameters, + void *callback_data) { + dns_view_t *view = callback_data; + char full_path[PATH_MAX]; + isc_result_t result; + + result = ns_plugin_expandpath(plugin_path, full_path, + sizeof(full_path)); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "%s: plugin configuration failed: " + "unable to get full plugin path: %s", + plugin_path, isc_result_totext(result)); + return (result); + } + + result = ns_plugin_register(full_path, parameters, config, + cfg_obj_file(obj), cfg_obj_line(obj), + named_g_mctx, named_g_lctx, + named_g_aclconfctx, view); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "%s: plugin configuration failed: %s", full_path, + isc_result_totext(result)); + } + + return (result); +} +#endif /* ifdef HAVE_DLOPEN */ + +/* + * Determine if a minimal-sized cache can be used for a given view, according + * to 'maps' (implicit defaults, global options, view options) and 'optionmaps' + * (global options, view options). This is only allowed for views which have + * recursion disabled and do not have "max-cache-size" set explicitly. Using + * minimal-sized caches prevents a situation in which all explicitly configured + * and built-in views inherit the default "max-cache-size 90%;" setting, which + * could lead to memory exhaustion with multiple views configured. + */ +static bool +minimal_cache_allowed(const cfg_obj_t *maps[4], + const cfg_obj_t *optionmaps[3]) { + const cfg_obj_t *obj; + + /* + * Do not use a minimal-sized cache for a view with recursion enabled. + */ + obj = NULL; + (void)named_config_get(maps, "recursion", &obj); + INSIST(obj != NULL); + if (cfg_obj_asboolean(obj)) { + return (false); + } + + /* + * Do not use a minimal-sized cache if a specific size was requested. + */ + obj = NULL; + (void)named_config_get(optionmaps, "max-cache-size", &obj); + if (obj != NULL) { + return (false); + } + + return (true); +} + +static const char *const response_synonyms[] = { "response", NULL }; + +/* + * Configure 'view' according to 'vconfig', taking defaults from 'config' + * where values are missing in 'vconfig'. + * + * When configuring the default view, 'vconfig' will be NULL and the + * global defaults in 'config' used exclusively. + */ +static isc_result_t +configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, + cfg_obj_t *vconfig, named_cachelist_t *cachelist, + dns_kasplist_t *kasplist, const cfg_obj_t *bindkeys, + isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints) { + const cfg_obj_t *maps[4]; + const cfg_obj_t *cfgmaps[3]; + const cfg_obj_t *optionmaps[3]; + const cfg_obj_t *options = NULL; + const cfg_obj_t *voptions = NULL; + const cfg_obj_t *forwardtype; + const cfg_obj_t *forwarders; + const cfg_obj_t *alternates; + const cfg_obj_t *zonelist; + const cfg_obj_t *dlzlist; + const cfg_obj_t *dlz; + const cfg_obj_t *prefetch_trigger; + const cfg_obj_t *prefetch_eligible; + unsigned int dlzargc; + char **dlzargv; + const cfg_obj_t *dyndb_list, *plugin_list; + const cfg_obj_t *disabled; + const cfg_obj_t *obj, *obj2; + const cfg_listelt_t *element = NULL; + const cfg_listelt_t *zone_element_latest = NULL; + in_port_t port; + dns_cache_t *cache = NULL; + isc_result_t result; + size_t max_cache_size; + uint32_t max_cache_size_percent = 0; + size_t max_adb_size; + uint32_t lame_ttl, fail_ttl; + uint32_t max_stale_ttl = 0; + uint32_t stale_refresh_time = 0; + dns_tsig_keyring_t *ring = NULL; + dns_view_t *pview = NULL; /* Production view */ + isc_mem_t *cmctx = NULL, *hmctx = NULL; + dns_dispatch_t *dispatch4 = NULL; + dns_dispatch_t *dispatch6 = NULL; + bool rpz_configured = false; + bool catz_configured = false; + bool reused_cache = false; + bool shared_cache = false; + int i = 0, j = 0, k = 0; + const char *str; + const char *cachename = NULL; + dns_order_t *order = NULL; + uint32_t udpsize; + uint32_t maxbits; + unsigned int resopts = 0; + dns_zone_t *zone = NULL; + uint32_t max_clients_per_query; + bool empty_zones_enable; + const cfg_obj_t *disablelist = NULL; + isc_stats_t *resstats = NULL; + dns_stats_t *resquerystats = NULL; + bool auto_root = false; + named_cache_t *nsc; + bool zero_no_soattl; + dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL; + unsigned int query_timeout, ndisp; + bool old_rpz_ok = false; + isc_dscp_t dscp4 = -1, dscp6 = -1; + dns_dyndbctx_t *dctx = NULL; + unsigned int resolver_param; + dns_ntatable_t *ntatable = NULL; + const char *qminmode = NULL; + + REQUIRE(DNS_VIEW_VALID(view)); + + if (config != NULL) { + (void)cfg_map_get(config, "options", &options); + } + + /* + * maps: view options, options, defaults + * cfgmaps: view options, config + * optionmaps: view options, options + */ + if (vconfig != NULL) { + voptions = cfg_tuple_get(vconfig, "options"); + maps[i++] = voptions; + optionmaps[j++] = voptions; + cfgmaps[k++] = voptions; + } + if (options != NULL) { + maps[i++] = options; + optionmaps[j++] = options; + } + + maps[i++] = named_g_defaults; + maps[i] = NULL; + optionmaps[j] = NULL; + if (config != NULL) { + cfgmaps[k++] = config; + } + cfgmaps[k] = NULL; + + /* + * Set the view's port number for outgoing queries. + */ + CHECKM(named_config_getport(config, &port), "port"); + dns_view_setdstport(view, port); + + /* + * Make the list of response policy zone names for a view that + * is used for real lookups and so cares about hints. + */ + obj = NULL; + if (view->rdclass == dns_rdataclass_in && need_hints && + named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) + { + CHECK(configure_rpz(view, NULL, maps, obj, &old_rpz_ok)); + rpz_configured = true; + } + + obj = NULL; + if (view->rdclass == dns_rdataclass_in && need_hints && + named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS) + { + CHECK(configure_catz(view, NULL, config, obj)); + catz_configured = true; + } + + /* + * Configure the zones. + */ + zonelist = NULL; + if (voptions != NULL) { + (void)cfg_map_get(voptions, "zone", &zonelist); + } else { + (void)cfg_map_get(config, "zone", &zonelist); + } + + /* + * Load zone configuration + */ + for (element = cfg_list_first(zonelist); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *zconfig = cfg_listelt_value(element); + CHECK(configure_zone(config, zconfig, vconfig, mctx, view, + viewlist, kasplist, actx, false, + old_rpz_ok, false)); + zone_element_latest = element; + } + + /* + * Check that a master or slave zone was found for each + * zone named in the response policy statement + * unless we are using RPZ service interface. + */ + if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) { + dns_rpz_num_t n; + + for (n = 0; n < view->rpzs->p.num_zones; ++n) { + if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) { + char namebuf[DNS_NAME_FORMATSIZE]; + + dns_name_format(&view->rpzs->zones[n]->origin, + namebuf, sizeof(namebuf)); + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, + DNS_RPZ_ERROR_LEVEL, + "rpz '%s'" + " is not a master or slave zone", + namebuf); + result = ISC_R_NOTFOUND; + goto cleanup; + } + } + } + + /* + * If we're allowing added zones, then load zone configuration + * from the newzone file for zones that were added during previous + * runs. + */ + CHECK(configure_newzones(view, config, vconfig, mctx, actx)); + + /* + * Create Dynamically Loadable Zone driver. + */ + dlzlist = NULL; + if (voptions != NULL) { + (void)cfg_map_get(voptions, "dlz", &dlzlist); + } else { + (void)cfg_map_get(config, "dlz", &dlzlist); + } + + for (element = cfg_list_first(dlzlist); element != NULL; + element = cfg_list_next(element)) + { + dlz = cfg_listelt_value(element); + + obj = NULL; + (void)cfg_map_get(dlz, "database", &obj); + if (obj != NULL) { + dns_dlzdb_t *dlzdb = NULL; + const cfg_obj_t *name, *search = NULL; + char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); + + if (s == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + + result = isc_commandline_strtoargv(mctx, s, &dlzargc, + &dlzargv, 0); + if (result != ISC_R_SUCCESS) { + isc_mem_free(mctx, s); + goto cleanup; + } + + name = cfg_map_getname(dlz); + result = dns_dlzcreate(mctx, cfg_obj_asstring(name), + dlzargv[0], dlzargc, dlzargv, + &dlzdb); + isc_mem_free(mctx, s); + isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv)); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + /* + * If the DLZ backend supports configuration, + * and is searchable, then call its configure + * method now. If not searchable, we'll take + * care of it when we process the zone statement. + */ + (void)cfg_map_get(dlz, "search", &search); + if (search == NULL || cfg_obj_asboolean(search)) { + dlzdb->search = true; + result = dns_dlzconfigure( + view, dlzdb, dlzconfigure_callback); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + ISC_LIST_APPEND(view->dlz_searched, dlzdb, + link); + } else { + dlzdb->search = false; + ISC_LIST_APPEND(view->dlz_unsearched, dlzdb, + link); + } + } + } + + /* + * Obtain configuration parameters that affect the decision of whether + * we can reuse/share an existing cache. + */ + obj = NULL; + result = named_config_get(maps, "max-cache-size", &obj); + INSIST(result == ISC_R_SUCCESS); + /* + * If "-T maxcachesize=..." is in effect, it overrides any other + * "max-cache-size" setting found in configuration, either implicit or + * explicit. For simplicity, the value passed to that command line + * option is always treated as the number of bytes to set + * "max-cache-size" to. + */ + if (named_g_maxcachesize != 0) { + max_cache_size = named_g_maxcachesize; + } else if (minimal_cache_allowed(maps, optionmaps)) { + /* + * dns_cache_setcachesize() will adjust this to the smallest + * allowed value. + */ + max_cache_size = 1; + } else if (cfg_obj_isstring(obj)) { + str = cfg_obj_asstring(obj); + INSIST(strcasecmp(str, "unlimited") == 0); + max_cache_size = 0; + } else if (cfg_obj_ispercentage(obj)) { + max_cache_size = SIZE_AS_PERCENT; + max_cache_size_percent = cfg_obj_aspercentage(obj); + } else { + isc_resourcevalue_t value; + value = cfg_obj_asuint64(obj); + if (value > SIZE_MAX) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "'max-cache-size " + "%" PRIu64 "' " + "is too large for this " + "system; reducing to %lu", + value, (unsigned long)SIZE_MAX); + value = SIZE_MAX; + } + max_cache_size = (size_t)value; + } + + if (max_cache_size == SIZE_AS_PERCENT) { + uint64_t totalphys = isc_meminfo_totalphys(); + + max_cache_size = + (size_t)(totalphys * max_cache_size_percent / 100); + if (totalphys == 0) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "Unable to determine amount of physical " + "memory, setting 'max-cache-size' to " + "unlimited"); + } else { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO, + "'max-cache-size %d%%' " + "- setting to %" PRIu64 "MB " + "(out of %" PRIu64 "MB)", + max_cache_size_percent, + (uint64_t)(max_cache_size / (1024 * 1024)), + totalphys / (1024 * 1024)); + } + } + + /* Check-names. */ + obj = NULL; + result = named_checknames_get(maps, response_synonyms, &obj); + INSIST(result == ISC_R_SUCCESS); + + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "fail") == 0) { + resopts |= DNS_RESOLVER_CHECKNAMES | + DNS_RESOLVER_CHECKNAMESFAIL; + view->checknames = true; + } else if (strcasecmp(str, "warn") == 0) { + resopts |= DNS_RESOLVER_CHECKNAMES; + view->checknames = false; + } else if (strcasecmp(str, "ignore") == 0) { + view->checknames = false; + } else { + UNREACHABLE(); + } + + obj = NULL; + result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj); + INSIST(result == ISC_R_SUCCESS); + zero_no_soattl = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "dns64", &obj); + if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") && + strcmp(view->name, "_meta")) + { + isc_netaddr_t na, suffix, *sp; + unsigned int prefixlen; + const char *server, *contact; + const cfg_obj_t *myobj; + + myobj = NULL; + result = named_config_get(maps, "dns64-server", &myobj); + if (result == ISC_R_SUCCESS) { + server = cfg_obj_asstring(myobj); + } else { + server = NULL; + } + + myobj = NULL; + result = named_config_get(maps, "dns64-contact", &myobj); + if (result == ISC_R_SUCCESS) { + contact = cfg_obj_asstring(myobj); + } else { + contact = NULL; + } + + for (element = cfg_list_first(obj); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *map = cfg_listelt_value(element); + dns_dns64_t *dns64 = NULL; + unsigned int dns64options = 0; + + cfg_obj_asnetprefix(cfg_map_getname(map), &na, + &prefixlen); + + obj = NULL; + (void)cfg_map_get(map, "suffix", &obj); + if (obj != NULL) { + sp = &suffix; + isc_netaddr_fromsockaddr( + sp, cfg_obj_assockaddr(obj)); + } else { + sp = NULL; + } + + clients = mapped = excluded = NULL; + obj = NULL; + (void)cfg_map_get(map, "clients", &obj); + if (obj != NULL) { + result = cfg_acl_fromconfig(obj, config, + named_g_lctx, actx, + mctx, 0, &clients); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } + obj = NULL; + (void)cfg_map_get(map, "mapped", &obj); + if (obj != NULL) { + result = cfg_acl_fromconfig(obj, config, + named_g_lctx, actx, + mctx, 0, &mapped); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } + obj = NULL; + (void)cfg_map_get(map, "exclude", &obj); + if (obj != NULL) { + result = cfg_acl_fromconfig(obj, config, + named_g_lctx, actx, + mctx, 0, &excluded); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } else { + if (named_g_mapped == NULL) { + result = create_mapped_acl(); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } + dns_acl_attach(named_g_mapped, &excluded); + } + + obj = NULL; + (void)cfg_map_get(map, "recursive-only", &obj); + if (obj != NULL && cfg_obj_asboolean(obj)) { + dns64options |= DNS_DNS64_RECURSIVE_ONLY; + } + + obj = NULL; + (void)cfg_map_get(map, "break-dnssec", &obj); + if (obj != NULL && cfg_obj_asboolean(obj)) { + dns64options |= DNS_DNS64_BREAK_DNSSEC; + } + + result = dns_dns64_create(mctx, &na, prefixlen, sp, + clients, mapped, excluded, + dns64options, &dns64); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + dns_dns64_append(&view->dns64, dns64); + view->dns64cnt++; + result = dns64_reverse(view, mctx, &na, prefixlen, + server, contact); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + if (clients != NULL) { + dns_acl_detach(&clients); + } + if (mapped != NULL) { + dns_acl_detach(&mapped); + } + if (excluded != NULL) { + dns_acl_detach(&excluded); + } + } + } + + obj = NULL; + result = named_config_get(maps, "dnssec-accept-expired", &obj); + INSIST(result == ISC_R_SUCCESS); + view->acceptexpired = cfg_obj_asboolean(obj); + + obj = NULL; + /* 'optionmaps', not 'maps': don't check named_g_defaults yet */ + (void)named_config_get(optionmaps, "dnssec-validation", &obj); + if (obj == NULL) { + /* + * Default to VALIDATION_DEFAULT as set in config.c. + */ + (void)cfg_map_get(named_g_defaults, "dnssec-validation", &obj); + INSIST(obj != NULL); + } + if (obj != NULL) { + if (cfg_obj_isboolean(obj)) { + view->enablevalidation = cfg_obj_asboolean(obj); + } else { + /* + * If dnssec-validation is set but not boolean, + * then it must be "auto" + */ + view->enablevalidation = true; + auto_root = true; + } + } + + obj = NULL; + result = named_config_get(maps, "max-cache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->maxcachettl = cfg_obj_asduration(obj); + + obj = NULL; + result = named_config_get(maps, "max-ncache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->maxncachettl = cfg_obj_asduration(obj); + + obj = NULL; + result = named_config_get(maps, "min-cache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->mincachettl = cfg_obj_asduration(obj); + + obj = NULL; + result = named_config_get(maps, "min-ncache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->minncachettl = cfg_obj_asduration(obj); + + obj = NULL; + result = named_config_get(maps, "synth-from-dnssec", &obj); + INSIST(result == ISC_R_SUCCESS); + view->synthfromdnssec = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "stale-cache-enable", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_asboolean(obj)) { + obj = NULL; + result = named_config_get(maps, "max-stale-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1); + } + /* + * If 'stale-cache-enable' is false, max_stale_ttl is set to 0, + * meaning keeping stale RRsets in cache is disabled. + */ + + obj = NULL; + result = named_config_get(maps, "stale-answer-enable", &obj); + INSIST(result == ISC_R_SUCCESS); + view->staleanswersenable = cfg_obj_asboolean(obj); + + result = dns_viewlist_find(&named_g_server->viewlist, view->name, + view->rdclass, &pview); + if (result == ISC_R_SUCCESS) { + view->staleanswersok = pview->staleanswersok; + dns_view_detach(&pview); + } else { + view->staleanswersok = dns_stale_answer_conf; + } + + obj = NULL; + result = named_config_get(maps, "stale-answer-client-timeout", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isstring(obj)) { + /* + * The only string values available for this option + * are "disabled" and "off". + * We use (uint32_t) -1 to represent disabled since + * a value of zero means that stale data can be used + * to promptly answer the query, while an attempt to + * refresh the RRset will still be made in background. + */ + view->staleanswerclienttimeout = (uint32_t)-1; + } else { + view->staleanswerclienttimeout = cfg_obj_asuint32(obj); + } + + obj = NULL; + result = named_config_get(maps, "stale-refresh-time", &obj); + INSIST(result == ISC_R_SUCCESS); + stale_refresh_time = cfg_obj_asduration(obj); + + /* + * Configure the view's cache. + * + * First, check to see if there are any attach-cache options. If yes, + * attempt to lookup an existing cache at attach it to the view. If + * there is not one, then try to reuse an existing cache if possible; + * otherwise create a new cache. + * + * Note that the ADB is not preserved or shared in either case. + * + * When a matching view is found, the associated statistics are also + * retrieved and reused. + * + * XXX Determining when it is safe to reuse or share a cache is tricky. + * When the view's configuration changes, the cached data may become + * invalid because it reflects our old view of the world. We check + * some of the configuration parameters that could invalidate the cache + * or otherwise make it unshareable, but there are other configuration + * options that should be checked. For example, if a view uses a + * forwarder, changes in the forwarder configuration may invalidate + * the cache. At the moment, it's the administrator's responsibility to + * ensure these configuration options don't invalidate reusing/sharing. + */ + obj = NULL; + result = named_config_get(maps, "attach-cache", &obj); + if (result == ISC_R_SUCCESS) { + cachename = cfg_obj_asstring(obj); + } else { + cachename = view->name; + } + cache = NULL; + nsc = cachelist_find(cachelist, cachename, view->rdclass); + if (nsc != NULL) { + if (!cache_sharable(nsc->primaryview, view, zero_no_soattl, + max_cache_size, max_stale_ttl, + stale_refresh_time)) + { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "views %s and %s can't share the cache " + "due to configuration parameter mismatch", + nsc->primaryview->name, view->name); + result = ISC_R_FAILURE; + goto cleanup; + } + dns_cache_attach(nsc->cache, &cache); + shared_cache = true; + } else { + if (strcmp(cachename, view->name) == 0) { + result = dns_viewlist_find(&named_g_server->viewlist, + cachename, view->rdclass, + &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) + { + goto cleanup; + } + if (pview != NULL) { + if (!cache_reusable(pview, view, + zero_no_soattl)) + { + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, + ISC_LOG_DEBUG(1), + "cache cannot be reused " + "for view %s due to " + "configuration parameter " + "mismatch", + view->name); + } else { + INSIST(pview->cache != NULL); + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, + ISC_LOG_DEBUG(3), + "reusing existing cache"); + reused_cache = true; + dns_cache_attach(pview->cache, &cache); + } + dns_view_getresstats(pview, &resstats); + dns_view_getresquerystats(pview, + &resquerystats); + dns_view_detach(&pview); + } + } + if (cache == NULL) { + /* + * Create a cache with the desired name. This normally + * equals the view name, but may also be a forward + * reference to a view that share the cache with this + * view but is not yet configured. If it is not the + * view name but not a forward reference either, then it + * is simply a named cache that is not shared. + * + * We use two separate memory contexts for the + * cache, for the main cache memory and the heap + * memory. + */ + isc_mem_create(&cmctx); + isc_mem_setname(cmctx, "cache", NULL); + isc_mem_create(&hmctx); + isc_mem_setname(hmctx, "cache_heap", NULL); + CHECK(dns_cache_create(cmctx, hmctx, named_g_taskmgr, + named_g_timermgr, view->rdclass, + cachename, "rbt", 0, NULL, + &cache)); + isc_mem_detach(&cmctx); + isc_mem_detach(&hmctx); + } + nsc = isc_mem_get(mctx, sizeof(*nsc)); + nsc->cache = NULL; + dns_cache_attach(cache, &nsc->cache); + nsc->primaryview = view; + nsc->needflush = false; + nsc->adbsizeadjusted = false; + nsc->rdclass = view->rdclass; + ISC_LINK_INIT(nsc, link); + ISC_LIST_APPEND(*cachelist, nsc, link); + } + dns_view_setcache(view, cache, shared_cache); + + /* + * cache-file cannot be inherited if views are present, but this + * should be caught by the configuration checking stage. + */ + obj = NULL; + result = named_config_get(maps, "cache-file", &obj); + if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) { + CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj))); + if (!reused_cache && !shared_cache) { + CHECK(dns_cache_load(cache)); + } + } + + dns_cache_setcachesize(cache, max_cache_size); + dns_cache_setservestalettl(cache, max_stale_ttl); + dns_cache_setservestalerefresh(cache, stale_refresh_time); + + dns_cache_detach(&cache); + + obj = NULL; + result = named_config_get(maps, "stale-answer-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1); + + /* + * Resolver. + * + * XXXRTH Hardwired number of tasks. + */ + CHECK(get_view_querysource_dispatch( + maps, AF_INET, &dispatch4, &dscp4, + (ISC_LIST_PREV(view, link) == NULL))); + CHECK(get_view_querysource_dispatch( + maps, AF_INET6, &dispatch6, &dscp6, + (ISC_LIST_PREV(view, link) == NULL))); + if (dispatch4 == NULL && dispatch6 == NULL) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "unable to obtain neither an IPv4 nor" + " an IPv6 dispatch"); + result = ISC_R_UNEXPECTED; + goto cleanup; + } + + if (resstats == NULL) { + CHECK(isc_stats_create(mctx, &resstats, + dns_resstatscounter_max)); + } + dns_view_setresstats(view, resstats); + if (resquerystats == NULL) { + CHECK(dns_rdatatypestats_create(mctx, &resquerystats)); + } + dns_view_setresquerystats(view, resquerystats); + + ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH); + CHECK(dns_view_createresolver( + view, named_g_taskmgr, RESOLVER_NTASKS_PERCPU * named_g_cpus, + ndisp, named_g_socketmgr, named_g_timermgr, resopts, + named_g_dispatchmgr, dispatch4, dispatch6)); + + if (dscp4 == -1) { + dscp4 = named_g_dscp; + } + if (dscp6 == -1) { + dscp6 = named_g_dscp; + } + if (dscp4 != -1) { + dns_resolver_setquerydscp4(view->resolver, dscp4); + } + if (dscp6 != -1) { + dns_resolver_setquerydscp6(view->resolver, dscp6); + } + + /* + * Set the ADB cache size to 1/8th of the max-cache-size or + * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared. + */ + max_adb_size = 0; + if (max_cache_size != 0U) { + max_adb_size = max_cache_size / 8; + if (max_adb_size == 0U) { + max_adb_size = 1; /* Force minimum. */ + } + if (view != nsc->primaryview && + max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) + { + max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE; + if (!nsc->adbsizeadjusted) { + dns_adb_setadbsize(nsc->primaryview->adb, + MAX_ADB_SIZE_FOR_CACHESHARE); + nsc->adbsizeadjusted = true; + } + } + } + dns_adb_setadbsize(view->adb, max_adb_size); + + /* + * Set up ADB quotas + */ + { + uint32_t fps, freq; + double low, high, discount; + + obj = NULL; + result = named_config_get(maps, "fetches-per-server", &obj); + INSIST(result == ISC_R_SUCCESS); + obj2 = cfg_tuple_get(obj, "fetches"); + fps = cfg_obj_asuint32(obj2); + obj2 = cfg_tuple_get(obj, "response"); + if (!cfg_obj_isvoid(obj2)) { + const char *resp = cfg_obj_asstring(obj2); + isc_result_t r = DNS_R_SERVFAIL; + + if (strcasecmp(resp, "drop") == 0) { + r = DNS_R_DROP; + } else if (strcasecmp(resp, "fail") == 0) { + r = DNS_R_SERVFAIL; + } else { + UNREACHABLE(); + } + + dns_resolver_setquotaresponse(view->resolver, + dns_quotatype_server, r); + } + + obj = NULL; + result = named_config_get(maps, "fetch-quota-params", &obj); + INSIST(result == ISC_R_SUCCESS); + + obj2 = cfg_tuple_get(obj, "frequency"); + freq = cfg_obj_asuint32(obj2); + + obj2 = cfg_tuple_get(obj, "low"); + low = (double)cfg_obj_asfixedpoint(obj2) / 100.0; + + obj2 = cfg_tuple_get(obj, "high"); + high = (double)cfg_obj_asfixedpoint(obj2) / 100.0; + + obj2 = cfg_tuple_get(obj, "discount"); + discount = (double)cfg_obj_asfixedpoint(obj2) / 100.0; + + dns_adb_setquota(view->adb, fps, freq, low, high, discount); + } + + /* + * Set resolver's lame-ttl. + */ + obj = NULL; + result = named_config_get(maps, "lame-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + lame_ttl = cfg_obj_asduration(obj); + if (lame_ttl > 0) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "disabling lame cache despite lame-ttl > 0 as it " + "may cause performance issues"); + lame_ttl = 0; + } + dns_resolver_setlamettl(view->resolver, lame_ttl); + + /* + * Set the resolver's query timeout. + */ + obj = NULL; + result = named_config_get(maps, "resolver-query-timeout", &obj); + INSIST(result == ISC_R_SUCCESS); + query_timeout = cfg_obj_asuint32(obj); + dns_resolver_settimeout(view->resolver, query_timeout); + + /* + * Adjust stale-answer-client-timeout upper bound + * to be resolver-query-timeout - 1s. + * This assignment is safe as dns_resolver_settimeout() + * ensures that resolver->querytimeout value will be in the + * [MINIMUM_QUERY_TIMEOUT, MAXIMUM_QUERY_TIMEOUT] range and + * MINIMUM_QUERY_TIMEOUT is > 1000 (in ms). + */ + if (view->staleanswerclienttimeout != (uint32_t)-1 && + view->staleanswerclienttimeout > + (dns_resolver_gettimeout(view->resolver) - 1000)) + { + view->staleanswerclienttimeout = + dns_resolver_gettimeout(view->resolver) - 1000; + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "stale-answer-client-timeout adjusted to %" PRIu32, + view->staleanswerclienttimeout); + } + + /* Specify whether to use 0-TTL for negative response for SOA query */ + dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl); + + /* + * Set the resolver's EDNS UDP size. + */ + obj = NULL; + result = named_config_get(maps, "edns-udp-size", &obj); + INSIST(result == ISC_R_SUCCESS); + udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) { + udpsize = 512; + } + if (udpsize > 4096) { + udpsize = 4096; + } + dns_resolver_setudpsize(view->resolver, (uint16_t)udpsize); + + /* + * Set the maximum UDP response size. + */ + obj = NULL; + result = named_config_get(maps, "max-udp-size", &obj); + INSIST(result == ISC_R_SUCCESS); + udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) { + udpsize = 512; + } + if (udpsize > 4096) { + udpsize = 4096; + } + view->maxudp = udpsize; + + /* + * Set the maximum UDP when a COOKIE is not provided. + */ + obj = NULL; + result = named_config_get(maps, "nocookie-udp-size", &obj); + INSIST(result == ISC_R_SUCCESS); + udpsize = cfg_obj_asuint32(obj); + if (udpsize < 128) { + udpsize = 128; + } + if (udpsize > view->maxudp) { + udpsize = view->maxudp; + } + view->nocookieudp = udpsize; + + /* + * Set the maximum rsa exponent bits. + */ + obj = NULL; + result = named_config_get(maps, "max-rsa-exponent-size", &obj); + INSIST(result == ISC_R_SUCCESS); + maxbits = cfg_obj_asuint32(obj); + if (maxbits != 0 && maxbits < 35) { + maxbits = 35; + } + if (maxbits > 4096) { + maxbits = 4096; + } + view->maxbits = maxbits; + + /* + * Set resolver retry parameters. + */ + obj = NULL; + CHECK(named_config_get(maps, "resolver-retry-interval", &obj)); + resolver_param = cfg_obj_asuint32(obj); + if (resolver_param > 0) { + dns_resolver_setretryinterval(view->resolver, resolver_param); + } + + obj = NULL; + CHECK(named_config_get(maps, "resolver-nonbackoff-tries", &obj)); + resolver_param = cfg_obj_asuint32(obj); + if (resolver_param > 0) { + dns_resolver_setnonbackofftries(view->resolver, resolver_param); + } + + /* + * Set supported DNSSEC algorithms. + */ + dns_resolver_reset_algorithms(view->resolver); + disabled = NULL; + (void)named_config_get(maps, "disable-algorithms", &disabled); + if (disabled != NULL) { + for (element = cfg_list_first(disabled); element != NULL; + element = cfg_list_next(element)) + { + CHECK(disable_algorithms(cfg_listelt_value(element), + view->resolver)); + } + } + + /* + * Set supported DS digest types. + */ + dns_resolver_reset_ds_digests(view->resolver); + disabled = NULL; + (void)named_config_get(maps, "disable-ds-digests", &disabled); + if (disabled != NULL) { + for (element = cfg_list_first(disabled); element != NULL; + element = cfg_list_next(element)) + { + CHECK(disable_ds_digests(cfg_listelt_value(element), + view->resolver)); + } + } + + /* + * A global or view "forwarders" option, if present, + * creates an entry for "." in the forwarding table. + */ + forwardtype = NULL; + forwarders = NULL; + (void)named_config_get(maps, "forward", &forwardtype); + (void)named_config_get(maps, "forwarders", &forwarders); + if (forwarders != NULL) { + CHECK(configure_forward(config, view, dns_rootname, forwarders, + forwardtype)); + } + + /* + * Dual Stack Servers. + */ + alternates = NULL; + (void)named_config_get(maps, "dual-stack-servers", &alternates); + if (alternates != NULL) { + CHECK(configure_alternates(config, view, alternates)); + } + + /* + * We have default hints for class IN if we need them. + */ + if (view->rdclass == dns_rdataclass_in && view->hints == NULL) { + dns_view_sethints(view, named_g_server->in_roothints); + } + + /* + * If we still have no hints, this is a non-IN view with no + * "hints zone" configured. Issue a warning, except if this + * is a root server. Root servers never need to consult + * their hints, so it's no point requiring users to configure + * them. + */ + if (view->hints == NULL) { + dns_zone_t *rootzone = NULL; + (void)dns_view_findzone(view, dns_rootname, &rootzone); + if (rootzone != NULL) { + dns_zone_detach(&rootzone); + need_hints = false; + } + if (need_hints) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "no root hints for view '%s'", + view->name); + } + } + + /* + * Configure the view's TSIG keys. + */ + CHECK(named_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring)); + if (named_g_server->sessionkey != NULL) { + CHECK(dns_tsigkeyring_add(ring, named_g_server->session_keyname, + named_g_server->sessionkey)); + } + dns_view_setkeyring(view, ring); + dns_tsigkeyring_detach(&ring); + + /* + * See if we can re-use a dynamic key ring. + */ + result = dns_viewlist_find(&named_g_server->viewlist, view->name, + view->rdclass, &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) { + goto cleanup; + } + if (pview != NULL) { + dns_view_getdynamickeyring(pview, &ring); + if (ring != NULL) { + dns_view_setdynamickeyring(view, ring); + } + dns_tsigkeyring_detach(&ring); + dns_view_detach(&pview); + } else { + dns_view_restorekeyring(view); + } + + /* + * Configure the view's peer list. + */ + { + const cfg_obj_t *peers = NULL; + dns_peerlist_t *newpeers = NULL; + + (void)named_config_get(cfgmaps, "server", &peers); + CHECK(dns_peerlist_new(mctx, &newpeers)); + for (element = cfg_list_first(peers); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *cpeer = cfg_listelt_value(element); + dns_peer_t *peer; + + CHECK(configure_peer(cpeer, mctx, &peer)); + dns_peerlist_addpeer(newpeers, peer); + dns_peer_detach(&peer); + } + dns_peerlist_detach(&view->peers); + view->peers = newpeers; /* Transfer ownership. */ + } + + /* + * Configure the views rrset-order. + */ + { + const cfg_obj_t *rrsetorder = NULL; + + (void)named_config_get(maps, "rrset-order", &rrsetorder); + CHECK(dns_order_create(mctx, &order)); + for (element = cfg_list_first(rrsetorder); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *ent = cfg_listelt_value(element); + + CHECK(configure_order(order, ent)); + } + if (view->order != NULL) { + dns_order_detach(&view->order); + } + dns_order_attach(order, &view->order); + dns_order_detach(&order); + } + /* + * Copy the aclenv object. + */ + dns_aclenv_copy(&view->aclenv, ns_interfacemgr_getaclenv( + named_g_server->interfacemgr)); + + /* + * Configure the "match-clients" and "match-destinations" ACL. + * (These are only meaningful at the view level, but 'config' + * must be passed so that named ACLs defined at the global level + * can be retrieved.) + */ + CHECK(configure_view_acl(vconfig, config, NULL, "match-clients", NULL, + actx, named_g_mctx, &view->matchclients)); + CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations", + NULL, actx, named_g_mctx, + &view->matchdestinations)); + + /* + * Configure the "match-recursive-only" option. + */ + obj = NULL; + (void)named_config_get(maps, "match-recursive-only", &obj); + if (obj != NULL && cfg_obj_asboolean(obj)) { + view->matchrecursiveonly = true; + } else { + view->matchrecursiveonly = false; + } + + /* + * Configure other configurable data. + */ + obj = NULL; + result = named_config_get(maps, "recursion", &obj); + INSIST(result == ISC_R_SUCCESS); + view->recursion = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "qname-minimization", &obj); + INSIST(result == ISC_R_SUCCESS); + qminmode = cfg_obj_asstring(obj); + INSIST(qminmode != NULL); + if (!strcmp(qminmode, "strict")) { + view->qminimization = true; + view->qmin_strict = true; + } else if (!strcmp(qminmode, "relaxed")) { + view->qminimization = true; + view->qmin_strict = false; + } else { /* "disabled" or "off" */ + view->qminimization = false; + view->qmin_strict = false; + } + + obj = NULL; + result = named_config_get(maps, "auth-nxdomain", &obj); + INSIST(result == ISC_R_SUCCESS); + view->auth_nxdomain = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "glue-cache", &obj); + INSIST(result == ISC_R_SUCCESS); + view->use_glue_cache = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "minimal-any", &obj); + INSIST(result == ISC_R_SUCCESS); + view->minimal_any = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "minimal-responses", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) { + view->minimalresponses = dns_minimal_yes; + } else { + view->minimalresponses = dns_minimal_no; + } + } else { + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "no-auth") == 0) { + view->minimalresponses = dns_minimal_noauth; + } else if (strcasecmp(str, "no-auth-recursive") == 0) { + view->minimalresponses = dns_minimal_noauthrec; + } else { + UNREACHABLE(); + } + } + + obj = NULL; + result = named_config_get(maps, "transfer-format", &obj); + INSIST(result == ISC_R_SUCCESS); + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "many-answers") == 0) { + view->transfer_format = dns_many_answers; + } else if (strcasecmp(str, "one-answer") == 0) { + view->transfer_format = dns_one_answer; + } else { + UNREACHABLE(); + } + + obj = NULL; + result = named_config_get(maps, "trust-anchor-telemetry", &obj); + INSIST(result == ISC_R_SUCCESS); + view->trust_anchor_telemetry = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "root-key-sentinel", &obj); + INSIST(result == ISC_R_SUCCESS); + view->root_key_sentinel = cfg_obj_asboolean(obj); + + /* + * Set the "allow-query", "allow-query-cache", "allow-recursion", + * "allow-recursion-on" and "allow-query-cache-on" ACLs if + * configured in named.conf, but NOT from the global defaults. + * This is done by leaving the third argument to configure_view_acl() + * NULL. + * + * We ignore the global defaults here because these ACLs + * can inherit from each other. If any are still unset after + * applying the inheritance rules, we'll look up the defaults at + * that time. + */ + + /* named.conf only */ + CHECK(configure_view_acl(vconfig, config, NULL, "allow-query", NULL, + actx, named_g_mctx, &view->queryacl)); + + /* named.conf only */ + CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache", + NULL, actx, named_g_mctx, &view->cacheacl)); + /* named.conf only */ + CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on", + NULL, actx, named_g_mctx, &view->cacheonacl)); + + if (strcmp(view->name, "_bind") != 0 && + view->rdclass != dns_rdataclass_chaos) + { + /* named.conf only */ + CHECK(configure_view_acl(vconfig, config, NULL, + "allow-recursion", NULL, actx, + named_g_mctx, &view->recursionacl)); + /* named.conf only */ + CHECK(configure_view_acl(vconfig, config, NULL, + "allow-recursion-on", NULL, actx, + named_g_mctx, &view->recursiononacl)); + } + + if (view->recursion) { + /* + * "allow-query-cache" inherits from "allow-recursion" if set, + * otherwise from "allow-query" if set. + */ + if (view->cacheacl == NULL) { + if (view->recursionacl != NULL) { + dns_acl_attach(view->recursionacl, + &view->cacheacl); + } else if (view->queryacl != NULL) { + dns_acl_attach(view->queryacl, &view->cacheacl); + } + } + + /* + * "allow-recursion" inherits from "allow-query-cache" if set, + * otherwise from "allow-query" if set. + */ + if (view->recursionacl == NULL) { + if (view->cacheacl != NULL) { + dns_acl_attach(view->cacheacl, + &view->recursionacl); + } else if (view->queryacl != NULL) { + dns_acl_attach(view->queryacl, + &view->recursionacl); + } + } + + /* + * "allow-query-cache-on" inherits from "allow-recursion-on" + * if set. + */ + if (view->cacheonacl == NULL) { + if (view->recursiononacl != NULL) { + dns_acl_attach(view->recursiononacl, + &view->cacheonacl); + } + } + + /* + * "allow-recursion-on" inherits from "allow-query-cache-on" + * if set. + */ + if (view->recursiononacl == NULL) { + if (view->cacheonacl != NULL) { + dns_acl_attach(view->cacheonacl, + &view->recursiononacl); + } + } + + /* + * If any are still unset at this point, we now get default + * values for from the global config. + */ + + if (view->recursionacl == NULL) { + /* global default only */ + CHECK(configure_view_acl( + NULL, NULL, named_g_config, "allow-recursion", + NULL, actx, named_g_mctx, &view->recursionacl)); + } + if (view->recursiononacl == NULL) { + /* global default only */ + CHECK(configure_view_acl(NULL, NULL, named_g_config, + "allow-recursion-on", NULL, + actx, named_g_mctx, + &view->recursiononacl)); + } + if (view->cacheacl == NULL) { + /* global default only */ + CHECK(configure_view_acl( + NULL, NULL, named_g_config, "allow-query-cache", + NULL, actx, named_g_mctx, &view->cacheacl)); + } + if (view->cacheonacl == NULL) { + /* global default only */ + CHECK(configure_view_acl(NULL, NULL, named_g_config, + "allow-query-cache-on", NULL, + actx, named_g_mctx, + &view->cacheonacl)); + } + } else { + /* + * We're not recursive; if the query-cache ACLs haven't + * been set at the options/view level, set them to none. + */ + if (view->cacheacl == NULL) { + CHECK(dns_acl_none(mctx, &view->cacheacl)); + } + if (view->cacheonacl == NULL) { + CHECK(dns_acl_none(mctx, &view->cacheonacl)); + } + } + + /* + * Finished setting recursion and query-cache ACLs, so now we + * can get the allow-query default if it wasn't set in named.conf + */ + if (view->queryacl == NULL) { + /* global default only */ + CHECK(configure_view_acl(NULL, NULL, named_g_config, + "allow-query", NULL, actx, + named_g_mctx, &view->queryacl)); + } + + /* + * Ignore case when compressing responses to the specified + * clients. This causes case not always to be preserved, + * and is needed by some broken clients. + */ + CHECK(configure_view_acl(vconfig, config, named_g_config, + "no-case-compress", NULL, actx, named_g_mctx, + &view->nocasecompress)); + + /* + * Disable name compression completely, this is a tradeoff + * between CPU and network usage. + */ + obj = NULL; + result = named_config_get(maps, "message-compression", &obj); + INSIST(result == ISC_R_SUCCESS); + view->msgcompression = cfg_obj_asboolean(obj); + + /* + * Filter setting on addresses in the answer section. + */ + CHECK(configure_view_acl(vconfig, config, named_g_config, + "deny-answer-addresses", "acl", actx, + named_g_mctx, &view->denyansweracl)); + CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses", + "except-from", named_g_mctx, + &view->answeracl_exclude)); + + /* + * Filter setting on names (CNAME/DNAME targets) in the answer section. + */ + CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", + "name", named_g_mctx, + &view->denyanswernames)); + CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", + "except-from", named_g_mctx, + &view->answernames_exclude)); + + /* + * Configure sortlist, if set + */ + CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx, + &view->sortlist)); + + /* + * Configure default allow-update and allow-update-forwarding ACLs, + * so they can be inherited by zones. (XXX: These are not + * read from the options/view level here. However, they may be + * read from there in zoneconf.c:configure_zone_acl() later.) + */ + if (view->updateacl == NULL) { + CHECK(configure_view_acl(NULL, NULL, named_g_config, + "allow-update", NULL, actx, + named_g_mctx, &view->updateacl)); + } + if (view->upfwdacl == NULL) { + CHECK(configure_view_acl(NULL, NULL, named_g_config, + "allow-update-forwarding", NULL, actx, + named_g_mctx, &view->upfwdacl)); + } + + /* + * Configure default allow-transfer and allow-notify ACLs so they + * can be inherited by zones. + */ + if (view->transferacl == NULL) { + CHECK(configure_view_acl(vconfig, config, named_g_config, + "allow-transfer", NULL, actx, + named_g_mctx, &view->transferacl)); + } + if (view->notifyacl == NULL) { + CHECK(configure_view_acl(vconfig, config, named_g_config, + "allow-notify", NULL, actx, + named_g_mctx, &view->notifyacl)); + } + + obj = NULL; + result = named_config_get(maps, "provide-ixfr", &obj); + INSIST(result == ISC_R_SUCCESS); + view->provideixfr = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "request-nsid", &obj); + INSIST(result == ISC_R_SUCCESS); + view->requestnsid = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "send-cookie", &obj); + INSIST(result == ISC_R_SUCCESS); + view->sendcookie = cfg_obj_asboolean(obj); + + obj = NULL; + if (view->pad_acl != NULL) { + dns_acl_detach(&view->pad_acl); + } + result = named_config_get(optionmaps, "response-padding", &obj); + if (result == ISC_R_SUCCESS) { + const cfg_obj_t *padobj = cfg_tuple_get(obj, "block-size"); + const cfg_obj_t *aclobj = cfg_tuple_get(obj, "acl"); + uint32_t padding = cfg_obj_asuint32(padobj); + + if (padding > 512U) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "response-padding block-size cannot " + "exceed 512: lowering"); + padding = 512U; + } + view->padding = (uint16_t)padding; + CHECK(cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, + named_g_mctx, 0, &view->pad_acl)); + } + + obj = NULL; + result = named_config_get(maps, "require-server-cookie", &obj); + INSIST(result == ISC_R_SUCCESS); + view->requireservercookie = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "v6-bias", &obj); + INSIST(result == ISC_R_SUCCESS); + view->v6bias = cfg_obj_asuint32(obj) * 1000; + + obj = NULL; + result = named_config_get(maps, "max-clients-per-query", &obj); + INSIST(result == ISC_R_SUCCESS); + max_clients_per_query = cfg_obj_asuint32(obj); + + obj = NULL; + result = named_config_get(maps, "clients-per-query", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj), + max_clients_per_query); + + obj = NULL; + result = named_config_get(maps, "max-recursion-depth", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "max-recursion-queries", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "fetches-per-zone", &obj); + INSIST(result == ISC_R_SUCCESS); + obj2 = cfg_tuple_get(obj, "fetches"); + dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2)); + obj2 = cfg_tuple_get(obj, "response"); + if (!cfg_obj_isvoid(obj2)) { + const char *resp = cfg_obj_asstring(obj2); + isc_result_t r = DNS_R_SERVFAIL; + + if (strcasecmp(resp, "drop") == 0) { + r = DNS_R_DROP; + } else if (strcasecmp(resp, "fail") == 0) { + r = DNS_R_SERVFAIL; + } else { + UNREACHABLE(); + } + + dns_resolver_setquotaresponse(view->resolver, + dns_quotatype_zone, r); + } + + obj = NULL; + result = named_config_get(maps, "prefetch", &obj); + INSIST(result == ISC_R_SUCCESS); + prefetch_trigger = cfg_tuple_get(obj, "trigger"); + view->prefetch_trigger = cfg_obj_asuint32(prefetch_trigger); + if (view->prefetch_trigger > 10) { + view->prefetch_trigger = 10; + } + prefetch_eligible = cfg_tuple_get(obj, "eligible"); + if (cfg_obj_isvoid(prefetch_eligible)) { + int m; + for (m = 1; maps[m] != NULL; m++) { + obj = NULL; + result = named_config_get(&maps[m], "prefetch", &obj); + INSIST(result == ISC_R_SUCCESS); + prefetch_eligible = cfg_tuple_get(obj, "eligible"); + if (cfg_obj_isuint32(prefetch_eligible)) { + break; + } + } + INSIST(cfg_obj_isuint32(prefetch_eligible)); + } + view->prefetch_eligible = cfg_obj_asuint32(prefetch_eligible); + if (view->prefetch_eligible < view->prefetch_trigger + 6) { + view->prefetch_eligible = view->prefetch_trigger + 6; + } + + /* + * For now, there is only one kind of trusted keys, the + * "security roots". + */ + CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys, + auto_root, mctx)); + dns_resolver_resetmustbesecure(view->resolver); + obj = NULL; + result = named_config_get(maps, "dnssec-must-be-secure", &obj); + if (result == ISC_R_SUCCESS) { + CHECK(mustbesecure(obj, view->resolver)); + } + + obj = NULL; + result = named_config_get(maps, "nta-recheck", &obj); + INSIST(result == ISC_R_SUCCESS); + view->nta_recheck = cfg_obj_asduration(obj); + + obj = NULL; + result = named_config_get(maps, "nta-lifetime", &obj); + INSIST(result == ISC_R_SUCCESS); + view->nta_lifetime = cfg_obj_asduration(obj); + + obj = NULL; + result = named_config_get(maps, "preferred-glue", &obj); + if (result == ISC_R_SUCCESS) { + str = cfg_obj_asstring(obj); + if (strcasecmp(str, "a") == 0) { + view->preferred_glue = dns_rdatatype_a; + } else if (strcasecmp(str, "aaaa") == 0) { + view->preferred_glue = dns_rdatatype_aaaa; + } else { + view->preferred_glue = 0; + } + } else { + view->preferred_glue = 0; + } + + obj = NULL; + result = named_config_get(maps, "root-delegation-only", &obj); + if (result == ISC_R_SUCCESS) { + dns_view_setrootdelonly(view, true); + } + if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) { + const cfg_obj_t *exclude; + dns_fixedname_t fixed; + dns_name_t *name; + + name = dns_fixedname_initname(&fixed); + for (element = cfg_list_first(obj); element != NULL; + element = cfg_list_next(element)) + { + exclude = cfg_listelt_value(element); + CHECK(dns_name_fromstring( + name, cfg_obj_asstring(exclude), 0, NULL)); + CHECK(dns_view_excludedelegationonly(view, name)); + } + } else { + dns_view_setrootdelonly(view, false); + } + + /* + * Load DynDB modules. + */ + dyndb_list = NULL; + if (voptions != NULL) { + (void)cfg_map_get(voptions, "dyndb", &dyndb_list); + } else { + (void)cfg_map_get(config, "dyndb", &dyndb_list); + } + +#ifdef HAVE_DLOPEN + for (element = cfg_list_first(dyndb_list); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *dyndb = cfg_listelt_value(element); + + if (dctx == NULL) { + const void *hashinit = isc_hash_get_initializer(); + CHECK(dns_dyndb_createctx(mctx, hashinit, named_g_lctx, + view, named_g_server->zonemgr, + named_g_server->task, + named_g_timermgr, &dctx)); + } + + CHECK(configure_dyndb(dyndb, mctx, dctx)); + } +#endif /* ifdef HAVE_DLOPEN */ + + /* + * Load plugins. + */ + plugin_list = NULL; + if (voptions != NULL) { + (void)cfg_map_get(voptions, "plugin", &plugin_list); + } else { + (void)cfg_map_get(config, "plugin", &plugin_list); + } + +#ifdef HAVE_DLOPEN + if (plugin_list != NULL) { + INSIST(view->hooktable == NULL); + CHECK(ns_hooktable_create(view->mctx, + (ns_hooktable_t **)&view->hooktable)); + view->hooktable_free = ns_hooktable_free; + + ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins); + view->plugins_free = ns_plugins_free; + + CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx, + register_one_plugin, view)); + } +#endif /* ifdef HAVE_DLOPEN */ + + /* + * Setup automatic empty zones. If recursion is off then + * they are disabled by default. + */ + obj = NULL; + (void)named_config_get(maps, "empty-zones-enable", &obj); + (void)named_config_get(maps, "disable-empty-zone", &disablelist); + if (obj == NULL && disablelist == NULL && + view->rdclass == dns_rdataclass_in) + { + empty_zones_enable = view->recursion; + } else if (view->rdclass == dns_rdataclass_in) { + if (obj != NULL) { + empty_zones_enable = cfg_obj_asboolean(obj); + } else { + empty_zones_enable = view->recursion; + } + } else { + empty_zones_enable = false; + } + + if (empty_zones_enable) { + const char *empty; + int empty_zone = 0; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t buffer; + char server[DNS_NAME_FORMATSIZE + 1]; + char contact[DNS_NAME_FORMATSIZE + 1]; + const char *empty_dbtype[4] = { "_builtin", "empty", NULL, + NULL }; + int empty_dbtypec = 4; + dns_zonestat_level_t statlevel = dns_zonestat_none; + + name = dns_fixedname_initname(&fixed); + + obj = NULL; + result = named_config_get(maps, "empty-server", &obj); + if (result == ISC_R_SUCCESS) { + CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), + 0, NULL)); + isc_buffer_init(&buffer, server, sizeof(server) - 1); + CHECK(dns_name_totext(name, false, &buffer)); + server[isc_buffer_usedlength(&buffer)] = 0; + empty_dbtype[2] = server; + } else { + empty_dbtype[2] = "@"; + } + + obj = NULL; + result = named_config_get(maps, "empty-contact", &obj); + if (result == ISC_R_SUCCESS) { + CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), + 0, NULL)); + isc_buffer_init(&buffer, contact, sizeof(contact) - 1); + CHECK(dns_name_totext(name, false, &buffer)); + contact[isc_buffer_usedlength(&buffer)] = 0; + empty_dbtype[3] = contact; + } else { + empty_dbtype[3] = "."; + } + + obj = NULL; + result = named_config_get(maps, "zone-statistics", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) { + statlevel = dns_zonestat_full; + } else { + statlevel = dns_zonestat_none; + } + } else { + const char *levelstr = cfg_obj_asstring(obj); + if (strcasecmp(levelstr, "full") == 0) { + statlevel = dns_zonestat_full; + } else if (strcasecmp(levelstr, "terse") == 0) { + statlevel = dns_zonestat_terse; + } else if (strcasecmp(levelstr, "none") == 0) { + statlevel = dns_zonestat_none; + } else { + UNREACHABLE(); + } + } + + for (empty = empty_zones[empty_zone]; empty != NULL; + empty = empty_zones[++empty_zone]) + { + dns_forwarders_t *dnsforwarders = NULL; + + /* + * Look for zone on drop list. + */ + CHECK(dns_name_fromstring(name, empty, 0, NULL)); + if (disablelist != NULL && + on_disable_list(disablelist, name)) + { + continue; + } + + /* + * This zone already exists. + */ + (void)dns_view_findzone(view, name, &zone); + if (zone != NULL) { + dns_zone_detach(&zone); + continue; + } + + /* + * If we would forward this name don't add a + * empty zone for it. + */ + result = dns_fwdtable_find(view->fwdtable, name, NULL, + &dnsforwarders); + if (result == ISC_R_SUCCESS && + dnsforwarders->fwdpolicy == dns_fwdpolicy_only) + { + continue; + } + + /* + * See if we can re-use a existing zone. + */ + result = dns_viewlist_find(&named_g_server->viewlist, + view->name, view->rdclass, + &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) + { + goto cleanup; + } + + if (pview != NULL) { + (void)dns_view_findzone(pview, name, &zone); + dns_view_detach(&pview); + } + + CHECK(create_empty_zone(zone, name, view, zonelist, + empty_dbtype, empty_dbtypec, + statlevel)); + if (zone != NULL) { + dns_zone_detach(&zone); + } + } + } + + obj = NULL; + result = named_config_get(maps, "rate-limit", &obj); + if (result == ISC_R_SUCCESS) { + result = configure_rrl(view, config, obj); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } + + /* + * Set the servfail-ttl. + */ + obj = NULL; + result = named_config_get(maps, "servfail-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + fail_ttl = cfg_obj_asduration(obj); + if (fail_ttl > 30) { + fail_ttl = 30; + } + dns_view_setfailttl(view, fail_ttl); + + /* + * Name space to look up redirect information in. + */ + obj = NULL; + result = named_config_get(maps, "nxdomain-redirect", &obj); + if (result == ISC_R_SUCCESS) { + dns_name_t *name = dns_fixedname_name(&view->redirectfixed); + CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0, + NULL)); + view->redirectzone = name; + } else { + view->redirectzone = NULL; + } + + /* + * Exceptions to DNSSEC validation. + */ + obj = NULL; + result = named_config_get(maps, "validate-except", &obj); + if (result == ISC_R_SUCCESS) { + result = dns_view_getntatable(view, &ntatable); + } + if (result == ISC_R_SUCCESS) { + for (element = cfg_list_first(obj); element != NULL; + element = cfg_list_next(element)) + { + dns_fixedname_t fntaname; + dns_name_t *ntaname; + + ntaname = dns_fixedname_initname(&fntaname); + obj = cfg_listelt_value(element); + CHECK(dns_name_fromstring( + ntaname, cfg_obj_asstring(obj), 0, NULL)); + CHECK(dns_ntatable_add(ntatable, ntaname, true, 0, + 0xffffffffU)); + } + } + +#ifdef HAVE_DNSTAP + /* + * Set up the dnstap environment and configure message + * types to log. + */ + CHECK(configure_dnstap(maps, view)); +#endif /* HAVE_DNSTAP */ + + result = ISC_R_SUCCESS; + +cleanup: + /* + * Revert to the old view if there was an error. + */ + if (result != ISC_R_SUCCESS) { + isc_result_t result2; + + result2 = dns_viewlist_find(&named_g_server->viewlist, + view->name, view->rdclass, &pview); + if (result2 == ISC_R_SUCCESS) { + dns_view_thaw(pview); + + obj = NULL; + if (rpz_configured && + pview->rdclass == dns_rdataclass_in && need_hints && + named_config_get(maps, "response-policy", &obj) == + ISC_R_SUCCESS) + { + /* + * We are swapping the places of the `view` and + * `pview` in the function's parameters list + * because we are reverting the same operation + * done previously in the "correct" order. + */ + result2 = configure_rpz(pview, view, maps, obj, + &old_rpz_ok); + if (result2 != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, + ISC_LOG_ERROR, + "rpz configuration " + "revert failed for view " + "'%s'", + pview->name); + } + } + + obj = NULL; + if (catz_configured && + pview->rdclass == dns_rdataclass_in && need_hints && + named_config_get(maps, "catalog-zones", &obj) == + ISC_R_SUCCESS) + { + /* + * We are swapping the places of the `view` and + * `pview` in the function's parameters list + * because we are reverting the same operation + * done previously in the "correct" order. + */ + result2 = configure_catz(pview, view, config, + obj); + if (result2 != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, + ISC_LOG_ERROR, + "catz configuration " + "revert failed for view " + "'%s'", + pview->name); + } + } + + dns_view_freeze(pview); + } + + if (pview != NULL) { + dns_view_detach(&pview); + } + + if (zone_element_latest != NULL) { + for (element = cfg_list_first(zonelist); + element != NULL; element = cfg_list_next(element)) + { + const cfg_obj_t *zconfig = + cfg_listelt_value(element); + configure_zone_setviewcommit(result, zconfig, + view); + if (element == zone_element_latest) { + /* + * This was the latest element that was + * successfully configured earlier. + */ + break; + } + } + } + } + + if (ntatable != NULL) { + dns_ntatable_detach(&ntatable); + } + if (clients != NULL) { + dns_acl_detach(&clients); + } + if (mapped != NULL) { + dns_acl_detach(&mapped); + } + if (excluded != NULL) { + dns_acl_detach(&excluded); + } + if (ring != NULL) { + dns_tsigkeyring_detach(&ring); + } + if (zone != NULL) { + dns_zone_detach(&zone); + } + if (dispatch4 != NULL) { + dns_dispatch_detach(&dispatch4); + } + if (dispatch6 != NULL) { + dns_dispatch_detach(&dispatch6); + } + if (resstats != NULL) { + isc_stats_detach(&resstats); + } + if (resquerystats != NULL) { + dns_stats_detach(&resquerystats); + } + if (order != NULL) { + dns_order_detach(&order); + } + if (cmctx != NULL) { + isc_mem_detach(&cmctx); + } + if (hmctx != NULL) { + isc_mem_detach(&hmctx); + } + if (cache != NULL) { + dns_cache_detach(&cache); + } + if (dctx != NULL) { + dns_dyndb_destroyctx(&dctx); + } + + return (result); +} + +static isc_result_t +configure_hints(dns_view_t *view, const char *filename) { + isc_result_t result; + dns_db_t *db; + + db = NULL; + result = dns_rootns_create(view->mctx, view->rdclass, filename, &db); + if (result == ISC_R_SUCCESS) { + dns_view_sethints(view, db); + dns_db_detach(&db); + } + + return (result); +} + +static isc_result_t +configure_alternates(const cfg_obj_t *config, dns_view_t *view, + const cfg_obj_t *alternates) { + const cfg_obj_t *portobj; + const cfg_obj_t *addresses; + const cfg_listelt_t *element; + isc_result_t result = ISC_R_SUCCESS; + in_port_t port; + + /* + * Determine which port to send requests to. + */ + CHECKM(named_config_getport(config, &port), "port"); + + if (alternates != NULL) { + portobj = cfg_tuple_get(alternates, "port"); + if (cfg_obj_isuint32(portobj)) { + uint32_t val = cfg_obj_asuint32(portobj); + if (val > UINT16_MAX) { + cfg_obj_log(portobj, named_g_lctx, + ISC_LOG_ERROR, + "port '%u' out of range", val); + return (ISC_R_RANGE); + } + port = (in_port_t)val; + } + } + + addresses = NULL; + if (alternates != NULL) { + addresses = cfg_tuple_get(alternates, "addresses"); + } + + for (element = cfg_list_first(addresses); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *alternate = cfg_listelt_value(element); + isc_sockaddr_t sa; + + if (!cfg_obj_issockaddr(alternate)) { + dns_fixedname_t fixed; + dns_name_t *name; + const char *str = cfg_obj_asstring( + cfg_tuple_get(alternate, "name")); + isc_buffer_t buffer; + in_port_t myport = port; + + isc_buffer_constinit(&buffer, str, strlen(str)); + isc_buffer_add(&buffer, strlen(str)); + name = dns_fixedname_initname(&fixed); + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, + NULL)); + + portobj = cfg_tuple_get(alternate, "port"); + if (cfg_obj_isuint32(portobj)) { + uint32_t val = cfg_obj_asuint32(portobj); + if (val > UINT16_MAX) { + cfg_obj_log(portobj, named_g_lctx, + ISC_LOG_ERROR, + "port '%u' out of range", + val); + return (ISC_R_RANGE); + } + myport = (in_port_t)val; + } + CHECK(dns_resolver_addalternate(view->resolver, NULL, + name, myport)); + continue; + } + + sa = *cfg_obj_assockaddr(alternate); + if (isc_sockaddr_getport(&sa) == 0) { + isc_sockaddr_setport(&sa, port); + } + CHECK(dns_resolver_addalternate(view->resolver, &sa, NULL, 0)); + } + +cleanup: + return (result); +} + +static isc_result_t +configure_forward(const cfg_obj_t *config, dns_view_t *view, + const dns_name_t *origin, const cfg_obj_t *forwarders, + const cfg_obj_t *forwardtype) { + const cfg_obj_t *portobj, *dscpobj; + const cfg_obj_t *faddresses; + const cfg_listelt_t *element; + dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none; + dns_forwarderlist_t fwdlist; + dns_forwarder_t *fwd; + isc_result_t result; + in_port_t port; + isc_dscp_t dscp = -1; + + ISC_LIST_INIT(fwdlist); + + /* + * Determine which port to send forwarded requests to. + */ + CHECKM(named_config_getport(config, &port), "port"); + + if (forwarders != NULL) { + portobj = cfg_tuple_get(forwarders, "port"); + if (cfg_obj_isuint32(portobj)) { + uint32_t val = cfg_obj_asuint32(portobj); + if (val > UINT16_MAX) { + cfg_obj_log(portobj, named_g_lctx, + ISC_LOG_ERROR, + "port '%u' out of range", val); + return (ISC_R_RANGE); + } + port = (in_port_t)val; + } + } + + /* + * DSCP value for forwarded requests. + */ + dscp = named_g_dscp; + if (forwarders != NULL) { + dscpobj = cfg_tuple_get(forwarders, "dscp"); + if (cfg_obj_isuint32(dscpobj)) { + if (cfg_obj_asuint32(dscpobj) > 63) { + cfg_obj_log(dscpobj, named_g_lctx, + ISC_LOG_ERROR, + "dscp value '%u' is out of range", + cfg_obj_asuint32(dscpobj)); + return (ISC_R_RANGE); + } + dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + } + } + + faddresses = NULL; + if (forwarders != NULL) { + faddresses = cfg_tuple_get(forwarders, "addresses"); + } + + for (element = cfg_list_first(faddresses); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *forwarder = cfg_listelt_value(element); + fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t)); + fwd->addr = *cfg_obj_assockaddr(forwarder); + if (isc_sockaddr_getport(&fwd->addr) == 0) { + isc_sockaddr_setport(&fwd->addr, port); + } + fwd->dscp = cfg_obj_getdscp(forwarder); + if (fwd->dscp == -1) { + fwd->dscp = dscp; + } + ISC_LINK_INIT(fwd, link); + ISC_LIST_APPEND(fwdlist, fwd, link); + } + + if (ISC_LIST_EMPTY(fwdlist)) { + if (forwardtype != NULL) { + cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING, + "no forwarders seen; disabling " + "forwarding"); + } + fwdpolicy = dns_fwdpolicy_none; + } else { + if (forwardtype == NULL) { + fwdpolicy = dns_fwdpolicy_first; + } else { + const char *forwardstr = cfg_obj_asstring(forwardtype); + if (strcasecmp(forwardstr, "first") == 0) { + fwdpolicy = dns_fwdpolicy_first; + } else if (strcasecmp(forwardstr, "only") == 0) { + fwdpolicy = dns_fwdpolicy_only; + } else { + UNREACHABLE(); + } + } + } + + result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist, + fwdpolicy); + if (result != ISC_R_SUCCESS) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(origin, namebuf, sizeof(namebuf)); + cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING, + "could not set up forwarding for domain '%s': %s", + namebuf, isc_result_totext(result)); + goto cleanup; + } + + result = ISC_R_SUCCESS; + +cleanup: + + while (!ISC_LIST_EMPTY(fwdlist)) { + fwd = ISC_LIST_HEAD(fwdlist); + ISC_LIST_UNLINK(fwdlist, fwd, link); + isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t)); + } + + return (result); +} + +static isc_result_t +get_viewinfo(const cfg_obj_t *vconfig, const char **namep, + dns_rdataclass_t *classp) { + isc_result_t result = ISC_R_SUCCESS; + const char *viewname; + dns_rdataclass_t viewclass; + + REQUIRE(namep != NULL && *namep == NULL); + REQUIRE(classp != NULL); + + if (vconfig != NULL) { + const cfg_obj_t *classobj = NULL; + + viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); + classobj = cfg_tuple_get(vconfig, "class"); + CHECK(named_config_getclass(classobj, dns_rdataclass_in, + &viewclass)); + if (dns_rdataclass_ismeta(viewclass)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "view '%s': class must not be meta", + viewname); + CHECK(ISC_R_FAILURE); + } + } else { + viewname = "_default"; + viewclass = dns_rdataclass_in; + } + + *namep = viewname; + *classp = viewclass; + +cleanup: + return (result); +} + +/* + * Find a view based on its configuration info and attach to it. + * + * If 'vconfig' is NULL, attach to the default view. + */ +static isc_result_t +find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, + dns_view_t **viewp) { + isc_result_t result; + const char *viewname = NULL; + dns_rdataclass_t viewclass; + dns_view_t *view = NULL; + + result = get_viewinfo(vconfig, &viewname, &viewclass); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = dns_viewlist_find(viewlist, viewname, viewclass, &view); + if (result != ISC_R_SUCCESS) { + return (result); + } + + *viewp = view; + return (ISC_R_SUCCESS); +} + +/* + * Create a new view and add it to the list. + * + * If 'vconfig' is NULL, create the default view. + * + * The view created is attached to '*viewp'. + */ +static isc_result_t +create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, + dns_view_t **viewp) { + isc_result_t result; + const char *viewname = NULL; + dns_rdataclass_t viewclass; + dns_view_t *view = NULL; + + result = get_viewinfo(vconfig, &viewname, &viewclass); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = dns_viewlist_find(viewlist, viewname, viewclass, &view); + if (result == ISC_R_SUCCESS) { + return (ISC_R_EXISTS); + } + if (result != ISC_R_NOTFOUND) { + return (result); + } + INSIST(view == NULL); + + result = dns_view_create(named_g_mctx, viewclass, viewname, &view); + if (result != ISC_R_SUCCESS) { + return (result); + } + + isc_nonce_buf(view->secret, sizeof(view->secret)); + + ISC_LIST_APPEND(*viewlist, view, link); + dns_view_attach(view, viewp); + return (ISC_R_SUCCESS); +} + +/* + * Configure or reconfigure a zone. + */ +static isc_result_t +configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, + const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, + dns_viewlist_t *viewlist, dns_kasplist_t *kasplist, + cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok, + bool modify) { + dns_view_t *pview = NULL; /* Production view */ + dns_zone_t *zone = NULL; /* New or reused zone */ + dns_zone_t *raw = NULL; /* New or reused raw zone */ + dns_zone_t *dupzone = NULL; + const cfg_obj_t *options = NULL; + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *typeobj = NULL; + const cfg_obj_t *forwarders = NULL; + const cfg_obj_t *forwardtype = NULL; + const cfg_obj_t *ixfrfromdiffs = NULL; + const cfg_obj_t *only = NULL; + const cfg_obj_t *viewobj = NULL; + isc_result_t result; + isc_result_t tresult; + isc_buffer_t buffer; + dns_fixedname_t fixorigin; + dns_name_t *origin; + const char *zname; + dns_rdataclass_t zclass; + const char *ztypestr; + dns_rpz_num_t rpz_num; + bool zone_is_catz = false; + bool zone_maybe_inline = false; + bool inline_signing = false; + bool fullsign = false; + + options = NULL; + (void)cfg_map_get(config, "options", &options); + + zoptions = cfg_tuple_get(zconfig, "options"); + + /* + * Get the zone origin as a dns_name_t. + */ + zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + isc_buffer_constinit(&buffer, zname, strlen(zname)); + isc_buffer_add(&buffer, strlen(zname)); + dns_fixedname_init(&fixorigin); + CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer, + dns_rootname, 0, NULL)); + origin = dns_fixedname_name(&fixorigin); + + CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"), + view->rdclass, &zclass)); + if (zclass != view->rdclass) { + const char *vname = NULL; + if (vconfig != NULL) { + vname = cfg_obj_asstring( + cfg_tuple_get(vconfig, "name")); + } else { + vname = ""; + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "zone '%s': wrong class for view '%s'", zname, + vname); + result = ISC_R_FAILURE; + goto cleanup; + } + + (void)cfg_map_get(zoptions, "in-view", &viewobj); + if (viewobj != NULL) { + const char *inview = cfg_obj_asstring(viewobj); + dns_view_t *otherview = NULL; + + if (viewlist == NULL) { + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "'in-view' option is not permitted in " + "dynamically added zones"); + result = ISC_R_FAILURE; + goto cleanup; + } + + result = dns_viewlist_find(viewlist, inview, view->rdclass, + &otherview); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "view '%s' is not yet defined.", inview); + result = ISC_R_FAILURE; + goto cleanup; + } + + result = dns_view_findzone(otherview, origin, &zone); + dns_view_detach(&otherview); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "zone '%s' not defined in view '%s'", zname, + inview); + result = ISC_R_FAILURE; + goto cleanup; + } + + CHECK(dns_view_addzone(view, zone)); + dns_zone_detach(&zone); + + /* + * If the zone contains a 'forwarders' statement, configure + * selective forwarding. Note: this is not inherited from the + * other view. + */ + forwarders = NULL; + result = cfg_map_get(zoptions, "forwarders", &forwarders); + if (result == ISC_R_SUCCESS) { + forwardtype = NULL; + (void)cfg_map_get(zoptions, "forward", &forwardtype); + CHECK(configure_forward(config, view, origin, + forwarders, forwardtype)); + } + result = ISC_R_SUCCESS; + goto cleanup; + } + + (void)cfg_map_get(zoptions, "type", &typeobj); + if (typeobj == NULL) { + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "zone '%s' 'type' not specified", zname); + result = ISC_R_FAILURE; + goto cleanup; + } + ztypestr = cfg_obj_asstring(typeobj); + + /* + * "hints zones" aren't zones. If we've got one, + * configure it and return. + */ + if (strcasecmp(ztypestr, "hint") == 0) { + const cfg_obj_t *fileobj = NULL; + if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "zone '%s': 'file' not specified", zname); + result = ISC_R_FAILURE; + goto cleanup; + } + if (dns_name_equal(origin, dns_rootname)) { + const char *hintsfile = cfg_obj_asstring(fileobj); + + CHECK(configure_hints(view, hintsfile)); + + /* + * Hint zones may also refer to delegation only points. + */ + only = NULL; + tresult = cfg_map_get(zoptions, "delegation-only", + &only); + if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) + { + CHECK(dns_view_adddelegationonly(view, origin)); + } + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "ignoring non-root hint zone '%s'", + zname); + result = ISC_R_SUCCESS; + } + /* Skip ordinary zone processing. */ + goto cleanup; + } + + /* + * "forward zones" aren't zones either. Translate this syntax into + * the appropriate selective forwarding configuration and return. + */ + if (strcasecmp(ztypestr, "forward") == 0) { + forwardtype = NULL; + forwarders = NULL; + + (void)cfg_map_get(zoptions, "forward", &forwardtype); + (void)cfg_map_get(zoptions, "forwarders", &forwarders); + CHECK(configure_forward(config, view, origin, forwarders, + forwardtype)); + + /* + * Forward zones may also set delegation only. + */ + only = NULL; + tresult = cfg_map_get(zoptions, "delegation-only", &only); + if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) { + CHECK(dns_view_adddelegationonly(view, origin)); + } + goto cleanup; + } + + /* + * "delegation-only zones" aren't zones either. + */ + if (strcasecmp(ztypestr, "delegation-only") == 0) { + result = dns_view_adddelegationonly(view, origin); + goto cleanup; + } + + /* + * Redirect zones only require minimal configuration. + */ + if (strcasecmp(ztypestr, "redirect") == 0) { + if (view->redirect != NULL) { + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "redirect zone already exists"); + result = ISC_R_EXISTS; + goto cleanup; + } + result = dns_viewlist_find(viewlist, view->name, view->rdclass, + &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) { + goto cleanup; + } + if (pview != NULL && pview->redirect != NULL) { + dns_zone_attach(pview->redirect, &zone); + dns_zone_setview(zone, view); + } else { + CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, + &zone)); + CHECK(dns_zone_setorigin(zone, origin)); + dns_zone_setview(zone, view); + CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, + zone)); + dns_zone_setstats(zone, named_g_server->zonestats); + } + CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, + kasplist, zone, NULL)); + dns_zone_attach(zone, &view->redirect); + goto cleanup; + } + + if (!modify) { + /* + * Check for duplicates in the new zone table. + */ + result = dns_view_findzone(view, origin, &dupzone); + if (result == ISC_R_SUCCESS) { + /* + * We already have this zone! + */ + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "zone '%s' already exists", zname); + dns_zone_detach(&dupzone); + result = ISC_R_EXISTS; + goto cleanup; + } + INSIST(dupzone == NULL); + } + + /* + * Note whether this is a response policy zone and which one if so, + * unless we are using RPZ service interface. In that case, the + * BIND zone database has nothing to do with rpz and so we don't care. + */ + for (rpz_num = 0;; ++rpz_num) { + if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones || + view->rpzs->p.dnsrps_enabled) + { + rpz_num = DNS_RPZ_INVALID_NUM; + break; + } + if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin)) + { + break; + } + } + + if (view->catzs != NULL && + dns_catz_get_zone(view->catzs, origin) != NULL) + { + zone_is_catz = true; + } + + /* + * See if we can reuse an existing zone. This is + * only possible if all of these are true: + * - The zone's view exists + * - A zone with the right name exists in the view + * - The zone is compatible with the config + * options (e.g., an existing master zone cannot + * be reused if the options specify a slave zone) + * - The zone was not and is still not a response policy zone + * or the zone is a policy zone with an unchanged number + * and we are using the old policy zone summary data. + */ + result = dns_viewlist_find(&named_g_server->viewlist, view->name, + view->rdclass, &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) { + goto cleanup; + } + if (pview != NULL) { + result = dns_view_findzone(pview, origin, &zone); + } + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) { + goto cleanup; + } + + if (zone != NULL && !named_zone_reusable(zone, zconfig)) { + dns_zone_detach(&zone); + fullsign = true; + } + + if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) || + (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok))) + { + dns_zone_detach(&zone); + } + + if (zone != NULL) { + /* + * We found a reusable zone. Make it use the + * new view. + */ + dns_zone_setview(zone, view); + } else { + /* + * We cannot reuse an existing zone, we have + * to create a new one. + */ + CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone)); + CHECK(dns_zone_setorigin(zone, origin)); + dns_zone_setview(zone, view); + CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone)); + dns_zone_setstats(zone, named_g_server->zonestats); + } + if (rpz_num != DNS_RPZ_INVALID_NUM) { + result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "zone '%s': incompatible" + " masterfile-format or database" + " for a response policy zone", + zname); + goto cleanup; + } + } + + if (zone_is_catz) { + dns_zone_catz_enable(zone, view->catzs); + } else if (dns_zone_catz_is_enabled(zone)) { + dns_zone_catz_disable(zone); + } + + /* + * If the zone contains a 'forwarders' statement, configure + * selective forwarding. + */ + forwarders = NULL; + if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) { + forwardtype = NULL; + (void)cfg_map_get(zoptions, "forward", &forwardtype); + CHECK(configure_forward(config, view, origin, forwarders, + forwardtype)); + } + + /* + * Stub and forward zones may also refer to delegation only points. + */ + only = NULL; + if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) { + if (cfg_obj_asboolean(only)) { + CHECK(dns_view_adddelegationonly(view, origin)); + } + } + + /* + * Mark whether the zone was originally added at runtime or not + */ + dns_zone_setadded(zone, added); + + /* + * Determine if we need to set up inline signing. + */ + zone_maybe_inline = ((strcasecmp(ztypestr, "primary") == 0 || + strcasecmp(ztypestr, "master") == 0 || + strcasecmp(ztypestr, "secondary") == 0 || + strcasecmp(ztypestr, "slave") == 0)); + + if (zone_maybe_inline) { + inline_signing = named_zone_inlinesigning(zconfig); + } + if (inline_signing) { + dns_zone_getraw(zone, &raw); + if (raw == NULL) { + CHECK(dns_zone_create(&raw, mctx)); + CHECK(dns_zone_setorigin(raw, origin)); + dns_zone_setview(raw, view); + dns_zone_setstats(raw, named_g_server->zonestats); + CHECK(dns_zone_link(zone, raw)); + } + if (cfg_map_get(zoptions, "ixfr-from-differences", + &ixfrfromdiffs) == ISC_R_SUCCESS) + { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "zone '%s': 'ixfr-from-differences' is " + "ignored for inline-signed zones", + zname); + } + } + + /* + * Configure the zone. + */ + CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist, + zone, raw)); + + /* + * Add the zone to its view in the new view list. + */ + if (!modify) { + CHECK(dns_view_addzone(view, zone)); + } + + if (zone_is_catz) { + /* + * force catz reload if the zone is loaded; + * if it's not it'll get reloaded on zone load + */ + dns_db_t *db = NULL; + + tresult = dns_zone_getdb(zone, &db); + if (tresult == ISC_R_SUCCESS) { + dns_catz_dbupdate_callback(db, view->catzs); + dns_db_detach(&db); + } + } + + /* + * Ensure that zone keys are reloaded on reconfig + */ + if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) { + dns_zone_rekey(zone, fullsign); + } + +cleanup: + if (zone != NULL) { + dns_zone_detach(&zone); + } + if (raw != NULL) { + dns_zone_detach(&raw); + } + if (pview != NULL) { + dns_view_detach(&pview); + } + + return (result); +} + +/* + * Configure built-in zone for storing managed-key data. + */ +static isc_result_t +add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) { + isc_result_t result; + dns_view_t *pview = NULL; + dns_zone_t *zone = NULL; + dns_acl_t *none = NULL; + char filename[PATH_MAX]; + bool defaultview; + + REQUIRE(view != NULL); + + /* See if we can re-use an existing keydata zone. */ + result = dns_viewlist_find(&named_g_server->viewlist, view->name, + view->rdclass, &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) { + return (result); + } + + if (pview != NULL) { + if (pview->managed_keys != NULL) { + dns_zone_attach(pview->managed_keys, + &view->managed_keys); + dns_zone_setview(pview->managed_keys, view); + dns_zone_setviewcommit(pview->managed_keys); + dns_view_detach(&pview); + dns_zone_synckeyzone(view->managed_keys); + return (ISC_R_SUCCESS); + } + + dns_view_detach(&pview); + } + + /* No existing keydata zone was found; create one */ + CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone)); + CHECK(dns_zone_setorigin(zone, dns_rootname)); + + defaultview = (strcmp(view->name, "_default") == 0); + CHECK(isc_file_sanitize( + directory, defaultview ? "managed-keys" : view->name, + defaultview ? "bind" : "mkeys", filename, sizeof(filename))); + CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text, + &dns_master_style_default)); + + dns_zone_setview(zone, view); + dns_zone_settype(zone, dns_zone_key); + dns_zone_setclass(zone, view->rdclass); + + CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone)); + + CHECK(dns_acl_none(mctx, &none)); + dns_zone_setqueryacl(zone, none); + dns_zone_setqueryonacl(zone, none); + dns_acl_detach(&none); + + dns_zone_setdialup(zone, dns_dialuptype_no); + dns_zone_setnotifytype(zone, dns_notifytype_no); + dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true); + dns_zone_setjournalsize(zone, 0); + + dns_zone_setstats(zone, named_g_server->zonestats); + CHECK(setquerystats(zone, mctx, dns_zonestat_none)); + + if (view->managed_keys != NULL) { + dns_zone_detach(&view->managed_keys); + } + dns_zone_attach(zone, &view->managed_keys); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "set up managed keys zone for view %s, file '%s'", + view->name, filename); + +cleanup: + if (zone != NULL) { + dns_zone_detach(&zone); + } + if (none != NULL) { + dns_acl_detach(&none); + } + + return (result); +} + +/* + * Configure a single server quota. + */ +static void +configure_server_quota(const cfg_obj_t **maps, const char *name, + isc_quota_t *quota) { + const cfg_obj_t *obj = NULL; + isc_result_t result; + + result = named_config_get(maps, name, &obj); + INSIST(result == ISC_R_SUCCESS); + isc_quota_max(quota, cfg_obj_asuint32(obj)); +} + +/* + * This function is called as soon as the 'directory' statement has been + * parsed. This can be extended to support other options if necessary. + */ +static isc_result_t +directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { + isc_result_t result; + const char *directory; + + REQUIRE(strcasecmp("directory", clausename) == 0); + + UNUSED(arg); + UNUSED(clausename); + + /* + * Change directory. + */ + directory = cfg_obj_asstring(obj); + + if (!isc_file_ischdiridempotent(directory)) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "option 'directory' contains relative path '%s'", + directory); + } + + if (!isc_file_isdirwritable(directory)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "directory '%s' is not writable", directory); + return (ISC_R_NOPERM); + } + + result = isc_dir_chdir(directory); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "change directory to '%s' failed: %s", directory, + isc_result_totext(result)); + return (result); + } + + return (ISC_R_SUCCESS); +} + +/* + * This event callback is invoked to do periodic network interface + * scanning. + */ + +static void +interface_timer_tick(isc_task_t *task, isc_event_t *event) { + named_server_t *server = (named_server_t *)event->ev_arg; + INSIST(task == server->task); + UNUSED(task); + + isc_event_free(&event); + ns_interfacemgr_scan(server->interfacemgr, false); +} + +static void +heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) { + named_server_t *server = (named_server_t *)event->ev_arg; + dns_view_t *view; + + UNUSED(task); + isc_event_free(&event); + view = ISC_LIST_HEAD(server->viewlist); + while (view != NULL) { + dns_view_dialup(view); + view = ISC_LIST_NEXT(view, link); + } +} + +typedef struct { + isc_mem_t *mctx; + isc_task_t *task; + dns_fetch_t *fetch; + dns_view_t *view; + dns_fixedname_t tatname; + dns_fixedname_t keyname; + dns_rdataset_t rdataset; + dns_rdataset_t sigrdataset; +} ns_tat_t; + +static int +cid(const void *a, const void *b) { + const uint16_t ida = *(const uint16_t *)a; + const uint16_t idb = *(const uint16_t *)b; + if (ida < idb) { + return (-1); + } else if (ida > idb) { + return (1); + } else { + return (0); + } +} + +static void +tat_done(isc_task_t *task, isc_event_t *event) { + dns_fetchevent_t *devent; + ns_tat_t *tat; + + INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE); + INSIST(event->ev_arg != NULL); + + UNUSED(task); + + tat = event->ev_arg; + devent = (dns_fetchevent_t *)event; + + /* Free resources which are not of interest */ + if (devent->node != NULL) { + dns_db_detachnode(devent->db, &devent->node); + } + if (devent->db != NULL) { + dns_db_detach(&devent->db); + } + isc_event_free(&event); + dns_resolver_destroyfetch(&tat->fetch); + if (dns_rdataset_isassociated(&tat->rdataset)) { + dns_rdataset_disassociate(&tat->rdataset); + } + if (dns_rdataset_isassociated(&tat->sigrdataset)) { + dns_rdataset_disassociate(&tat->sigrdataset); + } + dns_view_detach(&tat->view); + isc_task_detach(&tat->task); + isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat)); +} + +struct dotat_arg { + dns_view_t *view; + isc_task_t *task; +}; + +/*% + * Prepare the QNAME for the TAT query to be sent by processing the trust + * anchors present at 'keynode' of 'keytable'. Store the result in 'dst' and + * the domain name which 'keynode' is associated with in 'origin'. + * + * A maximum of 12 key IDs can be reported in a single TAT query due to the + * 63-octet length limit for any single label in a domain name. If there are + * more than 12 keys configured at 'keynode', only the first 12 will be + * reported in the TAT query. + */ +static isc_result_t +get_tat_qname(dns_name_t *target, dns_name_t *keyname, dns_keynode_t *keynode) { + dns_rdataset_t dsset; + unsigned int i, n = 0; + uint16_t ids[12]; + isc_textregion_t r; + char label[64]; + int m; + + dns_rdataset_init(&dsset); + if (dns_keynode_dsset(keynode, &dsset)) { + isc_result_t result; + + for (result = dns_rdataset_first(&dsset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&dsset)) + { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_ds_t ds; + + dns_rdata_reset(&rdata); + dns_rdataset_current(&dsset, &rdata); + result = dns_rdata_tostruct(&rdata, &ds, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (n < (sizeof(ids) / sizeof(ids[0]))) { + ids[n] = ds.key_tag; + n++; + } + } + dns_rdataset_disassociate(&dsset); + } + + if (n == 0) { + return (DNS_R_EMPTYNAME); + } + + if (n > 1) { + qsort(ids, n, sizeof(ids[0]), cid); + } + + /* + * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of + * of the keyid. + */ + label[0] = 0; + r.base = label; + r.length = sizeof(label); + m = snprintf(r.base, r.length, "_ta"); + if (m < 0 || (unsigned)m > r.length) { + return (ISC_R_FAILURE); + } + isc_textregion_consume(&r, m); + for (i = 0; i < n; i++) { + m = snprintf(r.base, r.length, "-%04x", ids[i]); + if (m < 0 || (unsigned)m > r.length) { + return (ISC_R_FAILURE); + } + isc_textregion_consume(&r, m); + } + + return (dns_name_fromstring2(target, label, keyname, 0, NULL)); +} + +static void +tat_send(isc_task_t *task, isc_event_t *event) { + ns_tat_t *tat; + char namebuf[DNS_NAME_FORMATSIZE]; + dns_fixedname_t fdomain; + dns_name_t *domain; + dns_rdataset_t nameservers; + isc_result_t result; + dns_name_t *keyname; + dns_name_t *tatname; + + INSIST(event != NULL && event->ev_type == NAMED_EVENT_TATSEND); + INSIST(event->ev_arg != NULL); + + UNUSED(task); + + tat = event->ev_arg; + + keyname = dns_fixedname_name(&tat->keyname); + tatname = dns_fixedname_name(&tat->tatname); + + dns_name_format(tatname, namebuf, sizeof(namebuf)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "%s: sending trust-anchor-telemetry query '%s/NULL'", + tat->view->name, namebuf); + + /* + * TAT queries should be sent to the authoritative servers for a given + * zone. If this function is called for a keytable node corresponding + * to a locally served zone, calling dns_resolver_createfetch() with + * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be + * resolved locally, without sending any TAT queries upstream. + * + * Work around this issue by calling dns_view_findzonecut() first. If + * the zone is served locally, the NS RRset for the given domain name + * will be retrieved from local data; if it is not, the deepest zone + * cut we have for it will be retrieved from cache. In either case, + * passing the results to dns_resolver_createfetch() will prevent it + * from returning NXDOMAIN for 'tatname' while still allowing it to + * chase down any potential delegations returned by upstream servers in + * order to eventually find the destination host to send the TAT query + * to. + * + * After the dns_view_findzonecut() call, 'domain' will hold the + * deepest zone cut we can find for 'keyname' while 'nameservers' will + * hold the NS RRset at that zone cut. + */ + domain = dns_fixedname_initname(&fdomain); + dns_rdataset_init(&nameservers); + result = dns_view_findzonecut(tat->view, keyname, domain, NULL, 0, 0, + true, true, &nameservers, NULL); + if (result == ISC_R_SUCCESS) { + result = dns_resolver_createfetch( + tat->view->resolver, tatname, dns_rdatatype_null, + domain, &nameservers, NULL, NULL, 0, 0, 0, NULL, + tat->task, tat_done, tat, &tat->rdataset, + &tat->sigrdataset, &tat->fetch); + } + + /* + * 'domain' holds the dns_name_t pointer inside a dst_key_t structure. + * dns_resolver_createfetch() creates its own copy of 'domain' if it + * succeeds. Thus, 'domain' is not freed here. + * + * Even if dns_view_findzonecut() returned something else than + * ISC_R_SUCCESS, it still could have associated 'nameservers'. + * dns_resolver_createfetch() creates its own copy of 'nameservers' if + * it succeeds. Thus, we need to check whether 'nameservers' is + * associated and release it if it is. + */ + if (dns_rdataset_isassociated(&nameservers)) { + dns_rdataset_disassociate(&nameservers); + } + + if (result != ISC_R_SUCCESS) { + dns_view_detach(&tat->view); + isc_task_detach(&tat->task); + isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat)); + } + isc_event_free(&event); +} + +static void +dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, dns_name_t *keyname, + void *arg) { + struct dotat_arg *dotat_arg = arg; + isc_result_t result; + dns_view_t *view; + isc_task_t *task; + ns_tat_t *tat; + isc_event_t *event; + + REQUIRE(keytable != NULL); + REQUIRE(keynode != NULL); + REQUIRE(dotat_arg != NULL); + + view = dotat_arg->view; + task = dotat_arg->task; + + tat = isc_mem_get(dotat_arg->view->mctx, sizeof(*tat)); + + tat->fetch = NULL; + tat->mctx = NULL; + tat->task = NULL; + tat->view = NULL; + dns_rdataset_init(&tat->rdataset); + dns_rdataset_init(&tat->sigrdataset); + dns_name_copynf(keyname, dns_fixedname_initname(&tat->keyname)); + result = get_tat_qname(dns_fixedname_initname(&tat->tatname), keyname, + keynode); + if (result != ISC_R_SUCCESS) { + isc_mem_put(dotat_arg->view->mctx, tat, sizeof(*tat)); + return; + } + isc_mem_attach(dotat_arg->view->mctx, &tat->mctx); + isc_task_attach(task, &tat->task); + dns_view_attach(view, &tat->view); + + /* + * We don't want to be holding the keytable lock when calling + * dns_view_findzonecut() as it creates a lock order loop so + * call dns_view_findzonecut() in a event handler. + * + * zone->lock (dns_zone_setviewcommit) while holding view->lock + * (dns_view_setviewcommit) + * + * keytable->lock (dns_keytable_find) while holding zone->lock + * (zone_asyncload) + * + * view->lock (dns_view_findzonecut) while holding keytable->lock + * (dns_keytable_forall) + */ + event = isc_event_allocate(tat->mctx, keytable, NAMED_EVENT_TATSEND, + tat_send, tat, sizeof(isc_event_t)); + isc_task_send(task, &event); +} + +static void +tat_timer_tick(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + named_server_t *server = (named_server_t *)event->ev_arg; + struct dotat_arg arg; + dns_view_t *view; + dns_keytable_t *secroots = NULL; + + isc_event_free(&event); + + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (!view->trust_anchor_telemetry || !view->enablevalidation) { + continue; + } + + result = dns_view_getsecroots(view, &secroots); + if (result != ISC_R_SUCCESS) { + continue; + } + + arg.view = view; + arg.task = task; + (void)dns_keytable_forall(secroots, dotat, &arg); + dns_keytable_detach(&secroots); + } +} + +static void +pps_timer_tick(isc_task_t *task, isc_event_t *event) { + static unsigned int oldrequests = 0; + unsigned int requests = atomic_load_relaxed(&ns_client_requests); + + UNUSED(task); + isc_event_free(&event); + + /* + * Don't worry about wrapping as the overflow result will be right. + */ + dns_pps = (requests - oldrequests) / 1200; + oldrequests = requests; +} + +/* + * Replace the current value of '*field', a dynamically allocated + * string or NULL, with a dynamically allocated copy of the + * null-terminated string pointed to by 'value', or NULL. + */ +static isc_result_t +setstring(named_server_t *server, char **field, const char *value) { + char *copy; + + if (value != NULL) { + copy = isc_mem_strdup(server->mctx, value); + } else { + copy = NULL; + } + + if (*field != NULL) { + isc_mem_free(server->mctx, *field); + } + + *field = copy; + return (ISC_R_SUCCESS); +} + +/* + * Replace the current value of '*field', a dynamically allocated + * string or NULL, with another dynamically allocated string + * or NULL if whether 'obj' is a string or void value, respectively. + */ +static isc_result_t +setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) { + if (cfg_obj_isvoid(obj)) { + return (setstring(server, field, NULL)); + } else { + return (setstring(server, field, cfg_obj_asstring(obj))); + } +} + +static void +set_limit(const cfg_obj_t **maps, const char *configname, + const char *description, isc_resource_t resourceid, + isc_resourcevalue_t defaultvalue) { + const cfg_obj_t *obj = NULL; + const char *resource; + isc_resourcevalue_t value; + isc_result_t result; + + if (named_config_get(maps, configname, &obj) != ISC_R_SUCCESS) { + return; + } + + if (cfg_obj_isstring(obj)) { + resource = cfg_obj_asstring(obj); + if (strcasecmp(resource, "unlimited") == 0) { + value = ISC_RESOURCE_UNLIMITED; + } else { + INSIST(strcasecmp(resource, "default") == 0); + value = defaultvalue; + } + } else { + value = cfg_obj_asuint64(obj); + } + + result = isc_resource_setlimit(resourceid, value); + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, + result == ISC_R_SUCCESS ? ISC_LOG_DEBUG(3) : ISC_LOG_WARNING, + "set maximum %s to %" PRIu64 ": %s", description, value, + isc_result_totext(result)); +} + +#define SETLIMIT(cfgvar, resource, description) \ + set_limit(maps, cfgvar, description, isc_resource_##resource, \ + named_g_init##resource) + +static void +set_limits(const cfg_obj_t **maps) { + SETLIMIT("stacksize", stacksize, "stack size"); + SETLIMIT("datasize", datasize, "data size"); + SETLIMIT("coresize", coresize, "core size"); + SETLIMIT("files", openfiles, "open files"); +} + +static void +portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports, + bool positive) { + const cfg_listelt_t *element; + + for (element = cfg_list_first(ports); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *obj = cfg_listelt_value(element); + + if (cfg_obj_isuint32(obj)) { + in_port_t port = (in_port_t)cfg_obj_asuint32(obj); + + if (positive) { + isc_portset_add(portset, port); + } else { + isc_portset_remove(portset, port); + } + } else { + const cfg_obj_t *obj_loport, *obj_hiport; + in_port_t loport, hiport; + + obj_loport = cfg_tuple_get(obj, "loport"); + loport = (in_port_t)cfg_obj_asuint32(obj_loport); + obj_hiport = cfg_tuple_get(obj, "hiport"); + hiport = (in_port_t)cfg_obj_asuint32(obj_hiport); + + if (positive) { + isc_portset_addrange(portset, loport, hiport); + } else { + isc_portset_removerange(portset, loport, + hiport); + } + } + } +} + +static isc_result_t +removed(dns_zone_t *zone, void *uap) { + if (dns_zone_getview(zone) != uap) { + return (ISC_R_SUCCESS); + } + + dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", + dns_zonetype_name(dns_zone_gettype(zone))); + return (ISC_R_SUCCESS); +} + +static void +cleanup_session_key(named_server_t *server, isc_mem_t *mctx) { + if (server->session_keyfile != NULL) { + isc_file_remove(server->session_keyfile); + isc_mem_free(mctx, server->session_keyfile); + server->session_keyfile = NULL; + } + + if (server->session_keyname != NULL) { + if (dns_name_dynamic(server->session_keyname)) { + dns_name_free(server->session_keyname, mctx); + } + isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t)); + server->session_keyname = NULL; + } + + if (server->sessionkey != NULL) { + dns_tsigkey_detach(&server->sessionkey); + } + + server->session_keyalg = DST_ALG_UNKNOWN; + server->session_keybits = 0; +} + +static isc_result_t +generate_session_key(const char *filename, const char *keynamestr, + const dns_name_t *keyname, const char *algstr, + const dns_name_t *algname, unsigned int algtype, + uint16_t bits, isc_mem_t *mctx, bool first_time, + dns_tsigkey_t **tsigkeyp) { + isc_result_t result = ISC_R_SUCCESS; + dst_key_t *key = NULL; + isc_buffer_t key_txtbuffer; + isc_buffer_t key_rawbuffer; + char key_txtsecret[256]; + char key_rawsecret[64]; + isc_region_t key_rawregion; + isc_stdtime_t now; + dns_tsigkey_t *tsigkey = NULL; + FILE *fp = NULL; + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "generating session key for dynamic DNS"); + + /* generate key */ + result = dst_key_generate(keyname, algtype, bits, 1, 0, + DNS_KEYPROTO_ANY, dns_rdataclass_in, mctx, + &key, NULL); + if (result != ISC_R_SUCCESS) { + return (result); + } + + /* + * Dump the key to the buffer for later use. Should be done before + * we transfer the ownership of key to tsigkey. + */ + isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret)); + CHECK(dst_key_tobuffer(key, &key_rawbuffer)); + + isc_buffer_usedregion(&key_rawbuffer, &key_rawregion); + isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); + CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer)); + + /* Store the key in tsigkey. */ + isc_stdtime_get(&now); + CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key, false, + NULL, now, now, mctx, NULL, &tsigkey)); + + /* Dump the key to the key file. */ + fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time); + if (fp == NULL) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "could not create %s", filename); + result = ISC_R_NOPERM; + goto cleanup; + } + + fprintf(fp, + "key \"%s\" {\n" + "\talgorithm %s;\n" + "\tsecret \"%.*s\";\n};\n", + keynamestr, algstr, (int)isc_buffer_usedlength(&key_txtbuffer), + (char *)isc_buffer_base(&key_txtbuffer)); + + CHECK(isc_stdio_flush(fp)); + result = isc_stdio_close(fp); + fp = NULL; + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + dst_key_free(&key); + + *tsigkeyp = tsigkey; + + return (ISC_R_SUCCESS); + +cleanup: + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed to generate session key " + "for dynamic DNS: %s", + isc_result_totext(result)); + if (fp != NULL) { + (void)isc_stdio_close(fp); + (void)isc_file_remove(filename); + } + if (tsigkey != NULL) { + dns_tsigkey_detach(&tsigkey); + } + if (key != NULL) { + dst_key_free(&key); + } + + return (result); +} + +static isc_result_t +configure_session_key(const cfg_obj_t **maps, named_server_t *server, + isc_mem_t *mctx, bool first_time) { + const char *keyfile, *keynamestr, *algstr; + unsigned int algtype; + dns_fixedname_t fname; + dns_name_t *keyname; + const dns_name_t *algname; + isc_buffer_t buffer; + uint16_t bits; + const cfg_obj_t *obj; + bool need_deleteold = false; + bool need_createnew = false; + isc_result_t result; + + obj = NULL; + result = named_config_get(maps, "session-keyfile", &obj); + if (result == ISC_R_SUCCESS) { + if (cfg_obj_isvoid(obj)) { + keyfile = NULL; /* disable it */ + } else { + keyfile = cfg_obj_asstring(obj); + } + } else { + keyfile = named_g_defaultsessionkeyfile; + } + + obj = NULL; + result = named_config_get(maps, "session-keyname", &obj); + INSIST(result == ISC_R_SUCCESS); + keynamestr = cfg_obj_asstring(obj); + isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr)); + isc_buffer_add(&buffer, strlen(keynamestr)); + keyname = dns_fixedname_initname(&fname); + result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + return (result); + } + + obj = NULL; + result = named_config_get(maps, "session-keyalg", &obj); + INSIST(result == ISC_R_SUCCESS); + algstr = cfg_obj_asstring(obj); + algname = NULL; + result = named_config_getkeyalgorithm2(algstr, &algname, &algtype, + &bits); + if (result != ISC_R_SUCCESS) { + const char *s = " (keeping current key)"; + + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "session-keyalg: " + "unsupported or unknown algorithm '%s'%s", + algstr, server->session_keyfile != NULL ? s : ""); + return (result); + } + + /* See if we need to (re)generate a new key. */ + if (keyfile == NULL) { + if (server->session_keyfile != NULL) { + need_deleteold = true; + } + } else if (server->session_keyfile == NULL) { + need_createnew = true; + } else if (strcmp(keyfile, server->session_keyfile) != 0 || + !dns_name_equal(server->session_keyname, keyname) || + server->session_keyalg != algtype || + server->session_keybits != bits) + { + need_deleteold = true; + need_createnew = true; + } + + if (need_deleteold) { + INSIST(server->session_keyfile != NULL); + INSIST(server->session_keyname != NULL); + INSIST(server->sessionkey != NULL); + + cleanup_session_key(server, mctx); + } + + if (need_createnew) { + INSIST(server->sessionkey == NULL); + INSIST(server->session_keyfile == NULL); + INSIST(server->session_keyname == NULL); + INSIST(server->session_keyalg == DST_ALG_UNKNOWN); + INSIST(server->session_keybits == 0); + + server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t)); + dns_name_init(server->session_keyname, NULL); + dns_name_dup(keyname, mctx, server->session_keyname); + + server->session_keyfile = isc_mem_strdup(mctx, keyfile); + + server->session_keyalg = algtype; + server->session_keybits = bits; + + CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr, + algname, algtype, bits, mctx, + first_time, &server->sessionkey)); + } + + return (result); + +cleanup: + cleanup_session_key(server, mctx); + return (result); +} + +#ifndef HAVE_LMDB +static isc_result_t +count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) { + isc_result_t result; + + /* The new zone file may not exist. That is OK. */ + if (!isc_file_exists(view->new_zone_file)) { + *num_zonesp = 0; + return (ISC_R_SUCCESS); + } + + /* + * In the case of NZF files, we also parse the configuration in + * the file at this stage. + * + * This may be called in multiple views, so we reset + * the parser each time. + */ + cfg_parser_reset(named_g_addparser); + result = cfg_parse_file(named_g_addparser, view->new_zone_file, + &cfg_type_addzoneconf, &nzcfg->nzf_config); + if (result == ISC_R_SUCCESS) { + int num_zones; + + num_zones = count_zones(nzcfg->nzf_config); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "NZF file '%s' contains %d zones", + view->new_zone_file, num_zones); + if (num_zonesp != NULL) { + *num_zonesp = num_zones; + } + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Error parsing NZF file '%s': %s", + view->new_zone_file, isc_result_totext(result)); + } + + return (result); +} + +#else /* HAVE_LMDB */ + +static isc_result_t +count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) { + isc_result_t result; + int n; + + UNUSED(nzcfg); + + REQUIRE(num_zonesp != NULL); + + LOCK(&view->new_zone_lock); + + CHECK(migrate_nzf(view)); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "loading NZD zone count from '%s' " + "for view '%s'", + view->new_zone_db, view->name); + + CHECK(nzd_count(view, &n)); + + *num_zonesp = n; + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "NZD database '%s' contains %d zones", view->new_zone_db, + n); + +cleanup: + if (result != ISC_R_SUCCESS) { + *num_zonesp = 0; + } + + UNLOCK(&view->new_zone_lock); + + return (ISC_R_SUCCESS); +} + +#endif /* HAVE_LMDB */ + +static isc_result_t +setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, + cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx, + int *num_zones) { + isc_result_t result = ISC_R_SUCCESS; + bool allow = false; + ns_cfgctx_t *nzcfg = NULL; + const cfg_obj_t *maps[4]; + const cfg_obj_t *options = NULL, *voptions = NULL; + const cfg_obj_t *nz = NULL; + const cfg_obj_t *nzdir = NULL; + const char *dir = NULL; + const cfg_obj_t *obj = NULL; + int i = 0; + uint64_t mapsize = 0ULL; + + REQUIRE(config != NULL); + + if (vconfig != NULL) { + voptions = cfg_tuple_get(vconfig, "options"); + } + if (voptions != NULL) { + maps[i++] = voptions; + } + result = cfg_map_get(config, "options", &options); + if (result == ISC_R_SUCCESS) { + maps[i++] = options; + } + maps[i++] = named_g_defaults; + maps[i] = NULL; + + result = named_config_get(maps, "allow-new-zones", &nz); + if (result == ISC_R_SUCCESS) { + allow = cfg_obj_asboolean(nz); + } + result = named_config_get(maps, "new-zones-directory", &nzdir); + if (result == ISC_R_SUCCESS) { + dir = cfg_obj_asstring(nzdir); + result = isc_file_isdirectory(dir); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "invalid new-zones-directory %s: %s", dir, + isc_result_totext(result)); + return (result); + } + if (!isc_file_isdirwritable(dir)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "new-zones-directory '%s' " + "is not writable", + dir); + return (ISC_R_NOPERM); + } + + dns_view_setnewzonedir(view, dir); + } + +#ifdef HAVE_LMDB + result = named_config_get(maps, "lmdb-mapsize", &obj); + if (result == ISC_R_SUCCESS && obj != NULL) { + mapsize = cfg_obj_asuint64(obj); + if (mapsize < (1ULL << 20)) { /* 1 megabyte */ + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "'lmdb-mapsize " + "%" PRId64 "' " + "is too small", + mapsize); + return (ISC_R_FAILURE); + } else if (mapsize > (1ULL << 40)) { /* 1 terabyte */ + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "'lmdb-mapsize " + "%" PRId64 "' " + "is too large", + mapsize); + return (ISC_R_FAILURE); + } + } +#else /* ifdef HAVE_LMDB */ + UNUSED(obj); +#endif /* HAVE_LMDB */ + + /* + * A non-empty catalog-zones statement implies allow-new-zones + */ + if (!allow) { + const cfg_obj_t *cz = NULL; + result = named_config_get(maps, "catalog-zones", &cz); + if (result == ISC_R_SUCCESS) { + const cfg_listelt_t *e = + cfg_list_first(cfg_tuple_get(cz, "zone list")); + if (e != NULL) { + allow = true; + } + } + } + + if (!allow) { + dns_view_setnewzones(view, false, NULL, NULL, 0ULL); + if (num_zones != NULL) { + *num_zones = 0; + } + return (ISC_R_SUCCESS); + } + + nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg)); + + /* + * We attach the parser that was used for config as well + * as the one that will be used for added zones, to avoid + * a shutdown race later. + */ + memset(nzcfg, 0, sizeof(*nzcfg)); + cfg_parser_attach(conf_parser, &nzcfg->conf_parser); + cfg_parser_attach(named_g_addparser, &nzcfg->add_parser); + isc_mem_attach(view->mctx, &nzcfg->mctx); + cfg_aclconfctx_attach(actx, &nzcfg->actx); + + result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy, + mapsize); + if (result != ISC_R_SUCCESS) { + dns_view_setnewzones(view, false, NULL, NULL, 0ULL); + return (result); + } + + cfg_obj_attach(config, &nzcfg->config); + if (vconfig != NULL) { + cfg_obj_attach(vconfig, &nzcfg->vconfig); + } + + result = count_newzones(view, nzcfg, num_zones); + return (result); +} + +static void +configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig, + dns_view_t *view) { + const char *zname; + dns_fixedname_t fixorigin; + dns_name_t *origin; + isc_result_t result2; + dns_view_t *pview = NULL; + dns_zone_t *zone = NULL; + + zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + origin = dns_fixedname_initname(&fixorigin); + + result2 = dns_name_fromstring(origin, zname, 0, NULL); + if (result2 != ISC_R_SUCCESS) { + return; + } + + result2 = dns_viewlist_find(&named_g_server->viewlist, view->name, + view->rdclass, &pview); + if (result2 != ISC_R_SUCCESS) { + return; + } + + result2 = dns_view_findzone(pview, origin, &zone); + if (result2 != ISC_R_SUCCESS) { + dns_view_detach(&pview); + return; + } + + if (result == ISC_R_SUCCESS) { + dns_zone_setviewcommit(zone); + } else { + dns_zone_setviewrevert(zone); + } + + dns_zone_detach(&zone); + dns_view_detach(&pview); +} + +#ifndef HAVE_LMDB + +static isc_result_t +configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, + isc_mem_t *mctx, cfg_aclconfctx_t *actx) { + isc_result_t result; + ns_cfgctx_t *nzctx; + const cfg_obj_t *zonelist; + const cfg_listelt_t *element; + + nzctx = view->new_zone_config; + if (nzctx == NULL || nzctx->nzf_config == NULL) { + return (ISC_R_SUCCESS); + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "loading additional zones for view '%s'", view->name); + + zonelist = NULL; + cfg_map_get(nzctx->nzf_config, "zone", &zonelist); + + for (element = cfg_list_first(zonelist); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *zconfig = cfg_listelt_value(element); + CHECK(configure_zone(config, zconfig, vconfig, mctx, view, + &named_g_server->viewlist, + &named_g_server->kasplist, actx, true, + false, false)); + } + + result = ISC_R_SUCCESS; + +cleanup: + for (element = cfg_list_first(zonelist); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *zconfig = cfg_listelt_value(element); + configure_zone_setviewcommit(result, zconfig, view); + } + + return (result); +} + +#else /* HAVE_LMDB */ + +static isc_result_t +data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text, + cfg_obj_t **zoneconfig) { + isc_result_t result; + const char *zone_name; + size_t zone_name_len; + const char *zone_config; + size_t zone_config_len; + cfg_obj_t *zoneconf = NULL; + char bufname[DNS_NAME_FORMATSIZE]; + + REQUIRE(view != NULL); + REQUIRE(key != NULL); + REQUIRE(data != NULL); + REQUIRE(text != NULL); + REQUIRE(zoneconfig != NULL && *zoneconfig == NULL); + + if (*text == NULL) { + isc_buffer_allocate(view->mctx, text, 256); + } else { + isc_buffer_clear(*text); + } + + zone_name = (const char *)key->mv_data; + zone_name_len = key->mv_size; + INSIST(zone_name != NULL && zone_name_len > 0); + + zone_config = (const char *)data->mv_data; + zone_config_len = data->mv_size; + INSIST(zone_config != NULL && zone_config_len > 0); + + /* zone zonename { config; }; */ + result = isc_buffer_reserve(text, 6 + zone_name_len + 2 + + zone_config_len + 2); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + CHECK(putstr(text, "zone \"")); + CHECK(putmem(text, (const void *)zone_name, zone_name_len)); + CHECK(putstr(text, "\" ")); + CHECK(putmem(text, (const void *)zone_config, zone_config_len)); + CHECK(putstr(text, ";\n")); + + snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len, + zone_name); + + cfg_parser_reset(named_g_addparser); + result = cfg_parse_buffer(named_g_addparser, *text, bufname, 0, + &cfg_type_addzoneconf, 0, &zoneconf); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "parsing config for zone '%.*s' in " + "NZD database '%s' failed", + (int)zone_name_len, zone_name, view->new_zone_db); + goto cleanup; + } + + *zoneconfig = zoneconf; + zoneconf = NULL; + result = ISC_R_SUCCESS; + +cleanup: + if (zoneconf != NULL) { + cfg_obj_destroy(named_g_addparser, &zoneconf); + } + + return (result); +} + +/*% + * Prototype for a callback which can be used with for_all_newzone_cfgs(). + */ +typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig, + cfg_obj_t *config, cfg_obj_t *vconfig, + isc_mem_t *mctx, dns_view_t *view, + cfg_aclconfctx_t *actx); + +/*% + * For each zone found in a NZD opened by the caller, create an object + * representing its configuration and invoke "callback" with the created + * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all + * these are non-global variables required to invoke configure_zone()). + * Immediately interrupt processing if an error is encountered while + * transforming NZD data into a zone configuration object or if "callback" + * returns an error. + * + * Caller must hold 'view->new_zone_lock'. + */ +static isc_result_t +for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config, + cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, + cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi) { + const cfg_obj_t *zconfig, *zlist; + isc_result_t result = ISC_R_SUCCESS; + cfg_obj_t *zconfigobj = NULL; + isc_buffer_t *text = NULL; + MDB_cursor *cursor = NULL; + MDB_val data, key; + int status; + + status = mdb_cursor_open(txn, dbi, &cursor); + if (status != MDB_SUCCESS) { + return (ISC_R_FAILURE); + } + + for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST); + status == MDB_SUCCESS; + status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) + { + /* + * Create a configuration object from data fetched from NZD. + */ + result = data_to_cfg(view, &key, &data, &text, &zconfigobj); + if (result != ISC_R_SUCCESS) { + break; + } + + /* + * Extract zone configuration from configuration object. + */ + zlist = NULL; + result = cfg_map_get(zconfigobj, "zone", &zlist); + if (result != ISC_R_SUCCESS) { + break; + } else if (!cfg_obj_islist(zlist)) { + result = ISC_R_FAILURE; + break; + } + zconfig = cfg_listelt_value(cfg_list_first(zlist)); + + /* + * Invoke callback. + */ + result = callback(zconfig, config, vconfig, mctx, view, actx); + if (result != ISC_R_SUCCESS) { + break; + } + + /* + * Destroy the configuration object created in this iteration. + */ + cfg_obj_destroy(named_g_addparser, &zconfigobj); + } + + if (text != NULL) { + isc_buffer_free(&text); + } + if (zconfigobj != NULL) { + cfg_obj_destroy(named_g_addparser, &zconfigobj); + } + mdb_cursor_close(cursor); + + return (result); +} + +/*% + * Attempt to configure a zone found in NZD and return the result. + */ +static isc_result_t +configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config, + cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, + cfg_aclconfctx_t *actx) { + return (configure_zone( + config, zconfig, vconfig, mctx, view, &named_g_server->viewlist, + &named_g_server->kasplist, actx, true, false, false)); +} + +/*% + * Revert new view assignment for a zone found in NZD. + */ +static isc_result_t +configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config, + cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, + cfg_aclconfctx_t *actx) { + UNUSED(config); + UNUSED(vconfig); + UNUSED(mctx); + UNUSED(actx); + + configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, + isc_mem_t *mctx, cfg_aclconfctx_t *actx) { + isc_result_t result; + MDB_txn *txn = NULL; + MDB_dbi dbi; + + if (view->new_zone_config == NULL) { + return (ISC_R_SUCCESS); + } + + LOCK(&view->new_zone_lock); + + result = nzd_open(view, MDB_RDONLY, &txn, &dbi); + if (result != ISC_R_SUCCESS) { + UNLOCK(&view->new_zone_lock); + return (ISC_R_SUCCESS); + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "loading NZD configs from '%s' " + "for view '%s'", + view->new_zone_db, view->name); + + result = for_all_newzone_cfgs(configure_newzone, config, vconfig, mctx, + view, actx, txn, dbi); + if (result != ISC_R_SUCCESS) { + /* + * An error was encountered while attempting to configure zones + * found in NZD. As this error may have been caused by a + * configure_zone() failure, try restoring a sane configuration + * by reattaching all zones found in NZD to the old view. If + * this also fails, too bad, there is nothing more we can do in + * terms of trying to make things right. + */ + (void)for_all_newzone_cfgs(configure_newzone_revert, config, + vconfig, mctx, view, actx, txn, dbi); + } + + (void)nzd_close(&txn, false); + + UNLOCK(&view->new_zone_lock); + + return (result); +} + +static isc_result_t +get_newzone_config(dns_view_t *view, const char *zonename, + cfg_obj_t **zoneconfig) { + isc_result_t result; + int status; + cfg_obj_t *zoneconf = NULL; + isc_buffer_t *text = NULL; + MDB_txn *txn = NULL; + MDB_dbi dbi; + MDB_val key, data; + char zname[DNS_NAME_FORMATSIZE]; + dns_fixedname_t fname; + dns_name_t *name; + isc_buffer_t b; + + INSIST(zoneconfig != NULL && *zoneconfig == NULL); + + LOCK(&view->new_zone_lock); + + CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi)); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "loading NZD config from '%s' " + "for zone '%s'", + view->new_zone_db, zonename); + + /* Normalize zone name */ + isc_buffer_constinit(&b, zonename, strlen(zonename)); + isc_buffer_add(&b, strlen(zonename)); + name = dns_fixedname_initname(&fname); + CHECK(dns_name_fromtext(name, &b, dns_rootname, DNS_NAME_DOWNCASE, + NULL)); + dns_name_format(name, zname, sizeof(zname)); + + key.mv_data = zname; + key.mv_size = strlen(zname); + + status = mdb_get(txn, dbi, &key, &data); + if (status != MDB_SUCCESS) { + CHECK(ISC_R_FAILURE); + } + + CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf)); + + *zoneconfig = zoneconf; + zoneconf = NULL; + result = ISC_R_SUCCESS; + +cleanup: + (void)nzd_close(&txn, false); + + UNLOCK(&view->new_zone_lock); + + if (zoneconf != NULL) { + cfg_obj_destroy(named_g_addparser, &zoneconf); + } + if (text != NULL) { + isc_buffer_free(&text); + } + + return (result); +} + +#endif /* HAVE_LMDB */ + +static int +count_zones(const cfg_obj_t *conf) { + const cfg_obj_t *zonelist = NULL; + const cfg_listelt_t *element; + int n = 0; + + REQUIRE(conf != NULL); + + cfg_map_get(conf, "zone", &zonelist); + for (element = cfg_list_first(zonelist); element != NULL; + element = cfg_list_next(element)) + { + n++; + } + + return (n); +} + +static isc_result_t +check_lockfile(named_server_t *server, const cfg_obj_t *config, + bool first_time) { + isc_result_t result; + const char *filename = NULL; + const cfg_obj_t *maps[3]; + const cfg_obj_t *options; + const cfg_obj_t *obj; + int i; + + i = 0; + options = NULL; + result = cfg_map_get(config, "options", &options); + if (result == ISC_R_SUCCESS) { + maps[i++] = options; + } + maps[i++] = named_g_defaults; + maps[i] = NULL; + + obj = NULL; + (void)named_config_get(maps, "lock-file", &obj); + + if (!first_time) { + if (obj != NULL && !cfg_obj_isstring(obj) && + server->lockfile != NULL && + strcmp(cfg_obj_asstring(obj), server->lockfile) != 0) + { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "changing 'lock-file' " + "has no effect until the " + "server is restarted"); + } + + return (ISC_R_SUCCESS); + } + + if (obj != NULL) { + if (cfg_obj_isvoid(obj)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), + "skipping lock-file check "); + return (ISC_R_SUCCESS); + } else if (named_g_forcelock) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "'lock-file' has no effect " + "because the server was run with -X"); + server->lockfile = isc_mem_strdup( + server->mctx, named_g_defaultlockfile); + } else { + filename = cfg_obj_asstring(obj); + server->lockfile = isc_mem_strdup(server->mctx, + filename); + } + + if (server->lockfile == NULL) { + return (ISC_R_NOMEMORY); + } + } + + if (named_g_forcelock && named_g_defaultlockfile != NULL) { + INSIST(server->lockfile == NULL); + server->lockfile = isc_mem_strdup(server->mctx, + named_g_defaultlockfile); + } + + if (server->lockfile == NULL) { + return (ISC_R_SUCCESS); + } + + if (named_os_issingleton(server->lockfile)) { + return (ISC_R_SUCCESS); + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "could not lock %s; another named " + "process may be running", + server->lockfile); + return (ISC_R_FAILURE); +} + +static isc_result_t +load_configuration(const char *filename, named_server_t *server, + bool first_time) { + cfg_obj_t *config = NULL, *bindkeys = NULL; + cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL; + const cfg_listelt_t *element; + const cfg_obj_t *builtin_views; + const cfg_obj_t *maps[3]; + const cfg_obj_t *obj; + const cfg_obj_t *options; + const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports; + const cfg_obj_t *kasps; + dns_kasp_t *kasp = NULL; + dns_kasp_t *kasp_next = NULL; + dns_kasplist_t tmpkasplist, kasplist; + const cfg_obj_t *views; + dns_view_t *view = NULL; + dns_view_t *view_next = NULL; + dns_viewlist_t tmpviewlist; + dns_viewlist_t viewlist, builtin_viewlist; + in_port_t listen_port, udpport_low, udpport_high; + int i, backlog; + int num_zones = 0; + bool exclusive = false; + isc_interval_t interval; + isc_logconfig_t *logc = NULL; + isc_portset_t *v4portset = NULL; + isc_portset_t *v6portset = NULL; + isc_resourcevalue_t nfiles; + isc_result_t result, tresult; + uint32_t heartbeat_interval; + uint32_t interface_interval; + uint32_t reserved; + uint32_t udpsize; + uint32_t transfer_message_size; + named_cache_t *nsc; + named_cachelist_t cachelist, tmpcachelist; + ns_altsecret_t *altsecret; + ns_altsecretlist_t altsecrets, tmpaltsecrets; + unsigned int maxsocks; + uint32_t softquota = 0; + uint32_t max; + uint64_t initial, idle, keepalive, advertised; + bool loadbalancesockets; + dns_aclenv_t *env = + ns_interfacemgr_getaclenv(named_g_server->interfacemgr); + + ISC_LIST_INIT(kasplist); + ISC_LIST_INIT(viewlist); + ISC_LIST_INIT(builtin_viewlist); + ISC_LIST_INIT(cachelist); + ISC_LIST_INIT(altsecrets); + + /* Create the ACL configuration context */ + if (named_g_aclconfctx != NULL) { + cfg_aclconfctx_detach(&named_g_aclconfctx); + } + CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx)); + + /* + * Shut down all dyndb instances. + */ + dns_dyndb_cleanup(false); + + /* + * Parse the global default pseudo-config file. + */ + if (first_time) { + result = named_config_parsedefaults(named_g_parser, + &named_g_config); + if (result != ISC_R_SUCCESS) { + named_main_earlyfatal("unable to load " + "internal defaults: %s", + isc_result_totext(result)); + } + RUNTIME_CHECK(cfg_map_get(named_g_config, "options", + &named_g_defaults) == ISC_R_SUCCESS); + } + + /* + * Parse the configuration file using the new config code. + */ + config = NULL; + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "loading configuration from '%s'", filename); + CHECK(cfg_parser_create(named_g_mctx, named_g_lctx, &conf_parser)); + cfg_parser_setcallback(conf_parser, directory_callback, NULL); + result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf, + &config); + + CHECK(result); + + /* + * Check the validity of the configuration. + * + * (Ignore plugin parameters for now; they will be + * checked later when the modules are actually loaded and + * registered.) + */ + CHECK(bind9_check_namedconf(config, false, named_g_lctx, named_g_mctx)); + + /* + * Fill in the maps array, used for resolving defaults. + */ + i = 0; + options = NULL; + result = cfg_map_get(config, "options", &options); + if (result == ISC_R_SUCCESS) { + maps[i++] = options; + } + maps[i++] = named_g_defaults; + maps[i] = NULL; + + /* + * If bind.keys exists, load it. If "dnssec-validation auto" + * is turned on, the root key found there will be used as a + * default trust anchor. + */ + obj = NULL; + result = named_config_get(maps, "bindkeys-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->bindkeysfile, cfg_obj_asstring(obj)), + "strdup"); + INSIST(server->bindkeysfile != NULL); + + if (access(server->bindkeysfile, R_OK) == 0) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "reading built-in trust anchors " + "from file '%s'", + server->bindkeysfile); + + CHECK(cfg_parser_create(named_g_mctx, named_g_lctx, + &bindkeys_parser)); + + result = cfg_parse_file(bindkeys_parser, server->bindkeysfile, + &cfg_type_bindkeys, &bindkeys); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "unable to parse '%s' error '%s'; using " + "built-in keys instead", + server->bindkeysfile, + isc_result_totext(result)); + } + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "unable to open '%s'; using built-in keys " + "instead", + server->bindkeysfile); + } + + /* Ensure exclusive access to configuration data. */ + if (!exclusive) { + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + exclusive = true; + } + + /* + * Set process limits, which (usually) needs to be done as root. + */ + set_limits(maps); + + /* + * Check the process lockfile. + */ + CHECK(check_lockfile(server, config, first_time)); + + /* + * Check if max number of open sockets that the system allows is + * sufficiently large. Failing this condition is not necessarily fatal, + * but may cause subsequent runtime failures for a busy recursive + * server. + */ + result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &maxsocks); + if (result != ISC_R_SUCCESS) { + maxsocks = 0; + } + result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles); + if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "max open files (%" PRIu64 ")" + " is smaller than max sockets (%u)", + nfiles, maxsocks); + } + + /* + * Set the number of socket reserved for TCP, stdio etc. + */ + obj = NULL; + result = named_config_get(maps, "reserved-sockets", &obj); + INSIST(result == ISC_R_SUCCESS); + reserved = cfg_obj_asuint32(obj); + if (maxsocks != 0) { + if (maxsocks < 128U) { /* Prevent underflow. */ + reserved = 0; + } else if (reserved > maxsocks - 128U) { /* Minimum UDP space. + */ + reserved = maxsocks - 128; + } + } + /* Minimum TCP/stdio space. */ + if (reserved < 128U) { + reserved = 128; + } + if (reserved + 128U > maxsocks && maxsocks != 0) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "less than 128 UDP sockets available after " + "applying 'reserved-sockets' and 'maxsockets'"); + } + isc_socketmgr_setreserved(named_g_socketmgr, reserved); + +#if defined(HAVE_GEOIP2) + /* + * Release any previously opened GeoIP2 databases. + */ + named_geoip_unload(); + + /* + * Initialize GeoIP databases from the configured location. + * This should happen before configuring any ACLs, so that we + * know what databases are available and can reject any GeoIP + * ACLs that can't work. + */ + obj = NULL; + result = named_config_get(maps, "geoip-directory", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isstring(obj)) { + char *dir; + DE_CONST(cfg_obj_asstring(obj), dir); + named_geoip_load(dir); + } + named_g_aclconfctx->geoip = named_g_geoip; +#endif /* HAVE_GEOIP2 */ + + /* + * Configure various server options. + */ + configure_server_quota(maps, "transfers-out", + &server->sctx->xfroutquota); + configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota); + configure_server_quota(maps, "recursive-clients", + &server->sctx->recursionquota); + configure_server_quota(maps, "update-quota", &server->sctx->updquota); + + max = isc_quota_getmax(&server->sctx->recursionquota); + if (max > 1000) { + unsigned margin = ISC_MAX(100, named_g_cpus + 1); + if (margin + 100 > max) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "'recursive-clients %d' too low when " + "running with %d worker threads", + max, named_g_cpus); + CHECK(ISC_R_RANGE); + } + softquota = max - margin; + } else { + softquota = (max * 90) / 100; + } + + isc_quota_soft(&server->sctx->recursionquota, softquota); + + /* + * Set "blackhole". Only legal at options level; there is + * no default. + */ + CHECK(configure_view_acl(NULL, config, NULL, "blackhole", NULL, + named_g_aclconfctx, named_g_mctx, + &server->sctx->blackholeacl)); + if (server->sctx->blackholeacl != NULL) { + dns_dispatchmgr_setblackhole(named_g_dispatchmgr, + server->sctx->blackholeacl); + } + + /* + * Set "keep-response-order". Only legal at options or + * global defaults level. + */ + CHECK(configure_view_acl(NULL, config, named_g_config, + "keep-response-order", NULL, + named_g_aclconfctx, named_g_mctx, + &server->sctx->keepresporder)); + + obj = NULL; + result = named_config_get(maps, "match-mapped-addresses", &obj); + INSIST(result == ISC_R_SUCCESS); + env->match_mapped = cfg_obj_asboolean(obj); + + CHECKM(named_statschannels_configure(named_g_server, config, + named_g_aclconfctx), + "configuring statistics server(s)"); + + obj = NULL; + result = named_config_get(maps, "tcp-initial-timeout", &obj); + INSIST(result == ISC_R_SUCCESS); + initial = cfg_obj_asuint32(obj) * 100; + if (initial > MAX_INITIAL_TIMEOUT) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "tcp-initial-timeout value is out of range: " + "lowering to %" PRIu32, + MAX_INITIAL_TIMEOUT / 100); + initial = MAX_INITIAL_TIMEOUT; + } else if (initial < MIN_INITIAL_TIMEOUT) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "tcp-initial-timeout value is out of range: " + "raising to %" PRIu32, + MIN_INITIAL_TIMEOUT / 100); + initial = MIN_INITIAL_TIMEOUT; + } + + obj = NULL; + result = named_config_get(maps, "tcp-idle-timeout", &obj); + INSIST(result == ISC_R_SUCCESS); + idle = cfg_obj_asuint32(obj) * 100; + if (idle > MAX_IDLE_TIMEOUT) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "tcp-idle-timeout value is out of range: " + "lowering to %" PRIu32, + MAX_IDLE_TIMEOUT / 100); + idle = MAX_IDLE_TIMEOUT; + } else if (idle < MIN_IDLE_TIMEOUT) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "tcp-idle-timeout value is out of range: " + "raising to %" PRIu32, + MIN_IDLE_TIMEOUT / 100); + idle = MIN_IDLE_TIMEOUT; + } + + obj = NULL; + result = named_config_get(maps, "tcp-keepalive-timeout", &obj); + INSIST(result == ISC_R_SUCCESS); + keepalive = cfg_obj_asuint32(obj) * 100; + if (keepalive > MAX_KEEPALIVE_TIMEOUT) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "tcp-keepalive-timeout value is out of range: " + "lowering to %" PRIu32, + MAX_KEEPALIVE_TIMEOUT / 100); + keepalive = MAX_KEEPALIVE_TIMEOUT; + } else if (keepalive < MIN_KEEPALIVE_TIMEOUT) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "tcp-keepalive-timeout value is out of range: " + "raising to %" PRIu32, + MIN_KEEPALIVE_TIMEOUT / 100); + keepalive = MIN_KEEPALIVE_TIMEOUT; + } + + obj = NULL; + result = named_config_get(maps, "tcp-advertised-timeout", &obj); + INSIST(result == ISC_R_SUCCESS); + advertised = cfg_obj_asuint32(obj) * 100; + if (advertised > MAX_ADVERTISED_TIMEOUT) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "tcp-advertized-timeout value is out of range: " + "lowering to %" PRIu32, + MAX_ADVERTISED_TIMEOUT / 100); + advertised = MAX_ADVERTISED_TIMEOUT; + } + + isc_nm_settimeouts(named_g_nm, initial, idle, keepalive, advertised); + + /* + * Configure sets of UDP query source ports. + */ + CHECKM(isc_portset_create(named_g_mctx, &v4portset), "creating UDP " + "port set"); + CHECKM(isc_portset_create(named_g_mctx, &v6portset), "creating UDP " + "port set"); + + usev4ports = NULL; + usev6ports = NULL; + avoidv4ports = NULL; + avoidv6ports = NULL; + + (void)named_config_get(maps, "use-v4-udp-ports", &usev4ports); + if (usev4ports != NULL) { + portset_fromconf(v4portset, usev4ports, true); + } else { + CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low, + &udpport_high), + "get the default UDP/IPv4 port range"); + if (udpport_low == udpport_high) { + isc_portset_add(v4portset, udpport_low); + } else { + isc_portset_addrange(v4portset, udpport_low, + udpport_high); + } + if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "using default UDP/IPv4 port range: " + "[%d, %d]", + udpport_low, udpport_high); + } + } + (void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports); + if (avoidv4ports != NULL) { + portset_fromconf(v4portset, avoidv4ports, false); + } + + (void)named_config_get(maps, "use-v6-udp-ports", &usev6ports); + if (usev6ports != NULL) { + portset_fromconf(v6portset, usev6ports, true); + } else { + CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low, + &udpport_high), + "get the default UDP/IPv6 port range"); + if (udpport_low == udpport_high) { + isc_portset_add(v6portset, udpport_low); + } else { + isc_portset_addrange(v6portset, udpport_low, + udpport_high); + } + if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "using default UDP/IPv6 port range: " + "[%d, %d]", + udpport_low, udpport_high); + } + } + (void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports); + if (avoidv6ports != NULL) { + portset_fromconf(v6portset, avoidv6ports, false); + } + + dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset, + v6portset); + + /* + * Set the EDNS UDP size when we don't match a view. + */ + obj = NULL; + result = named_config_get(maps, "edns-udp-size", &obj); + INSIST(result == ISC_R_SUCCESS); + udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) { + udpsize = 512; + } + if (udpsize > 4096) { + udpsize = 4096; + } + server->sctx->udpsize = (uint16_t)udpsize; + + /* Set the transfer message size for TCP */ + obj = NULL; + result = named_config_get(maps, "transfer-message-size", &obj); + INSIST(result == ISC_R_SUCCESS); + transfer_message_size = cfg_obj_asuint32(obj); + if (transfer_message_size < 512) { + transfer_message_size = 512; + } else if (transfer_message_size > 65535) { + transfer_message_size = 65535; + } + server->sctx->transfer_tcp_message_size = + (uint16_t)transfer_message_size; + + /* + * Configure the zone manager. + */ + obj = NULL; + result = named_config_get(maps, "transfers-in", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "transfers-per-ns", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "notify-rate", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "startup-notify-rate", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zonemgr_setstartupnotifyrate(server->zonemgr, + cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "serial-query-rate", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj)); + + /* + * Determine which port to use for listening for incoming connections. + */ + if (named_g_port != 0) { + listen_port = named_g_port; + } else { + CHECKM(named_config_getport(config, &listen_port), "port"); + } + + /* + * Determining the default DSCP code point. + */ + CHECKM(named_config_getdscp(config, &named_g_dscp), "dscp"); + + /* + * Find the listen queue depth. + */ + obj = NULL; + result = named_config_get(maps, "tcp-listen-queue", &obj); + INSIST(result == ISC_R_SUCCESS); + backlog = cfg_obj_asuint32(obj); + if ((backlog > 0) && (backlog < 10)) { + backlog = 10; + } + ns_interfacemgr_setbacklog(server->interfacemgr, backlog); + + obj = NULL; + result = named_config_get(maps, "reuseport", &obj); + INSIST(result == ISC_R_SUCCESS); + loadbalancesockets = cfg_obj_asboolean(obj); +#if HAVE_SO_REUSEPORT_LB + if (first_time) { + isc_nm_setloadbalancesockets(named_g_nm, + cfg_obj_asboolean(obj)); + } else if (loadbalancesockets != + isc_nm_getloadbalancesockets(named_g_nm)) + { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "changing reuseport value requires server restart"); + } +#else + if (loadbalancesockets) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "reuseport has no effect on this system"); + } +#endif + + /* + * Configure the interface manager according to the "listen-on" + * statement. + */ + { + const cfg_obj_t *clistenon = NULL; + ns_listenlist_t *listenon = NULL; + + clistenon = NULL; + /* + * Even though listen-on is present in the default + * configuration, this way is easier. + */ + if (options != NULL) { + (void)cfg_map_get(options, "listen-on", &clistenon); + } + if (clistenon != NULL) { + /* check return code? */ + (void)ns_listenlist_fromconfig( + clistenon, config, named_g_aclconfctx, + named_g_mctx, AF_INET, &listenon); + } else { + /* + * Not specified, use default. + */ + CHECK(ns_listenlist_default(named_g_mctx, listen_port, + -1, true, &listenon)); + } + if (listenon != NULL) { + ns_interfacemgr_setlistenon4(server->interfacemgr, + listenon); + ns_listenlist_detach(&listenon); + } + } + /* + * Ditto for IPv6. + */ + { + const cfg_obj_t *clistenon = NULL; + ns_listenlist_t *listenon = NULL; + + if (options != NULL) { + (void)cfg_map_get(options, "listen-on-v6", &clistenon); + } + if (clistenon != NULL) { + /* check return code? */ + (void)ns_listenlist_fromconfig( + clistenon, config, named_g_aclconfctx, + named_g_mctx, AF_INET6, &listenon); + } else { + /* + * Not specified, use default. + */ + CHECK(ns_listenlist_default(named_g_mctx, listen_port, + -1, true, &listenon)); + } + if (listenon != NULL) { + ns_interfacemgr_setlistenon6(server->interfacemgr, + listenon); + ns_listenlist_detach(&listenon); + } + } + + /* + * Rescan the interface list to pick up changes in the + * listen-on option. It's important that we do this before we try + * to configure the query source, since the dispatcher we use might + * be shared with an interface. + */ + result = ns_interfacemgr_scan(server->interfacemgr, true); + + /* + * Check that named is able to TCP listen on at least one + * interface. Otherwise, another named process could be running + * and we should fail. + */ + if (first_time && (result == ISC_R_ADDRINUSE)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "unable to listen on any configured interfaces"); + result = ISC_R_FAILURE; + goto cleanup; + } + + /* + * Arrange for further interface scanning to occur periodically + * as specified by the "interface-interval" option. + */ + obj = NULL; + result = named_config_get(maps, "interface-interval", &obj); + INSIST(result == ISC_R_SUCCESS); + interface_interval = cfg_obj_asduration(obj); + if (interface_interval == 0) { + CHECK(isc_timer_reset(server->interface_timer, + isc_timertype_inactive, NULL, NULL, + true)); + } else if (server->interface_interval != interface_interval) { + isc_interval_set(&interval, interface_interval, 0); + CHECK(isc_timer_reset(server->interface_timer, + isc_timertype_ticker, NULL, &interval, + false)); + } + server->interface_interval = interface_interval; + + /* + * Enable automatic interface scans. + */ + obj = NULL; + result = named_config_get(maps, "automatic-interface-scan", &obj); + INSIST(result == ISC_R_SUCCESS); + server->sctx->interface_auto = cfg_obj_asboolean(obj); + + /* + * Configure the dialup heartbeat timer. + */ + obj = NULL; + result = named_config_get(maps, "heartbeat-interval", &obj); + INSIST(result == ISC_R_SUCCESS); + heartbeat_interval = cfg_obj_asuint32(obj) * 60; + if (heartbeat_interval == 0) { + CHECK(isc_timer_reset(server->heartbeat_timer, + isc_timertype_inactive, NULL, NULL, + true)); + } else if (server->heartbeat_interval != heartbeat_interval) { + isc_interval_set(&interval, heartbeat_interval, 0); + CHECK(isc_timer_reset(server->heartbeat_timer, + isc_timertype_ticker, NULL, &interval, + false)); + } + server->heartbeat_interval = heartbeat_interval; + + isc_interval_set(&interval, 1200, 0); + CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL, + &interval, false)); + + isc_interval_set(&interval, named_g_tat_interval, 0); + CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker, NULL, + &interval, false)); + + /* + * Write the PID file. + */ + obj = NULL; + if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) { + if (cfg_obj_isvoid(obj)) { + named_os_writepidfile(NULL, first_time); + } else { + named_os_writepidfile(cfg_obj_asstring(obj), + first_time); + } + } else { + named_os_writepidfile(named_g_defaultpidfile, first_time); + } + + /* + * Configure the server-wide session key. This must be done before + * configure views because zone configuration may need to know + * session-keyname. + * + * Failure of session key generation isn't fatal at this time; if it + * turns out that a session key is really needed but doesn't exist, + * we'll treat it as a fatal error then. + */ + (void)configure_session_key(maps, server, named_g_mctx, first_time); + + /* + * Create the DNSSEC key and signing policies (KASP). + */ + kasps = NULL; + (void)cfg_map_get(config, "dnssec-policy", &kasps); + for (element = cfg_list_first(kasps); element != NULL; + element = cfg_list_next(element)) + { + cfg_obj_t *kconfig = cfg_listelt_value(element); + kasp = NULL; + CHECK(cfg_kasp_fromconfig(kconfig, NULL, named_g_mctx, + named_g_lctx, &kasplist, &kasp)); + INSIST(kasp != NULL); + dns_kasp_freeze(kasp); + dns_kasp_detach(&kasp); + } + /* + * Create the built-in kasp policies ("default", "insecure"). + */ + kasp = NULL; + CHECK(cfg_kasp_fromconfig(NULL, "default", named_g_mctx, named_g_lctx, + &kasplist, &kasp)); + INSIST(kasp != NULL); + dns_kasp_freeze(kasp); + dns_kasp_detach(&kasp); + + kasp = NULL; + CHECK(cfg_kasp_fromconfig(NULL, "insecure", named_g_mctx, named_g_lctx, + &kasplist, &kasp)); + INSIST(kasp != NULL); + dns_kasp_freeze(kasp); + dns_kasp_detach(&kasp); + + tmpkasplist = server->kasplist; + server->kasplist = kasplist; + kasplist = tmpkasplist; + + /* + * Configure the views. + */ + views = NULL; + (void)cfg_map_get(config, "view", &views); + + /* + * Create the views and count all the configured zones in + * order to correctly size the zone manager's task table. + * (We only count zones for configured views; the built-in + * "bind" view can be ignored as it only adds a negligible + * number of zones.) + * + * If we're allowing new zones, we need to be able to find the + * new zone file and count those as well. So we setup the new + * zone configuration context, but otherwise view configuration + * waits until after the zone manager's task list has been sized. + */ + for (element = cfg_list_first(views); element != NULL; + element = cfg_list_next(element)) + { + cfg_obj_t *vconfig = cfg_listelt_value(element); + const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options"); + int nzf_num_zones; + + view = NULL; + + CHECK(create_view(vconfig, &viewlist, &view)); + INSIST(view != NULL); + + num_zones += count_zones(voptions); + + CHECK(setup_newzones(view, config, vconfig, conf_parser, + named_g_aclconfctx, &nzf_num_zones)); + num_zones += nzf_num_zones; + + dns_view_detach(&view); + } + + /* + * If there were no explicit views then we do the default + * view here. + */ + if (views == NULL) { + int nzf_num_zones; + + CHECK(create_view(NULL, &viewlist, &view)); + INSIST(view != NULL); + + num_zones = count_zones(config); + + CHECK(setup_newzones(view, config, NULL, conf_parser, + named_g_aclconfctx, &nzf_num_zones)); + num_zones += nzf_num_zones; + + dns_view_detach(&view); + } + + /* + * Zones have been counted; set the zone manager task pool size. + */ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "sizing zone task pool based on %d zones", num_zones); + CHECK(dns_zonemgr_setsize(named_g_server->zonemgr, num_zones)); + + /* + * Configure and freeze all explicit views. Explicit + * views that have zones were already created at parsing + * time, but views with no zones must be created here. + */ + for (element = cfg_list_first(views); element != NULL; + element = cfg_list_next(element)) + { + cfg_obj_t *vconfig = cfg_listelt_value(element); + + view = NULL; + CHECK(find_view(vconfig, &viewlist, &view)); + CHECK(configure_view(view, &viewlist, config, vconfig, + &cachelist, &server->kasplist, bindkeys, + named_g_mctx, named_g_aclconfctx, true)); + dns_view_freeze(view); + dns_view_detach(&view); + } + + /* + * Make sure we have a default view if and only if there + * were no explicit views. + */ + if (views == NULL) { + view = NULL; + CHECK(find_view(NULL, &viewlist, &view)); + CHECK(configure_view(view, &viewlist, config, NULL, &cachelist, + &server->kasplist, bindkeys, named_g_mctx, + named_g_aclconfctx, true)); + dns_view_freeze(view); + dns_view_detach(&view); + } + + /* + * Create (or recreate) the built-in views. + */ + builtin_views = NULL; + RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) == + ISC_R_SUCCESS); + for (element = cfg_list_first(builtin_views); element != NULL; + element = cfg_list_next(element)) + { + cfg_obj_t *vconfig = cfg_listelt_value(element); + + CHECK(create_view(vconfig, &builtin_viewlist, &view)); + CHECK(configure_view(view, &viewlist, config, vconfig, + &cachelist, &server->kasplist, bindkeys, + named_g_mctx, named_g_aclconfctx, false)); + dns_view_freeze(view); + dns_view_detach(&view); + view = NULL; + } + + /* Now combine the two viewlists into one */ + ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link); + + /* + * Commit any dns_zone_setview() calls on all zones in the new + * view. + */ + for (view = ISC_LIST_HEAD(viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + dns_view_setviewcommit(view); + } + + /* Swap our new view list with the production one. */ + tmpviewlist = server->viewlist; + server->viewlist = viewlist; + viewlist = tmpviewlist; + + /* Make the view list available to each of the views */ + view = ISC_LIST_HEAD(server->viewlist); + while (view != NULL) { + view->viewlist = &server->viewlist; + view = ISC_LIST_NEXT(view, link); + } + + /* Swap our new cache list with the production one. */ + tmpcachelist = server->cachelist; + server->cachelist = cachelist; + cachelist = tmpcachelist; + + /* Load the TKEY information from the configuration. */ + if (options != NULL) { + dns_tkeyctx_t *t = NULL; + CHECKM(named_tkeyctx_fromconfig(options, named_g_mctx, &t), + "configuring TKEY"); + if (server->sctx->tkeyctx != NULL) { + dns_tkeyctx_destroy(&server->sctx->tkeyctx); + } + server->sctx->tkeyctx = t; + } + + /* + * Bind the control port(s). + */ + CHECKM(named_controls_configure(named_g_server->controls, config, + named_g_aclconfctx), + "binding control channel(s)"); + +#ifdef HAVE_LMDB + /* + * If we're using LMDB, we may have created newzones databases + * as root, making it impossible to reopen them later after + * switching to a new userid. We close them now, and reopen + * after relinquishing privileges them. + */ + if (first_time) { + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + nzd_env_close(view); + } + } +#endif /* HAVE_LMDB */ + + /* + * Relinquish root privileges. + */ + if (first_time) { + named_os_changeuser(); + } + + /* + * Check that the working directory is writable. + */ + if (!isc_file_isdirwritable(".")) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "the working directory is not writable"); + result = ISC_R_NOPERM; + goto cleanup; + } + +#ifdef HAVE_LMDB + /* + * Reopen NZD databases. + */ + if (first_time) { + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + nzd_env_reopen(view); + } + } +#endif /* HAVE_LMDB */ + + /* + * Configure the logging system. + * + * Do this after changing UID to make sure that any log + * files specified in named.conf get created by the + * unprivileged user, not root. + */ + if (named_g_logstderr) { + const cfg_obj_t *logobj = NULL; + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "not using config file logging " + "statement for logging due to " + "-g option"); + + (void)cfg_map_get(config, "logging", &logobj); + if (logobj != NULL) { + result = named_logconfig(NULL, logobj); + if (result != ISC_R_SUCCESS) { + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "checking logging configuration " + "failed: %s", + isc_result_totext(result)); + goto cleanup; + } + } + } else { + const cfg_obj_t *logobj = NULL; + + isc_logconfig_create(named_g_lctx, &logc); + + logobj = NULL; + (void)cfg_map_get(config, "logging", &logobj); + if (logobj != NULL) { + CHECKM(named_logconfig(logc, logobj), + "configuring logging"); + } else { + named_log_setdefaultchannels(logc); + CHECKM(named_log_setunmatchedcategory(logc), + "setting up default 'category unmatched'"); + CHECKM(named_log_setdefaultcategory(logc), + "setting up default 'category default'"); + } + + isc_logconfig_use(named_g_lctx, logc); + logc = NULL; + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), + "now using logging configuration from " + "config file"); + } + + /* + * Set the default value of the query logging flag depending + * whether a "queries" category has been defined. This is + * a disgusting hack, but we need to do this for BIND 8 + * compatibility. + */ + if (first_time) { + const cfg_obj_t *logobj = NULL; + const cfg_obj_t *categories = NULL; + + obj = NULL; + if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) { + ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES, + cfg_obj_asboolean(obj)); + } else { + (void)cfg_map_get(config, "logging", &logobj); + if (logobj != NULL) { + (void)cfg_map_get(logobj, "category", + &categories); + } + if (categories != NULL) { + for (element = cfg_list_first(categories); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *catobj; + const char *str; + + obj = cfg_listelt_value(element); + catobj = cfg_tuple_get(obj, "name"); + str = cfg_obj_asstring(catobj); + if (strcasecmp(str, "queries") == 0) { + ns_server_setoption( + server->sctx, + NS_SERVER_LOGQUERIES, + true); + } + } + } + } + } + + obj = NULL; + if (options != NULL && + cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS) + { + named_g_memstatistics = cfg_obj_asboolean(obj); + } else { + named_g_memstatistics = + ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0); + } + + obj = NULL; + if (named_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS) + { + named_main_setmemstats(cfg_obj_asstring(obj)); + } else if (named_g_memstatistics) { + named_main_setmemstats("named.memstats"); + } else { + named_main_setmemstats(NULL); + } + + obj = NULL; + result = named_config_get(maps, "statistics-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)), + "strdup"); + + obj = NULL; + result = named_config_get(maps, "dump-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)), + "strdup"); + + obj = NULL; + result = named_config_get(maps, "secroots-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)), + "strdup"); + + obj = NULL; + result = named_config_get(maps, "recursing-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)), + "strdup"); + + obj = NULL; + result = named_config_get(maps, "version", &obj); + if (result == ISC_R_SUCCESS) { + CHECKM(setoptstring(server, &server->version, obj), "strdup"); + server->version_set = true; + } else { + server->version_set = false; + } + + obj = NULL; + result = named_config_get(maps, "hostname", &obj); + if (result == ISC_R_SUCCESS) { + CHECKM(setoptstring(server, &server->hostname, obj), "strdup"); + server->hostname_set = true; + } else { + server->hostname_set = false; + } + + obj = NULL; + result = named_config_get(maps, "server-id", &obj); + server->sctx->gethostname = NULL; + if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { + /* The parser translates "hostname" to true */ + server->sctx->gethostname = named_os_gethostname; + result = ns_server_setserverid(server->sctx, NULL); + } else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) { + /* Found a quoted string */ + result = ns_server_setserverid(server->sctx, + cfg_obj_asstring(obj)); + } else { + result = ns_server_setserverid(server->sctx, NULL); + } + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + obj = NULL; + result = named_config_get(maps, "flush-zones-on-shutdown", &obj); + if (result == ISC_R_SUCCESS) { + server->flushonshutdown = cfg_obj_asboolean(obj); + } else { + server->flushonshutdown = false; + } + + obj = NULL; + result = named_config_get(maps, "answer-cookie", &obj); + INSIST(result == ISC_R_SUCCESS); + server->sctx->answercookie = cfg_obj_asboolean(obj); + + obj = NULL; + result = named_config_get(maps, "cookie-algorithm", &obj); + INSIST(result == ISC_R_SUCCESS); + if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) { + server->sctx->cookiealg = ns_cookiealg_siphash24; + } else if (strcasecmp(cfg_obj_asstring(obj), "aes") == 0) { + server->sctx->cookiealg = ns_cookiealg_aes; + } else { + UNREACHABLE(); + } + + obj = NULL; + result = named_config_get(maps, "cookie-secret", &obj); + if (result == ISC_R_SUCCESS) { + const char *str; + bool first = true; + isc_buffer_t b; + unsigned int usedlength; + unsigned int expectedlength; + + for (element = cfg_list_first(obj); element != NULL; + element = cfg_list_next(element)) + { + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(obj); + + if (first) { + memset(server->sctx->secret, 0, + sizeof(server->sctx->secret)); + isc_buffer_init(&b, server->sctx->secret, + sizeof(server->sctx->secret)); + result = isc_hex_decodestring(str, &b); + if (result != ISC_R_SUCCESS && + result != ISC_R_NOSPACE) + { + goto cleanup; + } + first = false; + } else { + altsecret = isc_mem_get(server->sctx->mctx, + sizeof(*altsecret)); + isc_buffer_init(&b, altsecret->secret, + sizeof(altsecret->secret)); + result = isc_hex_decodestring(str, &b); + if (result != ISC_R_SUCCESS && + result != ISC_R_NOSPACE) + { + isc_mem_put(server->sctx->mctx, + altsecret, + sizeof(*altsecret)); + goto cleanup; + } + ISC_LIST_INITANDAPPEND(altsecrets, altsecret, + link); + } + + usedlength = isc_buffer_usedlength(&b); + switch (server->sctx->cookiealg) { + case ns_cookiealg_siphash24: + expectedlength = ISC_SIPHASH24_KEY_LENGTH; + if (usedlength != expectedlength) { + CHECKM(ISC_R_RANGE, "SipHash-2-4 " + "cookie-secret " + "must be 128 bits"); + } + break; + case ns_cookiealg_aes: + expectedlength = ISC_AES128_KEYLENGTH; + if (usedlength != expectedlength) { + CHECKM(ISC_R_RANGE, "AES cookie-secret " + "must be 128 bits"); + } + break; + } + } + } else { + isc_nonce_buf(server->sctx->secret, + sizeof(server->sctx->secret)); + } + + /* + * Swap altsecrets lists. + */ + tmpaltsecrets = server->sctx->altsecrets; + server->sctx->altsecrets = altsecrets; + altsecrets = tmpaltsecrets; + + (void)named_server_loadnta(server); + +#ifdef USE_DNSRPS + /* + * Start and connect to the DNS Response Policy Service + * daemon, dnsrpzd, for each view that uses DNSRPS. + */ + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + result = dns_dnsrps_connect(view->rpzs); + if (result != ISC_R_SUCCESS) { + view = NULL; + goto cleanup; + } + } +#endif /* ifdef USE_DNSRPS */ + + result = ISC_R_SUCCESS; + +cleanup: + if (logc != NULL) { + isc_logconfig_destroy(&logc); + } + + if (v4portset != NULL) { + isc_portset_destroy(named_g_mctx, &v4portset); + } + + if (v6portset != NULL) { + isc_portset_destroy(named_g_mctx, &v6portset); + } + + if (conf_parser != NULL) { + if (config != NULL) { + cfg_obj_destroy(conf_parser, &config); + } + cfg_parser_destroy(&conf_parser); + } + + if (bindkeys_parser != NULL) { + if (bindkeys != NULL) { + cfg_obj_destroy(bindkeys_parser, &bindkeys); + } + cfg_parser_destroy(&bindkeys_parser); + } + + if (view != NULL) { + dns_view_detach(&view); + } + + if (kasp != NULL) { + dns_kasp_detach(&kasp); + } + + ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link); + + /* + * This cleans up either the old production view list + * or our temporary list depending on whether they + * were swapped above or not. + */ + for (view = ISC_LIST_HEAD(viewlist); view != NULL; view = view_next) { + view_next = ISC_LIST_NEXT(view, link); + ISC_LIST_UNLINK(viewlist, view, link); + if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) + { + dns_view_setviewrevert(view); + (void)dns_zt_apply(view->zonetable, isc_rwlocktype_read, + false, NULL, removed, view); + } + dns_view_detach(&view); + } + + /* + * Same cleanup for kasp list. + */ + for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) { + kasp_next = ISC_LIST_NEXT(kasp, link); + ISC_LIST_UNLINK(kasplist, kasp, link); + dns_kasp_detach(&kasp); + } + + /* Same cleanup for cache list. */ + while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) { + ISC_LIST_UNLINK(cachelist, nsc, link); + dns_cache_detach(&nsc->cache); + isc_mem_put(server->mctx, nsc, sizeof(*nsc)); + } + + /* Cleanup for altsecrets list. */ + while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) { + ISC_LIST_UNLINK(altsecrets, altsecret, link); + isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret)); + } + + /* + * Record the time of most recent configuration + */ + tresult = isc_time_now(&named_g_configtime); + if (tresult != ISC_R_SUCCESS) { + named_main_earlyfatal("isc_time_now() failed: %s", + isc_result_totext(result)); + } + + /* Relinquish exclusive access to configuration data. */ + if (exclusive) { + isc_task_endexclusive(server->task); + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), + "load_configuration: %s", isc_result_totext(result)); + + return (result); +} + +static isc_result_t +view_loaded(void *arg) { + isc_result_t result; + ns_zoneload_t *zl = (ns_zoneload_t *)arg; + + /* + * Force zone maintenance. Do this after loading + * so that we know when we need to force AXFR of + * slave zones whose master files are missing. + * + * We use the zoneload reference counter to let us + * know when all views are finished. + */ + if (isc_refcount_decrement(&zl->refs) == 1) { + named_server_t *server = zl->server; + bool reconfig = zl->reconfig; + dns_view_t *view = NULL; + + isc_refcount_destroy(&zl->refs); + isc_mem_put(server->mctx, zl, sizeof(*zl)); + + /* + * To maintain compatibility with log parsing tools that might + * be looking for this string after "rndc reconfig", we keep it + * as it is + */ + if (reconfig) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "any newly configured zones are now " + "loaded"); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE, + "all zones loaded"); + } + + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (view->managed_keys != NULL) { + result = dns_zone_synckeyzone( + view->managed_keys); + if (result != ISC_R_SUCCESS) { + isc_log_write( + named_g_lctx, + DNS_LOGCATEGORY_DNSSEC, + DNS_LOGMODULE_DNSSEC, + ISC_LOG_ERROR, + "failed to initialize " + "managed-keys for view %s " + "(%s): DNSSEC validation is " + "at risk", + view->name, + isc_result_totext(result)); + } + } + } + + CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr), + "forcing zone maintenance"); + + named_os_started(); + +#ifdef HAVE_FIPS_MODE + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE, + "FIPS mode is %s", + FIPS_mode() ? "enabled" : "disabled"); +#endif /* ifdef HAVE_FIPS_MODE */ + atomic_store(&server->reload_status, NAMED_RELOAD_DONE); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE, + "running"); + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +load_zones(named_server_t *server, bool init, bool reconfig) { + isc_result_t result; + isc_taskmgr_t *taskmgr = dns_zonemgr_gettaskmgr(server->zonemgr); + dns_view_t *view = NULL; + ns_zoneload_t *zl = NULL; + + zl = isc_mem_get(server->mctx, sizeof(*zl)); + zl->server = server; + zl->reconfig = reconfig; + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + isc_refcount_init(&zl->refs, 1); + + /* + * Schedule zones to be loaded from disk. + */ + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (view->managed_keys != NULL) { + result = dns_zone_load(view->managed_keys, false); + if (result != ISC_R_SUCCESS && + result != DNS_R_UPTODATE && + result != DNS_R_CONTINUE) + { + goto cleanup; + } + } + if (view->redirect != NULL) { + result = dns_zone_load(view->redirect, false); + if (result != ISC_R_SUCCESS && + result != DNS_R_UPTODATE && + result != DNS_R_CONTINUE) + { + goto cleanup; + } + } + + /* + * 'dns_view_asyncload' calls view_loaded if there are no + * zones. + */ + isc_refcount_increment(&zl->refs); + result = dns_view_asyncload(view, reconfig, view_loaded, zl); + if (result != ISC_R_SUCCESS) { + isc_refcount_decrement1(&zl->refs); + goto cleanup; + } + } + +cleanup: + if (isc_refcount_decrement(&zl->refs) == 1) { + isc_refcount_destroy(&zl->refs); + isc_mem_put(server->mctx, zl, sizeof(*zl)); + } + + if (init) { + /* + * If we're setting up the server for the first time, set + * the task manager into privileged mode; this ensures + * that no other tasks will begin to run until after zone + * loading is complete. We won't return from exclusive mode + * until the loading is finished; we can then drop out of + * privileged mode. + * + * We do *not* want to do this in the case of reload or + * reconfig, as loading a large zone could cause the server + * to be inactive for too long a time. + */ + isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged); + isc_task_endexclusive(server->task); + isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal); + } else { + isc_task_endexclusive(server->task); + } + + return (result); +} + +static void +run_server(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + named_server_t *server = (named_server_t *)event->ev_arg; + dns_geoip_databases_t *geoip; + + INSIST(task == server->task); + + isc_event_free(&event); + + CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, &named_g_dispatchmgr), + "creating dispatch manager"); + + dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats); + +#if defined(HAVE_GEOIP2) + geoip = named_g_geoip; +#else /* if defined(HAVE_GEOIP2) */ + geoip = NULL; +#endif /* if defined(HAVE_GEOIP2) */ + + CHECKFATAL(ns_interfacemgr_create( + named_g_mctx, server->sctx, named_g_taskmgr, + named_g_timermgr, named_g_socketmgr, named_g_nm, + named_g_dispatchmgr, server->task, named_g_udpdisp, + geoip, named_g_cpus, &server->interfacemgr), + "creating interface manager"); + + CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive, + NULL, NULL, server->task, + interface_timer_tick, server, + &server->interface_timer), + "creating interface timer"); + + CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive, + NULL, NULL, server->task, + heartbeat_timer_tick, server, + &server->heartbeat_timer), + "creating heartbeat timer"); + + CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive, + NULL, NULL, server->task, tat_timer_tick, + server, &server->tat_timer), + "creating trust anchor telemetry timer"); + + CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive, + NULL, NULL, server->task, pps_timer_tick, + server, &server->pps_timer), + "creating pps timer"); + + CHECKFATAL( + cfg_parser_create(named_g_mctx, named_g_lctx, &named_g_parser), + "creating default configuration parser"); + + CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx, + &named_g_addparser), + "creating additional configuration parser"); + + CHECKFATAL(load_configuration(named_g_conffile, server, true), + "loading configuration"); + + CHECKFATAL(load_zones(server, true, false), "loading zones"); +#ifdef ENABLE_AFL + named_g_run_done = true; +#endif /* ifdef ENABLE_AFL */ +} + +void +named_server_flushonshutdown(named_server_t *server, bool flush) { + REQUIRE(NAMED_SERVER_VALID(server)); + + server->flushonshutdown = flush; +} + +static void +shutdown_server(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + dns_view_t *view, *view_next = NULL; + dns_kasp_t *kasp, *kasp_next = NULL; + named_server_t *server = (named_server_t *)event->ev_arg; + bool flush = server->flushonshutdown; + named_cache_t *nsc; + + UNUSED(task); + INSIST(task == server->task); + + /* + * We need to shutdown the interface before going + * exclusive (which would pause the netmgr). + */ + ns_interfacemgr_shutdown(server->interfacemgr); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "shutting down%s", + flush ? ": flushing changes" : ""); + + named_statschannels_shutdown(server); + named_controls_shutdown(server->controls); + end_reserved_dispatches(server, true); + cleanup_session_key(server, server->mctx); + + if (named_g_aclconfctx != NULL) { + cfg_aclconfctx_detach(&named_g_aclconfctx); + } + + cfg_obj_destroy(named_g_parser, &named_g_config); + cfg_parser_destroy(&named_g_parser); + cfg_parser_destroy(&named_g_addparser); + + (void)named_server_saventa(server); + + for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL; + kasp = kasp_next) + { + kasp_next = ISC_LIST_NEXT(kasp, link); + ISC_LIST_UNLINK(server->kasplist, kasp, link); + dns_kasp_detach(&kasp); + } + + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = view_next) + { + view_next = ISC_LIST_NEXT(view, link); + ISC_LIST_UNLINK(server->viewlist, view, link); + if (flush) { + dns_view_flushanddetach(&view); + } else { + dns_view_detach(&view); + } + } + + /* + * Shut down all dyndb instances. + */ + dns_dyndb_cleanup(true); + + while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { + ISC_LIST_UNLINK(server->cachelist, nsc, link); + dns_cache_detach(&nsc->cache); + isc_mem_put(server->mctx, nsc, sizeof(*nsc)); + } + + isc_timer_destroy(&server->interface_timer); + isc_timer_destroy(&server->heartbeat_timer); + isc_timer_destroy(&server->pps_timer); + isc_timer_destroy(&server->tat_timer); + + ns_interfacemgr_detach(&server->interfacemgr); + + dns_dispatchmgr_destroy(&named_g_dispatchmgr); + + dns_zonemgr_shutdown(server->zonemgr); + + if (named_g_sessionkey != NULL) { + dns_tsigkey_detach(&named_g_sessionkey); + dns_name_free(&named_g_sessionkeyname, server->mctx); + } +#if defined(HAVE_GEOIP2) + named_geoip_shutdown(); +#endif /* HAVE_GEOIP2 */ + + dns_db_detach(&server->in_roothints); + + isc_task_endexclusive(server->task); + + isc_task_detach(&server->task); + + isc_event_free(&event); +} + +/*% + * Find a view that matches the source and destination addresses of a query. + */ +static isc_result_t +get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr, + dns_message_t *message, dns_aclenv_t *env, + isc_result_t *sigresult, dns_view_t **viewp) { + dns_view_t *view; + + REQUIRE(message != NULL); + REQUIRE(sigresult != NULL); + REQUIRE(viewp != NULL && *viewp == NULL); + + for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (message->rdclass == view->rdclass || + message->rdclass == dns_rdataclass_any) + { + const dns_name_t *tsig = NULL; + + *sigresult = dns_message_rechecksig(message, view); + if (*sigresult == ISC_R_SUCCESS) { + dns_tsigkey_t *tsigkey; + + tsigkey = message->tsigkey; + tsig = dns_tsigkey_identity(tsigkey); + } + + if (dns_acl_allowed(srcaddr, tsig, view->matchclients, + env) && + dns_acl_allowed(destaddr, tsig, + view->matchdestinations, env) && + !(view->matchrecursiveonly && + (message->flags & DNS_MESSAGEFLAG_RD) == 0)) + { + dns_view_attach(view, viewp); + return (ISC_R_SUCCESS); + } + } + } + + return (ISC_R_NOTFOUND); +} + +void +named_server_create(isc_mem_t *mctx, named_server_t **serverp) { + isc_result_t result; + named_server_t *server = isc_mem_get(mctx, sizeof(*server)); + + *server = (named_server_t){ + .mctx = mctx, + .statsfile = isc_mem_strdup(mctx, "named.stats"), + .bindkeysfile = isc_mem_strdup(mctx, named_g_defaultbindkeys), + .dumpfile = isc_mem_strdup(mctx, "named_dump.db"), + .secrootsfile = isc_mem_strdup(mctx, "named.secroots"), + .recfile = isc_mem_strdup(mctx, "named.recursing"), + }; + +#ifdef USE_DNSRPS + CHECKFATAL(dns_dnsrps_server_create(), "initializing RPZ service " + "interface"); +#endif /* ifdef USE_DNSRPS */ + + /* Initialize server data structures. */ + ISC_LIST_INIT(server->kasplist); + ISC_LIST_INIT(server->viewlist); + + /* Must be first. */ + CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine), "initializing " + "DST"); + + CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL, + &server->in_roothints), + "setting up root hints"); + + isc_mutex_init(&server->reload_event_lock); + + server->reload_event = isc_event_allocate( + named_g_mctx, server, NAMED_EVENT_RELOAD, named_server_reload, + server, sizeof(isc_event_t)); + CHECKFATAL(server->reload_event == NULL ? ISC_R_NOMEMORY + : ISC_R_SUCCESS, + "allocating reload event"); + atomic_init(&server->reload_status, NAMED_RELOAD_IN_PROGRESS); + + /* + * Setup the server task, which is responsible for coordinating + * startup and shutdown of the server, as well as all exclusive + * tasks. + */ + CHECKFATAL(isc_task_create_bound(named_g_taskmgr, 0, &server->task, 0), + "creating server task"); + isc_task_setname(server->task, "server", server); + isc_taskmgr_setexcltask(named_g_taskmgr, server->task); + + CHECKFATAL(ns_server_create(mctx, get_matching_view, &server->sctx), + "creating server context"); + +#if defined(HAVE_GEOIP2) + /* + * GeoIP must be initialized before the interface + * manager (which includes the ACL environment) + * is created. + */ + named_geoip_init(); +#endif /* HAVE_GEOIP2 */ + +#ifdef ENABLE_AFL + server->sctx->fuzztype = named_g_fuzz_type; + server->sctx->fuzznotify = named_fuzz_notify; +#endif /* ifdef ENABLE_AFL */ + + CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server), + "isc_task_onshutdown"); + CHECKFATAL( + isc_app_onrun(named_g_mctx, server->task, run_server, server), + "isc_app_onrun"); + + CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr, + named_g_timermgr, named_g_socketmgr, + &server->zonemgr), + "dns_zonemgr_create"); + CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_" + "setsize"); + + CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats, + isc_sockstatscounter_max), + "isc_stats_create"); + isc_socketmgr_setstats(named_g_socketmgr, server->sockstats); + isc_nm_setstats(named_g_nm, server->sockstats); + + CHECKFATAL(isc_stats_create(named_g_mctx, &server->zonestats, + dns_zonestatscounter_max), + "dns_stats_create (zone)"); + + CHECKFATAL(isc_stats_create(named_g_mctx, &server->resolverstats, + dns_resstatscounter_max), + "dns_stats_create (resolver)"); + + CHECKFATAL(named_controls_create(server, &server->controls), + "named_controls_create"); + + ISC_LIST_INIT(server->dispatches); + + ISC_LIST_INIT(server->statschannels); + + ISC_LIST_INIT(server->cachelist); + + server->magic = NAMED_SERVER_MAGIC; + *serverp = server; +} + +void +named_server_destroy(named_server_t **serverp) { + named_server_t *server = *serverp; + REQUIRE(NAMED_SERVER_VALID(server)); + +#ifdef HAVE_DNSTAP + if (server->dtenv != NULL) { + dns_dt_detach(&server->dtenv); + } +#endif /* HAVE_DNSTAP */ + +#ifdef USE_DNSRPS + dns_dnsrps_server_destroy(); +#endif /* ifdef USE_DNSRPS */ + + named_controls_destroy(&server->controls); + + isc_stats_detach(&server->zonestats); + isc_stats_detach(&server->sockstats); + isc_stats_detach(&server->resolverstats); + + if (server->sctx != NULL) { + ns_server_detach(&server->sctx); + } + + isc_mem_free(server->mctx, server->statsfile); + isc_mem_free(server->mctx, server->bindkeysfile); + isc_mem_free(server->mctx, server->dumpfile); + isc_mem_free(server->mctx, server->secrootsfile); + isc_mem_free(server->mctx, server->recfile); + + if (server->version != NULL) { + isc_mem_free(server->mctx, server->version); + } + if (server->hostname != NULL) { + isc_mem_free(server->mctx, server->hostname); + } + if (server->lockfile != NULL) { + isc_mem_free(server->mctx, server->lockfile); + } + + if (server->zonemgr != NULL) { + dns_zonemgr_detach(&server->zonemgr); + } + + dst_lib_destroy(); + + isc_event_free(&server->reload_event); + isc_mutex_destroy(&server->reload_event_lock); + + INSIST(ISC_LIST_EMPTY(server->kasplist)); + INSIST(ISC_LIST_EMPTY(server->viewlist)); + INSIST(ISC_LIST_EMPTY(server->cachelist)); + + server->magic = 0; + isc_mem_put(server->mctx, server, sizeof(*server)); + *serverp = NULL; +} + +static void +fatal(named_server_t *server, const char *msg, isc_result_t result) { + if (server != NULL && server->task != NULL) { + /* + * Prevent races between the OpenSSL on_exit registered + * function and any other OpenSSL calls from other tasks + * by requesting exclusive access to the task manager. + */ + (void)isc_task_beginexclusive(server->task); + } + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, "%s: %s", msg, + isc_result_totext(result)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, + "exiting (due to fatal error)"); + named_os_shutdown(); + exit(1); +} + +static void +start_reserved_dispatches(named_server_t *server) { + REQUIRE(NAMED_SERVER_VALID(server)); + + server->dispatchgen++; +} + +static void +end_reserved_dispatches(named_server_t *server, bool all) { + named_dispatch_t *dispatch, *nextdispatch; + + REQUIRE(NAMED_SERVER_VALID(server)); + + for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL; + dispatch = nextdispatch) + { + nextdispatch = ISC_LIST_NEXT(dispatch, link); + if (!all && server->dispatchgen == dispatch->dispatchgen) { + continue; + } + ISC_LIST_UNLINK(server->dispatches, dispatch, link); + dns_dispatch_detach(&dispatch->dispatch); + isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); + } +} + +void +named_add_reserved_dispatch(named_server_t *server, + const isc_sockaddr_t *addr) { + named_dispatch_t *dispatch; + in_port_t port; + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + isc_result_t result; + unsigned int attrs, attrmask; + + REQUIRE(NAMED_SERVER_VALID(server)); + + port = isc_sockaddr_getport(addr); + if (port == 0 || port >= 1024) { + return; + } + + for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL; + dispatch = ISC_LIST_NEXT(dispatch, link)) + { + if (isc_sockaddr_equal(&dispatch->addr, addr)) { + break; + } + } + if (dispatch != NULL) { + dispatch->dispatchgen = server->dispatchgen; + return; + } + + dispatch = isc_mem_get(server->mctx, sizeof(*dispatch)); + + dispatch->addr = *addr; + dispatch->dispatchgen = server->dispatchgen; + dispatch->dispatch = NULL; + + attrs = 0; + attrs |= DNS_DISPATCHATTR_UDP; + switch (isc_sockaddr_pf(addr)) { + case AF_INET: + attrs |= DNS_DISPATCHATTR_IPV4; + break; + case AF_INET6: + attrs |= DNS_DISPATCHATTR_IPV6; + break; + default: + result = ISC_R_NOTIMPLEMENTED; + goto cleanup; + } + attrmask = 0; + attrmask |= DNS_DISPATCHATTR_UDP; + attrmask |= DNS_DISPATCHATTR_TCP; + attrmask |= DNS_DISPATCHATTR_IPV4; + attrmask |= DNS_DISPATCHATTR_IPV6; + + result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr, + named_g_taskmgr, &dispatch->addr, 4096, + UDPBUFFERS, 32768, 16411, 16433, attrs, + attrmask, &dispatch->dispatch); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link); + + return; + +cleanup: + isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); + isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "unable to create dispatch for reserved port %s: %s", + addrbuf, isc_result_totext(result)); +} + +static isc_result_t +loadconfig(named_server_t *server) { + isc_result_t result; + start_reserved_dispatches(server); + result = load_configuration(named_g_conffile, server, false); + if (result == ISC_R_SUCCESS) { + end_reserved_dispatches(server, false); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "reloading configuration succeeded"); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "reloading configuration failed: %s", + isc_result_totext(result)); + atomic_store(&server->reload_status, NAMED_RELOAD_FAILED); + } + + return (result); +} + +static isc_result_t +reload(named_server_t *server) { + isc_result_t result; + + atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS); + + CHECK(loadconfig(server)); + + result = load_zones(server, false, false); + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "reloading zones succeeded"); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "reloading zones failed: %s", + isc_result_totext(result)); + atomic_store(&server->reload_status, NAMED_RELOAD_FAILED); + } +cleanup: + return (result); +} + +/* + * Handle a reload event (from SIGHUP). + */ +static void +named_server_reload(isc_task_t *task, isc_event_t *event) { + named_server_t *server = (named_server_t *)event->ev_arg; + + INSIST(task == server->task); + UNUSED(task); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "received SIGHUP signal to reload zones"); + (void)reload(server); + + LOCK(&server->reload_event_lock); + INSIST(server->reload_event == NULL); + server->reload_event = event; + UNLOCK(&server->reload_event_lock); +} + +void +named_server_reloadwanted(named_server_t *server) { + LOCK(&server->reload_event_lock); + if (server->reload_event != NULL) { + isc_task_send(server->task, &server->reload_event); + } + UNLOCK(&server->reload_event_lock); +} + +void +named_server_scan_interfaces(named_server_t *server) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), + "automatic interface rescan"); + + ns_interfacemgr_scan(server->interfacemgr, true); +} + +/* + * Get the next token from lexer 'lex'. + * + * NOTE: the token value for string tokens always uses the same pointer + * value. Multiple calls to this function on the same lexer will always + * return either that value (lex->data) or NULL. It is necessary to copy + * the token into local storage if it needs to be referenced after the next + * call to next_token(). + */ +static char * +next_token(isc_lex_t *lex, isc_buffer_t **text) { + isc_result_t result; + isc_token_t token; + + token.type = isc_tokentype_unknown; + result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING, + &token); + + switch (result) { + case ISC_R_NOMORE: + (void)isc_lex_close(lex); + break; + case ISC_R_SUCCESS: + if (token.type == isc_tokentype_eof) { + (void)isc_lex_close(lex); + } + break; + case ISC_R_NOSPACE: + if (text != NULL) { + (void)putstr(text, "token too large"); + (void)putnull(text); + } + return (NULL); + default: + if (text != NULL) { + (void)putstr(text, isc_result_totext(result)); + (void)putnull(text); + } + return (NULL); + } + + if (token.type == isc_tokentype_string || + token.type == isc_tokentype_qstring) + { + return (token.value.as_textregion.base); + } + + return (NULL); +} + +/* + * Find the zone specified in the control channel command, if any. + * If a zone is specified, point '*zonep' at it, otherwise + * set '*zonep' to NULL, and f 'zonename' is not NULL, copy + * the zone name into it (N.B. 'zonename' must have space to hold + * a full DNS name). + * + * If 'zonetxt' is set, the caller has already pulled a token + * off the command line that is to be used as the zone name. (This + * is sometimes done when it's necessary to check for an optional + * argument before the zone name, as in "rndc sync [-clean] zone".) + */ +static isc_result_t +zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt, + dns_zone_t **zonep, char *zonename, isc_buffer_t **text, + bool skip) { + char *ptr; + char *classtxt; + const char *viewtxt = NULL; + dns_fixedname_t fname; + dns_name_t *name; + isc_result_t result; + dns_view_t *view = NULL; + dns_rdataclass_t rdclass; + char problem[DNS_NAME_FORMATSIZE + 500] = ""; + char zonebuf[DNS_NAME_FORMATSIZE]; + bool redirect = false; + + REQUIRE(zonep != NULL && *zonep == NULL); + + if (skip) { + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + } + + /* Look for the zone name. */ + if (zonetxt == NULL) { + zonetxt = next_token(lex, text); + } + if (zonetxt == NULL) { + return (ISC_R_SUCCESS); + } + + /* Copy zonetxt because it'll be overwritten by next_token() */ + /* To locate a zone named "-redirect" use "-redirect." */ + if (strcmp(zonetxt, "-redirect") == 0) { + redirect = true; + strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE); + } else { + strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE); + } + if (zonename != NULL) { + strlcpy(zonename, redirect ? "." : zonetxt, + DNS_NAME_FORMATSIZE); + } + + name = dns_fixedname_initname(&fname); + CHECK(dns_name_fromstring(name, zonebuf, 0, NULL)); + + /* Look for the optional class name. */ + classtxt = next_token(lex, text); + if (classtxt != NULL) { + isc_textregion_t r; + r.base = classtxt; + r.length = strlen(classtxt); + CHECK(dns_rdataclass_fromtext(&rdclass, &r)); + + /* Look for the optional view name. */ + viewtxt = next_token(lex, text); + } else { + rdclass = dns_rdataclass_in; + } + + if (viewtxt == NULL) { + if (redirect) { + result = dns_viewlist_find(&server->viewlist, + "_default", + dns_rdataclass_in, &view); + if (result != ISC_R_SUCCESS || view->redirect == NULL) { + result = ISC_R_NOTFOUND; + snprintf(problem, sizeof(problem), + "redirect zone not found in " + "_default view"); + } else { + dns_zone_attach(view->redirect, zonep); + result = ISC_R_SUCCESS; + } + } else { + result = dns_viewlist_findzone(&server->viewlist, name, + (classtxt == NULL), + rdclass, zonep); + if (result == ISC_R_NOTFOUND) { + snprintf(problem, sizeof(problem), + "no matching zone '%s' in any view", + zonebuf); + } else if (result == ISC_R_MULTIPLE) { + snprintf(problem, sizeof(problem), + "zone '%s' was found in multiple " + "views", + zonebuf); + } + } + } else { + result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass, + &view); + if (result != ISC_R_SUCCESS) { + snprintf(problem, sizeof(problem), + "no matching view '%s'", viewtxt); + goto report; + } + + if (redirect) { + if (view->redirect != NULL) { + dns_zone_attach(view->redirect, zonep); + result = ISC_R_SUCCESS; + } else { + result = ISC_R_NOTFOUND; + } + } else { + result = dns_zt_find(view->zonetable, name, 0, NULL, + zonep); + } + if (result != ISC_R_SUCCESS) { + snprintf(problem, sizeof(problem), + "no matching zone '%s' in view '%s'", zonebuf, + viewtxt); + } + } + + /* Partial match? */ + if (result != ISC_R_SUCCESS && *zonep != NULL) { + dns_zone_detach(zonep); + } + if (result == DNS_R_PARTIALMATCH) { + result = ISC_R_NOTFOUND; + } +report: + if (result != ISC_R_SUCCESS) { + isc_result_t tresult; + + tresult = putstr(text, problem); + if (tresult == ISC_R_SUCCESS) { + (void)putnull(text); + } + } + +cleanup: + if (view != NULL) { + dns_view_detach(&view); + } + + return (result); +} + +/* + * Act on a "retransfer" command from the command channel. + */ +isc_result_t +named_server_retransfercommand(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_zone_t *raw = NULL; + dns_zonetype_t type; + + REQUIRE(text != NULL); + + result = zone_from_args(server, lex, NULL, &zone, NULL, text, true); + if (result != ISC_R_SUCCESS) { + return (result); + } + if (zone == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + dns_zone_getraw(zone, &raw); + if (raw != NULL) { + dns_zone_detach(&zone); + dns_zone_attach(raw, &zone); + dns_zone_detach(&raw); + } + type = dns_zone_gettype(zone); + if (type == dns_zone_secondary || type == dns_zone_mirror || + type == dns_zone_stub || + (type == dns_zone_redirect && + dns_zone_getredirecttype(zone) == dns_zone_secondary)) + { + dns_zone_forcereload(zone); + } else { + (void)putstr(text, "retransfer: inappropriate zone type: "); + (void)putstr(text, dns_zonetype_name(type)); + if (type == dns_zone_redirect) { + type = dns_zone_getredirecttype(zone); + (void)putstr(text, "("); + (void)putstr(text, dns_zonetype_name(type)); + (void)putstr(text, ")"); + } + (void)putnull(text); + result = ISC_R_FAILURE; + } + dns_zone_detach(&zone); + return (result); +} + +/* + * Act on a "reload" command from the command channel. + */ +isc_result_t +named_server_reloadcommand(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_zonetype_t type; + const char *msg = NULL; + + REQUIRE(text != NULL); + + result = zone_from_args(server, lex, NULL, &zone, NULL, text, true); + if (result != ISC_R_SUCCESS) { + return (result); + } + if (zone == NULL) { + result = reload(server); + if (result == ISC_R_SUCCESS) { + msg = "server reload successful"; + } + } else { + type = dns_zone_gettype(zone); + if (type == dns_zone_secondary || type == dns_zone_mirror || + type == dns_zone_stub) + { + dns_zone_refresh(zone); + dns_zone_detach(&zone); + msg = "zone refresh queued"; + } else { + result = dns_zone_load(zone, false); + dns_zone_detach(&zone); + switch (result) { + case ISC_R_SUCCESS: + msg = "zone reload successful"; + break; + case DNS_R_CONTINUE: + msg = "zone reload queued"; + result = ISC_R_SUCCESS; + break; + case DNS_R_UPTODATE: + msg = "zone reload up-to-date"; + result = ISC_R_SUCCESS; + break; + default: + /* failure message will be generated by rndc */ + break; + } + } + } + if (msg != NULL) { + (void)putstr(text, msg); + (void)putnull(text); + } + return (result); +} + +/* + * Act on a "reconfig" command from the command channel. + */ +isc_result_t +named_server_reconfigcommand(named_server_t *server) { + isc_result_t result; + atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS); + + CHECK(loadconfig(server)); + + result = load_zones(server, false, true); + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "scheduled loading new zones"); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "loading new zones failed: %s", + isc_result_totext(result)); + atomic_store(&server->reload_status, NAMED_RELOAD_FAILED); + } +cleanup: + return (result); +} + +/* + * Act on a "notify" command from the command channel. + */ +isc_result_t +named_server_notifycommand(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result; + dns_zone_t *zone = NULL; + const char msg[] = "zone notify queued"; + + REQUIRE(text != NULL); + + result = zone_from_args(server, lex, NULL, &zone, NULL, text, true); + if (result != ISC_R_SUCCESS) { + return (result); + } + if (zone == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + dns_zone_notify(zone); + dns_zone_detach(&zone); + (void)putstr(text, msg); + (void)putnull(text); + + return (ISC_R_SUCCESS); +} + +/* + * Act on a "refresh" command from the command channel. + */ +isc_result_t +named_server_refreshcommand(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result; + dns_zone_t *zone = NULL, *raw = NULL; + const char msg1[] = "zone refresh queued"; + const char msg2[] = "not a slave, mirror, or stub zone"; + dns_zonetype_t type; + + REQUIRE(text != NULL); + + result = zone_from_args(server, lex, NULL, &zone, NULL, text, true); + if (result != ISC_R_SUCCESS) { + return (result); + } + if (zone == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + dns_zone_getraw(zone, &raw); + if (raw != NULL) { + dns_zone_detach(&zone); + dns_zone_attach(raw, &zone); + dns_zone_detach(&raw); + } + + type = dns_zone_gettype(zone); + if (type == dns_zone_secondary || type == dns_zone_mirror || + type == dns_zone_stub) + { + dns_zone_refresh(zone); + dns_zone_detach(&zone); + (void)putstr(text, msg1); + (void)putnull(text); + return (ISC_R_SUCCESS); + } + + dns_zone_detach(&zone); + (void)putstr(text, msg2); + (void)putnull(text); + return (ISC_R_FAILURE); +} + +isc_result_t +named_server_togglequerylog(named_server_t *server, isc_lex_t *lex) { + bool prev, value; + char *ptr; + + /* Skip the command name. */ + ptr = next_token(lex, NULL); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + prev = ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES); + + ptr = next_token(lex, NULL); + if (ptr == NULL) { + value = !prev; + } else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || + !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) + { + value = true; + } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || + !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) + { + value = false; + } else { + return (DNS_R_SYNTAX); + } + + if (value == prev) { + return (ISC_R_SUCCESS); + } + + ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES, value); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "query logging is now %s", value ? "on" : "off"); + return (ISC_R_SUCCESS); +} + +static isc_result_t +ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, + uint16_t family, ns_listenlist_t **target) { + isc_result_t result; + const cfg_listelt_t *element; + ns_listenlist_t *dlist = NULL; + + REQUIRE(target != NULL && *target == NULL); + + result = ns_listenlist_create(mctx, &dlist); + if (result != ISC_R_SUCCESS) { + return (result); + } + + for (element = cfg_list_first(listenlist); element != NULL; + element = cfg_list_next(element)) + { + ns_listenelt_t *delt = NULL; + const cfg_obj_t *listener = cfg_listelt_value(element); + result = ns_listenelt_fromconfig(listener, config, actx, mctx, + family, &delt); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + ISC_LIST_APPEND(dlist->elts, delt, link); + } + *target = dlist; + return (ISC_R_SUCCESS); + +cleanup: + ns_listenlist_detach(&dlist); + return (result); +} + +/* + * Create a listen list from the corresponding configuration + * data structure. + */ +static isc_result_t +ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, + uint16_t family, ns_listenelt_t **target) { + isc_result_t result; + const cfg_obj_t *portobj, *dscpobj; + in_port_t port; + isc_dscp_t dscp = -1; + ns_listenelt_t *delt = NULL; + REQUIRE(target != NULL && *target == NULL); + + portobj = cfg_tuple_get(listener, "port"); + if (!cfg_obj_isuint32(portobj)) { + if (named_g_port != 0) { + port = named_g_port; + } else { + result = named_config_getport(config, &port); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + } else { + if (cfg_obj_asuint32(portobj) >= UINT16_MAX) { + cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR, + "port value '%u' is out of range", + cfg_obj_asuint32(portobj)); + return (ISC_R_RANGE); + } + port = (in_port_t)cfg_obj_asuint32(portobj); + } + + dscpobj = cfg_tuple_get(listener, "dscp"); + if (!cfg_obj_isuint32(dscpobj)) { + dscp = named_g_dscp; + } else { + if (cfg_obj_asuint32(dscpobj) > 63) { + cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR, + "dscp value '%u' is out of range", + cfg_obj_asuint32(dscpobj)); + return (ISC_R_RANGE); + } + dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + } + + result = ns_listenelt_create(mctx, port, dscp, NULL, &delt); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"), config, + named_g_lctx, actx, mctx, 0, family, + &delt->acl); + if (result != ISC_R_SUCCESS) { + ns_listenelt_destroy(delt); + return (result); + } + *target = delt; + return (ISC_R_SUCCESS); +} + +isc_result_t +named_server_dumpstats(named_server_t *server) { + isc_result_t result; + FILE *fp = NULL; + + CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), + "could not open statistics dump file", server->statsfile); + + result = named_stats_dump(server, fp); + +cleanup: + if (fp != NULL) { + (void)isc_stdio_close(fp); + } + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumpstats complete"); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumpstats failed: %s", + dns_result_totext(result)); + } + return (result); +} + +static isc_result_t +add_zone_tolist(dns_zone_t *zone, void *uap) { + struct dumpcontext *dctx = uap; + struct zonelistentry *zle; + + zle = isc_mem_get(dctx->mctx, sizeof *zle); + zle->zone = NULL; + dns_zone_attach(zone, &zle->zone); + ISC_LINK_INIT(zle, link); + ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link); + return (ISC_R_SUCCESS); +} + +static isc_result_t +add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) { + struct viewlistentry *vle; + isc_result_t result = ISC_R_SUCCESS; + + /* + * Prevent duplicate views. + */ + for (vle = ISC_LIST_HEAD(dctx->viewlist); vle != NULL; + vle = ISC_LIST_NEXT(vle, link)) + { + if (vle->view == view) { + return (ISC_R_SUCCESS); + } + } + + vle = isc_mem_get(dctx->mctx, sizeof *vle); + vle->view = NULL; + dns_view_attach(view, &vle->view); + ISC_LINK_INIT(vle, link); + ISC_LIST_INIT(vle->zonelist); + ISC_LIST_APPEND(dctx->viewlist, vle, link); + if (dctx->dumpzones) { + result = dns_zt_apply(view->zonetable, isc_rwlocktype_read, + true, NULL, add_zone_tolist, dctx); + } + return (result); +} + +static void +dumpcontext_destroy(struct dumpcontext *dctx) { + struct viewlistentry *vle; + struct zonelistentry *zle; + + vle = ISC_LIST_HEAD(dctx->viewlist); + while (vle != NULL) { + ISC_LIST_UNLINK(dctx->viewlist, vle, link); + zle = ISC_LIST_HEAD(vle->zonelist); + while (zle != NULL) { + ISC_LIST_UNLINK(vle->zonelist, zle, link); + dns_zone_detach(&zle->zone); + isc_mem_put(dctx->mctx, zle, sizeof *zle); + zle = ISC_LIST_HEAD(vle->zonelist); + } + dns_view_detach(&vle->view); + isc_mem_put(dctx->mctx, vle, sizeof *vle); + vle = ISC_LIST_HEAD(dctx->viewlist); + } + if (dctx->version != NULL) { + dns_db_closeversion(dctx->db, &dctx->version, false); + } + if (dctx->db != NULL) { + dns_db_detach(&dctx->db); + } + if (dctx->cache != NULL) { + dns_db_detach(&dctx->cache); + } + if (dctx->task != NULL) { + isc_task_detach(&dctx->task); + } + if (dctx->fp != NULL) { + (void)isc_stdio_close(dctx->fp); + } + if (dctx->mdctx != NULL) { + dns_dumpctx_detach(&dctx->mdctx); + } + isc_mem_put(dctx->mctx, dctx, sizeof *dctx); +} + +static void +dumpdone(void *arg, isc_result_t result) { + struct dumpcontext *dctx = arg; + char buf[1024 + 32]; + const dns_master_style_t *style; + + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + if (dctx->mdctx != NULL) { + dns_dumpctx_detach(&dctx->mdctx); + } + if (dctx->view == NULL) { + dctx->view = ISC_LIST_HEAD(dctx->viewlist); + if (dctx->view == NULL) { + goto done; + } + INSIST(dctx->zone == NULL); + } else { + goto resume; + } +nextview: + fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name); +resume: + if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) { + fprintf(dctx->fp, ";\n; Cache of view '%s' is shared as '%s'\n", + dctx->view->view->name, + dns_cache_getname(dctx->view->view->cache)); + } else if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) + { + if (dctx->dumpexpired) { + style = &dns_master_style_cache_with_expired; + } else { + style = &dns_master_style_cache; + } + /* start cache dump */ + if (dctx->view->view->cachedb != NULL) { + dns_db_attach(dctx->view->view->cachedb, &dctx->cache); + } + if (dctx->cache != NULL) { + fprintf(dctx->fp, + ";\n; Cache dump of view '%s' (cache %s)\n;\n", + dctx->view->view->name, + dns_cache_getname(dctx->view->view->cache)); + result = dns_master_dumptostreamasync( + dctx->mctx, dctx->cache, NULL, style, dctx->fp, + dctx->task, dumpdone, dctx, &dctx->mdctx); + if (result == DNS_R_CONTINUE) { + return; + } + if (result == ISC_R_NOTIMPLEMENTED) { + fprintf(dctx->fp, "; %s\n", + dns_result_totext(result)); + } else if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } + } + + if ((dctx->dumpadb || dctx->dumpbad || dctx->dumpfail) && + dctx->cache == NULL && dctx->view->view->cachedb != NULL) + { + dns_db_attach(dctx->view->view->cachedb, &dctx->cache); + } + + if (dctx->cache != NULL) { + if (dctx->dumpadb) { + dns_adb_dump(dctx->view->view->adb, dctx->fp); + } + if (dctx->dumpbad) { + dns_resolver_printbadcache(dctx->view->view->resolver, + dctx->fp); + } + if (dctx->dumpfail) { + dns_badcache_print(dctx->view->view->failcache, + "SERVFAIL cache", dctx->fp); + } + dns_db_detach(&dctx->cache); + } + if (dctx->dumpzones) { + style = &dns_master_style_full; + nextzone: + if (dctx->version != NULL) { + dns_db_closeversion(dctx->db, &dctx->version, false); + } + if (dctx->db != NULL) { + dns_db_detach(&dctx->db); + } + if (dctx->zone == NULL) { + dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist); + } else { + dctx->zone = ISC_LIST_NEXT(dctx->zone, link); + } + if (dctx->zone != NULL) { + /* start zone dump */ + dns_zone_name(dctx->zone->zone, buf, sizeof(buf)); + fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf); + result = dns_zone_getdb(dctx->zone->zone, &dctx->db); + if (result != ISC_R_SUCCESS) { + fprintf(dctx->fp, "; %s\n", + dns_result_totext(result)); + goto nextzone; + } + dns_db_currentversion(dctx->db, &dctx->version); + result = dns_master_dumptostreamasync( + dctx->mctx, dctx->db, dctx->version, style, + dctx->fp, dctx->task, dumpdone, dctx, + &dctx->mdctx); + if (result == DNS_R_CONTINUE) { + return; + } + if (result == ISC_R_NOTIMPLEMENTED) { + fprintf(dctx->fp, "; %s\n", + dns_result_totext(result)); + result = ISC_R_SUCCESS; + POST(result); + goto nextzone; + } + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } + } + if (dctx->view != NULL) { + dctx->view = ISC_LIST_NEXT(dctx->view, link); + if (dctx->view != NULL) { + goto nextview; + } + } +done: + fprintf(dctx->fp, "; Dump complete\n"); + result = isc_stdio_flush(dctx->fp); + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumpdb complete"); + } +cleanup: + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumpdb failed: %s", dns_result_totext(result)); + } + dumpcontext_destroy(dctx); +} + +isc_result_t +named_server_dumpdb(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + struct dumpcontext *dctx = NULL; + dns_view_t *view; + isc_result_t result; + char *ptr; + const char *sep; + bool found; + + REQUIRE(text != NULL); + + /* Skip the command name. */ + ptr = next_token(lex, NULL); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + dctx = isc_mem_get(server->mctx, sizeof(*dctx)); + + dctx->mctx = server->mctx; + dctx->dumpcache = true; + dctx->dumpadb = true; + dctx->dumpbad = true; + dctx->dumpexpired = false; + dctx->dumpfail = true; + dctx->dumpzones = false; + dctx->fp = NULL; + ISC_LIST_INIT(dctx->viewlist); + dctx->view = NULL; + dctx->zone = NULL; + dctx->cache = NULL; + dctx->mdctx = NULL; + dctx->db = NULL; + dctx->cache = NULL; + dctx->task = NULL; + dctx->version = NULL; + isc_task_attach(server->task, &dctx->task); + + CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp), + "could not open dump file", server->dumpfile); + + ptr = next_token(lex, NULL); + sep = (ptr == NULL) ? "" : ": "; + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : ""); + + if (ptr != NULL && strcmp(ptr, "-all") == 0) { + /* also dump zones */ + dctx->dumpzones = true; + ptr = next_token(lex, NULL); + } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) { + /* this is the default */ + ptr = next_token(lex, NULL); + } else if (ptr != NULL && strcmp(ptr, "-expired") == 0) { + /* this is the same as -cache but includes expired data */ + dctx->dumpexpired = true; + ptr = next_token(lex, NULL); + } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) { + /* only dump zones, suppress caches */ + dctx->dumpadb = false; + dctx->dumpbad = false; + dctx->dumpcache = false; + dctx->dumpfail = false; + dctx->dumpzones = true; + ptr = next_token(lex, NULL); + } else if (ptr != NULL && strcmp(ptr, "-adb") == 0) { + /* only dump adb, suppress other caches */ + dctx->dumpbad = false; + dctx->dumpcache = false; + dctx->dumpfail = false; + ptr = next_token(lex, NULL); + } else if (ptr != NULL && strcmp(ptr, "-bad") == 0) { + /* only dump badcache, suppress other caches */ + dctx->dumpadb = false; + dctx->dumpcache = false; + dctx->dumpfail = false; + ptr = next_token(lex, NULL); + } else if (ptr != NULL && strcmp(ptr, "-fail") == 0) { + /* only dump servfail cache, suppress other caches */ + dctx->dumpadb = false; + dctx->dumpbad = false; + dctx->dumpcache = false; + ptr = next_token(lex, NULL); + } + +nextview: + found = false; + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (ptr != NULL && strcmp(view->name, ptr) != 0) { + continue; + } + found = true; + CHECK(add_view_tolist(dctx, view)); + } + if (ptr != NULL) { + if (!found) { + CHECK(putstr(text, "view '")); + CHECK(putstr(text, ptr)); + CHECK(putstr(text, "' not found")); + CHECK(putnull(text)); + result = ISC_R_NOTFOUND; + dumpdone(dctx, result); + return (result); + } + ptr = next_token(lex, NULL); + if (ptr != NULL) { + goto nextview; + } + } + dumpdone(dctx, ISC_R_SUCCESS); + return (ISC_R_SUCCESS); + +cleanup: + dumpcontext_destroy(dctx); + return (result); +} + +isc_result_t +named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + dns_view_t *view; + dns_keytable_t *secroots = NULL; + dns_ntatable_t *ntatable = NULL; + isc_result_t result; + char *ptr; + FILE *fp = NULL; + isc_time_t now; + char tbuf[64]; + unsigned int used = isc_buffer_usedlength(*text); + bool first = true; + + REQUIRE(text != NULL); + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* "-" here means print the output instead of dumping to file */ + ptr = next_token(lex, text); + if (ptr != NULL && strcmp(ptr, "-") == 0) { + ptr = next_token(lex, text); + } else { + result = isc_stdio_open(server->secrootsfile, "w", &fp); + if (result != ISC_R_SUCCESS) { + (void)putstr(text, "could not open "); + (void)putstr(text, server->secrootsfile); + CHECKMF(result, "could not open secroots dump file", + server->secrootsfile); + } + } + + TIME_NOW(&now); + isc_time_formattimestamp(&now, tbuf, sizeof(tbuf)); + CHECK(putstr(text, "secure roots as of ")); + CHECK(putstr(text, tbuf)); + CHECK(putstr(text, ":\n")); + used = isc_buffer_usedlength(*text); + + do { + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (ptr != NULL && strcmp(view->name, ptr) != 0) { + continue; + } + if (secroots != NULL) { + dns_keytable_detach(&secroots); + } + result = dns_view_getsecroots(view, &secroots); + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + continue; + } + if (first || used != isc_buffer_usedlength(*text)) { + CHECK(putstr(text, "\n")); + first = false; + } + CHECK(putstr(text, " Start view ")); + CHECK(putstr(text, view->name)); + CHECK(putstr(text, "\n Secure roots:\n\n")); + used = isc_buffer_usedlength(*text); + CHECK(dns_keytable_totext(secroots, text)); + + if (ntatable != NULL) { + dns_ntatable_detach(&ntatable); + } + result = dns_view_getntatable(view, &ntatable); + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + continue; + } + if (used != isc_buffer_usedlength(*text)) { + CHECK(putstr(text, "\n")); + } + CHECK(putstr(text, " Negative trust anchors:\n\n")); + used = isc_buffer_usedlength(*text); + CHECK(dns_ntatable_totext(ntatable, NULL, text)); + } + + if (ptr != NULL) { + ptr = next_token(lex, text); + } + } while (ptr != NULL); + +cleanup: + if (secroots != NULL) { + dns_keytable_detach(&secroots); + } + if (ntatable != NULL) { + dns_ntatable_detach(&ntatable); + } + + if (fp != NULL) { + if (used != isc_buffer_usedlength(*text)) { + (void)putstr(text, "\n"); + } + fprintf(fp, "%.*s", (int)isc_buffer_usedlength(*text), + (char *)isc_buffer_base(*text)); + isc_buffer_clear(*text); + (void)isc_stdio_close(fp); + } else if (isc_buffer_usedlength(*text) > 0) { + (void)putnull(text); + } + + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumpsecroots complete"); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumpsecroots failed: %s", + dns_result_totext(result)); + } + return (result); +} + +isc_result_t +named_server_dumprecursing(named_server_t *server) { + FILE *fp = NULL; + dns_view_t *view; + isc_result_t result; + + CHECKMF(isc_stdio_open(server->recfile, "w", &fp), + "could not open dump file", server->recfile); + fprintf(fp, ";\n; Recursing Queries\n;\n"); + ns_interfacemgr_dumprecursing(fp, server->interfacemgr); + + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n", + view->name); + dns_resolver_dumpfetches(view->resolver, isc_statsformat_file, + fp); + } + + fprintf(fp, "; Dump complete\n"); + +cleanup: + if (fp != NULL) { + result = isc_stdio_close(fp); + } + if (result == ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumprecursing complete"); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumprecursing failed: %s", + dns_result_totext(result)); + } + return (result); +} + +isc_result_t +named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) { + char *ptr; + char *endp; + long newlevel; + + UNUSED(server); + + /* Skip the command name. */ + ptr = next_token(lex, NULL); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Look for the new level name. */ + ptr = next_token(lex, NULL); + if (ptr == NULL) { + if (named_g_debuglevel < 99) { + named_g_debuglevel++; + } + } else { + newlevel = strtol(ptr, &endp, 10); + if (*endp != '\0' || newlevel < 0 || newlevel > 99) { + return (ISC_R_RANGE); + } + named_g_debuglevel = (unsigned int)newlevel; + } + isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "debug level is now %u", named_g_debuglevel); + return (ISC_R_SUCCESS); +} + +isc_result_t +named_server_validation(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + char *ptr; + dns_view_t *view; + bool changed = false; + isc_result_t result; + bool enable = true, set = true, first = true; + + REQUIRE(text != NULL); + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Find out what we are to do. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || + !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) + { + enable = true; + } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || + !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) + { + enable = false; + } else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) { + set = false; + } else { + return (DNS_R_SYNTAX); + } + + /* Look for the view name. */ + ptr = next_token(lex, text); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if ((ptr != NULL && strcasecmp(ptr, view->name) != 0) || + strcasecmp("_bind", view->name) == 0) + { + continue; + } + + if (set) { + CHECK(dns_view_flushcache(view, false)); + view->enablevalidation = enable; + changed = true; + } else { + if (!first) { + CHECK(putstr(text, "\n")); + } + CHECK(putstr(text, "DNSSEC validation is ")); + CHECK(putstr(text, view->enablevalidation + ? "enabled" + : "disabled")); + CHECK(putstr(text, " (view ")); + CHECK(putstr(text, view->name)); + CHECK(putstr(text, ")")); + first = false; + } + } + CHECK(putnull(text)); + + if (!set) { + result = ISC_R_SUCCESS; + } else if (changed) { + result = ISC_R_SUCCESS; + } else { + result = ISC_R_FAILURE; + } +cleanup: + isc_task_endexclusive(server->task); + return (result); +} + +isc_result_t +named_server_flushcache(named_server_t *server, isc_lex_t *lex) { + char *ptr; + dns_view_t *view; + bool flushed; + bool found; + isc_result_t result; + named_cache_t *nsc; + + /* Skip the command name. */ + ptr = next_token(lex, NULL); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Look for the view name. */ + ptr = next_token(lex, NULL); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + flushed = true; + found = false; + + /* + * Flushing a cache is tricky when caches are shared by multiple views. + * We first identify which caches should be flushed in the local cache + * list, flush these caches, and then update other views that refer to + * the flushed cache DB. + */ + if (ptr != NULL) { + /* + * Mark caches that need to be flushed. This is an O(#view^2) + * operation in the very worst case, but should be normally + * much more lightweight because only a few (most typically just + * one) views will match. + */ + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (strcasecmp(ptr, view->name) != 0) { + continue; + } + found = true; + for (nsc = ISC_LIST_HEAD(server->cachelist); + nsc != NULL; nsc = ISC_LIST_NEXT(nsc, link)) + { + if (nsc->cache == view->cache) { + break; + } + } + INSIST(nsc != NULL); + nsc->needflush = true; + } + } else { + found = true; + } + + /* Perform flush */ + for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL; + nsc = ISC_LIST_NEXT(nsc, link)) + { + if (ptr != NULL && !nsc->needflush) { + continue; + } + nsc->needflush = true; + result = dns_view_flushcache(nsc->primaryview, false); + if (result != ISC_R_SUCCESS) { + flushed = false; + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing cache in view '%s' failed: %s", + nsc->primaryview->name, + isc_result_totext(result)); + } + } + + /* + * Fix up views that share a flushed cache: let the views update the + * cache DB they're referring to. This could also be an expensive + * operation, but should typically be marginal: the inner loop is only + * necessary for views that share a cache, and if there are many such + * views the number of shared cache should normally be small. + * A worst case is that we have n views and n/2 caches, each shared by + * two views. Then this will be a O(n^2/4) operation. + */ + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (!dns_view_iscacheshared(view)) { + continue; + } + for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL; + nsc = ISC_LIST_NEXT(nsc, link)) + { + if (!nsc->needflush || nsc->cache != view->cache) { + continue; + } + result = dns_view_flushcache(view, true); + if (result != ISC_R_SUCCESS) { + flushed = false; + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "fixing cache in view '%s' " + "failed: %s", + view->name, isc_result_totext(result)); + } + } + } + + /* Cleanup the cache list. */ + for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL; + nsc = ISC_LIST_NEXT(nsc, link)) + { + nsc->needflush = false; + } + + if (flushed && found) { + if (ptr != NULL) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing cache in view '%s' succeeded", + ptr); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing caches in all views succeeded"); + } + result = ISC_R_SUCCESS; + } else { + if (!found) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing cache in view '%s' failed: " + "view not found", + ptr); + result = ISC_R_NOTFOUND; + } else { + result = ISC_R_FAILURE; + } + } + isc_task_endexclusive(server->task); + return (result); +} + +isc_result_t +named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) { + char *ptr, *viewname; + char target[DNS_NAME_FORMATSIZE]; + dns_view_t *view; + bool flushed; + bool found; + isc_result_t result; + isc_buffer_t b; + dns_fixedname_t fixed; + dns_name_t *name; + + /* Skip the command name. */ + ptr = next_token(lex, NULL); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Find the domain name to flush. */ + ptr = next_token(lex, NULL); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + strlcpy(target, ptr, DNS_NAME_FORMATSIZE); + isc_buffer_constinit(&b, target, strlen(target)); + isc_buffer_add(&b, strlen(target)); + name = dns_fixedname_initname(&fixed); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + return (result); + } + + /* Look for the view name. */ + viewname = next_token(lex, NULL); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + flushed = true; + found = false; + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (viewname != NULL && strcasecmp(viewname, view->name) != 0) { + continue; + } + found = true; + /* + * It's a little inefficient to try flushing name for all views + * if some of the views share a single cache. But since the + * operation is lightweight we prefer simplicity here. + */ + result = dns_view_flushnode(view, name, tree); + if (result != ISC_R_SUCCESS) { + flushed = false; + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing %s '%s' in cache view '%s' " + "failed: %s", + tree ? "tree" : "name", target, + view->name, isc_result_totext(result)); + } + } + if (flushed && found) { + if (viewname != NULL) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing %s '%s' in cache view '%s' " + "succeeded", + tree ? "tree" : "name", target, viewname); + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "flushing %s '%s' in all cache views " + "succeeded", + tree ? "tree" : "name", target); + } + result = ISC_R_SUCCESS; + } else { + if (!found) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "flushing %s '%s' in cache view '%s' " + "failed: view not found", + tree ? "tree" : "name", target, viewname); + } + result = ISC_R_FAILURE; + } + isc_task_endexclusive(server->task); + return (result); +} + +isc_result_t +named_server_status(named_server_t *server, isc_buffer_t **text) { + isc_result_t result; + unsigned int zonecount, xferrunning, xferdeferred, soaqueries; + unsigned int automatic; + const char *ob = "", *cb = "", *alt = ""; + char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE]; + char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE]; + char line[1024], hostname[256]; + named_reload_t reload_status; + + REQUIRE(text != NULL); + + if (named_g_server->version_set) { + ob = " ("; + cb = ")"; + if (named_g_server->version == NULL) { + alt = "version.bind/txt/ch disabled"; + } else { + alt = named_g_server->version; + } + } + zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY); + xferrunning = dns_zonemgr_getcount(server->zonemgr, + DNS_ZONESTATE_XFERRUNNING); + xferdeferred = dns_zonemgr_getcount(server->zonemgr, + DNS_ZONESTATE_XFERDEFERRED); + soaqueries = dns_zonemgr_getcount(server->zonemgr, + DNS_ZONESTATE_SOAQUERY); + automatic = dns_zonemgr_getcount(server->zonemgr, + DNS_ZONESTATE_AUTOMATIC); + + isc_time_formathttptimestamp(&named_g_boottime, boottime, + sizeof(boottime)); + isc_time_formathttptimestamp(&named_g_configtime, configtime, + sizeof(configtime)); + + snprintf(line, sizeof(line), "version: %s %s%s%s %s%s%s\n", + named_g_product, named_g_version, + (*named_g_description != '\0') ? " " : "", named_g_description, + named_g_srcid, ob, alt, cb); + CHECK(putstr(text, line)); + + result = named_os_gethostname(hostname, sizeof(hostname)); + if (result != ISC_R_SUCCESS) { + strlcpy(hostname, "localhost", sizeof(hostname)); + } + snprintf(line, sizeof(line), "running on %s: %s\n", hostname, + named_os_uname()); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "boot time: %s\n", boottime); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "last configured: %s\n", configtime); + CHECK(putstr(text, line)); + + if (named_g_chrootdir != NULL) { + snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n", + named_g_conffile, named_g_chrootdir, named_g_conffile); + } else { + snprintf(line, sizeof(line), "configuration file: %s\n", + named_g_conffile); + } + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "UDP listeners per interface: %u\n", + named_g_udpdisp); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n", + zonecount, automatic); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "soa queries in progress: %u\n", + soaqueries); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "query logging is %s\n", + ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES) + ? "ON" + : "OFF"); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n", + isc_quota_getused(&server->sctx->recursionquota), + isc_quota_getsoft(&server->sctx->recursionquota), + isc_quota_getmax(&server->sctx->recursionquota)); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "tcp clients: %u/%u\n", + isc_quota_getused(&server->sctx->tcpquota), + isc_quota_getmax(&server->sctx->tcpquota)); + CHECK(putstr(text, line)); + + snprintf(line, sizeof(line), "TCP high-water: %u\n", + (unsigned)ns_stats_get_counter(server->sctx->nsstats, + ns_statscounter_tcphighwater)); + CHECK(putstr(text, line)); + + reload_status = atomic_load(&server->reload_status); + if (reload_status != NAMED_RELOAD_DONE) { + snprintf(line, sizeof(line), "reload/reconfig %s\n", + (reload_status == NAMED_RELOAD_FAILED + ? "failed" + : "in progress")); + CHECK(putstr(text, line)); + } + + CHECK(putstr(text, "server is up and running")); + CHECK(putnull(text)); + + return (ISC_R_SUCCESS); +cleanup: + return (result); +} + +isc_result_t +named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) { + isc_result_t result; + char *ptr; + unsigned long count; + unsigned long i; + const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789"; + + REQUIRE(text != NULL); + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + ptr = next_token(lex, text); + if (ptr == NULL) { + count = 26; + } else { + count = strtoul(ptr, NULL, 10); + } + + CHECK(isc_buffer_reserve(text, count)); + for (i = 0; i < count; i++) { + CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)])); + } + + CHECK(putnull(text)); + +cleanup: + return (result); +} + +static isc_result_t +delete_keynames(dns_tsig_keyring_t *ring, char *target, + unsigned int *foundkeys) { + char namestr[DNS_NAME_FORMATSIZE]; + isc_result_t result; + dns_rbtnodechain_t chain; + dns_name_t foundname; + dns_fixedname_t fixedorigin; + dns_name_t *origin; + dns_rbtnode_t *node; + dns_tsigkey_t *tkey; + + dns_name_init(&foundname, NULL); + origin = dns_fixedname_initname(&fixedorigin); + +again: + dns_rbtnodechain_init(&chain); + result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin); + if (result == ISC_R_NOTFOUND) { + dns_rbtnodechain_invalidate(&chain); + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + + for (;;) { + node = NULL; + dns_rbtnodechain_current(&chain, &foundname, origin, &node); + tkey = node->data; + + if (tkey != NULL) { + if (!tkey->generated) { + goto nextkey; + } + + dns_name_format(&tkey->name, namestr, sizeof(namestr)); + if (strcmp(namestr, target) == 0) { + (*foundkeys)++; + dns_rbtnodechain_invalidate(&chain); + (void)dns_rbt_deletename(ring->keys, + &tkey->name, false); + goto again; + } + } + + nextkey: + result = dns_rbtnodechain_next(&chain, &foundname, origin); + if (result == ISC_R_NOMORE) { + break; + } + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +named_server_tsigdelete(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result; + dns_view_t *view; + unsigned int foundkeys = 0; + char *ptr, *viewname; + char target[DNS_NAME_FORMATSIZE]; + char fbuf[16]; + + REQUIRE(text != NULL); + + (void)next_token(lex, text); /* skip command name */ + + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + strlcpy(target, ptr, DNS_NAME_FORMATSIZE); + + viewname = next_token(lex, text); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (viewname == NULL || strcmp(view->name, viewname) == 0) { + RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write); + result = delete_keynames(view->dynamickeys, target, + &foundkeys); + RWUNLOCK(&view->dynamickeys->lock, + isc_rwlocktype_write); + if (result != ISC_R_SUCCESS) { + isc_task_endexclusive(server->task); + return (result); + } + } + } + isc_task_endexclusive(server->task); + + snprintf(fbuf, sizeof(fbuf), "%u", foundkeys); + + CHECK(putstr(text, fbuf)); + CHECK(putstr(text, " tsig keys deleted.")); + CHECK(putnull(text)); + +cleanup: + return (result); +} + +static isc_result_t +list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t **text, + unsigned int *foundkeys) { + char namestr[DNS_NAME_FORMATSIZE]; + char creatorstr[DNS_NAME_FORMATSIZE]; + isc_result_t result; + dns_rbtnodechain_t chain; + dns_name_t foundname; + dns_fixedname_t fixedorigin; + dns_name_t *origin; + dns_rbtnode_t *node; + dns_tsigkey_t *tkey; + const char *viewname; + + if (view != NULL) { + viewname = view->name; + } else { + viewname = "(global)"; + } + + dns_name_init(&foundname, NULL); + origin = dns_fixedname_initname(&fixedorigin); + dns_rbtnodechain_init(&chain); + result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin); + if (result == ISC_R_NOTFOUND) { + dns_rbtnodechain_invalidate(&chain); + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return (result); + } + + for (;;) { + node = NULL; + dns_rbtnodechain_current(&chain, &foundname, origin, &node); + tkey = node->data; + + if (tkey != NULL) { + dns_name_format(&tkey->name, namestr, sizeof(namestr)); + if (tkey->generated) { + dns_name_format(tkey->creator, creatorstr, + sizeof(creatorstr)); + if (*foundkeys != 0) { + CHECK(putstr(text, "\n")); + } + CHECK(putstr(text, "view \"")); + CHECK(putstr(text, viewname)); + CHECK(putstr(text, "\"; type \"dynamic\"; key " + "\"")); + CHECK(putstr(text, namestr)); + CHECK(putstr(text, "\"; creator \"")); + CHECK(putstr(text, creatorstr)); + CHECK(putstr(text, "\";")); + } else { + if (*foundkeys != 0) { + CHECK(putstr(text, "\n")); + } + CHECK(putstr(text, "view \"")); + CHECK(putstr(text, viewname)); + CHECK(putstr(text, "\"; type \"static\"; key " + "\"")); + CHECK(putstr(text, namestr)); + CHECK(putstr(text, "\";")); + } + (*foundkeys)++; + } + result = dns_rbtnodechain_next(&chain, &foundname, origin); + if (result == ISC_R_NOMORE || result == DNS_R_NEWORIGIN) { + break; + } + } + + return (ISC_R_SUCCESS); +cleanup: + dns_rbtnodechain_invalidate(&chain); + return (result); +} + +isc_result_t +named_server_tsiglist(named_server_t *server, isc_buffer_t **text) { + isc_result_t result = ISC_R_SUCCESS; + dns_view_t *view; + unsigned int foundkeys = 0; + + REQUIRE(text != NULL); + + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + RWLOCK(&view->statickeys->lock, isc_rwlocktype_read); + result = list_keynames(view, view->statickeys, text, + &foundkeys); + RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read); + if (result != ISC_R_SUCCESS) { + return (result); + } + RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); + result = list_keynames(view, view->dynamickeys, text, + &foundkeys); + RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + + if (foundkeys == 0) { + CHECK(putstr(text, "no tsig keys found.")); + } + + if (isc_buffer_usedlength(*text) > 0) { + CHECK(putnull(text)); + } + +cleanup: + return (result); +} + +/* + * Act on a "sign" or "loadkeys" command from the command channel. + */ +isc_result_t +named_server_rekey(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_zonetype_t type; + uint16_t keyopts; + bool fullsign = false; + char *ptr; + + REQUIRE(text != NULL); + + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0) { + fullsign = true; + } + + REQUIRE(text != NULL); + + result = zone_from_args(server, lex, NULL, &zone, NULL, text, false); + if (result != ISC_R_SUCCESS) { + return (result); + } + if (zone == NULL) { + return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */ + } + + type = dns_zone_gettype(zone); + if (type != dns_zone_primary) { + dns_zone_detach(&zone); + return (DNS_R_NOTMASTER); + } + + keyopts = dns_zone_getkeyopts(zone); + + /* + * "rndc loadkeys" requires "auto-dnssec maintain" + * or a "dnssec-policy". + */ + if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) { + result = ISC_R_NOPERM; + } else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) { + result = ISC_R_NOPERM; + } else { + dns_zone_rekey(zone, fullsign); + } + + dns_zone_detach(&zone); + return (result); +} + +/* + * Act on a "sync" command from the command channel. + */ +static isc_result_t +synczone(dns_zone_t *zone, void *uap) { + bool cleanup = *(bool *)uap; + isc_result_t result; + dns_zone_t *raw = NULL; + char *journal; + + dns_zone_getraw(zone, &raw); + if (raw != NULL) { + synczone(raw, uap); + dns_zone_detach(&raw); + } + + result = dns_zone_flush(zone); + if (result != ISC_R_SUCCESS) { + cleanup = false; + } + if (cleanup) { + journal = dns_zone_getjournal(zone); + if (journal != NULL) { + (void)isc_file_remove(journal); + } + } + + return (result); +} + +isc_result_t +named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) { + isc_result_t result, tresult; + dns_view_t *view; + dns_zone_t *zone = NULL; + char classstr[DNS_RDATACLASS_FORMATSIZE]; + char zonename[DNS_NAME_FORMATSIZE]; + const char *vname, *sep, *arg; + bool cleanup = false; + + REQUIRE(text != NULL); + + (void)next_token(lex, text); + + arg = next_token(lex, text); + if (arg != NULL && + (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) + { + cleanup = true; + arg = next_token(lex, text); + } + + REQUIRE(text != NULL); + + result = zone_from_args(server, lex, arg, &zone, NULL, text, false); + if (result != ISC_R_SUCCESS) { + return (result); + } + + if (zone == NULL) { + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + tresult = ISC_R_SUCCESS; + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + result = dns_zt_apply(view->zonetable, + isc_rwlocktype_none, false, NULL, + synczone, &cleanup); + if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS) + { + tresult = result; + } + } + isc_task_endexclusive(server->task); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumping all zones%s: %s", + cleanup ? ", removing journal files" : "", + isc_result_totext(result)); + return (tresult); + } + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + result = synczone(zone, &cleanup); + isc_task_endexclusive(server->task); + + view = dns_zone_getview(zone); + if (strcmp(view->name, "_default") == 0 || + strcmp(view->name, "_bind") == 0) + { + vname = ""; + sep = ""; + } else { + vname = view->name; + sep = " "; + } + dns_rdataclass_format(dns_zone_getclass(zone), classstr, + sizeof(classstr)); + dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, + ISC_LOG_INFO, "sync: dumping zone '%s/%s'%s%s%s: %s", zonename, + classstr, sep, vname, cleanup ? ", removing journal file" : "", + isc_result_totext(result)); + dns_zone_detach(&zone); + return (result); +} + +/* + * Act on a "freeze" or "thaw" command from the command channel. + */ +isc_result_t +named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result, tresult; + dns_zone_t *mayberaw = NULL, *raw = NULL; + dns_zonetype_t type; + char classstr[DNS_RDATACLASS_FORMATSIZE]; + char zonename[DNS_NAME_FORMATSIZE]; + dns_view_t *view; + const char *vname, *sep; + bool frozen; + const char *msg = NULL; + + REQUIRE(text != NULL); + + result = zone_from_args(server, lex, NULL, &mayberaw, NULL, text, true); + if (result != ISC_R_SUCCESS) { + return (result); + } + if (mayberaw == NULL) { + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + tresult = ISC_R_SUCCESS; + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + result = dns_view_freezezones(view, freeze); + if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS) + { + tresult = result; + } + } + isc_task_endexclusive(server->task); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "%s all zones: %s", + freeze ? "freezing" : "thawing", + isc_result_totext(tresult)); + return (tresult); + } + dns_zone_getraw(mayberaw, &raw); + if (raw != NULL) { + dns_zone_detach(&mayberaw); + dns_zone_attach(raw, &mayberaw); + dns_zone_detach(&raw); + } + type = dns_zone_gettype(mayberaw); + if (type != dns_zone_primary) { + dns_zone_detach(&mayberaw); + return (DNS_R_NOTMASTER); + } + + if (freeze && !dns_zone_isdynamic(mayberaw, true)) { + dns_zone_detach(&mayberaw); + return (DNS_R_NOTDYNAMIC); + } + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + frozen = dns_zone_getupdatedisabled(mayberaw); + if (freeze) { + if (frozen) { + msg = "WARNING: The zone was already frozen.\n" + "Someone else may be editing it or " + "it may still be re-loading."; + result = DNS_R_FROZEN; + } + if (result == ISC_R_SUCCESS) { + result = dns_zone_flush(mayberaw); + if (result != ISC_R_SUCCESS) { + msg = "Flushing the zone updates to " + "disk failed."; + } + } + if (result == ISC_R_SUCCESS) { + dns_zone_setupdatedisabled(mayberaw, freeze); + } + } else { + if (frozen) { + result = dns_zone_loadandthaw(mayberaw); + switch (result) { + case ISC_R_SUCCESS: + case DNS_R_UPTODATE: + msg = "The zone reload and thaw was " + "successful."; + result = ISC_R_SUCCESS; + break; + case DNS_R_CONTINUE: + msg = "A zone reload and thaw was started.\n" + "Check the logs to see the result."; + result = ISC_R_SUCCESS; + break; + } + } + } + isc_task_endexclusive(server->task); + + if (msg != NULL) { + (void)putstr(text, msg); + (void)putnull(text); + } + + view = dns_zone_getview(mayberaw); + if (strcmp(view->name, "_default") == 0 || + strcmp(view->name, "_bind") == 0) + { + vname = ""; + sep = ""; + } else { + vname = view->name; + sep = " "; + } + dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr, + sizeof(classstr)); + dns_name_format(dns_zone_getorigin(mayberaw), zonename, + sizeof(zonename)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "%s zone '%s/%s'%s%s: %s", + freeze ? "freezing" : "thawing", zonename, classstr, sep, + vname, isc_result_totext(result)); + dns_zone_detach(&mayberaw); + return (result); +} + +#ifdef HAVE_LIBSCF +/* + * This function adds a message for rndc to echo if named + * is managed by smf and is also running chroot. + */ +isc_result_t +named_smf_add_message(isc_buffer_t **text) { + REQUIRE(text != NULL); + + return (putstr(text, "use svcadm(1M) to manage named")); +} +#endif /* HAVE_LIBSCF */ + +#ifndef HAVE_LMDB + +/* + * Emit a comment at the top of the nzf file containing the viewname + * Expects the fp to already be open for writing + */ +#define HEADER1 "# New zone file for view: " +#define HEADER2 \ + "\n# This file contains configuration for zones added by\n" \ + "# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n" +static isc_result_t +add_comment(FILE *fp, const char *viewname) { + isc_result_t result; + CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL)); + CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL)); + CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL)); +cleanup: + return (result); +} + +static void +dumpzone(void *arg, const char *buf, int len) { + FILE *fp = arg; + + (void)isc_stdio_write(buf, len, 1, fp, NULL); +} + +static isc_result_t +nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) { + isc_result_t result; + off_t offset; + FILE *fp = NULL; + bool offsetok = false; + + LOCK(&view->new_zone_lock); + + CHECK(isc_stdio_open(view->new_zone_file, "a", &fp)); + CHECK(isc_stdio_seek(fp, 0, SEEK_END)); + + CHECK(isc_stdio_tell(fp, &offset)); + offsetok = true; + if (offset == 0) { + CHECK(add_comment(fp, view->name)); + } + + CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL)); + cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp); + CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL)); + CHECK(isc_stdio_flush(fp)); + result = isc_stdio_close(fp); + fp = NULL; + +cleanup: + if (fp != NULL) { + (void)isc_stdio_close(fp); + if (offsetok) { + isc_result_t result2; + + result2 = isc_file_truncate(view->new_zone_file, + offset); + if (result2 != ISC_R_SUCCESS) { + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Error truncating NZF file '%s' " + "during rollback from append: " + "%s", + view->new_zone_file, + isc_result_totext(result2)); + } + } + } + UNLOCK(&view->new_zone_lock); + return (result); +} + +static isc_result_t +nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) { + const cfg_obj_t *zl = NULL; + cfg_list_t *list; + const cfg_listelt_t *elt; + + FILE *fp = NULL; + char tmp[1024]; + isc_result_t result; + + result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp, + sizeof(tmp)); + if (result == ISC_R_SUCCESS) { + result = isc_file_openunique(tmp, &fp); + } + if (result != ISC_R_SUCCESS) { + return (result); + } + + cfg_map_get(config, "zone", &zl); + if (!cfg_obj_islist(zl)) { + CHECK(ISC_R_FAILURE); + } + + DE_CONST(&zl->value.list, list); + + CHECK(add_comment(fp, view->name)); /* force a comment */ + + for (elt = ISC_LIST_HEAD(*list); elt != NULL; + elt = ISC_LIST_NEXT(elt, link)) + { + const cfg_obj_t *zconfig = cfg_listelt_value(elt); + + CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL)); + cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp); + CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL)); + } + + CHECK(isc_stdio_flush(fp)); + result = isc_stdio_close(fp); + fp = NULL; + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + CHECK(isc_file_rename(tmp, view->new_zone_file)); + return (result); + +cleanup: + if (fp != NULL) { + (void)isc_stdio_close(fp); + } + (void)isc_file_remove(tmp); + return (result); +} + +#else /* HAVE_LMDB */ + +static void +nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) { + dns_fixedname_t fixed; + + dns_fixedname_init(&fixed); + dns_name_downcase(name, dns_fixedname_name(&fixed), NULL); + dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen); + + key->mv_data = namebuf; + key->mv_size = strlen(namebuf); +} + +static void +dumpzone(void *arg, const char *buf, int len) { + ns_dzarg_t *dzarg = arg; + isc_result_t result; + + REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC)); + + result = putmem(dzarg->text, buf, len); + if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) { + dzarg->result = result; + } +} + +static isc_result_t +nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone, + const cfg_obj_t *zconfig) { + isc_result_t result; + int status; + dns_view_t *view; + bool commit = false; + isc_buffer_t *text = NULL; + char namebuf[1024]; + MDB_val key, data; + ns_dzarg_t dzarg; + + view = dns_zone_getview(zone); + + nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf)); + + if (zconfig == NULL) { + /* We're deleting the zone from the database */ + status = mdb_del(*txnp, dbi, &key, NULL); + if (status != MDB_SUCCESS && status != MDB_NOTFOUND) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Error deleting zone %s " + "from NZD database: %s", + namebuf, mdb_strerror(status)); + result = ISC_R_FAILURE; + goto cleanup; + } else if (status != MDB_NOTFOUND) { + commit = true; + } + } else { + /* We're creating or overwriting the zone */ + const cfg_obj_t *zoptions; + + isc_buffer_allocate(view->mctx, &text, 256); + + zoptions = cfg_tuple_get(zconfig, "options"); + if (zoptions == NULL) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Unable to get options from config in " + "nzd_save()"); + result = ISC_R_FAILURE; + goto cleanup; + } + + dzarg.magic = DZARG_MAGIC; + dzarg.text = &text; + dzarg.result = ISC_R_SUCCESS; + cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg); + if (dzarg.result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Error writing zone config to " + "buffer in nzd_save(): %s", + isc_result_totext(dzarg.result)); + result = dzarg.result; + goto cleanup; + } + + data.mv_data = isc_buffer_base(text); + data.mv_size = isc_buffer_usedlength(text); + + status = mdb_put(*txnp, dbi, &key, &data, 0); + if (status != MDB_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Error inserting zone in " + "NZD database: %s", + mdb_strerror(status)); + result = ISC_R_FAILURE; + goto cleanup; + } + + commit = true; + } + + result = ISC_R_SUCCESS; + +cleanup: + if (!commit || result != ISC_R_SUCCESS) { + (void)mdb_txn_abort(*txnp); + } else { + status = mdb_txn_commit(*txnp); + if (status != MDB_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Error committing " + "NZD database: %s", + mdb_strerror(status)); + result = ISC_R_FAILURE; + } + } + *txnp = NULL; + + if (text != NULL) { + isc_buffer_free(&text); + } + + return (result); +} + +/* + * Check whether the new zone database for 'view' can be opened for writing. + * + * Caller must hold 'view->new_zone_lock'. + */ +static isc_result_t +nzd_writable(dns_view_t *view) { + isc_result_t result = ISC_R_SUCCESS; + int status; + MDB_dbi dbi; + MDB_txn *txn = NULL; + + REQUIRE(view != NULL); + + status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn); + if (status != MDB_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "mdb_txn_begin: %s", mdb_strerror(status)); + return (ISC_R_FAILURE); + } + + status = mdb_dbi_open(txn, NULL, 0, &dbi); + if (status != MDB_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "mdb_dbi_open: %s", mdb_strerror(status)); + result = ISC_R_FAILURE; + } + + mdb_txn_abort(txn); + return (result); +} + +/* + * Open the new zone database for 'view' and start a transaction for it. + * + * Caller must hold 'view->new_zone_lock'. + */ +static isc_result_t +nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) { + int status; + MDB_txn *txn = NULL; + + REQUIRE(view != NULL); + REQUIRE(txnp != NULL && *txnp == NULL); + REQUIRE(dbi != NULL); + + status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn); + if (status != MDB_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "mdb_txn_begin: %s", mdb_strerror(status)); + goto cleanup; + } + + status = mdb_dbi_open(txn, NULL, 0, dbi); + if (status != MDB_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "mdb_dbi_open: %s", mdb_strerror(status)); + goto cleanup; + } + + *txnp = txn; + +cleanup: + if (status != MDB_SUCCESS) { + if (txn != NULL) { + mdb_txn_abort(txn); + } + return (ISC_R_FAILURE); + } + + return (ISC_R_SUCCESS); +} + +/* + * nzd_env_close() and nzd_env_reopen are a kluge to address the + * problem of an NZD file possibly being created before we drop + * root privileges. + */ +static void +nzd_env_close(dns_view_t *view) { + const char *dbpath = NULL; + char dbpath_copy[PATH_MAX]; + char lockpath[PATH_MAX]; + int status, ret; + + if (view->new_zone_dbenv == NULL) { + return; + } + + status = mdb_env_get_path(view->new_zone_dbenv, &dbpath); + INSIST(status == MDB_SUCCESS); + snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath); + strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy)); + mdb_env_close((MDB_env *)view->new_zone_dbenv); + + /* + * Database files must be owned by the eventual user, not by root. + */ + ret = chown(dbpath_copy, ns_os_uid(), -1); + UNUSED(ret); + + /* + * Some platforms need the lockfile not to exist when we reopen the + * environment. + */ + (void)isc_file_remove(lockpath); + + view->new_zone_dbenv = NULL; +} + +static isc_result_t +nzd_env_reopen(dns_view_t *view) { + isc_result_t result; + MDB_env *env = NULL; + int status; + + if (view->new_zone_db == NULL) { + return (ISC_R_SUCCESS); + } + + nzd_env_close(view); + + status = mdb_env_create(&env); + if (status != MDB_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_OTHER, ISC_LOG_ERROR, + "mdb_env_create failed: %s", + mdb_strerror(status)); + CHECK(ISC_R_FAILURE); + } + + if (view->new_zone_mapsize != 0ULL) { + status = mdb_env_set_mapsize(env, view->new_zone_mapsize); + if (status != MDB_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_OTHER, ISC_LOG_ERROR, + "mdb_env_set_mapsize failed: %s", + mdb_strerror(status)); + CHECK(ISC_R_FAILURE); + } + } + + status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600); + if (status != MDB_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_OTHER, ISC_LOG_ERROR, + "mdb_env_open of '%s' failed: %s", + view->new_zone_db, mdb_strerror(status)); + CHECK(ISC_R_FAILURE); + } + + view->new_zone_dbenv = env; + env = NULL; + result = ISC_R_SUCCESS; + +cleanup: + if (env != NULL) { + mdb_env_close(env); + } + return (result); +} + +/* + * If 'commit' is true, commit the new zone database transaction pointed to by + * 'txnp'; otherwise, abort that transaction. + * + * Caller must hold 'view->new_zone_lock' for the view that the transaction + * pointed to by 'txnp' was started for. + */ +static isc_result_t +nzd_close(MDB_txn **txnp, bool commit) { + isc_result_t result = ISC_R_SUCCESS; + int status; + + REQUIRE(txnp != NULL); + + if (*txnp != NULL) { + if (commit) { + status = mdb_txn_commit(*txnp); + if (status != MDB_SUCCESS) { + result = ISC_R_FAILURE; + } + } else { + mdb_txn_abort(*txnp); + } + *txnp = NULL; + } + + return (result); +} + +/* + * Count the zones configured in the new zone database for 'view' and store the + * result in 'countp'. + * + * Caller must hold 'view->new_zone_lock'. + */ +static isc_result_t +nzd_count(dns_view_t *view, int *countp) { + isc_result_t result; + int status; + MDB_txn *txn = NULL; + MDB_dbi dbi; + MDB_stat statbuf; + + REQUIRE(countp != NULL); + + result = nzd_open(view, MDB_RDONLY, &txn, &dbi); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + status = mdb_stat(txn, dbi, &statbuf); + if (status != MDB_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "mdb_stat: %s", mdb_strerror(status)); + result = ISC_R_FAILURE; + goto cleanup; + } + + *countp = statbuf.ms_entries; + +cleanup: + (void)nzd_close(&txn, false); + + return (result); +} + +/* + * Migrate zone configuration from an NZF file to an NZD database. + * Caller must hold view->new_zone_lock. + */ +static isc_result_t +migrate_nzf(dns_view_t *view) { + isc_result_t result; + cfg_obj_t *nzf_config = NULL; + int status, n; + isc_buffer_t *text = NULL; + bool commit = false; + const cfg_obj_t *zonelist; + const cfg_listelt_t *element; + char tempname[PATH_MAX]; + MDB_txn *txn = NULL; + MDB_dbi dbi; + MDB_val key, data; + ns_dzarg_t dzarg; + + /* + * If NZF file doesn't exist, or NZD DB exists and already + * has data, return without attempting migration. + */ + if (!isc_file_exists(view->new_zone_file)) { + result = ISC_R_SUCCESS; + goto cleanup; + } + + result = nzd_count(view, &n); + if (result == ISC_R_SUCCESS && n > 0) { + result = ISC_R_SUCCESS; + goto cleanup; + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "Migrating zones from NZF file '%s' to " + "NZD database '%s'", + view->new_zone_file, view->new_zone_db); + /* + * Instead of blindly copying lines, we parse the NZF file using + * the configuration parser, because it validates it against the + * config type, giving us a guarantee that valid configuration + * will be written to DB. + */ + cfg_parser_reset(named_g_addparser); + result = cfg_parse_file(named_g_addparser, view->new_zone_file, + &cfg_type_addzoneconf, &nzf_config); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Error parsing NZF file '%s': %s", + view->new_zone_file, isc_result_totext(result)); + goto cleanup; + } + + zonelist = NULL; + CHECK(cfg_map_get(nzf_config, "zone", &zonelist)); + if (!cfg_obj_islist(zonelist)) { + CHECK(ISC_R_FAILURE); + } + + CHECK(nzd_open(view, 0, &txn, &dbi)); + + isc_buffer_allocate(view->mctx, &text, 256); + + for (element = cfg_list_first(zonelist); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *zconfig; + const cfg_obj_t *zoptions; + char zname[DNS_NAME_FORMATSIZE]; + dns_fixedname_t fname; + dns_name_t *name; + const char *origin; + isc_buffer_t b; + + zconfig = cfg_listelt_value(element); + + origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + if (origin == NULL) { + result = ISC_R_FAILURE; + goto cleanup; + } + + /* Normalize zone name */ + isc_buffer_constinit(&b, origin, strlen(origin)); + isc_buffer_add(&b, strlen(origin)); + name = dns_fixedname_initname(&fname); + CHECK(dns_name_fromtext(name, &b, dns_rootname, + DNS_NAME_DOWNCASE, NULL)); + dns_name_format(name, zname, sizeof(zname)); + + key.mv_data = zname; + key.mv_size = strlen(zname); + + zoptions = cfg_tuple_get(zconfig, "options"); + if (zoptions == NULL) { + result = ISC_R_FAILURE; + goto cleanup; + } + + isc_buffer_clear(text); + dzarg.magic = DZARG_MAGIC; + dzarg.text = &text; + dzarg.result = ISC_R_SUCCESS; + cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg); + if (dzarg.result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Error writing zone config to " + "buffer in migrate_nzf(): %s", + isc_result_totext(result)); + result = dzarg.result; + goto cleanup; + } + + data.mv_data = isc_buffer_base(text); + data.mv_size = isc_buffer_usedlength(text); + + status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE); + if (status != MDB_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Error inserting zone in " + "NZD database: %s", + mdb_strerror(status)); + result = ISC_R_FAILURE; + goto cleanup; + } + + commit = true; + } + + result = ISC_R_SUCCESS; + + /* + * Leaving the NZF file in place is harmless as we won't use it + * if an NZD database is found for the view. But we rename NZF file + * to a backup name here. + */ + strlcpy(tempname, view->new_zone_file, sizeof(tempname)); + if (strlen(tempname) < sizeof(tempname) - 1) { + strlcat(tempname, "~", sizeof(tempname)); + isc_file_rename(view->new_zone_file, tempname); + } + +cleanup: + if (result != ISC_R_SUCCESS) { + (void)nzd_close(&txn, false); + } else { + result = nzd_close(&txn, commit); + } + + if (text != NULL) { + isc_buffer_free(&text); + } + + if (nzf_config != NULL) { + cfg_obj_destroy(named_g_addparser, &nzf_config); + } + + return (result); +} + +#endif /* HAVE_LMDB */ + +static isc_result_t +newzone_parse(named_server_t *server, char *command, dns_view_t **viewp, + cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp, + bool *redirectp, isc_buffer_t **text) { + isc_result_t result; + isc_buffer_t argbuf; + bool redirect = false; + cfg_obj_t *zoneconf = NULL; + const cfg_obj_t *zlist = NULL; + const cfg_obj_t *zoneobj = NULL; + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *obj = NULL; + const char *viewname = NULL; + dns_rdataclass_t rdclass; + dns_view_t *view = NULL; + const char *bn = NULL; + + REQUIRE(viewp != NULL && *viewp == NULL); + REQUIRE(zoneobjp != NULL && *zoneobjp == NULL); + REQUIRE(zoneconfp != NULL && *zoneconfp == NULL); + REQUIRE(redirectp != NULL); + + /* Try to parse the argument string */ + isc_buffer_init(&argbuf, command, (unsigned int)strlen(command)); + isc_buffer_add(&argbuf, strlen(command)); + + if (strncasecmp(command, "add", 3) == 0) { + bn = "addzone"; + } else if (strncasecmp(command, "mod", 3) == 0) { + bn = "modzone"; + } else { + UNREACHABLE(); + } + + /* + * Convert the "addzone" or "modzone" to just "zone", for + * the benefit of the parser + */ + isc_buffer_forward(&argbuf, 3); + + cfg_parser_reset(named_g_addparser); + CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0, + &cfg_type_addzoneconf, 0, &zoneconf)); + CHECK(cfg_map_get(zoneconf, "zone", &zlist)); + if (!cfg_obj_islist(zlist)) { + CHECK(ISC_R_FAILURE); + } + + /* For now we only support adding one zone at a time */ + zoneobj = cfg_listelt_value(cfg_list_first(zlist)); + + /* Check the zone type for ones that are not supported by addzone. */ + zoptions = cfg_tuple_get(zoneobj, "options"); + + obj = NULL; + (void)cfg_map_get(zoptions, "type", &obj); + if (obj == NULL) { + (void)cfg_map_get(zoptions, "in-view", &obj); + if (obj != NULL) { + (void)putstr(text, "'in-view' zones not supported by "); + (void)putstr(text, bn); + } else { + (void)putstr(text, "zone type not specified"); + } + CHECK(ISC_R_FAILURE); + } + + if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 || + strcasecmp(cfg_obj_asstring(obj), "forward") == 0 || + strcasecmp(cfg_obj_asstring(obj), "delegation-only") == 0) + { + (void)putstr(text, "'"); + (void)putstr(text, cfg_obj_asstring(obj)); + (void)putstr(text, "' zones not supported by "); + (void)putstr(text, bn); + CHECK(ISC_R_FAILURE); + } + + if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0) { + redirect = true; + } + + /* Make sense of optional class argument */ + obj = cfg_tuple_get(zoneobj, "class"); + CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass)); + + /* Make sense of optional view argument */ + obj = cfg_tuple_get(zoneobj, "view"); + if (obj && cfg_obj_isstring(obj)) { + viewname = cfg_obj_asstring(obj); + } + if (viewname == NULL || *viewname == '\0') { + viewname = "_default"; + } + result = dns_viewlist_find(&server->viewlist, viewname, rdclass, &view); + if (result == ISC_R_NOTFOUND) { + (void)putstr(text, "no matching view found for '"); + (void)putstr(text, viewname); + (void)putstr(text, "'"); + goto cleanup; + } else if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + *viewp = view; + *zoneobjp = zoneobj; + *zoneconfp = zoneconf; + *redirectp = redirect; + + return (ISC_R_SUCCESS); + +cleanup: + if (zoneconf != NULL) { + cfg_obj_destroy(named_g_addparser, &zoneconf); + } + if (view != NULL) { + dns_view_detach(&view); + } + + return (result); +} + +static isc_result_t +delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config, + const dns_name_t *zname, nzfwriter_t nzfwriter) { + isc_result_t result = ISC_R_NOTFOUND; + const cfg_listelt_t *elt = NULL; + const cfg_obj_t *zl = NULL; + cfg_list_t *list; + dns_fixedname_t myfixed; + dns_name_t *myname; + + REQUIRE(view != NULL); + REQUIRE(pctx != NULL); + REQUIRE(config != NULL); + REQUIRE(zname != NULL); + + LOCK(&view->new_zone_lock); + + cfg_map_get(config, "zone", &zl); + + if (!cfg_obj_islist(zl)) { + CHECK(ISC_R_FAILURE); + } + + DE_CONST(&zl->value.list, list); + + myname = dns_fixedname_initname(&myfixed); + + for (elt = ISC_LIST_HEAD(*list); elt != NULL; + elt = ISC_LIST_NEXT(elt, link)) + { + const cfg_obj_t *zconf = cfg_listelt_value(elt); + const char *zn; + cfg_listelt_t *e; + + zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name")); + result = dns_name_fromstring(myname, zn, 0, NULL); + if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname)) { + continue; + } + + DE_CONST(elt, e); + ISC_LIST_UNLINK(*list, e, link); + cfg_obj_destroy(pctx, &e->obj); + isc_mem_put(pctx->mctx, e, sizeof(*e)); + result = ISC_R_SUCCESS; + break; + } + + /* + * Write config to NZF file if appropriate + */ + if (nzfwriter != NULL && view->new_zone_file != NULL) { + result = nzfwriter(config, view); + } + +cleanup: + UNLOCK(&view->new_zone_lock); + return (result); +} + +static isc_result_t +do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view, + dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj, + bool redirect, isc_buffer_t **text) { + isc_result_t result, tresult; + dns_zone_t *zone = NULL; +#ifndef HAVE_LMDB + FILE *fp = NULL; + bool cleanup_config = false; +#else /* HAVE_LMDB */ + MDB_txn *txn = NULL; + MDB_dbi dbi; + bool locked = false; + + UNUSED(zoneconf); +#endif + + /* Zone shouldn't already exist */ + if (redirect) { + result = (view->redirect != NULL) ? ISC_R_SUCCESS + : ISC_R_NOTFOUND; + } else { + result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); + } + if (result == ISC_R_SUCCESS) { + result = ISC_R_EXISTS; + goto cleanup; + } else if (result == DNS_R_PARTIALMATCH) { + /* Create our sub-zone anyway */ + dns_zone_detach(&zone); + zone = NULL; + } else if (result != ISC_R_NOTFOUND) { + goto cleanup; + } + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + +#ifndef HAVE_LMDB + /* + * Make sure we can open the configuration save file + */ + result = isc_stdio_open(view->new_zone_file, "a", &fp); + if (result != ISC_R_SUCCESS) { + isc_task_endexclusive(server->task); + TCHECK(putstr(text, "unable to create '")); + TCHECK(putstr(text, view->new_zone_file)); + TCHECK(putstr(text, "': ")); + TCHECK(putstr(text, isc_result_totext(result))); + goto cleanup; + } + + (void)isc_stdio_close(fp); + fp = NULL; +#else /* HAVE_LMDB */ + LOCK(&view->new_zone_lock); + locked = true; + /* Make sure we can open the NZD database */ + result = nzd_writable(view); + if (result != ISC_R_SUCCESS) { + isc_task_endexclusive(server->task); + TCHECK(putstr(text, "unable to open NZD database for '")); + TCHECK(putstr(text, view->new_zone_db)); + TCHECK(putstr(text, "'")); + result = ISC_R_FAILURE; + goto cleanup; + } +#endif /* HAVE_LMDB */ + + /* Mark view unfrozen and configure zone */ + dns_view_thaw(view); + result = configure_zone(cfg->config, zoneobj, cfg->vconfig, + server->mctx, view, &server->viewlist, + &server->kasplist, cfg->actx, true, false, + false); + dns_view_freeze(view); + + isc_task_endexclusive(server->task); + + if (result != ISC_R_SUCCESS) { + TCHECK(putstr(text, "configure_zone failed: ")); + TCHECK(putstr(text, isc_result_totext(result))); + goto cleanup; + } + + /* Is it there yet? */ + if (redirect) { + if (view->redirect == NULL) { + CHECK(ISC_R_NOTFOUND); + } + dns_zone_attach(view->redirect, &zone); + } else { + result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "added new zone was not found: %s", + isc_result_totext(result)); + goto cleanup; + } + } + +#ifndef HAVE_LMDB + /* + * If there wasn't a previous newzone config, just save the one + * we've created. If there was a previous one, merge the new + * zone into it. + */ + if (cfg->nzf_config == NULL) { + cfg_obj_attach(zoneconf, &cfg->nzf_config); + } else { + cfg_obj_t *z; + DE_CONST(zoneobj, z); + CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, + "zone")); + } + cleanup_config = true; +#endif /* HAVE_LMDB */ + + /* + * Load the zone from the master file. If this fails, we'll + * need to undo the configuration we've done already. + */ + result = dns_zone_load(zone, true); + if (result != ISC_R_SUCCESS) { + dns_db_t *dbp = NULL; + + TCHECK(putstr(text, "dns_zone_loadnew failed: ")); + TCHECK(putstr(text, isc_result_totext(result))); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "addzone failed; reverting."); + + /* If the zone loaded partially, unload it */ + if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { + dns_db_detach(&dbp); + dns_zone_unload(zone); + } + + /* Remove the zone from the zone table */ + dns_zt_unmount(view->zonetable, zone); + goto cleanup; + } + + /* Flag the zone as having been added at runtime */ + dns_zone_setadded(zone, true); + +#ifdef HAVE_LMDB + /* Save the new zone configuration into the NZD */ + CHECK(nzd_open(view, 0, &txn, &dbi)); + CHECK(nzd_save(&txn, dbi, zone, zoneobj)); +#else /* ifdef HAVE_LMDB */ + /* Append the zone configuration to the NZF */ + result = nzf_append(view, zoneobj); +#endif /* HAVE_LMDB */ + +cleanup: + +#ifndef HAVE_LMDB + if (fp != NULL) { + (void)isc_stdio_close(fp); + } + if (result != ISC_R_SUCCESS && cleanup_config) { + tresult = delete_zoneconf(view, cfg->add_parser, + cfg->nzf_config, name, NULL); + RUNTIME_CHECK(tresult == ISC_R_SUCCESS); + } +#else /* HAVE_LMDB */ + if (txn != NULL) { + (void)nzd_close(&txn, false); + } + if (locked) { + UNLOCK(&view->new_zone_lock); + } +#endif /* HAVE_LMDB */ + + if (zone != NULL) { + dns_zone_detach(&zone); + } + + return (result); +} + +static isc_result_t +do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view, + dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj, + bool redirect, isc_buffer_t **text) { + isc_result_t result, tresult; + dns_zone_t *zone = NULL; + bool added; + bool exclusive = false; +#ifndef HAVE_LMDB + FILE *fp = NULL; + cfg_obj_t *z; +#else /* HAVE_LMDB */ + MDB_txn *txn = NULL; + MDB_dbi dbi; + bool locked = false; +#endif /* HAVE_LMDB */ + + /* Zone must already exist */ + if (redirect) { + if (view->redirect != NULL) { + dns_zone_attach(view->redirect, &zone); + result = ISC_R_SUCCESS; + } else { + result = ISC_R_NOTFOUND; + } + } else { + result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); + } + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + added = dns_zone_getadded(zone); + dns_zone_detach(&zone); + +#ifndef HAVE_LMDB + cfg = (ns_cfgctx_t *)view->new_zone_config; + if (cfg == NULL) { + TCHECK(putstr(text, "new zone config is not set")); + CHECK(ISC_R_FAILURE); + } +#endif /* ifndef HAVE_LMDB */ + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + exclusive = true; + +#ifndef HAVE_LMDB + /* Make sure we can open the configuration save file */ + result = isc_stdio_open(view->new_zone_file, "a", &fp); + if (result != ISC_R_SUCCESS) { + TCHECK(putstr(text, "unable to open '")); + TCHECK(putstr(text, view->new_zone_file)); + TCHECK(putstr(text, "': ")); + TCHECK(putstr(text, isc_result_totext(result))); + goto cleanup; + } + (void)isc_stdio_close(fp); + fp = NULL; +#else /* HAVE_LMDB */ + LOCK(&view->new_zone_lock); + locked = true; + /* Make sure we can open the NZD database */ + result = nzd_writable(view); + if (result != ISC_R_SUCCESS) { + TCHECK(putstr(text, "unable to open NZD database for '")); + TCHECK(putstr(text, view->new_zone_db)); + TCHECK(putstr(text, "'")); + result = ISC_R_FAILURE; + goto cleanup; + } +#endif /* HAVE_LMDB */ + + /* Reconfigure the zone */ + dns_view_thaw(view); + result = configure_zone(cfg->config, zoneobj, cfg->vconfig, + server->mctx, view, &server->viewlist, + &server->kasplist, cfg->actx, true, false, + true); + dns_view_freeze(view); + + exclusive = false; + isc_task_endexclusive(server->task); + + if (result != ISC_R_SUCCESS) { + TCHECK(putstr(text, "configure_zone failed: ")); + TCHECK(putstr(text, isc_result_totext(result))); + goto cleanup; + } + + /* Is it there yet? */ + if (redirect) { + if (view->redirect == NULL) { + CHECK(ISC_R_NOTFOUND); + } + dns_zone_attach(view->redirect, &zone); + } else { + CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone)); + } + +#ifndef HAVE_LMDB + /* Remove old zone from configuration (and NZF file if applicable) */ + if (added) { + result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config, + dns_zone_getorigin(zone), + nzf_writeconf); + if (result != ISC_R_SUCCESS) { + TCHECK(putstr(text, "former zone configuration " + "not deleted: ")); + TCHECK(putstr(text, isc_result_totext(result))); + goto cleanup; + } + } +#endif /* HAVE_LMDB */ + + if (!added) { + if (cfg->vconfig == NULL) { + result = delete_zoneconf( + view, cfg->conf_parser, cfg->config, + dns_zone_getorigin(zone), NULL); + } else { + const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig, + "options"); + result = delete_zoneconf( + view, cfg->conf_parser, voptions, + dns_zone_getorigin(zone), NULL); + } + + if (result != ISC_R_SUCCESS) { + TCHECK(putstr(text, "former zone configuration " + "not deleted: ")); + TCHECK(putstr(text, isc_result_totext(result))); + goto cleanup; + } + } + + /* Load the zone from the master file if it needs reloading. */ + result = dns_zone_load(zone, true); + + /* + * Dynamic zones need no reloading, so we can pass this result. + */ + if (result == DNS_R_DYNAMIC) { + result = ISC_R_SUCCESS; + } + + if (result != ISC_R_SUCCESS) { + dns_db_t *dbp = NULL; + + TCHECK(putstr(text, "failed to load zone '")); + TCHECK(putstr(text, zname)); + TCHECK(putstr(text, "': ")); + TCHECK(putstr(text, isc_result_totext(result))); + TCHECK(putstr(text, "\nThe zone is no longer being served. ")); + TCHECK(putstr(text, "Use 'rndc addzone' to correct\n")); + TCHECK(putstr(text, "the problem and restore service.")); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "modzone failed; removing zone."); + + /* If the zone loaded partially, unload it */ + if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { + dns_db_detach(&dbp); + dns_zone_unload(zone); + } + + /* Remove the zone from the zone table */ + dns_zt_unmount(view->zonetable, zone); + goto cleanup; + } + +#ifndef HAVE_LMDB + /* Store the new zone configuration; also in NZF if applicable */ + DE_CONST(zoneobj, z); + CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone")); +#endif /* HAVE_LMDB */ + + if (added) { +#ifdef HAVE_LMDB + CHECK(nzd_open(view, 0, &txn, &dbi)); + CHECK(nzd_save(&txn, dbi, zone, zoneobj)); +#else /* ifdef HAVE_LMDB */ + result = nzf_append(view, zoneobj); + if (result != ISC_R_SUCCESS) { + TCHECK(putstr(text, "\nNew zone config not saved: ")); + TCHECK(putstr(text, isc_result_totext(result))); + goto cleanup; + } +#endif /* HAVE_LMDB */ + + TCHECK(putstr(text, "zone '")); + TCHECK(putstr(text, zname)); + TCHECK(putstr(text, "' reconfigured.")); + } else { + TCHECK(putstr(text, "zone '")); + TCHECK(putstr(text, zname)); + TCHECK(putstr(text, "' must also be reconfigured in\n")); + TCHECK(putstr(text, "named.conf to make changes permanent.")); + } + +cleanup: + if (exclusive) { + isc_task_endexclusive(server->task); + } + +#ifndef HAVE_LMDB + if (fp != NULL) { + (void)isc_stdio_close(fp); + } +#else /* HAVE_LMDB */ + if (txn != NULL) { + (void)nzd_close(&txn, false); + } + if (locked) { + UNLOCK(&view->new_zone_lock); + } +#endif /* HAVE_LMDB */ + + if (zone != NULL) { + dns_zone_detach(&zone); + } + + return (result); +} + +/* + * Act on an "addzone" or "modzone" command from the command channel. + */ +isc_result_t +named_server_changezone(named_server_t *server, char *command, + isc_buffer_t **text) { + isc_result_t result; + bool addzone; + bool redirect = false; + ns_cfgctx_t *cfg = NULL; + cfg_obj_t *zoneconf = NULL; + const cfg_obj_t *zoneobj = NULL; + const char *zonename; + dns_view_t *view = NULL; + isc_buffer_t buf; + dns_fixedname_t fname; + dns_name_t *dnsname; + + REQUIRE(text != NULL); + + if (strncasecmp(command, "add", 3) == 0) { + addzone = true; + } else { + INSIST(strncasecmp(command, "mod", 3) == 0); + addzone = false; + } + + CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj, + &redirect, text)); + + /* Are we accepting new zones in this view? */ +#ifdef HAVE_LMDB + if (view->new_zone_db == NULL) +#else /* ifdef HAVE_LMDB */ + if (view->new_zone_file == NULL) +#endif /* HAVE_LMDB */ + { + (void)putstr(text, "Not allowing new zones in view '"); + (void)putstr(text, view->name); + (void)putstr(text, "'"); + result = ISC_R_NOPERM; + goto cleanup; + } + + cfg = (ns_cfgctx_t *)view->new_zone_config; + if (cfg == NULL) { + result = ISC_R_FAILURE; + goto cleanup; + } + + zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name")); + isc_buffer_constinit(&buf, zonename, strlen(zonename)); + isc_buffer_add(&buf, strlen(zonename)); + + dnsname = dns_fixedname_initname(&fname); + CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL)); + + if (redirect) { + if (!dns_name_equal(dnsname, dns_rootname)) { + (void)putstr(text, "redirect zones must be called " + "\".\""); + CHECK(ISC_R_FAILURE); + } + } + + if (addzone) { + CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj, + redirect, text)); + } else { + CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj, + redirect, text)); + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "%s zone %s in view %s via %s", + addzone ? "added" : "updated", zonename, view->name, + addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE); + + /* Changing a zone counts as reconfiguration */ + CHECK(isc_time_now(&named_g_configtime)); + +cleanup: + if (isc_buffer_usedlength(*text) > 0) { + (void)putnull(text); + } + if (zoneconf != NULL) { + cfg_obj_destroy(named_g_addparser, &zoneconf); + } + if (view != NULL) { + dns_view_detach(&view); + } + + return (result); +} + +static bool +inuse(const char *file, bool first, isc_buffer_t **text) { + if (file != NULL && isc_file_exists(file)) { + if (first) { + (void)putstr(text, "The following files were in use " + "and may now be removed:\n"); + } else { + (void)putstr(text, "\n"); + } + (void)putstr(text, file); + (void)putnull(text); + return (false); + } + return (first); +} + +typedef struct { + dns_zone_t *zone; + bool cleanup; +} ns_dzctx_t; + +/* + * Carry out a zone deletion scheduled by named_server_delzone(). + */ +static void +rmzone(isc_task_t *task, isc_event_t *event) { + ns_dzctx_t *dz = (ns_dzctx_t *)event->ev_arg; + dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL; + dns_catz_zone_t *catz = NULL; + char zonename[DNS_NAME_FORMATSIZE]; + dns_view_t *view = NULL; + ns_cfgctx_t *cfg = NULL; + dns_db_t *dbp = NULL; + bool added; + isc_result_t result; +#ifdef HAVE_LMDB + MDB_txn *txn = NULL; + MDB_dbi dbi; +#endif /* ifdef HAVE_LMDB */ + + REQUIRE(dz != NULL); + + isc_event_free(&event); + + /* Dig out configuration for this zone */ + zone = dz->zone; + view = dns_zone_getview(zone); + cfg = (ns_cfgctx_t *)view->new_zone_config; + dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "deleting zone %s in view %s via delzone", zonename, + view->name); + + /* + * Remove the zone from configuration (and NZF file if applicable) + * (If this is a catalog zone member then nzf_config can be NULL) + */ + added = dns_zone_getadded(zone); + catz = dns_zone_get_parentcatz(zone); + + if (added && catz == NULL && cfg != NULL) { +#ifdef HAVE_LMDB + /* Make sure we can open the NZD database */ + LOCK(&view->new_zone_lock); + result = nzd_open(view, 0, &txn, &dbi); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "unable to open NZD database for '%s'", + view->new_zone_db); + } else { + result = nzd_save(&txn, dbi, zone, NULL); + } + + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "unable to delete zone configuration: %s", + isc_result_totext(result)); + } + + if (txn != NULL) { + (void)nzd_close(&txn, false); + } + UNLOCK(&view->new_zone_lock); +#else /* ifdef HAVE_LMDB */ + result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config, + dns_zone_getorigin(zone), + nzf_writeconf); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "unable to delete zone configuration: %s", + isc_result_totext(result)); + } +#endif /* HAVE_LMDB */ + } + + if (!added && cfg != NULL) { + if (cfg->vconfig != NULL) { + const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig, + "options"); + result = delete_zoneconf( + view, cfg->conf_parser, voptions, + dns_zone_getorigin(zone), NULL); + } else { + result = delete_zoneconf( + view, cfg->conf_parser, cfg->config, + dns_zone_getorigin(zone), NULL); + } + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "unable to delete zone configuration: %s", + isc_result_totext(result)); + } + } + + /* Unload zone database */ + if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { + dns_db_detach(&dbp); + dns_zone_unload(zone); + } + + /* Clean up stub/slave zone files if requested to do so */ + dns_zone_getraw(zone, &raw); + mayberaw = (raw != NULL) ? raw : zone; + + if (added && dz->cleanup) { + const char *file; + + file = dns_zone_getfile(mayberaw); + result = isc_file_remove(file); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "file %s not removed: %s", file, + isc_result_totext(result)); + } + + file = dns_zone_getjournal(mayberaw); + result = isc_file_remove(file); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "file %s not removed: %s", file, + isc_result_totext(result)); + } + + if (zone != mayberaw) { + file = dns_zone_getfile(zone); + result = isc_file_remove(file); + if (result != ISC_R_SUCCESS) { + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "file %s not removed: %s", file, + isc_result_totext(result)); + } + + file = dns_zone_getjournal(zone); + result = isc_file_remove(file); + if (result != ISC_R_SUCCESS) { + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "file %s not removed: %s", file, + isc_result_totext(result)); + } + } + } + + if (raw != NULL) { + dns_zone_detach(&raw); + } + dns_zone_detach(&zone); + isc_mem_put(named_g_mctx, dz, sizeof(*dz)); + isc_task_detach(&task); +} + +/* + * Act on a "delzone" command from the command channel. + */ +isc_result_t +named_server_delzone(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result, tresult; + dns_zone_t *zone = NULL; + dns_zone_t *raw = NULL; + dns_zone_t *mayberaw; + dns_view_t *view = NULL; + char zonename[DNS_NAME_FORMATSIZE]; + bool cleanup = false; + const char *ptr; + bool added; + ns_dzctx_t *dz = NULL; + isc_event_t *dzevent = NULL; + isc_task_t *task = NULL; + + REQUIRE(text != NULL); + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Find out what we are to do. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) { + cleanup = true; + ptr = next_token(lex, text); + } + + CHECK(zone_from_args(server, lex, ptr, &zone, zonename, text, false)); + if (zone == NULL) { + result = ISC_R_UNEXPECTEDEND; + goto cleanup; + } + + INSIST(zonename != NULL); + + /* Is this a policy zone? */ + if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) { + TCHECK(putstr(text, "zone '")); + TCHECK(putstr(text, zonename)); + TCHECK(putstr(text, + "' cannot be deleted: response-policy zone.")); + result = ISC_R_FAILURE; + goto cleanup; + } + + view = dns_zone_getview(zone); + if (dns_zone_gettype(zone) == dns_zone_redirect) { + dns_zone_detach(&view->redirect); + } else { + CHECK(dns_zt_unmount(view->zonetable, zone)); + } + + /* Send cleanup event */ + dz = isc_mem_get(named_g_mctx, sizeof(*dz)); + + dz->cleanup = cleanup; + dz->zone = NULL; + dns_zone_attach(zone, &dz->zone); + dzevent = isc_event_allocate(named_g_mctx, server, NAMED_EVENT_DELZONE, + rmzone, dz, sizeof(isc_event_t)); + + dns_zone_gettask(zone, &task); + isc_task_send(task, &dzevent); + dz = NULL; + + /* Inform user about cleaning up stub/slave zone files */ + dns_zone_getraw(zone, &raw); + mayberaw = (raw != NULL) ? raw : zone; + + added = dns_zone_getadded(zone); + if (!added) { + TCHECK(putstr(text, "zone '")); + TCHECK(putstr(text, zonename)); + TCHECK(putstr(text, "' is no longer active and will be " + "deleted.\n")); + TCHECK(putstr(text, "To keep it from returning ")); + TCHECK(putstr(text, "when the server is restarted, it\n")); + TCHECK(putstr(text, "must also be removed from named.conf.")); + } else if (cleanup) { + TCHECK(putstr(text, "zone '")); + TCHECK(putstr(text, zonename)); + TCHECK(putstr(text, "' and associated files will be deleted.")); + } else if (dns_zone_gettype(mayberaw) == dns_zone_secondary || + dns_zone_gettype(mayberaw) == dns_zone_mirror || + dns_zone_gettype(mayberaw) == dns_zone_stub) + { + bool first; + const char *file; + + TCHECK(putstr(text, "zone '")); + TCHECK(putstr(text, zonename)); + TCHECK(putstr(text, "' will be deleted.")); + + file = dns_zone_getfile(mayberaw); + first = inuse(file, true, text); + + file = dns_zone_getjournal(mayberaw); + first = inuse(file, first, text); + + if (zone != mayberaw) { + file = dns_zone_getfile(zone); + first = inuse(file, first, text); + + file = dns_zone_getjournal(zone); + (void)inuse(file, first, text); + } + } + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "zone %s scheduled for removal via delzone", zonename); + + /* Removing a zone counts as reconfiguration */ + CHECK(isc_time_now(&named_g_configtime)); + + result = ISC_R_SUCCESS; + +cleanup: + if (isc_buffer_usedlength(*text) > 0) { + (void)putnull(text); + } + if (raw != NULL) { + dns_zone_detach(&raw); + } + if (zone != NULL) { + dns_zone_detach(&zone); + } + + return (result); +} + +static const cfg_obj_t * +find_name_in_list_from_map(const cfg_obj_t *config, + const char *map_key_for_list, const char *name, + bool redirect) { + const cfg_obj_t *list = NULL; + const cfg_listelt_t *element; + const cfg_obj_t *obj = NULL; + dns_fixedname_t fixed1, fixed2; + dns_name_t *name1 = NULL, *name2 = NULL; + isc_result_t result; + + if (strcmp(map_key_for_list, "zone") == 0) { + name1 = dns_fixedname_initname(&fixed1); + name2 = dns_fixedname_initname(&fixed2); + result = dns_name_fromstring(name1, name, 0, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + } + + cfg_map_get(config, map_key_for_list, &list); + for (element = cfg_list_first(list); element != NULL; + element = cfg_list_next(element)) + { + const char *vname; + + obj = cfg_listelt_value(element); + INSIST(obj != NULL); + vname = cfg_obj_asstring(cfg_tuple_get(obj, "name")); + if (vname == NULL) { + obj = NULL; + continue; + } + + if (name1 != NULL) { + result = dns_name_fromstring(name2, vname, 0, NULL); + if (result == ISC_R_SUCCESS && + dns_name_equal(name1, name2)) + { + const cfg_obj_t *zoptions; + const cfg_obj_t *typeobj = NULL; + zoptions = cfg_tuple_get(obj, "options"); + + if (zoptions != NULL) { + cfg_map_get(zoptions, "type", &typeobj); + } + if (redirect && typeobj != NULL && + strcasecmp(cfg_obj_asstring(typeobj), + "redirect") == 0) + { + break; + } else if (!redirect) { + break; + } + } + } else if (strcasecmp(vname, name) == 0) { + break; + } + + obj = NULL; + } + + return (obj); +} + +static void +emitzone(void *arg, const char *buf, int len) { + ns_dzarg_t *dzarg = arg; + isc_result_t result; + + REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC)); + result = putmem(dzarg->text, buf, len); + if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) { + dzarg->result = result; + } +} + +/* + * Act on a "showzone" command from the command channel. + */ +isc_result_t +named_server_showzone(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result; + const cfg_obj_t *vconfig = NULL, *zconfig = NULL; + char zonename[DNS_NAME_FORMATSIZE]; + const cfg_obj_t *map; + dns_view_t *view = NULL; + dns_zone_t *zone = NULL; + ns_cfgctx_t *cfg = NULL; +#ifdef HAVE_LMDB + cfg_obj_t *nzconfig = NULL; +#endif /* HAVE_LMDB */ + bool added, redirect; + ns_dzarg_t dzarg; + + REQUIRE(text != NULL); + + /* Parse parameters */ + CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true)); + if (zone == NULL) { + result = ISC_R_UNEXPECTEDEND; + goto cleanup; + } + + redirect = dns_zone_gettype(zone) == dns_zone_redirect; + added = dns_zone_getadded(zone); + view = dns_zone_getview(zone); + dns_zone_detach(&zone); + + cfg = (ns_cfgctx_t *)view->new_zone_config; + if (cfg == NULL) { + result = ISC_R_FAILURE; + goto cleanup; + } + + if (!added) { + /* Find the view statement */ + vconfig = find_name_in_list_from_map(cfg->config, "view", + view->name, false); + + /* Find the zone statement */ + if (vconfig != NULL) { + map = cfg_tuple_get(vconfig, "options"); + } else { + map = cfg->config; + } + + zconfig = find_name_in_list_from_map(map, "zone", zonename, + redirect); + } + +#ifndef HAVE_LMDB + if (zconfig == NULL && cfg->nzf_config != NULL) { + zconfig = find_name_in_list_from_map(cfg->nzf_config, "zone", + zonename, redirect); + } +#else /* HAVE_LMDB */ + if (zconfig == NULL) { + const cfg_obj_t *zlist = NULL; + CHECK(get_newzone_config(view, zonename, &nzconfig)); + CHECK(cfg_map_get(nzconfig, "zone", &zlist)); + if (!cfg_obj_islist(zlist)) { + CHECK(ISC_R_FAILURE); + } + + zconfig = cfg_listelt_value(cfg_list_first(zlist)); + } +#endif /* HAVE_LMDB */ + + if (zconfig == NULL) { + CHECK(ISC_R_NOTFOUND); + } + + CHECK(putstr(text, "zone ")); + dzarg.magic = DZARG_MAGIC; + dzarg.text = text; + dzarg.result = ISC_R_SUCCESS; + cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg); + CHECK(dzarg.result); + + CHECK(putstr(text, ";")); + + result = ISC_R_SUCCESS; + +cleanup: +#ifdef HAVE_LMDB + if (nzconfig != NULL) { + cfg_obj_destroy(named_g_addparser, &nzconfig); + } +#endif /* HAVE_LMDB */ + if (isc_buffer_usedlength(*text) > 0) { + (void)putnull(text); + } + + return (result); +} + +static void +newzone_cfgctx_destroy(void **cfgp) { + ns_cfgctx_t *cfg; + + REQUIRE(cfgp != NULL && *cfgp != NULL); + + cfg = *cfgp; + + if (cfg->conf_parser != NULL) { + if (cfg->config != NULL) { + cfg_obj_destroy(cfg->conf_parser, &cfg->config); + } + if (cfg->vconfig != NULL) { + cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig); + } + cfg_parser_destroy(&cfg->conf_parser); + } + if (cfg->add_parser != NULL) { + if (cfg->nzf_config != NULL) { + cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config); + } + cfg_parser_destroy(&cfg->add_parser); + } + + if (cfg->actx != NULL) { + cfg_aclconfctx_detach(&cfg->actx); + } + + isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg)); + *cfgp = NULL; +} + +isc_result_t +named_server_signing(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result = ISC_R_SUCCESS; + dns_zone_t *zone = NULL; + dns_name_t *origin; + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + dns_dbversion_t *version = NULL; + dns_rdatatype_t privatetype; + dns_rdataset_t privset; + bool first = true; + bool list = false, clear = false; + bool chain = false; + bool setserial = false; + bool resalt = false; + uint32_t serial = 0; + char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/ */ + unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0; + unsigned char salt[255]; + const char *ptr; + size_t n; + + REQUIRE(text != NULL); + + dns_rdataset_init(&privset); + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Find out what we are to do. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + if (strcasecmp(ptr, "-list") == 0) { + list = true; + } else if ((strcasecmp(ptr, "-clear") == 0) || + (strcasecmp(ptr, "-clean") == 0)) + { + clear = true; + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + strlcpy(keystr, ptr, sizeof(keystr)); + } else if (strcasecmp(ptr, "-nsec3param") == 0) { + char hashbuf[64], flagbuf[64], iterbuf[64]; + char nbuf[256]; + + chain = true; + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + if (strcasecmp(ptr, "none") == 0) { + hash = 0; + } else { + strlcpy(hashbuf, ptr, sizeof(hashbuf)); + + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + strlcpy(flagbuf, ptr, sizeof(flagbuf)); + + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + strlcpy(iterbuf, ptr, sizeof(iterbuf)); + n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", hashbuf, + flagbuf, iterbuf); + if (n == sizeof(nbuf)) { + return (ISC_R_NOSPACE); + } + n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter); + if (n != 3U) { + return (ISC_R_BADNUMBER); + } + + if (hash > 0xffU || flags > 0xffU || + iter > dns_nsec3_maxiterations()) + { + return (ISC_R_RANGE); + } + + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } else if (strcasecmp(ptr, "auto") == 0) { + /* Auto-generate a random salt. + * XXXMUKS: This currently uses the + * minimum recommended length by RFC + * 5155 (64 bits). It should be made + * configurable. + */ + saltlen = 8; + resalt = true; + } else if (strcmp(ptr, "-") != 0) { + isc_buffer_t buf; + + isc_buffer_init(&buf, salt, sizeof(salt)); + CHECK(isc_hex_decodestring(ptr, &buf)); + saltlen = isc_buffer_usedlength(&buf); + } + } + } else if (strcasecmp(ptr, "-serial") == 0) { + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + CHECK(isc_parse_uint32(&serial, ptr, 10)); + setserial = true; + } else { + CHECK(DNS_R_SYNTAX); + } + + CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false)); + if (zone == NULL) { + CHECK(ISC_R_UNEXPECTEDEND); + } + + if (dns_zone_getkasp(zone) != NULL) { + (void)putstr(text, "zone uses dnssec-policy, use rndc dnssec " + "command instead"); + (void)putnull(text); + goto cleanup; + } + + if (clear) { + CHECK(dns_zone_keydone(zone, keystr)); + (void)putstr(text, "request queued"); + (void)putnull(text); + } else if (chain) { + CHECK(dns_zone_setnsec3param( + zone, (uint8_t)hash, (uint8_t)flags, iter, + (uint8_t)saltlen, salt, true, resalt)); + (void)putstr(text, "nsec3param request queued"); + (void)putnull(text); + } else if (setserial) { + CHECK(dns_zone_setserial(zone, serial)); + (void)putstr(text, "serial request queued"); + (void)putnull(text); + } else if (list) { + privatetype = dns_zone_getprivatetype(zone); + origin = dns_zone_getorigin(zone); + CHECK(dns_zone_getdb(zone, &db)); + CHECK(dns_db_findnode(db, origin, false, &node)); + dns_db_currentversion(db, &version); + + result = dns_db_findrdataset(db, node, version, privatetype, + dns_rdatatype_none, 0, &privset, + NULL); + if (result == ISC_R_NOTFOUND) { + (void)putstr(text, "No signing records found"); + (void)putnull(text); + result = ISC_R_SUCCESS; + goto cleanup; + } + + for (result = dns_rdataset_first(&privset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&privset)) + { + dns_rdata_t priv = DNS_RDATA_INIT; + /* + * In theory, the output buffer could hold a full RDATA + * record which is 16-bit and then some text around + * it + */ + char output[UINT16_MAX + BUFSIZ]; + isc_buffer_t buf; + + dns_rdataset_current(&privset, &priv); + + isc_buffer_init(&buf, output, sizeof(output)); + CHECK(dns_private_totext(&priv, &buf)); + if (!first) { + CHECK(putstr(text, "\n")); + } + CHECK(putstr(text, output)); + first = false; + } + if (!first) { + CHECK(putnull(text)); + } + + if (result == ISC_R_NOMORE) { + result = ISC_R_SUCCESS; + } + } + +cleanup: + if (dns_rdataset_isassociated(&privset)) { + dns_rdataset_disassociate(&privset); + } + if (node != NULL) { + dns_db_detachnode(db, &node); + } + if (version != NULL) { + dns_db_closeversion(db, &version, false); + } + if (db != NULL) { + dns_db_detach(&db); + } + if (zone != NULL) { + dns_zone_detach(&zone); + } + + return (result); +} + +static bool +argcheck(char *cmd, const char *full) { + size_t l; + + if (cmd == NULL || cmd[0] != '-') { + return (false); + } + + cmd++; + l = strlen(cmd); + if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) { + return (false); + } + + return (true); +} + +isc_result_t +named_server_dnssec(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result = ISC_R_SUCCESS; + dns_zone_t *zone = NULL; + dns_kasp_t *kasp = NULL; + dns_dnsseckeylist_t keys; + dns_dnsseckey_t *key; + char *ptr, *zonetext = NULL; + const char *msg = NULL; + /* variables for -checkds */ + bool checkds = false, dspublish = false; + /* variables for -rollover */ + bool rollover = false; + /* variables for -key */ + bool use_keyid = false; + dns_keytag_t keyid = 0; + uint8_t algorithm = 0; + /* variables for -status */ + bool status = false; + char output[4096]; + isc_stdtime_t now, when; + isc_time_t timenow, timewhen; + const char *dir; + dns_db_t *db = NULL; + dns_dbversion_t *version = NULL; + + REQUIRE(text != NULL); + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Find out what we are to do. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Initialize current time and key list. */ + TIME_NOW(&timenow); + now = isc_time_seconds(&timenow); + when = now; + + ISC_LIST_INIT(keys); + + if (strcasecmp(ptr, "-status") == 0) { + status = true; + } else if (strcasecmp(ptr, "-rollover") == 0) { + rollover = true; + } else if (strcasecmp(ptr, "-checkds") == 0) { + checkds = true; + } else { + CHECK(DNS_R_SYNTAX); + } + + if (rollover || checkds) { + /* Check for options */ + for (;;) { + ptr = next_token(lex, text); + if (ptr == NULL) { + msg = "Bad format"; + CHECK(ISC_R_UNEXPECTEDEND); + } else if (argcheck(ptr, "alg")) { + isc_consttextregion_t alg; + ptr = next_token(lex, text); + if (ptr == NULL) { + msg = "No key algorithm specified"; + CHECK(ISC_R_UNEXPECTEDEND); + } + alg.base = ptr; + alg.length = strlen(alg.base); + result = dns_secalg_fromtext( + &algorithm, (isc_textregion_t *)&alg); + if (result != ISC_R_SUCCESS) { + msg = "Bad algorithm"; + CHECK(DNS_R_SYNTAX); + } + continue; + } else if (argcheck(ptr, "key")) { + uint16_t id; + ptr = next_token(lex, text); + if (ptr == NULL) { + msg = "No key identifier specified"; + CHECK(ISC_R_UNEXPECTEDEND); + } + CHECK(isc_parse_uint16(&id, ptr, 10)); + keyid = (dns_keytag_t)id; + use_keyid = true; + continue; + } else if (argcheck(ptr, "when")) { + uint32_t tw; + ptr = next_token(lex, text); + if (ptr == NULL) { + msg = "No time specified"; + CHECK(ISC_R_UNEXPECTEDEND); + } + CHECK(dns_time32_fromtext(ptr, &tw)); + when = (isc_stdtime_t)tw; + continue; + } else if (ptr[0] == '-') { + msg = "Unknown option"; + CHECK(DNS_R_SYNTAX); + } else if (checkds) { + /* + * No arguments provided, so we must be + * parsing "published|withdrawn". + */ + if (strcasecmp(ptr, "published") == 0) { + dspublish = true; + } else if (strcasecmp(ptr, "withdrawn") != 0) { + CHECK(DNS_R_SYNTAX); + } + } else if (rollover) { + /* + * No arguments provided, so we must be + * parsing the zone. + */ + zonetext = ptr; + } + break; + } + + if (rollover && !use_keyid) { + msg = "Key id is required when scheduling rollover"; + CHECK(DNS_R_SYNTAX); + } + + if (algorithm > 0 && !use_keyid) { + msg = "Key id is required when setting algorithm"; + CHECK(DNS_R_SYNTAX); + } + } + + /* Get zone. */ + CHECK(zone_from_args(server, lex, zonetext, &zone, NULL, text, false)); + if (zone == NULL) { + msg = "Zone not found"; + CHECK(ISC_R_UNEXPECTEDEND); + } + + /* Trailing garbage? */ + ptr = next_token(lex, text); + if (ptr != NULL) { + msg = "Too many arguments"; + CHECK(DNS_R_SYNTAX); + } + + /* Get dnssec-policy. */ + kasp = dns_zone_getkasp(zone); + if (kasp == NULL) { + msg = "Zone does not have dnssec-policy"; + goto cleanup; + } + + /* Get DNSSEC keys. */ + dir = dns_zone_getkeydirectory(zone); + CHECK(dns_zone_getdb(zone, &db)); + dns_db_currentversion(db, &version); + LOCK(&kasp->lock); + result = dns_zone_getdnsseckeys(zone, db, version, now, &keys); + UNLOCK(&kasp->lock); + if (result != ISC_R_SUCCESS) { + if (result != ISC_R_NOTFOUND) { + goto cleanup; + } + } + + if (status) { + /* + * Output the DNSSEC status of the key and signing policy. + */ + LOCK(&kasp->lock); + dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output)); + UNLOCK(&kasp->lock); + CHECK(putstr(text, output)); + } else if (checkds) { + /* + * Mark DS record has been seen, so it may move to the + * rumoured state. + */ + char whenbuf[80]; + isc_time_set(&timewhen, when, 0); + isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf)); + isc_result_t ret; + + LOCK(&kasp->lock); + if (use_keyid) { + result = dns_keymgr_checkds_id(kasp, &keys, dir, now, + when, dspublish, keyid, + (unsigned int)algorithm); + } else { + result = dns_keymgr_checkds(kasp, &keys, dir, now, when, + dspublish); + } + UNLOCK(&kasp->lock); + + switch (result) { + case ISC_R_SUCCESS: + /* + * Rekey after checkds command because the next key + * event may have changed. + */ + dns_zone_rekey(zone, false); + + if (use_keyid) { + char tagbuf[6]; + snprintf(tagbuf, sizeof(tagbuf), "%u", keyid); + CHECK(putstr(text, "KSK ")); + CHECK(putstr(text, tagbuf)); + CHECK(putstr(text, ": ")); + } + CHECK(putstr(text, "Marked DS as ")); + if (dspublish) { + CHECK(putstr(text, "published ")); + } else { + CHECK(putstr(text, "withdrawn ")); + } + CHECK(putstr(text, "since ")); + CHECK(putstr(text, whenbuf)); + break; + case DNS_R_TOOMANYKEYS: + CHECK(putstr(text, + "Error: multiple possible keys found, " + "retry command with -key id")); + break; + default: + ret = result; + CHECK(putstr(text, + "Error executing checkds command: ")); + CHECK(putstr(text, isc_result_totext(ret))); + break; + } + } else if (rollover) { + /* + * Manually rollover a key. + */ + char whenbuf[80]; + isc_time_set(&timewhen, when, 0); + isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf)); + isc_result_t ret; + + LOCK(&kasp->lock); + result = dns_keymgr_rollover(kasp, &keys, dir, now, when, keyid, + (unsigned int)algorithm); + UNLOCK(&kasp->lock); + + switch (result) { + case ISC_R_SUCCESS: + /* + * Rekey after rollover command because the next key + * event may have changed. + */ + dns_zone_rekey(zone, false); + + if (use_keyid) { + char tagbuf[6]; + snprintf(tagbuf, sizeof(tagbuf), "%u", keyid); + CHECK(putstr(text, "Key ")); + CHECK(putstr(text, tagbuf)); + CHECK(putstr(text, ": ")); + } + CHECK(putstr(text, "Rollover scheduled on ")); + CHECK(putstr(text, whenbuf)); + break; + case DNS_R_TOOMANYKEYS: + CHECK(putstr(text, + "Error: multiple possible keys found, " + "retry command with -alg algorithm")); + break; + default: + ret = result; + CHECK(putstr(text, + "Error executing rollover command: ")); + CHECK(putstr(text, isc_result_totext(ret))); + break; + } + } + CHECK(putnull(text)); + +cleanup: + if (msg != NULL) { + (void)putstr(text, msg); + (void)putnull(text); + } + + if (version != NULL) { + dns_db_closeversion(db, &version, false); + } + if (db != NULL) { + dns_db_detach(&db); + } + + while (!ISC_LIST_EMPTY(keys)) { + key = ISC_LIST_HEAD(keys); + ISC_LIST_UNLINK(keys, key, link); + dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key); + } + + if (zone != NULL) { + dns_zone_detach(&zone); + } + + return (result); +} + +static isc_result_t +putmem(isc_buffer_t **b, const char *str, size_t len) { + isc_result_t result; + + result = isc_buffer_reserve(b, (unsigned int)len); + if (result != ISC_R_SUCCESS) { + return (ISC_R_NOSPACE); + } + + isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len); + return (ISC_R_SUCCESS); +} + +static isc_result_t +putstr(isc_buffer_t **b, const char *str) { + return (putmem(b, str, strlen(str))); +} + +static isc_result_t +putuint8(isc_buffer_t **b, uint8_t val) { + isc_result_t result; + + result = isc_buffer_reserve(b, 1); + if (result != ISC_R_SUCCESS) { + return (ISC_R_NOSPACE); + } + + isc_buffer_putuint8(*b, val); + return (ISC_R_SUCCESS); +} + +static isc_result_t +putnull(isc_buffer_t **b) { + return (putuint8(b, 0)); +} + +isc_result_t +named_server_zonestatus(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result = ISC_R_SUCCESS; + dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL; + const char *type, *file; + char zonename[DNS_NAME_FORMATSIZE]; + uint32_t serial, signed_serial, nodes; + char serbuf[16], sserbuf[16], nodebuf[16]; + char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2]; + char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE]; + char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE]; + char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE]; + char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE]; + char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE]; + isc_time_t loadtime, expiretime, refreshtime; + isc_time_t refreshkeytime, resigntime; + dns_zonetype_t zonetype; + bool dynamic = false, frozen = false; + bool hasraw = false; + bool secure, maintain, allow; + dns_db_t *db = NULL, *rawdb = NULL; + char **incfiles = NULL; + int nfiles = 0; + + REQUIRE(text != NULL); + + isc_time_settoepoch(&loadtime); + isc_time_settoepoch(&refreshtime); + isc_time_settoepoch(&expiretime); + isc_time_settoepoch(&refreshkeytime); + isc_time_settoepoch(&resigntime); + + CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true)); + if (zone == NULL) { + result = ISC_R_UNEXPECTEDEND; + goto cleanup; + } + + /* Inline signing? */ + CHECK(dns_zone_getdb(zone, &db)); + dns_zone_getraw(zone, &raw); + hasraw = (raw != NULL); + if (hasraw) { + mayberaw = raw; + zonetype = dns_zone_gettype(raw); + CHECK(dns_zone_getdb(raw, &rawdb)); + } else { + mayberaw = zone; + zonetype = dns_zone_gettype(zone); + } + + type = dns_zonetype_name(zonetype); + + /* Serial number */ + result = dns_zone_getserial(mayberaw, &serial); + + /* This is to mirror old behavior with dns_zone_getserial */ + if (result != ISC_R_SUCCESS) { + serial = 0; + } + + snprintf(serbuf, sizeof(serbuf), "%u", serial); + if (hasraw) { + result = dns_zone_getserial(zone, &signed_serial); + if (result != ISC_R_SUCCESS) { + serial = 0; + } + snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial); + } + + /* Database node count */ + nodes = dns_db_nodecount(hasraw ? rawdb : db); + snprintf(nodebuf, sizeof(nodebuf), "%u", nodes); + + /* Security */ + secure = dns_db_issecure(db); + allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0); + maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0); + + /* Master files */ + file = dns_zone_getfile(mayberaw); + nfiles = dns_zone_getincludes(mayberaw, &incfiles); + + /* Load time */ + dns_zone_getloadtime(zone, &loadtime); + isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf)); + + /* Refresh/expire times */ + if (zonetype == dns_zone_secondary || zonetype == dns_zone_mirror || + zonetype == dns_zone_stub || zonetype == dns_zone_redirect) + { + dns_zone_getexpiretime(mayberaw, &expiretime); + isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf)); + dns_zone_getrefreshtime(mayberaw, &refreshtime); + isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf)); + } + + /* Key refresh time */ + if (zonetype == dns_zone_primary || + (zonetype == dns_zone_secondary && hasraw)) + { + dns_zone_getrefreshkeytime(zone, &refreshkeytime); + isc_time_formathttptimestamp(&refreshkeytime, kbuf, + sizeof(kbuf)); + } + + /* Dynamic? */ + if (zonetype == dns_zone_primary) { + dynamic = dns_zone_isdynamic(mayberaw, true); + frozen = dynamic && !dns_zone_isdynamic(mayberaw, false); + } + + /* Next resign event */ + if (secure && + (zonetype == dns_zone_primary || + (zonetype == dns_zone_secondary && hasraw)) && + ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0)) + { + dns_name_t *name; + dns_fixedname_t fixed; + dns_rdataset_t next; + + dns_rdataset_init(&next); + name = dns_fixedname_initname(&fixed); + + result = dns_db_getsigningtime(db, &next, name); + if (result == ISC_R_SUCCESS) { + isc_stdtime_t timenow; + char namebuf[DNS_NAME_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + + isc_stdtime_get(&timenow); + dns_name_format(name, namebuf, sizeof(namebuf)); + dns_rdatatype_format(next.covers, typebuf, + sizeof(typebuf)); + snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf, + typebuf); + isc_time_set( + &resigntime, + next.resign - + dns_zone_getsigresigninginterval(zone), + 0); + isc_time_formathttptimestamp(&resigntime, rtbuf, + sizeof(rtbuf)); + dns_rdataset_disassociate(&next); + } + } + + /* Create text */ + CHECK(putstr(text, "name: ")); + CHECK(putstr(text, zonename)); + + CHECK(putstr(text, "\ntype: ")); + CHECK(putstr(text, type)); + + if (file != NULL) { + int i; + CHECK(putstr(text, "\nfiles: ")); + CHECK(putstr(text, file)); + for (i = 0; i < nfiles; i++) { + CHECK(putstr(text, ", ")); + if (incfiles[i] != NULL) { + CHECK(putstr(text, incfiles[i])); + } + } + } + + CHECK(putstr(text, "\nserial: ")); + CHECK(putstr(text, serbuf)); + if (hasraw) { + CHECK(putstr(text, "\nsigned serial: ")); + CHECK(putstr(text, sserbuf)); + } + + CHECK(putstr(text, "\nnodes: ")); + CHECK(putstr(text, nodebuf)); + + if (!isc_time_isepoch(&loadtime)) { + CHECK(putstr(text, "\nlast loaded: ")); + CHECK(putstr(text, lbuf)); + } + + if (!isc_time_isepoch(&refreshtime)) { + CHECK(putstr(text, "\nnext refresh: ")); + CHECK(putstr(text, rbuf)); + } + + if (!isc_time_isepoch(&expiretime)) { + CHECK(putstr(text, "\nexpires: ")); + CHECK(putstr(text, xbuf)); + } + + if (secure) { + CHECK(putstr(text, "\nsecure: yes")); + if (hasraw) { + CHECK(putstr(text, "\ninline signing: yes")); + } else { + CHECK(putstr(text, "\ninline signing: no")); + } + } else { + CHECK(putstr(text, "\nsecure: no")); + } + + if (maintain) { + CHECK(putstr(text, "\nkey maintenance: automatic")); + if (!isc_time_isepoch(&refreshkeytime)) { + CHECK(putstr(text, "\nnext key event: ")); + CHECK(putstr(text, kbuf)); + } + } else if (allow) { + CHECK(putstr(text, "\nkey maintenance: on command")); + } else if (secure || hasraw) { + CHECK(putstr(text, "\nkey maintenance: none")); + } + + if (!isc_time_isepoch(&resigntime)) { + CHECK(putstr(text, "\nnext resign node: ")); + CHECK(putstr(text, resignbuf)); + CHECK(putstr(text, "\nnext resign time: ")); + CHECK(putstr(text, rtbuf)); + } + + if (dynamic) { + CHECK(putstr(text, "\ndynamic: yes")); + if (frozen) { + CHECK(putstr(text, "\nfrozen: yes")); + } else { + CHECK(putstr(text, "\nfrozen: no")); + } + } else { + CHECK(putstr(text, "\ndynamic: no")); + } + + CHECK(putstr(text, "\nreconfigurable via modzone: ")); + CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no")); + +cleanup: + /* Indicate truncated output if possible. */ + if (result == ISC_R_NOSPACE) { + (void)putstr(text, "\n..."); + } + if ((result == ISC_R_SUCCESS || result == ISC_R_NOSPACE)) { + (void)putnull(text); + } + + if (db != NULL) { + dns_db_detach(&db); + } + if (rawdb != NULL) { + dns_db_detach(&rawdb); + } + if (incfiles != NULL && mayberaw != NULL) { + int i; + isc_mem_t *mctx = dns_zone_getmctx(mayberaw); + + for (i = 0; i < nfiles; i++) { + if (incfiles[i] != NULL) { + isc_mem_free(mctx, incfiles[i]); + } + } + isc_mem_free(mctx, incfiles); + } + if (raw != NULL) { + dns_zone_detach(&raw); + } + if (zone != NULL) { + dns_zone_detach(&zone); + } + return (result); +} + +isc_result_t +named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly, + isc_buffer_t **text) { + dns_view_t *view; + dns_ntatable_t *ntatable = NULL; + isc_result_t result = ISC_R_SUCCESS; + char *ptr, *nametext = NULL, *viewname; + char namebuf[DNS_NAME_FORMATSIZE]; + char viewbuf[DNS_NAME_FORMATSIZE]; + isc_stdtime_t now, when; + isc_time_t t; + char tbuf[64]; + const char *msg = NULL; + bool dump = false, force = false; + dns_fixedname_t fn; + const dns_name_t *ntaname; + dns_name_t *fname; + dns_ttl_t ntattl; + bool ttlset = false, excl = false, viewfound = false; + dns_rdataclass_t rdclass = dns_rdataclass_in; + bool first = true; + + REQUIRE(text != NULL); + + UNUSED(force); + + fname = dns_fixedname_initname(&fn); + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + for (;;) { + /* Check for options */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + if (strcmp(ptr, "--") == 0) { + break; + } else if (argcheck(ptr, "dump")) { + dump = true; + } else if (argcheck(ptr, "remove")) { + ntattl = 0; + ttlset = true; + } else if (argcheck(ptr, "force")) { + force = true; + continue; + } else if (argcheck(ptr, "lifetime")) { + isc_textregion_t tr; + + ptr = next_token(lex, text); + if (ptr == NULL) { + msg = "No lifetime specified"; + CHECK(ISC_R_UNEXPECTEDEND); + } + + tr.base = ptr; + tr.length = strlen(ptr); + result = dns_ttl_fromtext(&tr, &ntattl); + if (result != ISC_R_SUCCESS) { + msg = "could not parse NTA lifetime"; + CHECK(result); + } + + if (ntattl > 604800) { + msg = "NTA lifetime cannot exceed one week"; + CHECK(ISC_R_RANGE); + } + + ttlset = true; + continue; + } else if (argcheck(ptr, "class")) { + isc_textregion_t tr; + + ptr = next_token(lex, text); + if (ptr == NULL) { + msg = "No class specified"; + CHECK(ISC_R_UNEXPECTEDEND); + } + + tr.base = ptr; + tr.length = strlen(ptr); + CHECK(dns_rdataclass_fromtext(&rdclass, &tr)); + continue; + } else if (ptr[0] == '-') { + msg = "Unknown option"; + CHECK(DNS_R_SYNTAX); + } else { + nametext = ptr; + } + + break; + } + + /* + * If -dump was specified, list NTA's and return + */ + if (dump) { + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (ntatable != NULL) { + dns_ntatable_detach(&ntatable); + } + result = dns_view_getntatable(view, &ntatable); + if (result == ISC_R_NOTFOUND) { + continue; + } + + CHECK(dns_ntatable_totext(ntatable, view->name, text)); + } + CHECK(putnull(text)); + + goto cleanup; + } + + if (readonly) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO, + "rejecting restricted control channel " + "NTA command"); + CHECK(ISC_R_FAILURE); + } + + /* Get the NTA name if not found above. */ + if (nametext == NULL) { + nametext = next_token(lex, text); + } + if (nametext == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Copy nametext as it'll be overwritten by next_token() */ + strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE); + + if (strcmp(namebuf, ".") == 0) { + ntaname = dns_rootname; + } else { + isc_buffer_t b; + isc_buffer_init(&b, namebuf, strlen(namebuf)); + isc_buffer_add(&b, strlen(namebuf)); + CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL)); + ntaname = fname; + } + + /* Look for the view name. */ + viewname = next_token(lex, text); + if (viewname != NULL) { + strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE); + viewname = viewbuf; + } + + if (next_token(lex, text) != NULL) { + CHECK(DNS_R_SYNTAX); + } + + isc_stdtime_get(&now); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + excl = true; + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (viewname != NULL && strcmp(view->name, viewname) != 0) { + continue; + } + viewfound = true; + + if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) { + continue; + } + + if (view->nta_lifetime == 0) { + continue; + } + + if (!ttlset) { + ntattl = view->nta_lifetime; + } + + if (ntatable != NULL) { + dns_ntatable_detach(&ntatable); + } + + result = dns_view_getntatable(view, &ntatable); + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + continue; + } + + result = dns_view_flushnode(view, ntaname, true); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "flush tree '%s' in cache view '%s': %s", namebuf, + view->name, isc_result_totext(result)); + + if (ntattl != 0) { + CHECK(dns_ntatable_add(ntatable, ntaname, force, now, + ntattl)); + + when = now + ntattl; + isc_time_set(&t, when, 0); + isc_time_formattimestamp(&t, tbuf, sizeof(tbuf)); + + if (!first) { + CHECK(putstr(text, "\n")); + } + first = false; + + CHECK(putstr(text, "Negative trust anchor added: ")); + CHECK(putstr(text, namebuf)); + CHECK(putstr(text, "/")); + CHECK(putstr(text, view->name)); + CHECK(putstr(text, ", expires ")); + CHECK(putstr(text, tbuf)); + + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "added NTA '%s' (%d sec) in view '%s'", + namebuf, ntattl, view->name); + } else { + bool wasremoved; + + result = dns_ntatable_delete(ntatable, ntaname); + if (result == ISC_R_SUCCESS) { + wasremoved = true; + } else if (result == ISC_R_NOTFOUND) { + wasremoved = false; + } else { + goto cleanup; + } + + if (!first) { + CHECK(putstr(text, "\n")); + } + first = false; + + CHECK(putstr(text, "Negative trust anchor ")); + CHECK(putstr(text, + wasremoved ? "removed: " : "not found: ")); + CHECK(putstr(text, namebuf)); + CHECK(putstr(text, "/")); + CHECK(putstr(text, view->name)); + + if (wasremoved) { + isc_log_write( + named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, + "removed NTA '%s' in view %s", namebuf, + view->name); + } + } + + result = dns_view_saventa(view); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "error writing NTA file " + "for view '%s': %s", + view->name, isc_result_totext(result)); + } + } + + if (!viewfound) { + msg = "No such view"; + CHECK(ISC_R_NOTFOUND); + } + + (void)putnull(text); + +cleanup: + if (msg != NULL) { + (void)putstr(text, msg); + (void)putnull(text); + } + + if (excl) { + isc_task_endexclusive(server->task); + } + if (ntatable != NULL) { + dns_ntatable_detach(&ntatable); + } + return (result); +} + +isc_result_t +named_server_saventa(named_server_t *server) { + dns_view_t *view; + + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + isc_result_t result = dns_view_saventa(view); + + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "error writing NTA file " + "for view '%s': %s", + view->name, isc_result_totext(result)); + } + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +named_server_loadnta(named_server_t *server) { + dns_view_t *view; + + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + isc_result_t result = dns_view_loadnta(view); + + if ((result != ISC_R_SUCCESS) && + (result != ISC_R_FILENOTFOUND) && + (result != ISC_R_NOTFOUND)) + { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "error loading NTA file " + "for view '%s': %s", + view->name, isc_result_totext(result)); + } + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +mkey_refresh(dns_view_t *view, isc_buffer_t **text) { + isc_result_t result; + char msg[DNS_NAME_FORMATSIZE + 500] = ""; + + snprintf(msg, sizeof(msg), "refreshing managed keys for '%s'", + view->name); + CHECK(putstr(text, msg)); + CHECK(dns_zone_synckeyzone(view->managed_keys)); + +cleanup: + return (result); +} + +static isc_result_t +mkey_destroy(named_server_t *server, dns_view_t *view, isc_buffer_t **text) { + isc_result_t result; + char msg[DNS_NAME_FORMATSIZE + 500] = ""; + bool exclusive = false; + const char *file = NULL; + dns_db_t *dbp = NULL; + dns_zone_t *mkzone = NULL; + bool removed_a_file = false; + + if (view->managed_keys == NULL) { + CHECK(ISC_R_NOTFOUND); + } + + snprintf(msg, sizeof(msg), "destroying managed-keys database for '%s'", + view->name); + CHECK(putstr(text, msg)); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + exclusive = true; + + /* Remove and clean up managed keys zone from view */ + mkzone = view->managed_keys; + view->managed_keys = NULL; + (void)dns_zone_flush(mkzone); + + /* Unload zone database */ + if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) { + dns_db_detach(&dbp); + dns_zone_unload(mkzone); + } + + /* Delete files */ + file = dns_zone_getfile(mkzone); + result = isc_file_remove(file); + if (result == ISC_R_SUCCESS) { + removed_a_file = true; + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "file %s not removed: %s", file, + isc_result_totext(result)); + } + + file = dns_zone_getjournal(mkzone); + result = isc_file_remove(file); + if (result == ISC_R_SUCCESS) { + removed_a_file = true; + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "file %s not removed: %s", file, + isc_result_totext(result)); + } + + if (!removed_a_file) { + CHECK(putstr(text, "error: no files could be removed")); + CHECK(ISC_R_FAILURE); + } + + dns_zone_detach(&mkzone); + result = ISC_R_SUCCESS; + +cleanup: + if (exclusive) { + isc_task_endexclusive(server->task); + } + return (result); +} + +static isc_result_t +mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) { + isc_result_t result; + dns_db_t *db = NULL; + dns_dbversion_t *ver = NULL; + dns_rriterator_t rrit; + isc_stdtime_t now; + dns_name_t *prevname = NULL; + + isc_stdtime_get(&now); + + CHECK(dns_zone_getdb(view->managed_keys, &db)); + dns_db_currentversion(db, &ver); + dns_rriterator_init(&rrit, db, ver, 0); + for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS; + result = dns_rriterator_nextrrset(&rrit)) + { + char buf[DNS_NAME_FORMATSIZE + 500]; + dns_name_t *name = NULL; + dns_rdataset_t *kdset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_keydata_t kd; + uint32_t ttl; + + dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL); + if (kdset == NULL || kdset->type != dns_rdatatype_keydata || + !dns_rdataset_isassociated(kdset)) + { + continue; + } + + if (name != prevname) { + char nbuf[DNS_NAME_FORMATSIZE]; + dns_name_format(name, nbuf, sizeof(nbuf)); + snprintf(buf, sizeof(buf), "\n\n name: %s", nbuf); + CHECK(putstr(text, buf)); + } + + for (result = dns_rdataset_first(kdset); + result == ISC_R_SUCCESS; result = dns_rdataset_next(kdset)) + { + char alg[DNS_SECALG_FORMATSIZE]; + char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE]; + dns_keytag_t keyid; + isc_region_t r; + isc_time_t t; + bool revoked; + + dns_rdata_reset(&rdata); + dns_rdataset_current(kdset, &rdata); + result = dns_rdata_tostruct(&rdata, &kd, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + dns_rdata_toregion(&rdata, &r); + isc_region_consume(&r, 12); + keyid = dst_region_computeid(&r); + + snprintf(buf, sizeof(buf), "\n keyid: %u", keyid); + CHECK(putstr(text, buf)); + + dns_secalg_format(kd.algorithm, alg, sizeof(alg)); + snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg); + CHECK(putstr(text, buf)); + + revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0); + snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s", + revoked ? " REVOKE" : "", + ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP" + : "", + (kd.flags == 0) ? " (none)" : ""); + CHECK(putstr(text, buf)); + + isc_time_set(&t, kd.refresh, 0); + isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf)); + snprintf(buf, sizeof(buf), "\n\tnext refresh: %s", + tbuf); + CHECK(putstr(text, buf)); + + if (kd.removehd != 0) { + isc_time_set(&t, kd.removehd, 0); + isc_time_formathttptimestamp(&t, tbuf, + sizeof(tbuf)); + snprintf(buf, sizeof(buf), "\n\tremove at: %s", + tbuf); + CHECK(putstr(text, buf)); + } + + isc_time_set(&t, kd.addhd, 0); + isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf)); + if (kd.addhd == 0) { + snprintf(buf, sizeof(buf), "\n\tno trust"); + } else if (revoked) { + snprintf(buf, sizeof(buf), "\n\ttrust revoked"); + } else if (kd.addhd <= now) { + snprintf(buf, sizeof(buf), + "\n\ttrusted since: %s", tbuf); + } else if (kd.addhd > now) { + snprintf(buf, sizeof(buf), + "\n\ttrust pending: %s", tbuf); + } + CHECK(putstr(text, buf)); + } + } + + if (result == ISC_R_NOMORE) { + result = ISC_R_SUCCESS; + } + +cleanup: + if (ver != NULL) { + dns_rriterator_destroy(&rrit); + dns_db_closeversion(db, &ver, false); + } + if (db != NULL) { + dns_db_detach(&db); + } + + return (result); +} + +static isc_result_t +mkey_status(dns_view_t *view, isc_buffer_t **text) { + isc_result_t result; + char msg[ISC_FORMATHTTPTIMESTAMP_SIZE]; + isc_time_t t; + + CHECK(putstr(text, "view: ")); + CHECK(putstr(text, view->name)); + + CHECK(putstr(text, "\nnext scheduled event: ")); + + dns_zone_getrefreshkeytime(view->managed_keys, &t); + if (isc_time_isepoch(&t)) { + CHECK(putstr(text, "never")); + } else { + isc_time_formathttptimestamp(&t, msg, sizeof(msg)); + CHECK(putstr(text, msg)); + } + + CHECK(mkey_dumpzone(view, text)); + +cleanup: + return (result); +} + +isc_result_t +named_server_mkeys(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + char *cmd, *classtxt, *viewtxt = NULL; + isc_result_t result = ISC_R_SUCCESS; + dns_view_t *view = NULL; + dns_rdataclass_t rdclass; + char msg[DNS_NAME_FORMATSIZE + 500] = ""; + enum { NONE, STATUS, REFRESH, SYNC, DESTROY } opt = NONE; + bool found = false; + bool first = true; + + REQUIRE(text != NULL); + + /* Skip rndc command name */ + cmd = next_token(lex, text); + if (cmd == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Get managed-keys subcommand */ + cmd = next_token(lex, text); + if (cmd == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + if (strcasecmp(cmd, "status") == 0) { + opt = STATUS; + } else if (strcasecmp(cmd, "refresh") == 0) { + opt = REFRESH; + } else if (strcasecmp(cmd, "sync") == 0) { + opt = SYNC; + } else if (strcasecmp(cmd, "destroy") == 0) { + opt = DESTROY; + } else { + snprintf(msg, sizeof(msg), "unknown command '%s'", cmd); + (void)putstr(text, msg); + result = ISC_R_UNEXPECTED; + goto cleanup; + } + + /* Look for the optional class name. */ + classtxt = next_token(lex, text); + if (classtxt != NULL) { + isc_textregion_t r; + r.base = classtxt; + r.length = strlen(classtxt); + result = dns_rdataclass_fromtext(&rdclass, &r); + if (result != ISC_R_SUCCESS) { + snprintf(msg, sizeof(msg), "unknown class '%s'", + classtxt); + (void)putstr(text, msg); + goto cleanup; + } + viewtxt = next_token(lex, text); + } + + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (viewtxt != NULL && (rdclass != view->rdclass || + strcmp(view->name, viewtxt) != 0)) + { + continue; + } + + if (view->managed_keys == NULL) { + if (viewtxt != NULL) { + snprintf(msg, sizeof(msg), + "view '%s': no managed keys", viewtxt); + CHECK(putstr(text, msg)); + goto cleanup; + } else { + continue; + } + } + + found = true; + + switch (opt) { + case REFRESH: + if (!first) { + CHECK(putstr(text, "\n")); + } + CHECK(mkey_refresh(view, text)); + break; + case STATUS: + if (!first) { + CHECK(putstr(text, "\n\n")); + } + CHECK(mkey_status(view, text)); + break; + case SYNC: + CHECK(dns_zone_flush(view->managed_keys)); + break; + case DESTROY: + if (!first) { + CHECK(putstr(text, "\n")); + } + CHECK(mkey_destroy(server, view, text)); + break; + default: + UNREACHABLE(); + } + + if (viewtxt != NULL) { + break; + } + first = false; + } + + if (!found) { + CHECK(putstr(text, "no views with managed keys")); + } + +cleanup: + if (isc_buffer_usedlength(*text) > 0) { + (void)putnull(text); + } + + return (result); +} + +isc_result_t +named_server_dnstap(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { +#ifdef HAVE_DNSTAP + char *ptr; + isc_result_t result; + bool reopen = false; + int backups = 0; + + REQUIRE(text != NULL); + + if (server->dtenv == NULL) { + return (ISC_R_NOTFOUND); + } + + /* Check the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* "dnstap-reopen" was used in 9.11.0b1 */ + if (strcasecmp(ptr, "dnstap-reopen") == 0) { + reopen = true; + } else { + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + } + + if (reopen || strcasecmp(ptr, "-reopen") == 0) { + backups = ISC_LOG_ROLLNEVER; + } else if ((strcasecmp(ptr, "-roll") == 0)) { + unsigned int n; + ptr = next_token(lex, text); + if (ptr != NULL) { + unsigned int u; + n = sscanf(ptr, "%u", &u); + if (n != 1U || u > INT_MAX) { + return (ISC_R_BADNUMBER); + } + backups = u; + } else { + backups = ISC_LOG_ROLLINFINITE; + } + } else { + return (DNS_R_SYNTAX); + } + + result = dns_dt_reopen(server->dtenv, backups); + return (result); +#else /* ifdef HAVE_DNSTAP */ + UNUSED(server); + UNUSED(lex); + UNUSED(text); + return (ISC_R_NOTIMPLEMENTED); +#endif /* ifdef HAVE_DNSTAP */ +} + +isc_result_t +named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) { + char *ptr; + isc_result_t result = ISC_R_SUCCESS; + uint32_t initial, idle, keepalive, advertised; + char msg[128]; + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + isc_nm_gettimeouts(named_g_nm, &initial, &idle, &keepalive, + &advertised); + + /* Look for optional arguments. */ + ptr = next_token(lex, NULL); + if (ptr != NULL) { + CHECK(isc_parse_uint32(&initial, ptr, 10)); + initial *= 100; + if (initial > MAX_INITIAL_TIMEOUT) { + CHECK(ISC_R_RANGE); + } + if (initial < MIN_INITIAL_TIMEOUT) { + CHECK(ISC_R_RANGE); + } + + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + CHECK(isc_parse_uint32(&idle, ptr, 10)); + idle *= 100; + if (idle > MAX_IDLE_TIMEOUT) { + CHECK(ISC_R_RANGE); + } + if (idle < MIN_IDLE_TIMEOUT) { + CHECK(ISC_R_RANGE); + } + + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + CHECK(isc_parse_uint32(&keepalive, ptr, 10)); + keepalive *= 100; + if (keepalive > MAX_KEEPALIVE_TIMEOUT) { + CHECK(ISC_R_RANGE); + } + if (keepalive < MIN_KEEPALIVE_TIMEOUT) { + CHECK(ISC_R_RANGE); + } + + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + CHECK(isc_parse_uint32(&advertised, ptr, 10)); + advertised *= 100; + if (advertised > MAX_ADVERTISED_TIMEOUT) { + CHECK(ISC_R_RANGE); + } + + result = isc_task_beginexclusive(named_g_server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + isc_nm_settimeouts(named_g_nm, initial, idle, keepalive, + advertised); + + isc_task_endexclusive(named_g_server->task); + } + + snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100); + CHECK(putstr(text, msg)); + snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100); + CHECK(putstr(text, msg)); + snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n", + keepalive / 100); + CHECK(putstr(text, msg)); + snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u", + advertised / 100); + CHECK(putstr(text, msg)); + +cleanup: + if (isc_buffer_usedlength(*text) > 0) { + (void)putnull(text); + } + + return (result); +} + +isc_result_t +named_server_servestale(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + char *ptr, *classtxt, *viewtxt = NULL; + char msg[128]; + dns_rdataclass_t rdclass = dns_rdataclass_in; + dns_view_t *view; + bool found = false; + dns_stale_answer_t staleanswersok = dns_stale_answer_conf; + bool wantstatus = false; + isc_result_t result = ISC_R_SUCCESS; + bool exclusive = false; + + REQUIRE(text != NULL); + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + ptr = next_token(lex, NULL); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || + !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) + { + staleanswersok = dns_stale_answer_yes; + } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || + !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) + { + staleanswersok = dns_stale_answer_no; + } else if (strcasecmp(ptr, "reset") == 0) { + staleanswersok = dns_stale_answer_conf; + } else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) { + wantstatus = true; + } else { + return (DNS_R_SYNTAX); + } + + /* Look for the optional class name. */ + classtxt = next_token(lex, text); + if (classtxt != NULL) { + isc_textregion_t r; + + /* Look for the optional view name. */ + viewtxt = next_token(lex, text); + + /* + * If 'classtext' is not a valid class then it us a view name. + */ + r.base = classtxt; + r.length = strlen(classtxt); + result = dns_rdataclass_fromtext(&rdclass, &r); + if (result != ISC_R_SUCCESS) { + if (viewtxt != NULL) { + snprintf(msg, sizeof(msg), "unknown class '%s'", + classtxt); + (void)putstr(text, msg); + goto cleanup; + } + + viewtxt = classtxt; + classtxt = NULL; + } + } + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + exclusive = true; + + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + dns_ttl_t stale_ttl = 0; + uint32_t stale_refresh = 0; + dns_db_t *db = NULL; + + if (classtxt != NULL && rdclass != view->rdclass) { + continue; + } + + if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0) { + continue; + } + + if (!wantstatus) { + view->staleanswersok = staleanswersok; + found = true; + continue; + } + + db = NULL; + dns_db_attach(view->cachedb, &db); + (void)dns_db_getservestalettl(db, &stale_ttl); + (void)dns_db_getservestalerefresh(db, &stale_refresh); + dns_db_detach(&db); + if (found) { + CHECK(putstr(text, "\n")); + } + CHECK(putstr(text, view->name)); + CHECK(putstr(text, ": ")); + switch (view->staleanswersok) { + case dns_stale_answer_yes: + if (stale_ttl > 0) { + CHECK(putstr(text, "on (rndc)")); + } else { + CHECK(putstr(text, "off (not-cached)")); + } + break; + case dns_stale_answer_no: + CHECK(putstr(text, "off (rndc)")); + break; + case dns_stale_answer_conf: + if (view->staleanswersenable && stale_ttl > 0) { + CHECK(putstr(text, "on")); + } else if (view->staleanswersenable) { + CHECK(putstr(text, "off (not-cached)")); + } else { + CHECK(putstr(text, "off")); + } + break; + } + if (stale_ttl > 0) { + snprintf(msg, sizeof(msg), + " (stale-answer-ttl=%u max-stale-ttl=%u " + "stale-refresh-time=%u)", + view->staleanswerttl, stale_ttl, + stale_refresh); + CHECK(putstr(text, msg)); + } + found = true; + } + + if (!found) { + result = ISC_R_NOTFOUND; + } + +cleanup: + if (exclusive) { + isc_task_endexclusive(named_g_server->task); + } + + if (isc_buffer_usedlength(*text) > 0) { + (void)putnull(text); + } + + return (result); +} diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c new file mode 100644 index 0000000..ff3deab --- /dev/null +++ b/bin/named/statschannel.c @@ -0,0 +1,4224 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#if HAVE_JSON_C +#include +#include +#endif /* HAVE_JSON_C */ + +#if HAVE_LIBXML2 +#include +#define ISC_XMLCHAR (const xmlChar *) +#endif /* HAVE_LIBXML2 */ + +#include "bind9.xsl.h" + +#define CHECK(m) \ + do { \ + result = (m); \ + if (result != ISC_R_SUCCESS) \ + goto error; \ + } while (0) + +struct named_statschannel { + /* Unlocked */ + isc_httpdmgr_t *httpdmgr; + isc_sockaddr_t address; + isc_mem_t *mctx; + + /* + * Locked by channel lock: can be referenced and modified by both + * the server task and the channel task. + */ + isc_mutex_t lock; + dns_acl_t *acl; + + /* Locked by server task */ + ISC_LINK(struct named_statschannel) link; +}; + +typedef struct stats_dumparg { + isc_statsformat_t type; + void *arg; /* type dependent argument */ + int ncounters; /* for general statistics */ + int *counterindices; /* for general statistics */ + uint64_t *countervalues; /* for general statistics */ + isc_result_t result; +} stats_dumparg_t; + +static isc_once_t once = ISC_ONCE_INIT; + +#if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) +#define EXTENDED_STATS +#else /* if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) */ +#undef EXTENDED_STATS +#endif /* if defined(HAVE_LIBXML2) || defined(HAVE_JSON_C) */ + +#ifdef EXTENDED_STATS +static const char * +user_zonetype(dns_zone_t *zone) { + dns_zonetype_t ztype; + dns_view_t *view; + static const struct zt { + const dns_zonetype_t type; + const char *const string; + } typemap[] = { { dns_zone_none, "none" }, + { dns_zone_primary, "master" }, + { dns_zone_secondary, "slave" }, + { dns_zone_mirror, "mirror" }, + { dns_zone_stub, "stub" }, + { dns_zone_staticstub, "static-stub" }, + { dns_zone_key, "key" }, + { dns_zone_dlz, "dlz" }, + { dns_zone_redirect, "redirect" }, + { 0, NULL } }; + const struct zt *tp; + + if ((dns_zone_getoptions(zone) & DNS_ZONEOPT_AUTOEMPTY) != 0) { + return ("builtin"); + } + + view = dns_zone_getview(zone); + if (view != NULL && strcmp(view->name, "_bind") == 0) { + return ("builtin"); + } + + ztype = dns_zone_gettype(zone); + for (tp = typemap; tp->string != NULL && tp->type != ztype; tp++) { + /* empty */ + } + return (tp->string); +} +#endif /* ifdef EXTENDED_STATS */ + +/*% + * Statistics descriptions. These could be statistically initialized at + * compile time, but we configure them run time in the init_desc() function + * below so that they'll be less susceptible to counter name changes. + */ +static const char *nsstats_desc[ns_statscounter_max]; +static const char *resstats_desc[dns_resstatscounter_max]; +static const char *adbstats_desc[dns_adbstats_max]; +static const char *zonestats_desc[dns_zonestatscounter_max]; +static const char *sockstats_desc[isc_sockstatscounter_max]; +static const char *dnssecstats_desc[dns_dnssecstats_max]; +static const char *udpinsizestats_desc[dns_sizecounter_in_max]; +static const char *udpoutsizestats_desc[dns_sizecounter_out_max]; +static const char *tcpinsizestats_desc[dns_sizecounter_in_max]; +static const char *tcpoutsizestats_desc[dns_sizecounter_out_max]; +static const char *dnstapstats_desc[dns_dnstapcounter_max]; +static const char *gluecachestats_desc[dns_gluecachestatscounter_max]; +#if defined(EXTENDED_STATS) +static const char *nsstats_xmldesc[ns_statscounter_max]; +static const char *resstats_xmldesc[dns_resstatscounter_max]; +static const char *adbstats_xmldesc[dns_adbstats_max]; +static const char *zonestats_xmldesc[dns_zonestatscounter_max]; +static const char *sockstats_xmldesc[isc_sockstatscounter_max]; +static const char *dnssecstats_xmldesc[dns_dnssecstats_max]; +static const char *udpinsizestats_xmldesc[dns_sizecounter_in_max]; +static const char *udpoutsizestats_xmldesc[dns_sizecounter_out_max]; +static const char *tcpinsizestats_xmldesc[dns_sizecounter_in_max]; +static const char *tcpoutsizestats_xmldesc[dns_sizecounter_out_max]; +static const char *dnstapstats_xmldesc[dns_dnstapcounter_max]; +static const char *gluecachestats_xmldesc[dns_gluecachestatscounter_max]; +#else /* if defined(EXTENDED_STATS) */ +#define nsstats_xmldesc NULL +#define resstats_xmldesc NULL +#define adbstats_xmldesc NULL +#define zonestats_xmldesc NULL +#define sockstats_xmldesc NULL +#define dnssecstats_xmldesc NULL +#define udpinsizestats_xmldesc NULL +#define udpoutsizestats_xmldesc NULL +#define tcpinsizestats_xmldesc NULL +#define tcpoutsizestats_xmldesc NULL +#define dnstapstats_xmldesc NULL +#define gluecachestats_xmldesc NULL +#endif /* EXTENDED_STATS */ + +#define TRY0(a) \ + do { \ + xmlrc = (a); \ + if (xmlrc < 0) \ + goto error; \ + } while (0) + +/*% + * Mapping arrays to represent statistics counters in the order of our + * preference, regardless of the order of counter indices. For example, + * nsstats_desc[nsstats_index[0]] will be the description that is shown first. + */ +static int nsstats_index[ns_statscounter_max]; +static int resstats_index[dns_resstatscounter_max]; +static int adbstats_index[dns_adbstats_max]; +static int zonestats_index[dns_zonestatscounter_max]; +static int sockstats_index[isc_sockstatscounter_max]; +static int dnssecstats_index[dns_dnssecstats_max]; +static int udpinsizestats_index[dns_sizecounter_in_max]; +static int udpoutsizestats_index[dns_sizecounter_out_max]; +static int tcpinsizestats_index[dns_sizecounter_in_max]; +static int tcpoutsizestats_index[dns_sizecounter_out_max]; +static int dnstapstats_index[dns_dnstapcounter_max]; +static int gluecachestats_index[dns_gluecachestatscounter_max]; + +static void +set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs, + const char *xdesc, const char **xdescs) { + REQUIRE(counter < maxcounter); + REQUIRE(fdescs != NULL && fdescs[counter] == NULL); +#if defined(EXTENDED_STATS) + REQUIRE(xdescs != NULL && xdescs[counter] == NULL); +#endif /* if defined(EXTENDED_STATS) */ + + fdescs[counter] = fdesc; +#if defined(EXTENDED_STATS) + xdescs[counter] = xdesc; +#else /* if defined(EXTENDED_STATS) */ + UNUSED(xdesc); + UNUSED(xdescs); +#endif /* if defined(EXTENDED_STATS) */ +} + +static void +init_desc(void) { + int i; + + /* Initialize name server statistics */ + for (i = 0; i < ns_statscounter_max; i++) { + nsstats_desc[i] = NULL; + } +#if defined(EXTENDED_STATS) + for (i = 0; i < ns_statscounter_max; i++) { + nsstats_xmldesc[i] = NULL; + } +#endif /* if defined(EXTENDED_STATS) */ + +#define SET_NSSTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(ns_statscounter_##counterid, ns_statscounter_max, \ + desc, nsstats_desc, xmldesc, nsstats_xmldesc); \ + nsstats_index[i++] = ns_statscounter_##counterid; \ + } while (0) + + i = 0; + SET_NSSTATDESC(requestv4, "IPv4 requests received", "Requestv4"); + SET_NSSTATDESC(requestv6, "IPv6 requests received", "Requestv6"); + SET_NSSTATDESC(edns0in, "requests with EDNS(0) received", "ReqEdns0"); + SET_NSSTATDESC(badednsver, + "requests with unsupported EDNS version received", + "ReqBadEDNSVer"); + SET_NSSTATDESC(tsigin, "requests with TSIG received", "ReqTSIG"); + SET_NSSTATDESC(sig0in, "requests with SIG(0) received", "ReqSIG0"); + SET_NSSTATDESC(invalidsig, "requests with invalid signature", + "ReqBadSIG"); + SET_NSSTATDESC(requesttcp, "TCP requests received", "ReqTCP"); + SET_NSSTATDESC(tcphighwater, "TCP connection high-water", + "TCPConnHighWater"); + SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej"); + SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej"); + SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej"); + SET_NSSTATDESC(updaterej, "update requests rejected", "UpdateRej"); + SET_NSSTATDESC(response, "responses sent", "Response"); + SET_NSSTATDESC(truncatedresp, "truncated responses sent", + "TruncatedResp"); + SET_NSSTATDESC(edns0out, "responses with EDNS(0) sent", "RespEDNS0"); + SET_NSSTATDESC(tsigout, "responses with TSIG sent", "RespTSIG"); + SET_NSSTATDESC(sig0out, "responses with SIG(0) sent", "RespSIG0"); + SET_NSSTATDESC(success, "queries resulted in successful answer", + "QrySuccess"); + SET_NSSTATDESC(authans, "queries resulted in authoritative answer", + "QryAuthAns"); + SET_NSSTATDESC(nonauthans, + "queries resulted in non authoritative answer", + "QryNoauthAns"); + SET_NSSTATDESC(referral, "queries resulted in referral answer", + "QryReferral"); + SET_NSSTATDESC(nxrrset, "queries resulted in nxrrset", "QryNxrrset"); + SET_NSSTATDESC(servfail, "queries resulted in SERVFAIL", "QrySERVFAIL"); + SET_NSSTATDESC(formerr, "queries resulted in FORMERR", "QryFORMERR"); + SET_NSSTATDESC(nxdomain, "queries resulted in NXDOMAIN", "QryNXDOMAIN"); + SET_NSSTATDESC(recursion, "queries caused recursion", "QryRecursion"); + SET_NSSTATDESC(duplicate, "duplicate queries received", "QryDuplicate"); + SET_NSSTATDESC(dropped, "queries dropped", "QryDropped"); + SET_NSSTATDESC(failure, "other query failures", "QryFailure"); + SET_NSSTATDESC(xfrdone, "requested transfers completed", "XfrReqDone"); + SET_NSSTATDESC(updatereqfwd, "update requests forwarded", + "UpdateReqFwd"); + SET_NSSTATDESC(updaterespfwd, "update responses forwarded", + "UpdateRespFwd"); + SET_NSSTATDESC(updatefwdfail, "update forward failed", "UpdateFwdFail"); + SET_NSSTATDESC(updatedone, "updates completed", "UpdateDone"); + SET_NSSTATDESC(updatefail, "updates failed", "UpdateFail"); + SET_NSSTATDESC(updatebadprereq, + "updates rejected due to prerequisite failure", + "UpdateBadPrereq"); + SET_NSSTATDESC(recursclients, "recursing clients", "RecursClients"); + SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64"); + SET_NSSTATDESC(ratedropped, "responses dropped for rate limits", + "RateDropped"); + SET_NSSTATDESC(rateslipped, "responses truncated for rate limits", + "RateSlipped"); + SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites", + "RPZRewrites"); + SET_NSSTATDESC(udp, "UDP queries received", "QryUDP"); + SET_NSSTATDESC(tcp, "TCP queries received", "QryTCP"); + SET_NSSTATDESC(nsidopt, "NSID option received", "NSIDOpt"); + SET_NSSTATDESC(expireopt, "Expire option received", "ExpireOpt"); + SET_NSSTATDESC(keepaliveopt, "EDNS TCP keepalive option received", + "KeepAliveOpt"); + SET_NSSTATDESC(padopt, "EDNS padding option received", "PadOpt"); + SET_NSSTATDESC(otheropt, "Other EDNS option received", "OtherOpt"); + SET_NSSTATDESC(cookiein, "COOKIE option received", "CookieIn"); + SET_NSSTATDESC(cookienew, "COOKIE - client only", "CookieNew"); + SET_NSSTATDESC(cookiebadsize, "COOKIE - bad size", "CookieBadSize"); + SET_NSSTATDESC(cookiebadtime, "COOKIE - bad time", "CookieBadTime"); + SET_NSSTATDESC(cookienomatch, "COOKIE - no match", "CookieNoMatch"); + SET_NSSTATDESC(cookiematch, "COOKIE - match", "CookieMatch"); + SET_NSSTATDESC(ecsopt, "EDNS client subnet option received", "ECSOpt"); + SET_NSSTATDESC(nxdomainredirect, + "queries resulted in NXDOMAIN that were redirected", + "QryNXRedir"); + SET_NSSTATDESC(nxdomainredirect_rlookup, + "queries resulted in NXDOMAIN that were redirected and " + "resulted in a successful remote lookup", + "QryNXRedirRLookup"); + SET_NSSTATDESC(badcookie, "sent badcookie response", "QryBADCOOKIE"); + SET_NSSTATDESC(nxdomainsynth, "synthesized a NXDOMAIN response", + "SynthNXDOMAIN"); + SET_NSSTATDESC(nodatasynth, "syththesized a no-data response", + "SynthNODATA"); + SET_NSSTATDESC(wildcardsynth, "synthesized a wildcard response", + "SynthWILDCARD"); + SET_NSSTATDESC(trystale, + "attempts to use stale cache data after lookup failure", + "QryTryStale"); + SET_NSSTATDESC(usedstale, + "successful uses of stale cache data after lookup " + "failure", + "QryUsedStale"); + SET_NSSTATDESC(prefetch, "queries triggered prefetch", "Prefetch"); + SET_NSSTATDESC(keytagopt, "Keytag option received", "KeyTagOpt"); + SET_NSSTATDESC(reclimitdropped, + "queries dropped due to recursive client limit", + "RecLimitDropped"); + SET_NSSTATDESC(updatequota, "Update quota exceeded", "UpdateQuota"); + + INSIST(i == ns_statscounter_max); + + /* Initialize resolver statistics */ + for (i = 0; i < dns_resstatscounter_max; i++) { + resstats_desc[i] = NULL; + } +#if defined(EXTENDED_STATS) + for (i = 0; i < dns_resstatscounter_max; i++) { + resstats_xmldesc[i] = NULL; + } +#endif /* if defined(EXTENDED_STATS) */ + +#define SET_RESSTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(dns_resstatscounter_##counterid, \ + dns_resstatscounter_max, desc, resstats_desc, \ + xmldesc, resstats_xmldesc); \ + resstats_index[i++] = dns_resstatscounter_##counterid; \ + } while (0) + + i = 0; + SET_RESSTATDESC(queryv4, "IPv4 queries sent", "Queryv4"); + SET_RESSTATDESC(queryv6, "IPv6 queries sent", "Queryv6"); + SET_RESSTATDESC(responsev4, "IPv4 responses received", "Responsev4"); + SET_RESSTATDESC(responsev6, "IPv6 responses received", "Responsev6"); + SET_RESSTATDESC(nxdomain, "NXDOMAIN received", "NXDOMAIN"); + SET_RESSTATDESC(servfail, "SERVFAIL received", "SERVFAIL"); + SET_RESSTATDESC(formerr, "FORMERR received", "FORMERR"); + SET_RESSTATDESC(othererror, "other errors received", "OtherError"); + SET_RESSTATDESC(edns0fail, "EDNS(0) query failures", "EDNS0Fail"); + SET_RESSTATDESC(mismatch, "mismatch responses received", "Mismatch"); + SET_RESSTATDESC(truncated, "truncated responses received", "Truncated"); + SET_RESSTATDESC(lame, "lame delegations received", "Lame"); + SET_RESSTATDESC(retry, "query retries", "Retry"); + SET_RESSTATDESC(dispabort, "queries aborted due to quota", + "QueryAbort"); + SET_RESSTATDESC(dispsockfail, "failures in opening query sockets", + "QuerySockFail"); + SET_RESSTATDESC(disprequdp, "UDP queries in progress", "QueryCurUDP"); + SET_RESSTATDESC(dispreqtcp, "TCP queries in progress", "QueryCurTCP"); + SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout"); + SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4"); + SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6"); + SET_RESSTATDESC(gluefetchv4fail, "IPv4 NS address fetch failed", + "GlueFetchv4Fail"); + SET_RESSTATDESC(gluefetchv6fail, "IPv6 NS address fetch failed", + "GlueFetchv6Fail"); + SET_RESSTATDESC(val, "DNSSEC validation attempted", "ValAttempt"); + SET_RESSTATDESC(valsuccess, "DNSSEC validation succeeded", "ValOk"); + SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded", + "ValNegOk"); + SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail"); + SET_RESSTATDESC(queryrtt0, + "queries with RTT < " DNS_RESOLVER_QRYRTTCLASS0STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR); + SET_RESSTATDESC(queryrtt1, + "queries with RTT " DNS_RESOLVER_QRYRTTCLASS0STR + "-" DNS_RESOLVER_QRYRTTCLASS1STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR); + SET_RESSTATDESC(queryrtt2, + "queries with RTT " DNS_RESOLVER_QRYRTTCLASS1STR + "-" DNS_RESOLVER_QRYRTTCLASS2STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR); + SET_RESSTATDESC(queryrtt3, + "queries with RTT " DNS_RESOLVER_QRYRTTCLASS2STR + "-" DNS_RESOLVER_QRYRTTCLASS3STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR); + SET_RESSTATDESC(queryrtt4, + "queries with RTT " DNS_RESOLVER_QRYRTTCLASS3STR + "-" DNS_RESOLVER_QRYRTTCLASS4STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR); + SET_RESSTATDESC(queryrtt5, + "queries with RTT > " DNS_RESOLVER_QRYRTTCLASS4STR "ms", + "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+"); + SET_RESSTATDESC(nfetch, "active fetches", "NumFetch"); + SET_RESSTATDESC(buckets, "bucket size", "BucketSize"); + SET_RESSTATDESC(refused, "REFUSED received", "REFUSED"); + SET_RESSTATDESC(cookienew, "COOKIE send with client cookie only", + "ClientCookieOut"); + SET_RESSTATDESC(cookieout, "COOKIE sent with client and server cookie", + "ServerCookieOut"); + SET_RESSTATDESC(cookiein, "COOKIE replies received", "CookieIn"); + SET_RESSTATDESC(cookieok, "COOKIE client ok", "CookieClientOk"); + SET_RESSTATDESC(badvers, "bad EDNS version", "BadEDNSVersion"); + SET_RESSTATDESC(badcookie, "bad cookie rcode", "BadCookieRcode"); + SET_RESSTATDESC(zonequota, "spilled due to zone quota", "ZoneQuota"); + SET_RESSTATDESC(serverquota, "spilled due to server quota", + "ServerQuota"); + SET_RESSTATDESC(nextitem, "waited for next item", "NextItem"); + SET_RESSTATDESC(priming, "priming queries", "Priming"); + + INSIST(i == dns_resstatscounter_max); + + /* Initialize adb statistics */ + for (i = 0; i < dns_adbstats_max; i++) { + adbstats_desc[i] = NULL; + } +#if defined(EXTENDED_STATS) + for (i = 0; i < dns_adbstats_max; i++) { + adbstats_xmldesc[i] = NULL; + } +#endif /* if defined(EXTENDED_STATS) */ + +#define SET_ADBSTATDESC(id, desc, xmldesc) \ + do { \ + set_desc(dns_adbstats_##id, dns_adbstats_max, desc, \ + adbstats_desc, xmldesc, adbstats_xmldesc); \ + adbstats_index[i++] = dns_adbstats_##id; \ + } while (0) + i = 0; + SET_ADBSTATDESC(nentries, "Address hash table size", "nentries"); + SET_ADBSTATDESC(entriescnt, "Addresses in hash table", "entriescnt"); + SET_ADBSTATDESC(nnames, "Name hash table size", "nnames"); + SET_ADBSTATDESC(namescnt, "Names in hash table", "namescnt"); + + INSIST(i == dns_adbstats_max); + + /* Initialize zone statistics */ + for (i = 0; i < dns_zonestatscounter_max; i++) { + zonestats_desc[i] = NULL; + } +#if defined(EXTENDED_STATS) + for (i = 0; i < dns_zonestatscounter_max; i++) { + zonestats_xmldesc[i] = NULL; + } +#endif /* if defined(EXTENDED_STATS) */ + +#define SET_ZONESTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(dns_zonestatscounter_##counterid, \ + dns_zonestatscounter_max, desc, zonestats_desc, \ + xmldesc, zonestats_xmldesc); \ + zonestats_index[i++] = dns_zonestatscounter_##counterid; \ + } while (0) + + i = 0; + SET_ZONESTATDESC(notifyoutv4, "IPv4 notifies sent", "NotifyOutv4"); + SET_ZONESTATDESC(notifyoutv6, "IPv6 notifies sent", "NotifyOutv6"); + SET_ZONESTATDESC(notifyinv4, "IPv4 notifies received", "NotifyInv4"); + SET_ZONESTATDESC(notifyinv6, "IPv6 notifies received", "NotifyInv6"); + SET_ZONESTATDESC(notifyrej, "notifies rejected", "NotifyRej"); + SET_ZONESTATDESC(soaoutv4, "IPv4 SOA queries sent", "SOAOutv4"); + SET_ZONESTATDESC(soaoutv6, "IPv6 SOA queries sent", "SOAOutv6"); + SET_ZONESTATDESC(axfrreqv4, "IPv4 AXFR requested", "AXFRReqv4"); + SET_ZONESTATDESC(axfrreqv6, "IPv6 AXFR requested", "AXFRReqv6"); + SET_ZONESTATDESC(ixfrreqv4, "IPv4 IXFR requested", "IXFRReqv4"); + SET_ZONESTATDESC(ixfrreqv6, "IPv6 IXFR requested", "IXFRReqv6"); + SET_ZONESTATDESC(xfrsuccess, "transfer requests succeeded", + "XfrSuccess"); + SET_ZONESTATDESC(xfrfail, "transfer requests failed", "XfrFail"); + INSIST(i == dns_zonestatscounter_max); + + /* Initialize socket statistics */ + for (i = 0; i < isc_sockstatscounter_max; i++) { + sockstats_desc[i] = NULL; + } +#if defined(EXTENDED_STATS) + for (i = 0; i < isc_sockstatscounter_max; i++) { + sockstats_xmldesc[i] = NULL; + } +#endif /* if defined(EXTENDED_STATS) */ + +#define SET_SOCKSTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(isc_sockstatscounter_##counterid, \ + isc_sockstatscounter_max, desc, sockstats_desc, \ + xmldesc, sockstats_xmldesc); \ + sockstats_index[i++] = isc_sockstatscounter_##counterid; \ + } while (0) + + i = 0; + SET_SOCKSTATDESC(udp4open, "UDP/IPv4 sockets opened", "UDP4Open"); + SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open"); + SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open"); + SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open"); + SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen"); + SET_SOCKSTATDESC(rawopen, "Raw sockets opened", "RawOpen"); + SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures", + "UDP4OpenFail"); + SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures", + "UDP6OpenFail"); + SET_SOCKSTATDESC(tcp4openfail, "TCP/IPv4 socket open failures", + "TCP4OpenFail"); + SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures", + "TCP6OpenFail"); + SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures", + "UnixOpenFail"); + SET_SOCKSTATDESC(rawopenfail, "Raw socket open failures", + "RawOpenFail"); + SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close"); + SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close"); + SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close"); + SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close"); + SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose"); + SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed", + "FDWatchClose"); + SET_SOCKSTATDESC(rawclose, "Raw sockets closed", "RawClose"); + SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures", + "UDP4BindFail"); + SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures", + "UDP6BindFail"); + SET_SOCKSTATDESC(tcp4bindfail, "TCP/IPv4 socket bind failures", + "TCP4BindFail"); + SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures", + "TCP6BindFail"); + SET_SOCKSTATDESC(unixbindfail, "Unix domain socket bind failures", + "UnixBindFail"); + SET_SOCKSTATDESC(fdwatchbindfail, "FDwatch socket bind failures", + "FdwatchBindFail"); + SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures", + "UDP4ConnFail"); + SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures", + "UDP6ConnFail"); + SET_SOCKSTATDESC(tcp4connectfail, "TCP/IPv4 socket connect failures", + "TCP4ConnFail"); + SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures", + "TCP6ConnFail"); + SET_SOCKSTATDESC(unixconnectfail, "Unix domain socket connect failures", + "UnixConnFail"); + SET_SOCKSTATDESC(fdwatchconnectfail, "FDwatch socket connect failures", + "FDwatchConnFail"); + SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established", + "UDP4Conn"); + SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established", + "UDP6Conn"); + SET_SOCKSTATDESC(tcp4connect, "TCP/IPv4 connections established", + "TCP4Conn"); + SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established", + "TCP6Conn"); + SET_SOCKSTATDESC(unixconnect, "Unix domain connections established", + "UnixConn"); + SET_SOCKSTATDESC(fdwatchconnect, + "FDwatch domain connections established", + "FDwatchConn"); + SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures", + "TCP4AcceptFail"); + SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures", + "TCP6AcceptFail"); + SET_SOCKSTATDESC(unixacceptfail, + "Unix domain connection accept failures", + "UnixAcceptFail"); + SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted", + "TCP4Accept"); + SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted", + "TCP6Accept"); + SET_SOCKSTATDESC(unixaccept, "Unix domain connections accepted", + "UnixAccept"); + SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr"); + SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr"); + SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr"); + SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr"); + SET_SOCKSTATDESC(unixsendfail, "Unix domain send errors", + "UnixSendErr"); + SET_SOCKSTATDESC(fdwatchsendfail, "FDwatch send errors", + "FDwatchSendErr"); + SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr"); + SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr"); + SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr"); + SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr"); + SET_SOCKSTATDESC(unixrecvfail, "Unix domain recv errors", + "UnixRecvErr"); + SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors", + "FDwatchRecvErr"); + SET_SOCKSTATDESC(rawrecvfail, "Raw recv errors", "RawRecvErr"); + SET_SOCKSTATDESC(udp4active, "UDP/IPv4 sockets active", "UDP4Active"); + SET_SOCKSTATDESC(udp6active, "UDP/IPv6 sockets active", "UDP6Active"); + SET_SOCKSTATDESC(tcp4active, "TCP/IPv4 sockets active", "TCP4Active"); + SET_SOCKSTATDESC(tcp6active, "TCP/IPv6 sockets active", "TCP6Active"); + SET_SOCKSTATDESC(unixactive, "Unix domain sockets active", + "UnixActive"); + SET_SOCKSTATDESC(rawactive, "Raw sockets active", "RawActive"); + INSIST(i == isc_sockstatscounter_max); + + /* Initialize DNSSEC statistics */ + for (i = 0; i < dns_dnssecstats_max; i++) { + dnssecstats_desc[i] = NULL; + } +#if defined(EXTENDED_STATS) + for (i = 0; i < dns_dnssecstats_max; i++) { + dnssecstats_xmldesc[i] = NULL; + } +#endif /* if defined(EXTENDED_STATS) */ + +#define SET_DNSSECSTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(dns_dnssecstats_##counterid, dns_dnssecstats_max, \ + desc, dnssecstats_desc, xmldesc, \ + dnssecstats_xmldesc); \ + dnssecstats_index[i++] = dns_dnssecstats_##counterid; \ + } while (0) + + i = 0; + SET_DNSSECSTATDESC(asis, + "dnssec validation success with signer " + "\"as is\"", + "DNSSECasis"); + SET_DNSSECSTATDESC(downcase, + "dnssec validation success with signer " + "lower cased", + "DNSSECdowncase"); + SET_DNSSECSTATDESC(wildcard, "dnssec validation of wildcard signature", + "DNSSECwild"); + SET_DNSSECSTATDESC(fail, "dnssec validation failures", "DNSSECfail"); + INSIST(i == dns_dnssecstats_max); + + /* Initialize dnstap statistics */ + for (i = 0; i < dns_dnstapcounter_max; i++) { + dnstapstats_desc[i] = NULL; + } +#if defined(EXTENDED_STATS) + for (i = 0; i < dns_dnstapcounter_max; i++) { + dnstapstats_xmldesc[i] = NULL; + } +#endif /* if defined(EXTENDED_STATS) */ + +#define SET_DNSTAPSTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(dns_dnstapcounter_##counterid, dns_dnstapcounter_max, \ + desc, dnstapstats_desc, xmldesc, \ + dnstapstats_xmldesc); \ + dnstapstats_index[i++] = dns_dnstapcounter_##counterid; \ + } while (0) + i = 0; + SET_DNSTAPSTATDESC(success, "dnstap messages written", "DNSTAPsuccess"); + SET_DNSTAPSTATDESC(drop, "dnstap messages dropped", "DNSTAPdropped"); + INSIST(i == dns_dnstapcounter_max); + +#define SET_GLUECACHESTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(dns_gluecachestatscounter_##counterid, \ + dns_gluecachestatscounter_max, desc, \ + gluecachestats_desc, xmldesc, \ + gluecachestats_xmldesc); \ + gluecachestats_index[i++] = \ + dns_gluecachestatscounter_##counterid; \ + } while (0) + i = 0; + SET_GLUECACHESTATDESC(hits_present, "Hits for present glue (cached)", + "GLUECACHEhitspresent"); + SET_GLUECACHESTATDESC(hits_absent, + "Hits for non-existent glue (cached)", + "GLUECACHEhitsabsent"); + SET_GLUECACHESTATDESC(inserts_present, + "Miss-plus-cache-inserts for present glue", + "GLUECACHEinsertspresent"); + SET_GLUECACHESTATDESC(inserts_absent, + "Miss-plus-cache-inserts for non-existent glue", + "GLUECACHEinsertsabsent"); + INSIST(i == dns_gluecachestatscounter_max); + + /* Sanity check */ + for (i = 0; i < ns_statscounter_max; i++) { + INSIST(nsstats_desc[i] != NULL); + } + for (i = 0; i < dns_resstatscounter_max; i++) { + INSIST(resstats_desc[i] != NULL); + } + for (i = 0; i < dns_adbstats_max; i++) { + INSIST(adbstats_desc[i] != NULL); + } + for (i = 0; i < dns_zonestatscounter_max; i++) { + INSIST(zonestats_desc[i] != NULL); + } + for (i = 0; i < isc_sockstatscounter_max; i++) { + INSIST(sockstats_desc[i] != NULL); + } + for (i = 0; i < dns_dnssecstats_max; i++) { + INSIST(dnssecstats_desc[i] != NULL); + } + for (i = 0; i < dns_dnstapcounter_max; i++) { + INSIST(dnstapstats_desc[i] != NULL); + } + for (i = 0; i < dns_gluecachestatscounter_max; i++) { + INSIST(gluecachestats_desc[i] != NULL); + } +#if defined(EXTENDED_STATS) + for (i = 0; i < ns_statscounter_max; i++) { + INSIST(nsstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_resstatscounter_max; i++) { + INSIST(resstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_adbstats_max; i++) { + INSIST(adbstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_zonestatscounter_max; i++) { + INSIST(zonestats_xmldesc[i] != NULL); + } + for (i = 0; i < isc_sockstatscounter_max; i++) { + INSIST(sockstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_dnssecstats_max; i++) { + INSIST(dnssecstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_dnstapcounter_max; i++) { + INSIST(dnstapstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_gluecachestatscounter_max; i++) { + INSIST(gluecachestats_xmldesc[i] != NULL); + } +#endif /* if defined(EXTENDED_STATS) */ + + /* Initialize traffic size statistics */ + for (i = 0; i < dns_sizecounter_in_max; i++) { + udpinsizestats_desc[i] = NULL; + tcpinsizestats_desc[i] = NULL; +#if defined(EXTENDED_STATS) + udpinsizestats_xmldesc[i] = NULL; + tcpinsizestats_xmldesc[i] = NULL; +#endif /* if defined(EXTENDED_STATS) */ + } + for (i = 0; i < dns_sizecounter_out_max; i++) { + udpoutsizestats_desc[i] = NULL; + tcpoutsizestats_desc[i] = NULL; +#if defined(EXTENDED_STATS) + udpoutsizestats_xmldesc[i] = NULL; + tcpoutsizestats_xmldesc[i] = NULL; +#endif /* if defined(EXTENDED_STATS) */ + } + +#define SET_SIZESTATDESC(counterid, desc, xmldesc, inout) \ + do { \ + set_desc(dns_sizecounter_##inout##_##counterid, \ + dns_sizecounter_##inout##_max, desc, \ + udp##inout##sizestats_desc, xmldesc, \ + udp##inout##sizestats_xmldesc); \ + set_desc(dns_sizecounter_##inout##_##counterid, \ + dns_sizecounter_##inout##_max, desc, \ + tcp##inout##sizestats_desc, xmldesc, \ + tcp##inout##sizestats_xmldesc); \ + udp##inout##sizestats_index[i] = \ + dns_sizecounter_##inout##_##counterid; \ + tcp##inout##sizestats_index[i] = \ + dns_sizecounter_##inout##_##counterid; \ + i++; \ + } while (0) + + i = 0; + SET_SIZESTATDESC(0, "requests received 0-15 bytes", "0-15", in); + SET_SIZESTATDESC(16, "requests received 16-31 bytes", "16-31", in); + SET_SIZESTATDESC(32, "requests received 32-47 bytes", "32-47", in); + SET_SIZESTATDESC(48, "requests received 48-63 bytes", "48-63", in); + SET_SIZESTATDESC(64, "requests received 64-79 bytes", "64-79", in); + SET_SIZESTATDESC(80, "requests received 80-95 bytes", "80-95", in); + SET_SIZESTATDESC(96, "requests received 96-111 bytes", "96-111", in); + SET_SIZESTATDESC(112, "requests received 112-127 bytes", "112-127", in); + SET_SIZESTATDESC(128, "requests received 128-143 bytes", "128-143", in); + SET_SIZESTATDESC(144, "requests received 144-159 bytes", "144-159", in); + SET_SIZESTATDESC(160, "requests received 160-175 bytes", "160-175", in); + SET_SIZESTATDESC(176, "requests received 176-191 bytes", "176-191", in); + SET_SIZESTATDESC(192, "requests received 192-207 bytes", "192-207", in); + SET_SIZESTATDESC(208, "requests received 208-223 bytes", "208-223", in); + SET_SIZESTATDESC(224, "requests received 224-239 bytes", "224-239", in); + SET_SIZESTATDESC(240, "requests received 240-255 bytes", "240-255", in); + SET_SIZESTATDESC(256, "requests received 256-271 bytes", "256-271", in); + SET_SIZESTATDESC(272, "requests received 272-287 bytes", "272-287", in); + SET_SIZESTATDESC(288, "requests received 288+ bytes", "288+", in); + INSIST(i == dns_sizecounter_in_max); + + i = 0; + SET_SIZESTATDESC(0, "responses sent 0-15 bytes", "0-15", out); + SET_SIZESTATDESC(16, "responses sent 16-31 bytes", "16-31", out); + SET_SIZESTATDESC(32, "responses sent 32-47 bytes", "32-47", out); + SET_SIZESTATDESC(48, "responses sent 48-63 bytes", "48-63", out); + SET_SIZESTATDESC(64, "responses sent 64-79 bytes", "64-79", out); + SET_SIZESTATDESC(80, "responses sent 80-95 bytes", "80-95", out); + SET_SIZESTATDESC(96, "responses sent 96-111 bytes", "96-111", out); + SET_SIZESTATDESC(112, "responses sent 112-127 bytes", "112-127", out); + SET_SIZESTATDESC(128, "responses sent 128-143 bytes", "128-143", out); + SET_SIZESTATDESC(144, "responses sent 144-159 bytes", "144-159", out); + SET_SIZESTATDESC(160, "responses sent 160-175 bytes", "160-175", out); + SET_SIZESTATDESC(176, "responses sent 176-191 bytes", "176-191", out); + SET_SIZESTATDESC(192, "responses sent 192-207 bytes", "192-207", out); + SET_SIZESTATDESC(208, "responses sent 208-223 bytes", "208-223", out); + SET_SIZESTATDESC(224, "responses sent 224-239 bytes", "224-239", out); + SET_SIZESTATDESC(240, "responses sent 240-255 bytes", "240-255", out); + SET_SIZESTATDESC(256, "responses sent 256-271 bytes", "256-271", out); + SET_SIZESTATDESC(272, "responses sent 272-287 bytes", "272-287", out); + SET_SIZESTATDESC(288, "responses sent 288-303 bytes", "288-303", out); + SET_SIZESTATDESC(304, "responses sent 304-319 bytes", "304-319", out); + SET_SIZESTATDESC(320, "responses sent 320-335 bytes", "320-335", out); + SET_SIZESTATDESC(336, "responses sent 336-351 bytes", "336-351", out); + SET_SIZESTATDESC(352, "responses sent 352-367 bytes", "352-367", out); + SET_SIZESTATDESC(368, "responses sent 368-383 bytes", "368-383", out); + SET_SIZESTATDESC(384, "responses sent 384-399 bytes", "384-399", out); + SET_SIZESTATDESC(400, "responses sent 400-415 bytes", "400-415", out); + SET_SIZESTATDESC(416, "responses sent 416-431 bytes", "416-431", out); + SET_SIZESTATDESC(432, "responses sent 432-447 bytes", "432-447", out); + SET_SIZESTATDESC(448, "responses sent 448-463 bytes", "448-463", out); + SET_SIZESTATDESC(464, "responses sent 464-479 bytes", "464-479", out); + SET_SIZESTATDESC(480, "responses sent 480-495 bytes", "480-495", out); + SET_SIZESTATDESC(496, "responses sent 496-511 bytes", "496-511", out); + SET_SIZESTATDESC(512, "responses sent 512-527 bytes", "512-527", out); + SET_SIZESTATDESC(528, "responses sent 528-543 bytes", "528-543", out); + SET_SIZESTATDESC(544, "responses sent 544-559 bytes", "544-559", out); + SET_SIZESTATDESC(560, "responses sent 560-575 bytes", "560-575", out); + SET_SIZESTATDESC(576, "responses sent 576-591 bytes", "576-591", out); + SET_SIZESTATDESC(592, "responses sent 592-607 bytes", "592-607", out); + SET_SIZESTATDESC(608, "responses sent 608-623 bytes", "608-623", out); + SET_SIZESTATDESC(624, "responses sent 624-639 bytes", "624-639", out); + SET_SIZESTATDESC(640, "responses sent 640-655 bytes", "640-655", out); + SET_SIZESTATDESC(656, "responses sent 656-671 bytes", "656-671", out); + SET_SIZESTATDESC(672, "responses sent 672-687 bytes", "672-687", out); + SET_SIZESTATDESC(688, "responses sent 688-703 bytes", "688-703", out); + SET_SIZESTATDESC(704, "responses sent 704-719 bytes", "704-719", out); + SET_SIZESTATDESC(720, "responses sent 720-735 bytes", "720-735", out); + SET_SIZESTATDESC(736, "responses sent 736-751 bytes", "736-751", out); + SET_SIZESTATDESC(752, "responses sent 752-767 bytes", "752-767", out); + SET_SIZESTATDESC(768, "responses sent 768-783 bytes", "768-783", out); + SET_SIZESTATDESC(784, "responses sent 784-799 bytes", "784-799", out); + SET_SIZESTATDESC(800, "responses sent 800-815 bytes", "800-815", out); + SET_SIZESTATDESC(816, "responses sent 816-831 bytes", "816-831", out); + SET_SIZESTATDESC(832, "responses sent 832-847 bytes", "832-847", out); + SET_SIZESTATDESC(848, "responses sent 848-863 bytes", "848-863", out); + SET_SIZESTATDESC(864, "responses sent 864-879 bytes", "864-879", out); + SET_SIZESTATDESC(880, "responses sent 880-895 bytes", "880-895", out); + SET_SIZESTATDESC(896, "responses sent 896-911 bytes", "896-911", out); + SET_SIZESTATDESC(912, "responses sent 912-927 bytes", "912-927", out); + SET_SIZESTATDESC(928, "responses sent 928-943 bytes", "928-943", out); + SET_SIZESTATDESC(944, "responses sent 944-959 bytes", "944-959", out); + SET_SIZESTATDESC(960, "responses sent 960-975 bytes", "960-975", out); + SET_SIZESTATDESC(976, "responses sent 976-991 bytes", "976-991", out); + SET_SIZESTATDESC(992, "responses sent 992-1007 bytes", "992-1007", out); + SET_SIZESTATDESC(1008, "responses sent 1008-1023 bytes", "1008-1023", + out); + SET_SIZESTATDESC(1024, "responses sent 1024-1039 bytes", "1024-1039", + out); + SET_SIZESTATDESC(1040, "responses sent 1040-1055 bytes", "1040-1055", + out); + SET_SIZESTATDESC(1056, "responses sent 1056-1071 bytes", "1056-1071", + out); + SET_SIZESTATDESC(1072, "responses sent 1072-1087 bytes", "1072-1087", + out); + SET_SIZESTATDESC(1088, "responses sent 1088-1103 bytes", "1088-1103", + out); + SET_SIZESTATDESC(1104, "responses sent 1104-1119 bytes", "1104-1119", + out); + SET_SIZESTATDESC(1120, "responses sent 1120-1135 bytes", "1120-1135", + out); + SET_SIZESTATDESC(1136, "responses sent 1136-1151 bytes", "1136-1151", + out); + SET_SIZESTATDESC(1152, "responses sent 1152-1167 bytes", "1152-1167", + out); + SET_SIZESTATDESC(1168, "responses sent 1168-1183 bytes", "1168-1183", + out); + SET_SIZESTATDESC(1184, "responses sent 1184-1199 bytes", "1184-1199", + out); + SET_SIZESTATDESC(1200, "responses sent 1200-1215 bytes", "1200-1215", + out); + SET_SIZESTATDESC(1216, "responses sent 1216-1231 bytes", "1216-1231", + out); + SET_SIZESTATDESC(1232, "responses sent 1232-1247 bytes", "1232-1247", + out); + SET_SIZESTATDESC(1248, "responses sent 1248-1263 bytes", "1248-1263", + out); + SET_SIZESTATDESC(1264, "responses sent 1264-1279 bytes", "1264-1279", + out); + SET_SIZESTATDESC(1280, "responses sent 1280-1295 bytes", "1280-1295", + out); + SET_SIZESTATDESC(1296, "responses sent 1296-1311 bytes", "1296-1311", + out); + SET_SIZESTATDESC(1312, "responses sent 1312-1327 bytes", "1312-1327", + out); + SET_SIZESTATDESC(1328, "responses sent 1328-1343 bytes", "1328-1343", + out); + SET_SIZESTATDESC(1344, "responses sent 1344-1359 bytes", "1344-1359", + out); + SET_SIZESTATDESC(1360, "responses sent 1360-1375 bytes", "1360-1375", + out); + SET_SIZESTATDESC(1376, "responses sent 1376-1391 bytes", "1376-1391", + out); + SET_SIZESTATDESC(1392, "responses sent 1392-1407 bytes", "1392-1407", + out); + SET_SIZESTATDESC(1408, "responses sent 1408-1423 bytes", "1408-1423", + out); + SET_SIZESTATDESC(1424, "responses sent 1424-1439 bytes", "1424-1439", + out); + SET_SIZESTATDESC(1440, "responses sent 1440-1455 bytes", "1440-1455", + out); + SET_SIZESTATDESC(1456, "responses sent 1456-1471 bytes", "1456-1471", + out); + SET_SIZESTATDESC(1472, "responses sent 1472-1487 bytes", "1472-1487", + out); + SET_SIZESTATDESC(1488, "responses sent 1488-1503 bytes", "1488-1503", + out); + SET_SIZESTATDESC(1504, "responses sent 1504-1519 bytes", "1504-1519", + out); + SET_SIZESTATDESC(1520, "responses sent 1520-1535 bytes", "1520-1535", + out); + SET_SIZESTATDESC(1536, "responses sent 1536-1551 bytes", "1536-1551", + out); + SET_SIZESTATDESC(1552, "responses sent 1552-1567 bytes", "1552-1567", + out); + SET_SIZESTATDESC(1568, "responses sent 1568-1583 bytes", "1568-1583", + out); + SET_SIZESTATDESC(1584, "responses sent 1584-1599 bytes", "1584-1599", + out); + SET_SIZESTATDESC(1600, "responses sent 1600-1615 bytes", "1600-1615", + out); + SET_SIZESTATDESC(1616, "responses sent 1616-1631 bytes", "1616-1631", + out); + SET_SIZESTATDESC(1632, "responses sent 1632-1647 bytes", "1632-1647", + out); + SET_SIZESTATDESC(1648, "responses sent 1648-1663 bytes", "1648-1663", + out); + SET_SIZESTATDESC(1664, "responses sent 1664-1679 bytes", "1664-1679", + out); + SET_SIZESTATDESC(1680, "responses sent 1680-1695 bytes", "1680-1695", + out); + SET_SIZESTATDESC(1696, "responses sent 1696-1711 bytes", "1696-1711", + out); + SET_SIZESTATDESC(1712, "responses sent 1712-1727 bytes", "1712-1727", + out); + SET_SIZESTATDESC(1728, "responses sent 1728-1743 bytes", "1728-1743", + out); + SET_SIZESTATDESC(1744, "responses sent 1744-1759 bytes", "1744-1759", + out); + SET_SIZESTATDESC(1760, "responses sent 1760-1775 bytes", "1760-1775", + out); + SET_SIZESTATDESC(1776, "responses sent 1776-1791 bytes", "1776-1791", + out); + SET_SIZESTATDESC(1792, "responses sent 1792-1807 bytes", "1792-1807", + out); + SET_SIZESTATDESC(1808, "responses sent 1808-1823 bytes", "1808-1823", + out); + SET_SIZESTATDESC(1824, "responses sent 1824-1839 bytes", "1824-1839", + out); + SET_SIZESTATDESC(1840, "responses sent 1840-1855 bytes", "1840-1855", + out); + SET_SIZESTATDESC(1856, "responses sent 1856-1871 bytes", "1856-1871", + out); + SET_SIZESTATDESC(1872, "responses sent 1872-1887 bytes", "1872-1887", + out); + SET_SIZESTATDESC(1888, "responses sent 1888-1903 bytes", "1888-1903", + out); + SET_SIZESTATDESC(1904, "responses sent 1904-1919 bytes", "1904-1919", + out); + SET_SIZESTATDESC(1920, "responses sent 1920-1935 bytes", "1920-1935", + out); + SET_SIZESTATDESC(1936, "responses sent 1936-1951 bytes", "1936-1951", + out); + SET_SIZESTATDESC(1952, "responses sent 1952-1967 bytes", "1952-1967", + out); + SET_SIZESTATDESC(1968, "responses sent 1968-1983 bytes", "1968-1983", + out); + SET_SIZESTATDESC(1984, "responses sent 1984-1999 bytes", "1984-1999", + out); + SET_SIZESTATDESC(2000, "responses sent 2000-2015 bytes", "2000-2015", + out); + SET_SIZESTATDESC(2016, "responses sent 2016-2031 bytes", "2016-2031", + out); + SET_SIZESTATDESC(2032, "responses sent 2032-2047 bytes", "2032-2047", + out); + SET_SIZESTATDESC(2048, "responses sent 2048-2063 bytes", "2048-2063", + out); + SET_SIZESTATDESC(2064, "responses sent 2064-2079 bytes", "2064-2079", + out); + SET_SIZESTATDESC(2080, "responses sent 2080-2095 bytes", "2080-2095", + out); + SET_SIZESTATDESC(2096, "responses sent 2096-2111 bytes", "2096-2111", + out); + SET_SIZESTATDESC(2112, "responses sent 2112-2127 bytes", "2112-2127", + out); + SET_SIZESTATDESC(2128, "responses sent 2128-2143 bytes", "2128-2143", + out); + SET_SIZESTATDESC(2144, "responses sent 2144-2159 bytes", "2144-2159", + out); + SET_SIZESTATDESC(2160, "responses sent 2160-2175 bytes", "2160-2175", + out); + SET_SIZESTATDESC(2176, "responses sent 2176-2191 bytes", "2176-2191", + out); + SET_SIZESTATDESC(2192, "responses sent 2192-2207 bytes", "2192-2207", + out); + SET_SIZESTATDESC(2208, "responses sent 2208-2223 bytes", "2208-2223", + out); + SET_SIZESTATDESC(2224, "responses sent 2224-2239 bytes", "2224-2239", + out); + SET_SIZESTATDESC(2240, "responses sent 2240-2255 bytes", "2240-2255", + out); + SET_SIZESTATDESC(2256, "responses sent 2256-2271 bytes", "2256-2271", + out); + SET_SIZESTATDESC(2272, "responses sent 2272-2287 bytes", "2272-2287", + out); + SET_SIZESTATDESC(2288, "responses sent 2288-2303 bytes", "2288-2303", + out); + SET_SIZESTATDESC(2304, "responses sent 2304-2319 bytes", "2304-2319", + out); + SET_SIZESTATDESC(2320, "responses sent 2320-2335 bytes", "2320-2335", + out); + SET_SIZESTATDESC(2336, "responses sent 2336-2351 bytes", "2336-2351", + out); + SET_SIZESTATDESC(2352, "responses sent 2352-2367 bytes", "2352-2367", + out); + SET_SIZESTATDESC(2368, "responses sent 2368-2383 bytes", "2368-2383", + out); + SET_SIZESTATDESC(2384, "responses sent 2384-2399 bytes", "2384-2399", + out); + SET_SIZESTATDESC(2400, "responses sent 2400-2415 bytes", "2400-2415", + out); + SET_SIZESTATDESC(2416, "responses sent 2416-2431 bytes", "2416-2431", + out); + SET_SIZESTATDESC(2432, "responses sent 2432-2447 bytes", "2432-2447", + out); + SET_SIZESTATDESC(2448, "responses sent 2448-2463 bytes", "2448-2463", + out); + SET_SIZESTATDESC(2464, "responses sent 2464-2479 bytes", "2464-2479", + out); + SET_SIZESTATDESC(2480, "responses sent 2480-2495 bytes", "2480-2495", + out); + SET_SIZESTATDESC(2496, "responses sent 2496-2511 bytes", "2496-2511", + out); + SET_SIZESTATDESC(2512, "responses sent 2512-2527 bytes", "2512-2527", + out); + SET_SIZESTATDESC(2528, "responses sent 2528-2543 bytes", "2528-2543", + out); + SET_SIZESTATDESC(2544, "responses sent 2544-2559 bytes", "2544-2559", + out); + SET_SIZESTATDESC(2560, "responses sent 2560-2575 bytes", "2560-2575", + out); + SET_SIZESTATDESC(2576, "responses sent 2576-2591 bytes", "2576-2591", + out); + SET_SIZESTATDESC(2592, "responses sent 2592-2607 bytes", "2592-2607", + out); + SET_SIZESTATDESC(2608, "responses sent 2608-2623 bytes", "2608-2623", + out); + SET_SIZESTATDESC(2624, "responses sent 2624-2639 bytes", "2624-2639", + out); + SET_SIZESTATDESC(2640, "responses sent 2640-2655 bytes", "2640-2655", + out); + SET_SIZESTATDESC(2656, "responses sent 2656-2671 bytes", "2656-2671", + out); + SET_SIZESTATDESC(2672, "responses sent 2672-2687 bytes", "2672-2687", + out); + SET_SIZESTATDESC(2688, "responses sent 2688-2703 bytes", "2688-2703", + out); + SET_SIZESTATDESC(2704, "responses sent 2704-2719 bytes", "2704-2719", + out); + SET_SIZESTATDESC(2720, "responses sent 2720-2735 bytes", "2720-2735", + out); + SET_SIZESTATDESC(2736, "responses sent 2736-2751 bytes", "2736-2751", + out); + SET_SIZESTATDESC(2752, "responses sent 2752-2767 bytes", "2752-2767", + out); + SET_SIZESTATDESC(2768, "responses sent 2768-2783 bytes", "2768-2783", + out); + SET_SIZESTATDESC(2784, "responses sent 2784-2799 bytes", "2784-2799", + out); + SET_SIZESTATDESC(2800, "responses sent 2800-2815 bytes", "2800-2815", + out); + SET_SIZESTATDESC(2816, "responses sent 2816-2831 bytes", "2816-2831", + out); + SET_SIZESTATDESC(2832, "responses sent 2832-2847 bytes", "2832-2847", + out); + SET_SIZESTATDESC(2848, "responses sent 2848-2863 bytes", "2848-2863", + out); + SET_SIZESTATDESC(2864, "responses sent 2864-2879 bytes", "2864-2879", + out); + SET_SIZESTATDESC(2880, "responses sent 2880-2895 bytes", "2880-2895", + out); + SET_SIZESTATDESC(2896, "responses sent 2896-2911 bytes", "2896-2911", + out); + SET_SIZESTATDESC(2912, "responses sent 2912-2927 bytes", "2912-2927", + out); + SET_SIZESTATDESC(2928, "responses sent 2928-2943 bytes", "2928-2943", + out); + SET_SIZESTATDESC(2944, "responses sent 2944-2959 bytes", "2944-2959", + out); + SET_SIZESTATDESC(2960, "responses sent 2960-2975 bytes", "2960-2975", + out); + SET_SIZESTATDESC(2976, "responses sent 2976-2991 bytes", "2976-2991", + out); + SET_SIZESTATDESC(2992, "responses sent 2992-3007 bytes", "2992-3007", + out); + SET_SIZESTATDESC(3008, "responses sent 3008-3023 bytes", "3008-3023", + out); + SET_SIZESTATDESC(3024, "responses sent 3024-3039 bytes", "3024-3039", + out); + SET_SIZESTATDESC(3040, "responses sent 3040-3055 bytes", "3040-3055", + out); + SET_SIZESTATDESC(3056, "responses sent 3056-3071 bytes", "3056-3071", + out); + SET_SIZESTATDESC(3072, "responses sent 3072-3087 bytes", "3072-3087", + out); + SET_SIZESTATDESC(3088, "responses sent 3088-3103 bytes", "3088-3103", + out); + SET_SIZESTATDESC(3104, "responses sent 3104-3119 bytes", "3104-3119", + out); + SET_SIZESTATDESC(3120, "responses sent 3120-3135 bytes", "3120-3135", + out); + SET_SIZESTATDESC(3136, "responses sent 3136-3151 bytes", "3136-3151", + out); + SET_SIZESTATDESC(3152, "responses sent 3152-3167 bytes", "3152-3167", + out); + SET_SIZESTATDESC(3168, "responses sent 3168-3183 bytes", "3168-3183", + out); + SET_SIZESTATDESC(3184, "responses sent 3184-3199 bytes", "3184-3199", + out); + SET_SIZESTATDESC(3200, "responses sent 3200-3215 bytes", "3200-3215", + out); + SET_SIZESTATDESC(3216, "responses sent 3216-3231 bytes", "3216-3231", + out); + SET_SIZESTATDESC(3232, "responses sent 3232-3247 bytes", "3232-3247", + out); + SET_SIZESTATDESC(3248, "responses sent 3248-3263 bytes", "3248-3263", + out); + SET_SIZESTATDESC(3264, "responses sent 3264-3279 bytes", "3264-3279", + out); + SET_SIZESTATDESC(3280, "responses sent 3280-3295 bytes", "3280-3295", + out); + SET_SIZESTATDESC(3296, "responses sent 3296-3311 bytes", "3296-3311", + out); + SET_SIZESTATDESC(3312, "responses sent 3312-3327 bytes", "3312-3327", + out); + SET_SIZESTATDESC(3328, "responses sent 3328-3343 bytes", "3328-3343", + out); + SET_SIZESTATDESC(3344, "responses sent 3344-3359 bytes", "3344-3359", + out); + SET_SIZESTATDESC(3360, "responses sent 3360-3375 bytes", "3360-3375", + out); + SET_SIZESTATDESC(3376, "responses sent 3376-3391 bytes", "3376-3391", + out); + SET_SIZESTATDESC(3392, "responses sent 3392-3407 bytes", "3392-3407", + out); + SET_SIZESTATDESC(3408, "responses sent 3408-3423 bytes", "3408-3423", + out); + SET_SIZESTATDESC(3424, "responses sent 3424-3439 bytes", "3424-3439", + out); + SET_SIZESTATDESC(3440, "responses sent 3440-3455 bytes", "3440-3455", + out); + SET_SIZESTATDESC(3456, "responses sent 3456-3471 bytes", "3456-3471", + out); + SET_SIZESTATDESC(3472, "responses sent 3472-3487 bytes", "3472-3487", + out); + SET_SIZESTATDESC(3488, "responses sent 3488-3503 bytes", "3488-3503", + out); + SET_SIZESTATDESC(3504, "responses sent 3504-3519 bytes", "3504-3519", + out); + SET_SIZESTATDESC(3520, "responses sent 3520-3535 bytes", "3520-3535", + out); + SET_SIZESTATDESC(3536, "responses sent 3536-3551 bytes", "3536-3551", + out); + SET_SIZESTATDESC(3552, "responses sent 3552-3567 bytes", "3552-3567", + out); + SET_SIZESTATDESC(3568, "responses sent 3568-3583 bytes", "3568-3583", + out); + SET_SIZESTATDESC(3584, "responses sent 3584-3599 bytes", "3584-3599", + out); + SET_SIZESTATDESC(3600, "responses sent 3600-3615 bytes", "3600-3615", + out); + SET_SIZESTATDESC(3616, "responses sent 3616-3631 bytes", "3616-3631", + out); + SET_SIZESTATDESC(3632, "responses sent 3632-3647 bytes", "3632-3647", + out); + SET_SIZESTATDESC(3648, "responses sent 3648-3663 bytes", "3648-3663", + out); + SET_SIZESTATDESC(3664, "responses sent 3664-3679 bytes", "3664-3679", + out); + SET_SIZESTATDESC(3680, "responses sent 3680-3695 bytes", "3680-3695", + out); + SET_SIZESTATDESC(3696, "responses sent 3696-3711 bytes", "3696-3711", + out); + SET_SIZESTATDESC(3712, "responses sent 3712-3727 bytes", "3712-3727", + out); + SET_SIZESTATDESC(3728, "responses sent 3728-3743 bytes", "3728-3743", + out); + SET_SIZESTATDESC(3744, "responses sent 3744-3759 bytes", "3744-3759", + out); + SET_SIZESTATDESC(3760, "responses sent 3760-3775 bytes", "3760-3775", + out); + SET_SIZESTATDESC(3776, "responses sent 3776-3791 bytes", "3776-3791", + out); + SET_SIZESTATDESC(3792, "responses sent 3792-3807 bytes", "3792-3807", + out); + SET_SIZESTATDESC(3808, "responses sent 3808-3823 bytes", "3808-3823", + out); + SET_SIZESTATDESC(3824, "responses sent 3824-3839 bytes", "3824-3839", + out); + SET_SIZESTATDESC(3840, "responses sent 3840-3855 bytes", "3840-3855", + out); + SET_SIZESTATDESC(3856, "responses sent 3856-3871 bytes", "3856-3871", + out); + SET_SIZESTATDESC(3872, "responses sent 3872-3887 bytes", "3872-3887", + out); + SET_SIZESTATDESC(3888, "responses sent 3888-3903 bytes", "3888-3903", + out); + SET_SIZESTATDESC(3904, "responses sent 3904-3919 bytes", "3904-3919", + out); + SET_SIZESTATDESC(3920, "responses sent 3920-3935 bytes", "3920-3935", + out); + SET_SIZESTATDESC(3936, "responses sent 3936-3951 bytes", "3936-3951", + out); + SET_SIZESTATDESC(3952, "responses sent 3952-3967 bytes", "3952-3967", + out); + SET_SIZESTATDESC(3968, "responses sent 3968-3983 bytes", "3968-3983", + out); + SET_SIZESTATDESC(3984, "responses sent 3984-3999 bytes", "3984-3999", + out); + SET_SIZESTATDESC(4000, "responses sent 4000-4015 bytes", "4000-4015", + out); + SET_SIZESTATDESC(4016, "responses sent 4016-4031 bytes", "4016-4031", + out); + SET_SIZESTATDESC(4032, "responses sent 4032-4047 bytes", "4032-4047", + out); + SET_SIZESTATDESC(4048, "responses sent 4048-4063 bytes", "4048-4063", + out); + SET_SIZESTATDESC(4064, "responses sent 4064-4079 bytes", "4064-4079", + out); + SET_SIZESTATDESC(4080, "responses sent 4080-4095 bytes", "4080-4095", + out); + SET_SIZESTATDESC(4096, "responses sent 4096+ bytes", "4096+", out); + INSIST(i == dns_sizecounter_out_max); + + /* Sanity check */ + for (i = 0; i < ns_statscounter_max; i++) { + INSIST(nsstats_desc[i] != NULL); + } + for (i = 0; i < dns_resstatscounter_max; i++) { + INSIST(resstats_desc[i] != NULL); + } + for (i = 0; i < dns_adbstats_max; i++) { + INSIST(adbstats_desc[i] != NULL); + } + for (i = 0; i < dns_zonestatscounter_max; i++) { + INSIST(zonestats_desc[i] != NULL); + } + for (i = 0; i < isc_sockstatscounter_max; i++) { + INSIST(sockstats_desc[i] != NULL); + } + for (i = 0; i < dns_dnssecstats_max; i++) { + INSIST(dnssecstats_desc[i] != NULL); + } + for (i = 0; i < dns_sizecounter_in_max; i++) { + INSIST(udpinsizestats_desc[i] != NULL); + INSIST(tcpinsizestats_desc[i] != NULL); + } + for (i = 0; i < dns_sizecounter_out_max; i++) { + INSIST(udpoutsizestats_desc[i] != NULL); + INSIST(tcpoutsizestats_desc[i] != NULL); + } +#if defined(EXTENDED_STATS) + for (i = 0; i < ns_statscounter_max; i++) { + INSIST(nsstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_resstatscounter_max; i++) { + INSIST(resstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_adbstats_max; i++) { + INSIST(adbstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_zonestatscounter_max; i++) { + INSIST(zonestats_xmldesc[i] != NULL); + } + for (i = 0; i < isc_sockstatscounter_max; i++) { + INSIST(sockstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_dnssecstats_max; i++) { + INSIST(dnssecstats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_sizecounter_in_max; i++) { + INSIST(udpinsizestats_xmldesc[i] != NULL); + INSIST(tcpinsizestats_xmldesc[i] != NULL); + } + for (i = 0; i < dns_sizecounter_out_max; i++) { + INSIST(udpoutsizestats_xmldesc[i] != NULL); + INSIST(tcpoutsizestats_xmldesc[i] != NULL); + } +#endif /* if defined(EXTENDED_STATS) */ +} + +/*% + * Dump callback functions. + */ +static void +generalstat_dump(isc_statscounter_t counter, uint64_t val, void *arg) { + stats_dumparg_t *dumparg = arg; + + REQUIRE(counter < dumparg->ncounters); + dumparg->countervalues[counter] = val; +} + +static isc_result_t +dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg, + const char *category, const char **desc, int ncounters, + int *indices, uint64_t *values, int options) { + int i, idx; + uint64_t value; + stats_dumparg_t dumparg; + FILE *fp; +#ifdef HAVE_LIBXML2 + void *writer; + int xmlrc; +#endif /* ifdef HAVE_LIBXML2 */ +#ifdef HAVE_JSON_C + json_object *job, *cat, *counter; +#endif /* ifdef HAVE_JSON_C */ + +#if !defined(EXTENDED_STATS) + UNUSED(category); +#endif /* if !defined(EXTENDED_STATS) */ + + dumparg.type = type; + dumparg.ncounters = ncounters; + dumparg.counterindices = indices; + dumparg.countervalues = values; + + memset(values, 0, sizeof(values[0]) * ncounters); + isc_stats_dump(stats, generalstat_dump, &dumparg, options); + +#ifdef HAVE_JSON_C + cat = job = (json_object *)arg; + if (ncounters > 0 && type == isc_statsformat_json) { + if (category != NULL) { + cat = json_object_new_object(); + if (cat == NULL) { + return (ISC_R_NOMEMORY); + } + json_object_object_add(job, category, cat); + } + } +#endif /* ifdef HAVE_JSON_C */ + + for (i = 0; i < ncounters; i++) { + idx = indices[i]; + value = values[idx]; + + if (value == 0 && (options & ISC_STATSDUMP_VERBOSE) == 0) { + continue; + } + + switch (dumparg.type) { + case isc_statsformat_file: + fp = arg; + fprintf(fp, "%20" PRIu64 " %s\n", value, desc[idx]); + break; + case isc_statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = arg; + + if (category != NULL) { + /* */ + TRY0(xmlTextWriterStartElement( + writer, ISC_XMLCHAR category)); + + /* inside category */ + TRY0(xmlTextWriterStartElement( + writer, ISC_XMLCHAR "name")); + TRY0(xmlTextWriterWriteString( + writer, ISC_XMLCHAR desc[idx])); + TRY0(xmlTextWriterEndElement(writer)); + /* */ + + /* */ + TRY0(xmlTextWriterStartElement( + writer, ISC_XMLCHAR "counter")); + TRY0(xmlTextWriterWriteFormatString( + writer, "%" PRIu64, value)); + + TRY0(xmlTextWriterEndElement(writer)); + /* */ + TRY0(xmlTextWriterEndElement(writer)); + /* */ + } else { + TRY0(xmlTextWriterStartElement( + writer, ISC_XMLCHAR "counter")); + TRY0(xmlTextWriterWriteAttribute( + writer, ISC_XMLCHAR "name", + ISC_XMLCHAR desc[idx])); + TRY0(xmlTextWriterWriteFormatString( + writer, "%" PRIu64, value)); + TRY0(xmlTextWriterEndElement(writer)); + /* counter */ + } + +#endif /* ifdef HAVE_LIBXML2 */ + break; + case isc_statsformat_json: +#ifdef HAVE_JSON_C + counter = json_object_new_int64(value); + if (counter == NULL) { + return (ISC_R_NOMEMORY); + } + json_object_object_add(cat, desc[idx], counter); +#endif /* ifdef HAVE_JSON_C */ + break; + } + } + return (ISC_R_SUCCESS); +#ifdef HAVE_LIBXML2 +error: + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed at dump_counters()"); + return (ISC_R_FAILURE); +#endif /* ifdef HAVE_LIBXML2 */ +} + +static void +rdtypestat_dump(dns_rdatastatstype_t type, uint64_t val, void *arg) { + char typebuf[64]; + const char *typestr; + stats_dumparg_t *dumparg = arg; + FILE *fp; +#ifdef HAVE_LIBXML2 + void *writer; + int xmlrc; +#endif /* ifdef HAVE_LIBXML2 */ +#ifdef HAVE_JSON_C + json_object *zoneobj, *obj; +#endif /* ifdef HAVE_JSON_C */ + + if ((DNS_RDATASTATSTYPE_ATTR(type) & + DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) == 0) + { + dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, + sizeof(typebuf)); + typestr = typebuf; + } else { + typestr = "Others"; + } + + switch (dumparg->type) { + case isc_statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" PRIu64 " %s\n", val, typestr); + break; + case isc_statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", + ISC_XMLCHAR typestr)); + + TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); + + TRY0(xmlTextWriterEndElement(writer)); /* type */ +#endif /* ifdef HAVE_LIBXML2 */ + break; + case isc_statsformat_json: +#ifdef HAVE_JSON_C + zoneobj = (json_object *)dumparg->arg; + obj = json_object_new_int64(val); + if (obj == NULL) { + return; + } + json_object_object_add(zoneobj, typestr, obj); +#endif /* ifdef HAVE_JSON_C */ + break; + } + return; +#ifdef HAVE_LIBXML2 +error: + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed at rdtypestat_dump()"); + dumparg->result = ISC_R_FAILURE; + return; +#endif /* ifdef HAVE_LIBXML2 */ +} + +static bool +rdatastatstype_attr(dns_rdatastatstype_t type, unsigned int attr) { + return ((DNS_RDATASTATSTYPE_ATTR(type) & attr) != 0); +} + +static void +rdatasetstats_dump(dns_rdatastatstype_t type, uint64_t val, void *arg) { + stats_dumparg_t *dumparg = arg; + FILE *fp; + char typebuf[64]; + const char *typestr; + bool nxrrset = false; + bool stale = false; + bool ancient = false; +#ifdef HAVE_LIBXML2 + void *writer; + int xmlrc; +#endif /* ifdef HAVE_LIBXML2 */ +#ifdef HAVE_JSON_C + json_object *zoneobj, *obj; + char buf[1024]; +#endif /* ifdef HAVE_JSON_C */ + + if ((DNS_RDATASTATSTYPE_ATTR(type) & + DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0) + { + typestr = "NXDOMAIN"; + } else if ((DNS_RDATASTATSTYPE_ATTR(type) & + DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0) + { + typestr = "Others"; + } else { + dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, + sizeof(typebuf)); + typestr = typebuf; + } + + nxrrset = rdatastatstype_attr(type, DNS_RDATASTATSTYPE_ATTR_NXRRSET); + stale = rdatastatstype_attr(type, DNS_RDATASTATSTYPE_ATTR_STALE); + ancient = rdatastatstype_attr(type, DNS_RDATASTATSTYPE_ATTR_ANCIENT); + + switch (dumparg->type) { + case isc_statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" PRIu64 " %s%s%s%s\n", val, ancient ? "~" : "", + stale ? "#" : "", nxrrset ? "!" : "", typestr); + break; + case isc_statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name")); + TRY0(xmlTextWriterWriteFormatString( + writer, "%s%s%s%s", ancient ? "~" : "", + stale ? "#" : "", nxrrset ? "!" : "", typestr)); + TRY0(xmlTextWriterEndElement(writer)); /* name */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); + TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); + TRY0(xmlTextWriterEndElement(writer)); /* counter */ + + TRY0(xmlTextWriterEndElement(writer)); /* rrset */ +#endif /* ifdef HAVE_LIBXML2 */ + break; + case isc_statsformat_json: +#ifdef HAVE_JSON_C + zoneobj = (json_object *)dumparg->arg; + snprintf(buf, sizeof(buf), "%s%s%s%s", ancient ? "~" : "", + stale ? "#" : "", nxrrset ? "!" : "", typestr); + obj = json_object_new_int64(val); + if (obj == NULL) { + return; + } + json_object_object_add(zoneobj, buf, obj); +#endif /* ifdef HAVE_JSON_C */ + break; + } + return; +#ifdef HAVE_LIBXML2 +error: + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed at rdatasetstats_dump()"); + dumparg->result = ISC_R_FAILURE; +#endif /* ifdef HAVE_LIBXML2 */ +} + +static void +opcodestat_dump(dns_opcode_t code, uint64_t val, void *arg) { + FILE *fp; + isc_buffer_t b; + char codebuf[64]; + stats_dumparg_t *dumparg = arg; +#ifdef HAVE_LIBXML2 + void *writer; + int xmlrc; +#endif /* ifdef HAVE_LIBXML2 */ +#ifdef HAVE_JSON_C + json_object *zoneobj, *obj; +#endif /* ifdef HAVE_JSON_C */ + + isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1); + dns_opcode_totext(code, &b); + codebuf[isc_buffer_usedlength(&b)] = '\0'; + + switch (dumparg->type) { + case isc_statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" PRIu64 " %s\n", val, codebuf); + break; + case isc_statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", + ISC_XMLCHAR codebuf)); + TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); + TRY0(xmlTextWriterEndElement(writer)); /* counter */ +#endif /* ifdef HAVE_LIBXML2 */ + break; + case isc_statsformat_json: +#ifdef HAVE_JSON_C + zoneobj = (json_object *)dumparg->arg; + obj = json_object_new_int64(val); + if (obj == NULL) { + return; + } + json_object_object_add(zoneobj, codebuf, obj); +#endif /* ifdef HAVE_JSON_C */ + break; + } + return; + +#ifdef HAVE_LIBXML2 +error: + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed at opcodestat_dump()"); + dumparg->result = ISC_R_FAILURE; + return; +#endif /* ifdef HAVE_LIBXML2 */ +} + +static void +rcodestat_dump(dns_rcode_t code, uint64_t val, void *arg) { + FILE *fp; + isc_buffer_t b; + char codebuf[64]; + stats_dumparg_t *dumparg = arg; +#ifdef HAVE_LIBXML2 + void *writer; + int xmlrc; +#endif /* ifdef HAVE_LIBXML2 */ +#ifdef HAVE_JSON_C + json_object *zoneobj, *obj; +#endif /* ifdef HAVE_JSON_C */ + + isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1); + dns_rcode_totext(code, &b); + codebuf[isc_buffer_usedlength(&b)] = '\0'; + + switch (dumparg->type) { + case isc_statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" PRIu64 " %s\n", val, codebuf); + break; + case isc_statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", + ISC_XMLCHAR codebuf)); + TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); + TRY0(xmlTextWriterEndElement(writer)); /* counter */ +#endif /* ifdef HAVE_LIBXML2 */ + break; + case isc_statsformat_json: +#ifdef HAVE_JSON_C + zoneobj = (json_object *)dumparg->arg; + obj = json_object_new_int64(val); + if (obj == NULL) { + return; + } + json_object_object_add(zoneobj, codebuf, obj); +#endif /* ifdef HAVE_JSON_C */ + break; + } + return; + +#ifdef HAVE_LIBXML2 +error: + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed at rcodestat_dump()"); + dumparg->result = ISC_R_FAILURE; + return; +#endif /* ifdef HAVE_LIBXML2 */ +} + +#if defined(EXTENDED_STATS) +static void +dnssecsignstat_dump(dns_keytag_t tag, uint64_t val, void *arg) { + FILE *fp; + char tagbuf[64]; + stats_dumparg_t *dumparg = arg; +#ifdef HAVE_LIBXML2 + xmlTextWriterPtr writer; + int xmlrc; +#endif /* ifdef HAVE_LIBXML2 */ +#ifdef HAVE_JSON_C + json_object *zoneobj, *obj; +#endif /* ifdef HAVE_JSON_C */ + + snprintf(tagbuf, sizeof(tagbuf), "%u", tag); + + switch (dumparg->type) { + case isc_statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" PRIu64 " %s\n", val, tagbuf); + break; + case isc_statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", + ISC_XMLCHAR tagbuf)); + TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, val)); + TRY0(xmlTextWriterEndElement(writer)); /* counter */ +#endif /* ifdef HAVE_LIBXML2 */ + break; + case isc_statsformat_json: +#ifdef HAVE_JSON_C + zoneobj = (json_object *)dumparg->arg; + obj = json_object_new_int64(val); + if (obj == NULL) { + return; + } + json_object_object_add(zoneobj, tagbuf, obj); +#endif /* ifdef HAVE_JSON_C */ + break; + } + return; +#ifdef HAVE_LIBXML2 +error: + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed at dnssecsignstat_dump()"); + dumparg->result = ISC_R_FAILURE; + return; +#endif /* ifdef HAVE_LIBXML2 */ +} +#endif /* defined(EXTENDED_STATS) */ + +#ifdef HAVE_LIBXML2 +/* + * Which statistics to include when rendering to XML + */ +#define STATS_XML_STATUS 0x00 /* display only common statistics */ +#define STATS_XML_SERVER 0x01 +#define STATS_XML_ZONES 0x02 +#define STATS_XML_TASKS 0x04 +#define STATS_XML_NET 0x08 +#define STATS_XML_MEM 0x10 +#define STATS_XML_TRAFFIC 0x20 +#define STATS_XML_ALL 0xff + +static isc_result_t +zone_xmlrender(dns_zone_t *zone, void *arg) { + isc_result_t result; + char buf[1024 + 32]; /* sufficiently large for zone name and class */ + dns_rdataclass_t rdclass; + uint32_t serial; + xmlTextWriterPtr writer = arg; + dns_zonestat_level_t statlevel; + int xmlrc; + stats_dumparg_t dumparg; + const char *ztype; + + statlevel = dns_zone_getstatlevel(zone); + if (statlevel == dns_zonestat_none) { + return (ISC_R_SUCCESS); + } + + dumparg.type = isc_statsformat_xml; + dumparg.arg = writer; + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone")); + + dns_zone_nameonly(zone, buf, sizeof(buf)); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", + ISC_XMLCHAR buf)); + + rdclass = dns_zone_getclass(zone); + dns_rdataclass_format(rdclass, buf, sizeof(buf)); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "rdataclass", + ISC_XMLCHAR buf)); + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type")); + ztype = user_zonetype(zone); + if (ztype != NULL) { + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR ztype)); + } else { + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "unknown")); + } + TRY0(xmlTextWriterEndElement(writer)); /* type */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial")); + if (dns_zone_getserial(zone, &serial) == ISC_R_SUCCESS) { + TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial)); + } else { + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); + } + TRY0(xmlTextWriterEndElement(writer)); /* serial */ + + /* + * Export zone timers to the statistics channel in XML format. For + * master zones, only include the loaded time. For slave zones, also + * include the expires and refresh times. + */ + isc_time_t timestamp; + + result = dns_zone_getloadtime(zone, ×tamp); + if (result != ISC_R_SUCCESS) { + goto error; + } + + isc_time_formatISO8601(×tamp, buf, 64); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "loaded")); + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf)); + TRY0(xmlTextWriterEndElement(writer)); + + if (dns_zone_gettype(zone) == dns_zone_secondary) { + result = dns_zone_getexpiretime(zone, ×tamp); + if (result != ISC_R_SUCCESS) { + goto error; + } + isc_time_formatISO8601(×tamp, buf, 64); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "expires")); + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf)); + TRY0(xmlTextWriterEndElement(writer)); + + result = dns_zone_getrefreshtime(zone, ×tamp); + if (result != ISC_R_SUCCESS) { + goto error; + } + isc_time_formatISO8601(×tamp, buf, 64); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "refresh")); + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR buf)); + TRY0(xmlTextWriterEndElement(writer)); + } + + if (statlevel == dns_zonestat_full) { + isc_stats_t *zonestats; + isc_stats_t *gluecachestats; + dns_stats_t *rcvquerystats; + dns_stats_t *dnssecsignstats; + uint64_t nsstat_values[ns_statscounter_max]; + uint64_t gluecachestats_values[dns_gluecachestatscounter_max]; + + zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) { + TRY0(xmlTextWriterStartElement(writer, + ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, + ISC_XMLCHAR "type", + ISC_XMLCHAR "rcode")); + + result = dump_counters(zonestats, isc_statsformat_xml, + writer, NULL, nsstats_xmldesc, + ns_statscounter_max, + nsstats_index, nsstat_values, + ISC_STATSDUMP_VERBOSE); + if (result != ISC_R_SUCCESS) { + goto error; + } + /* counters type="rcode"*/ + TRY0(xmlTextWriterEndElement(writer)); + } + + gluecachestats = dns_zone_getgluecachestats(zone); + if (gluecachestats != NULL) { + TRY0(xmlTextWriterStartElement(writer, + ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute( + writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "gluecache")); + + result = dump_counters( + gluecachestats, isc_statsformat_xml, writer, + NULL, gluecachestats_xmldesc, + dns_gluecachestatscounter_max, + gluecachestats_index, gluecachestats_values, + ISC_STATSDUMP_VERBOSE); + if (result != ISC_R_SUCCESS) { + goto error; + } + /* counters type="rcode"*/ + TRY0(xmlTextWriterEndElement(writer)); + } + + rcvquerystats = dns_zone_getrcvquerystats(zone); + if (rcvquerystats != NULL) { + TRY0(xmlTextWriterStartElement(writer, + ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, + ISC_XMLCHAR "type", + ISC_XMLCHAR "qtype")); + + dumparg.result = ISC_R_SUCCESS; + dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump, + &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + goto error; + } + + /* counters type="qtype"*/ + TRY0(xmlTextWriterEndElement(writer)); + } + + dnssecsignstats = dns_zone_getdnssecsignstats(zone); + if (dnssecsignstats != NULL) { + /* counters type="dnssec-sign"*/ + TRY0(xmlTextWriterStartElement(writer, + ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute( + writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "dnssec-sign")); + + dumparg.result = ISC_R_SUCCESS; + dns_dnssecsignstats_dump( + dnssecsignstats, dns_dnssecsignstats_sign, + dnssecsignstat_dump, &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + goto error; + } + + /* counters type="dnssec-sign"*/ + TRY0(xmlTextWriterEndElement(writer)); + + /* counters type="dnssec-refresh"*/ + TRY0(xmlTextWriterStartElement(writer, + ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute( + writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "dnssec-refresh")); + + dumparg.result = ISC_R_SUCCESS; + dns_dnssecsignstats_dump( + dnssecsignstats, dns_dnssecsignstats_refresh, + dnssecsignstat_dump, &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + goto error; + } + + /* counters type="dnssec-refresh"*/ + TRY0(xmlTextWriterEndElement(writer)); + } + } + + TRY0(xmlTextWriterEndElement(writer)); /* zone */ + + return (ISC_R_SUCCESS); +error: + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "Failed at zone_xmlrender()"); + return (ISC_R_FAILURE); +} + +static isc_result_t +generatexml(named_server_t *server, uint32_t flags, int *buflen, + xmlChar **buf) { + char boottime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; + char configtime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; + char nowstr[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; + isc_time_t now; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + int xmlrc; + dns_view_t *view; + stats_dumparg_t dumparg; + dns_stats_t *cacherrstats; + uint64_t nsstat_values[ns_statscounter_max]; + uint64_t resstat_values[dns_resstatscounter_max]; + uint64_t adbstat_values[dns_adbstats_max]; + uint64_t zonestat_values[dns_zonestatscounter_max]; + uint64_t sockstat_values[isc_sockstatscounter_max]; + uint64_t udpinsizestat_values[dns_sizecounter_in_max]; + uint64_t udpoutsizestat_values[dns_sizecounter_out_max]; + uint64_t tcpinsizestat_values[dns_sizecounter_in_max]; + uint64_t tcpoutsizestat_values[dns_sizecounter_out_max]; +#ifdef HAVE_DNSTAP + uint64_t dnstapstat_values[dns_dnstapcounter_max]; +#endif /* ifdef HAVE_DNSTAP */ + isc_result_t result; + + isc_time_now(&now); + isc_time_formatISO8601ms(&named_g_boottime, boottime, sizeof boottime); + isc_time_formatISO8601ms(&named_g_configtime, configtime, + sizeof configtime); + isc_time_formatISO8601ms(&now, nowstr, sizeof nowstr); + + writer = xmlNewTextWriterDoc(&doc, 0); + if (writer == NULL) { + goto error; + } + TRY0(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL)); + TRY0(xmlTextWriterWritePI(writer, ISC_XMLCHAR "xml-stylesheet", + ISC_XMLCHAR "type=\"text/xsl\" " + "href=\"/bind9.xsl\"")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", + ISC_XMLCHAR "3.11.1")); + + /* Set common fields for statistics dump */ + dumparg.type = isc_statsformat_xml; + dumparg.arg = writer; + + /* Render server information */ + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time")); + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime)); + TRY0(xmlTextWriterEndElement(writer)); /* boot-time */ + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "config-time")); + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR configtime)); + TRY0(xmlTextWriterEndElement(writer)); /* config-time */ + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time")); + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr)); + TRY0(xmlTextWriterEndElement(writer)); /* current-time */ + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "version")); + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR named_g_version)); + TRY0(xmlTextWriterEndElement(writer)); /* version */ + + if ((flags & STATS_XML_SERVER) != 0) { + dumparg.result = ISC_R_SUCCESS; + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "opcode")); + + dns_opcodestats_dump(server->sctx->opcodestats, opcodestat_dump, + &dumparg, ISC_STATSDUMP_VERBOSE); + if (dumparg.result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "rcode")); + + dns_rcodestats_dump(server->sctx->rcodestats, rcodestat_dump, + &dumparg, ISC_STATSDUMP_VERBOSE); + if (dumparg.result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "qtype")); + + dumparg.result = ISC_R_SUCCESS; + dns_rdatatypestats_dump(server->sctx->rcvquerystats, + rdtypestat_dump, &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + goto error; + } + TRY0(xmlTextWriterEndElement(writer)); /* counters */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "nsstat")); + + result = dump_counters(ns_stats_get(server->sctx->nsstats), + isc_statsformat_xml, writer, NULL, + nsstats_xmldesc, ns_statscounter_max, + nsstats_index, nsstat_values, + ISC_STATSDUMP_VERBOSE); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* /nsstat */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "zonestat")); + + result = dump_counters(server->zonestats, isc_statsformat_xml, + writer, NULL, zonestats_xmldesc, + dns_zonestatscounter_max, + zonestats_index, zonestat_values, + ISC_STATSDUMP_VERBOSE); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* /zonestat */ + + /* + * Most of the common resolver statistics entries are 0, so + * we don't use the verbose dump here. + */ + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "resstat")); + result = dump_counters( + server->resolverstats, isc_statsformat_xml, writer, + NULL, resstats_xmldesc, dns_resstatscounter_max, + resstats_index, resstat_values, 0); + if (result != ISC_R_SUCCESS) { + goto error; + } + TRY0(xmlTextWriterEndElement(writer)); /* resstat */ + +#ifdef HAVE_DNSTAP + if (server->dtenv != NULL) { + isc_stats_t *dnstapstats = NULL; + TRY0(xmlTextWriterStartElement(writer, + ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, + ISC_XMLCHAR "type", + ISC_XMLCHAR "dnstap")); + dns_dt_getstats(named_g_server->dtenv, &dnstapstats); + result = dump_counters( + dnstapstats, isc_statsformat_xml, writer, NULL, + dnstapstats_xmldesc, dns_dnstapcounter_max, + dnstapstats_index, dnstapstat_values, 0); + isc_stats_detach(&dnstapstats); + if (result != ISC_R_SUCCESS) { + goto error; + } + TRY0(xmlTextWriterEndElement(writer)); /* dnstap */ + } +#endif /* ifdef HAVE_DNSTAP */ + } + + if ((flags & STATS_XML_NET) != 0) { + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "sockstat")); + + result = dump_counters(server->sockstats, isc_statsformat_xml, + writer, NULL, sockstats_xmldesc, + isc_sockstatscounter_max, + sockstats_index, sockstat_values, + ISC_STATSDUMP_VERBOSE); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* /sockstat */ + } + TRY0(xmlTextWriterEndElement(writer)); /* /server */ + + if ((flags & STATS_XML_TRAFFIC) != 0) { + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "traffic")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ipv4")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "udp")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "request-size")); + + result = dump_counters( + server->sctx->udpinstats4, isc_statsformat_xml, writer, + NULL, udpinsizestats_xmldesc, dns_sizecounter_in_max, + udpinsizestats_index, udpinsizestat_values, 0); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "response-size")); + + result = dump_counters( + server->sctx->udpoutstats4, isc_statsformat_xml, writer, + NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max, + udpoutsizestats_index, udpoutsizestat_values, 0); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* */ + TRY0(xmlTextWriterEndElement(writer)); /* */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tcp")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "request-size")); + + result = dump_counters( + server->sctx->tcpinstats4, isc_statsformat_xml, writer, + NULL, tcpinsizestats_xmldesc, dns_sizecounter_in_max, + tcpinsizestats_index, tcpinsizestat_values, 0); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "response-size")); + + result = dump_counters( + server->sctx->tcpoutstats4, isc_statsformat_xml, writer, + NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max, + tcpoutsizestats_index, tcpoutsizestat_values, 0); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* */ + TRY0(xmlTextWriterEndElement(writer)); /* */ + TRY0(xmlTextWriterEndElement(writer)); /* */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ipv6")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "udp")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "request-size")); + + result = dump_counters( + server->sctx->udpinstats6, isc_statsformat_xml, writer, + NULL, udpinsizestats_xmldesc, dns_sizecounter_in_max, + udpinsizestats_index, udpinsizestat_values, 0); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "response-size")); + + result = dump_counters( + server->sctx->udpoutstats6, isc_statsformat_xml, writer, + NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max, + udpoutsizestats_index, udpoutsizestat_values, 0); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* */ + TRY0(xmlTextWriterEndElement(writer)); /* */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tcp")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "request-size")); + + result = dump_counters( + server->sctx->tcpinstats6, isc_statsformat_xml, writer, + NULL, tcpinsizestats_xmldesc, dns_sizecounter_in_max, + tcpinsizestats_index, tcpinsizestat_values, 0); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "response-size")); + + result = dump_counters( + server->sctx->tcpoutstats6, isc_statsformat_xml, writer, + NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max, + tcpoutsizestats_index, tcpoutsizestat_values, 0); + if (result != ISC_R_SUCCESS) { + goto error; + } + + TRY0(xmlTextWriterEndElement(writer)); /* */ + TRY0(xmlTextWriterEndElement(writer)); /* */ + TRY0(xmlTextWriterEndElement(writer)); /* */ + TRY0(xmlTextWriterEndElement(writer)); /* */ + } + + /* + * Render views. For each view we know of, call its + * rendering function. + */ + view = ISC_LIST_HEAD(server->viewlist); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views")); + while (view != NULL && + ((flags & (STATS_XML_SERVER | STATS_XML_ZONES)) != 0)) + { + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name", + ISC_XMLCHAR view->name)); + + if ((flags & STATS_XML_ZONES) != 0) { + TRY0(xmlTextWriterStartElement(writer, + ISC_XMLCHAR "zones")); + CHECK(dns_zt_apply(view->zonetable, isc_rwlocktype_read, + true, NULL, zone_xmlrender, writer)); + TRY0(xmlTextWriterEndElement(writer)); /* /zones */ + } + + if ((flags & STATS_XML_SERVER) == 0) { + TRY0(xmlTextWriterEndElement(writer)); /* /view */ + view = ISC_LIST_NEXT(view, link); + continue; + } + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "resqtype")); + + if (view->resquerystats != NULL) { + dumparg.result = ISC_R_SUCCESS; + dns_rdatatypestats_dump(view->resquerystats, + rdtypestat_dump, &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + goto error; + } + } + TRY0(xmlTextWriterEndElement(writer)); + + /* */ + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "resstats")); + if (view->resstats != NULL) { + result = dump_counters( + view->resstats, isc_statsformat_xml, writer, + NULL, resstats_xmldesc, dns_resstatscounter_max, + resstats_index, resstat_values, + ISC_STATSDUMP_VERBOSE); + if (result != ISC_R_SUCCESS) { + goto error; + } + } + TRY0(xmlTextWriterEndElement(writer)); /* */ + + cacherrstats = dns_db_getrrsetstats(view->cachedb); + if (cacherrstats != NULL) { + TRY0(xmlTextWriterStartElement(writer, + ISC_XMLCHAR "cache")); + TRY0(xmlTextWriterWriteAttribute( + writer, ISC_XMLCHAR "name", + ISC_XMLCHAR dns_cache_getname(view->cache))); + dumparg.result = ISC_R_SUCCESS; + dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump, + &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + goto error; + } + TRY0(xmlTextWriterEndElement(writer)); /* cache */ + } + + /* */ + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "adbstat")); + if (view->adbstats != NULL) { + result = dump_counters( + view->adbstats, isc_statsformat_xml, writer, + NULL, adbstats_xmldesc, dns_adbstats_max, + adbstats_index, adbstat_values, + ISC_STATSDUMP_VERBOSE); + if (result != ISC_R_SUCCESS) { + goto error; + } + } + TRY0(xmlTextWriterEndElement(writer)); /* */ + + /* */ + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR "cachestats")); + TRY0(dns_cache_renderxml(view->cache, writer)); + TRY0(xmlTextWriterEndElement(writer)); /* */ + + TRY0(xmlTextWriterEndElement(writer)); /* view */ + + view = ISC_LIST_NEXT(view, link); + } + TRY0(xmlTextWriterEndElement(writer)); /* /views */ + + if ((flags & STATS_XML_NET) != 0) { + TRY0(xmlTextWriterStartElement(writer, + ISC_XMLCHAR "socketmgr")); + TRY0(isc_socketmgr_renderxml(named_g_socketmgr, writer)); + TRY0(xmlTextWriterEndElement(writer)); /* /socketmgr */ + } + + if ((flags & STATS_XML_TASKS) != 0) { + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr")); + TRY0(isc_taskmgr_renderxml(named_g_taskmgr, writer)); + TRY0(xmlTextWriterEndElement(writer)); /* /taskmgr */ + } + + if ((flags & STATS_XML_MEM) != 0) { + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory")); + TRY0(isc_mem_renderxml(writer)); + TRY0(xmlTextWriterEndElement(writer)); /* /memory */ + } + + TRY0(xmlTextWriterEndElement(writer)); /* /statistics */ + TRY0(xmlTextWriterEndDocument(writer)); + + xmlDocDumpFormatMemoryEnc(doc, buf, buflen, "UTF-8", 0); + if (*buf == NULL) { + goto error; + } + + xmlFreeTextWriter(writer); + xmlFreeDoc(doc); + return (ISC_R_SUCCESS); + +error: + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed generating XML response"); + if (writer != NULL) { + xmlFreeTextWriter(writer); + } + if (doc != NULL) { + xmlFreeDoc(doc); + } + return (ISC_R_FAILURE); +} + +static void +wrap_xmlfree(isc_buffer_t *buffer, void *arg) { + UNUSED(arg); + + xmlFree(isc_buffer_base(buffer)); +} + +static isc_result_t +render_xml(uint32_t flags, const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, const char **mimetype, + isc_buffer_t *b, isc_httpdfree_t **freecb, void **freecb_args) { + unsigned char *msg = NULL; + int msglen; + named_server_t *server = arg; + isc_result_t result; + + UNUSED(url); + UNUSED(urlinfo); + UNUSED(headers); + UNUSED(querystring); + + result = generatexml(server, flags, &msglen, &msg); + + if (result == ISC_R_SUCCESS) { + *retcode = 200; + *retmsg = "OK"; + *mimetype = "text/xml"; + isc_buffer_reinit(b, msg, msglen); + isc_buffer_add(b, msglen); + *freecb = wrap_xmlfree; + *freecb_args = NULL; + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed at rendering XML()"); + } + + return (result); +} + +static isc_result_t +render_xml_all(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb, + void **freecb_args) { + return (render_xml(STATS_XML_ALL, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_xml_status(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_xml(STATS_XML_STATUS, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_xml_server(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_xml(STATS_XML_SERVER, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_xml_zones(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_xml(STATS_XML_ZONES, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_xml_net(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb, + void **freecb_args) { + return (render_xml(STATS_XML_NET, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_xml_tasks(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_xml(STATS_XML_TASKS, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_xml_mem(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, isc_httpdfree_t **freecb, + void **freecb_args) { + return (render_xml(STATS_XML_MEM, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_xml_traffic(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_xml(STATS_XML_TRAFFIC, url, urlinfo, querystring, + headers, arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +#endif /* HAVE_LIBXML2 */ + +#ifdef HAVE_JSON_C +/* + * Which statistics to include when rendering to JSON + */ +#define STATS_JSON_STATUS 0x00 /* display only common statistics */ +#define STATS_JSON_SERVER 0x01 +#define STATS_JSON_ZONES 0x02 +#define STATS_JSON_TASKS 0x04 +#define STATS_JSON_NET 0x08 +#define STATS_JSON_MEM 0x10 +#define STATS_JSON_TRAFFIC 0x20 +#define STATS_JSON_ALL 0xff + +#define CHECKMEM(m) \ + do { \ + if (m == NULL) { \ + result = ISC_R_NOMEMORY; \ + goto error; \ + } \ + } while (0) + +static void +wrap_jsonfree(isc_buffer_t *buffer, void *arg) { + json_object_put(isc_buffer_base(buffer)); + if (arg != NULL) { + json_object_put((json_object *)arg); + } +} + +static json_object * +addzone(char *name, char *classname, const char *ztype, uint32_t serial, + bool add_serial) { + json_object *node = json_object_new_object(); + + if (node == NULL) { + return (NULL); + } + + json_object_object_add(node, "name", json_object_new_string(name)); + json_object_object_add(node, "class", + json_object_new_string(classname)); + if (add_serial) { + json_object_object_add(node, "serial", + json_object_new_int64(serial)); + } + if (ztype != NULL) { + json_object_object_add(node, "type", + json_object_new_string(ztype)); + } + return (node); +} + +static isc_result_t +zone_jsonrender(dns_zone_t *zone, void *arg) { + isc_result_t result = ISC_R_SUCCESS; + char buf[1024 + 32]; /* sufficiently large for zone name and class */ + char classbuf[64]; /* sufficiently large for class */ + char *zone_name_only = NULL; + char *class_only = NULL; + dns_rdataclass_t rdclass; + uint32_t serial; + json_object *zonearray = (json_object *)arg; + json_object *zoneobj = NULL; + dns_zonestat_level_t statlevel; + + statlevel = dns_zone_getstatlevel(zone); + if (statlevel == dns_zonestat_none) { + return (ISC_R_SUCCESS); + } + + dns_zone_nameonly(zone, buf, sizeof(buf)); + zone_name_only = buf; + + rdclass = dns_zone_getclass(zone); + dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); + class_only = classbuf; + + if (dns_zone_getserial(zone, &serial) != ISC_R_SUCCESS) { + zoneobj = addzone(zone_name_only, class_only, + user_zonetype(zone), 0, false); + } else { + zoneobj = addzone(zone_name_only, class_only, + user_zonetype(zone), serial, true); + } + + if (zoneobj == NULL) { + return (ISC_R_NOMEMORY); + } + + /* + * Export zone timers to the statistics channel in JSON format. For + * master zones, only include the loaded time. For slave zones, also + * include the expires and refresh times. + */ + + isc_time_t timestamp; + + result = dns_zone_getloadtime(zone, ×tamp); + if (result != ISC_R_SUCCESS) { + goto error; + } + + isc_time_formatISO8601(×tamp, buf, 64); + json_object_object_add(zoneobj, "loaded", json_object_new_string(buf)); + + if (dns_zone_gettype(zone) == dns_zone_secondary) { + result = dns_zone_getexpiretime(zone, ×tamp); + if (result != ISC_R_SUCCESS) { + goto error; + } + isc_time_formatISO8601(×tamp, buf, 64); + json_object_object_add(zoneobj, "expires", + json_object_new_string(buf)); + + result = dns_zone_getrefreshtime(zone, ×tamp); + if (result != ISC_R_SUCCESS) { + goto error; + } + isc_time_formatISO8601(×tamp, buf, 64); + json_object_object_add(zoneobj, "refresh", + json_object_new_string(buf)); + } + + if (statlevel == dns_zonestat_full) { + isc_stats_t *zonestats; + isc_stats_t *gluecachestats; + dns_stats_t *rcvquerystats; + dns_stats_t *dnssecsignstats; + uint64_t nsstat_values[ns_statscounter_max]; + uint64_t gluecachestats_values[dns_gluecachestatscounter_max]; + + zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) { + json_object *counters = json_object_new_object(); + if (counters == NULL) { + result = ISC_R_NOMEMORY; + goto error; + } + + result = dump_counters(zonestats, isc_statsformat_json, + counters, NULL, nsstats_xmldesc, + ns_statscounter_max, + nsstats_index, nsstat_values, 0); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(zoneobj, "rcodes", + counters); + } else { + json_object_put(counters); + } + } + + gluecachestats = dns_zone_getgluecachestats(zone); + if (gluecachestats != NULL) { + json_object *counters = json_object_new_object(); + if (counters == NULL) { + result = ISC_R_NOMEMORY; + goto error; + } + + result = dump_counters( + gluecachestats, isc_statsformat_json, counters, + NULL, gluecachestats_xmldesc, + dns_gluecachestatscounter_max, + gluecachestats_index, gluecachestats_values, 0); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(zoneobj, "gluecache", + counters); + } else { + json_object_put(counters); + } + } + + rcvquerystats = dns_zone_getrcvquerystats(zone); + if (rcvquerystats != NULL) { + stats_dumparg_t dumparg; + json_object *counters = json_object_new_object(); + CHECKMEM(counters); + + dumparg.type = isc_statsformat_json; + dumparg.arg = counters; + dumparg.result = ISC_R_SUCCESS; + dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump, + &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(zoneobj, "qtypes", + counters); + } else { + json_object_put(counters); + } + } + + dnssecsignstats = dns_zone_getdnssecsignstats(zone); + if (dnssecsignstats != NULL) { + stats_dumparg_t dumparg; + json_object *sign_counters = json_object_new_object(); + CHECKMEM(sign_counters); + + dumparg.type = isc_statsformat_json; + dumparg.arg = sign_counters; + dumparg.result = ISC_R_SUCCESS; + dns_dnssecsignstats_dump( + dnssecsignstats, dns_dnssecsignstats_sign, + dnssecsignstat_dump, &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + json_object_put(sign_counters); + goto error; + } + + if (json_object_get_object(sign_counters)->count != 0) { + json_object_object_add(zoneobj, "dnssec-sign", + sign_counters); + } else { + json_object_put(sign_counters); + } + + json_object *refresh_counters = + json_object_new_object(); + CHECKMEM(refresh_counters); + + dumparg.type = isc_statsformat_json; + dumparg.arg = refresh_counters; + dumparg.result = ISC_R_SUCCESS; + dns_dnssecsignstats_dump( + dnssecsignstats, dns_dnssecsignstats_refresh, + dnssecsignstat_dump, &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + json_object_put(refresh_counters); + goto error; + } + + if (json_object_get_object(refresh_counters)->count != + 0) + { + json_object_object_add(zoneobj, + "dnssec-refresh", + refresh_counters); + } else { + json_object_put(refresh_counters); + } + } + } + + json_object_array_add(zonearray, zoneobj); + zoneobj = NULL; + result = ISC_R_SUCCESS; + +error: + if (zoneobj != NULL) { + json_object_put(zoneobj); + } + return (result); +} + +static isc_result_t +generatejson(named_server_t *server, size_t *msglen, const char **msg, + json_object **rootp, uint32_t flags) { + dns_view_t *view; + isc_result_t result = ISC_R_SUCCESS; + json_object *bindstats, *viewlist, *counters, *obj; + json_object *traffic = NULL; + json_object *udpreq4 = NULL, *udpresp4 = NULL; + json_object *tcpreq4 = NULL, *tcpresp4 = NULL; + json_object *udpreq6 = NULL, *udpresp6 = NULL; + json_object *tcpreq6 = NULL, *tcpresp6 = NULL; + uint64_t nsstat_values[ns_statscounter_max]; + uint64_t resstat_values[dns_resstatscounter_max]; + uint64_t adbstat_values[dns_adbstats_max]; + uint64_t zonestat_values[dns_zonestatscounter_max]; + uint64_t sockstat_values[isc_sockstatscounter_max]; + uint64_t udpinsizestat_values[dns_sizecounter_in_max]; + uint64_t udpoutsizestat_values[dns_sizecounter_out_max]; + uint64_t tcpinsizestat_values[dns_sizecounter_in_max]; + uint64_t tcpoutsizestat_values[dns_sizecounter_out_max]; +#ifdef HAVE_DNSTAP + uint64_t dnstapstat_values[dns_dnstapcounter_max]; +#endif /* ifdef HAVE_DNSTAP */ + stats_dumparg_t dumparg; + char boottime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; + char configtime[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; + char nowstr[sizeof "yyyy-mm-ddThh:mm:ss.sssZ"]; + isc_time_t now; + + REQUIRE(msglen != NULL); + REQUIRE(msg != NULL && *msg == NULL); + REQUIRE(rootp == NULL || *rootp == NULL); + + bindstats = json_object_new_object(); + if (bindstats == NULL) { + return (ISC_R_NOMEMORY); + } + + /* + * These statistics are included no matter which URL we use. + */ + obj = json_object_new_string("1.5.1"); + CHECKMEM(obj); + json_object_object_add(bindstats, "json-stats-version", obj); + + isc_time_now(&now); + isc_time_formatISO8601ms(&named_g_boottime, boottime, sizeof(boottime)); + isc_time_formatISO8601ms(&named_g_configtime, configtime, + sizeof configtime); + isc_time_formatISO8601ms(&now, nowstr, sizeof(nowstr)); + + obj = json_object_new_string(boottime); + CHECKMEM(obj); + json_object_object_add(bindstats, "boot-time", obj); + + obj = json_object_new_string(configtime); + CHECKMEM(obj); + json_object_object_add(bindstats, "config-time", obj); + + obj = json_object_new_string(nowstr); + CHECKMEM(obj); + json_object_object_add(bindstats, "current-time", obj); + obj = json_object_new_string(named_g_version); + CHECKMEM(obj); + json_object_object_add(bindstats, "version", obj); + + if ((flags & STATS_JSON_SERVER) != 0) { + /* OPCODE counters */ + counters = json_object_new_object(); + + dumparg.result = ISC_R_SUCCESS; + dumparg.type = isc_statsformat_json; + dumparg.arg = counters; + + dns_opcodestats_dump(server->sctx->opcodestats, opcodestat_dump, + &dumparg, ISC_STATSDUMP_VERBOSE); + if (dumparg.result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(bindstats, "opcodes", counters); + } else { + json_object_put(counters); + } + + /* OPCODE counters */ + counters = json_object_new_object(); + + dumparg.type = isc_statsformat_json; + dumparg.arg = counters; + + dns_rcodestats_dump(server->sctx->rcodestats, rcodestat_dump, + &dumparg, ISC_STATSDUMP_VERBOSE); + if (dumparg.result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(bindstats, "rcodes", counters); + } else { + json_object_put(counters); + } + + /* QTYPE counters */ + counters = json_object_new_object(); + + dumparg.result = ISC_R_SUCCESS; + dumparg.arg = counters; + + dns_rdatatypestats_dump(server->sctx->rcvquerystats, + rdtypestat_dump, &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(bindstats, "qtypes", counters); + } else { + json_object_put(counters); + } + + /* server stat counters */ + counters = json_object_new_object(); + + dumparg.result = ISC_R_SUCCESS; + dumparg.arg = counters; + + result = dump_counters(ns_stats_get(server->sctx->nsstats), + isc_statsformat_json, counters, NULL, + nsstats_xmldesc, ns_statscounter_max, + nsstats_index, nsstat_values, 0); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(bindstats, "nsstats", counters); + } else { + json_object_put(counters); + } + + /* zone stat counters */ + counters = json_object_new_object(); + + dumparg.result = ISC_R_SUCCESS; + dumparg.arg = counters; + + result = dump_counters(server->zonestats, isc_statsformat_json, + counters, NULL, zonestats_xmldesc, + dns_zonestatscounter_max, + zonestats_index, zonestat_values, 0); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(bindstats, "zonestats", + counters); + } else { + json_object_put(counters); + } + + /* resolver stat counters */ + counters = json_object_new_object(); + + dumparg.result = ISC_R_SUCCESS; + dumparg.arg = counters; + + result = dump_counters( + server->resolverstats, isc_statsformat_json, counters, + NULL, resstats_xmldesc, dns_resstatscounter_max, + resstats_index, resstat_values, 0); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(bindstats, "resstats", counters); + } else { + json_object_put(counters); + } + +#ifdef HAVE_DNSTAP + /* dnstap stat counters */ + if (named_g_server->dtenv != NULL) { + isc_stats_t *dnstapstats = NULL; + dns_dt_getstats(named_g_server->dtenv, &dnstapstats); + counters = json_object_new_object(); + dumparg.result = ISC_R_SUCCESS; + dumparg.arg = counters; + result = dump_counters( + dnstapstats, isc_statsformat_json, counters, + NULL, dnstapstats_xmldesc, + dns_dnstapcounter_max, dnstapstats_index, + dnstapstat_values, 0); + isc_stats_detach(&dnstapstats); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(bindstats, "dnstapstats", + counters); + } else { + json_object_put(counters); + } + } +#endif /* ifdef HAVE_DNSTAP */ + } + + if ((flags & (STATS_JSON_ZONES | STATS_JSON_SERVER)) != 0) { + viewlist = json_object_new_object(); + CHECKMEM(viewlist); + + json_object_object_add(bindstats, "views", viewlist); + + view = ISC_LIST_HEAD(server->viewlist); + while (view != NULL) { + json_object *za, *v = json_object_new_object(); + + CHECKMEM(v); + json_object_object_add(viewlist, view->name, v); + + za = json_object_new_array(); + CHECKMEM(za); + + if ((flags & STATS_JSON_ZONES) != 0) { + CHECK(dns_zt_apply(view->zonetable, + isc_rwlocktype_read, true, + NULL, zone_jsonrender, za)); + } + + if (json_object_array_length(za) != 0) { + json_object_object_add(v, "zones", za); + } else { + json_object_put(za); + } + + if ((flags & STATS_JSON_SERVER) != 0) { + json_object *res; + dns_stats_t *dstats; + isc_stats_t *istats; + + res = json_object_new_object(); + CHECKMEM(res); + json_object_object_add(v, "resolver", res); + + istats = view->resstats; + if (istats != NULL) { + counters = json_object_new_object(); + CHECKMEM(counters); + + result = dump_counters( + istats, isc_statsformat_json, + counters, NULL, + resstats_xmldesc, + dns_resstatscounter_max, + resstats_index, resstat_values, + 0); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + result = dumparg.result; + goto error; + } + + json_object_object_add(res, "stats", + counters); + } + + dstats = view->resquerystats; + if (dstats != NULL) { + counters = json_object_new_object(); + CHECKMEM(counters); + + dumparg.arg = counters; + dumparg.result = ISC_R_SUCCESS; + dns_rdatatypestats_dump(dstats, + rdtypestat_dump, + &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + json_object_put(counters); + result = dumparg.result; + goto error; + } + + json_object_object_add(res, "qtypes", + counters); + } + + dstats = dns_db_getrrsetstats(view->cachedb); + if (dstats != NULL) { + counters = json_object_new_object(); + CHECKMEM(counters); + + dumparg.arg = counters; + dumparg.result = ISC_R_SUCCESS; + dns_rdatasetstats_dump( + dstats, rdatasetstats_dump, + &dumparg, 0); + if (dumparg.result != ISC_R_SUCCESS) { + json_object_put(counters); + result = dumparg.result; + goto error; + } + + json_object_object_add(res, "cache", + counters); + } + + counters = json_object_new_object(); + CHECKMEM(counters); + + result = dns_cache_renderjson(view->cache, + counters); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + json_object_object_add(res, "cachestats", + counters); + + istats = view->adbstats; + if (istats != NULL) { + counters = json_object_new_object(); + CHECKMEM(counters); + + result = dump_counters( + istats, isc_statsformat_json, + counters, NULL, + adbstats_xmldesc, + dns_adbstats_max, + adbstats_index, adbstat_values, + 0); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + result = dumparg.result; + goto error; + } + + json_object_object_add(res, "adb", + counters); + } + } + + view = ISC_LIST_NEXT(view, link); + } + } + + if ((flags & STATS_JSON_NET) != 0) { + /* socket stat counters */ + json_object *sockets; + counters = json_object_new_object(); + + dumparg.result = ISC_R_SUCCESS; + dumparg.arg = counters; + + result = dump_counters(server->sockstats, isc_statsformat_json, + counters, NULL, sockstats_xmldesc, + isc_sockstatscounter_max, + sockstats_index, sockstat_values, 0); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + goto error; + } + + if (json_object_get_object(counters)->count != 0) { + json_object_object_add(bindstats, "sockstats", + counters); + } else { + json_object_put(counters); + } + + sockets = json_object_new_object(); + CHECKMEM(sockets); + + result = isc_socketmgr_renderjson(named_g_socketmgr, sockets); + if (result != ISC_R_SUCCESS) { + json_object_put(sockets); + goto error; + } + + json_object_object_add(bindstats, "socketmgr", sockets); + } + + if ((flags & STATS_JSON_TASKS) != 0) { + json_object *tasks = json_object_new_object(); + CHECKMEM(tasks); + + result = isc_taskmgr_renderjson(named_g_taskmgr, tasks); + if (result != ISC_R_SUCCESS) { + json_object_put(tasks); + goto error; + } + + json_object_object_add(bindstats, "taskmgr", tasks); + } + + if ((flags & STATS_JSON_MEM) != 0) { + json_object *memory = json_object_new_object(); + CHECKMEM(memory); + + result = isc_mem_renderjson(memory); + if (result != ISC_R_SUCCESS) { + json_object_put(memory); + goto error; + } + + json_object_object_add(bindstats, "memory", memory); + } + + if ((flags & STATS_JSON_TRAFFIC) != 0) { + traffic = json_object_new_object(); + CHECKMEM(traffic); + + udpreq4 = json_object_new_object(); + CHECKMEM(udpreq4); + + udpresp4 = json_object_new_object(); + CHECKMEM(udpresp4); + + tcpreq4 = json_object_new_object(); + CHECKMEM(tcpreq4); + + tcpresp4 = json_object_new_object(); + CHECKMEM(tcpresp4); + + udpreq6 = json_object_new_object(); + CHECKMEM(udpreq6); + + udpresp6 = json_object_new_object(); + CHECKMEM(udpresp6); + + tcpreq6 = json_object_new_object(); + CHECKMEM(tcpreq6); + + tcpresp6 = json_object_new_object(); + CHECKMEM(tcpresp6); + + CHECK(dump_counters( + server->sctx->udpinstats4, isc_statsformat_json, + udpreq4, NULL, udpinsizestats_xmldesc, + dns_sizecounter_in_max, udpinsizestats_index, + udpinsizestat_values, 0)); + + CHECK(dump_counters( + server->sctx->udpoutstats4, isc_statsformat_json, + udpresp4, NULL, udpoutsizestats_xmldesc, + dns_sizecounter_out_max, udpoutsizestats_index, + udpoutsizestat_values, 0)); + + CHECK(dump_counters( + server->sctx->tcpinstats4, isc_statsformat_json, + tcpreq4, NULL, tcpinsizestats_xmldesc, + dns_sizecounter_in_max, tcpinsizestats_index, + tcpinsizestat_values, 0)); + + CHECK(dump_counters( + server->sctx->tcpoutstats4, isc_statsformat_json, + tcpresp4, NULL, tcpoutsizestats_xmldesc, + dns_sizecounter_out_max, tcpoutsizestats_index, + tcpoutsizestat_values, 0)); + + CHECK(dump_counters( + server->sctx->udpinstats6, isc_statsformat_json, + udpreq6, NULL, udpinsizestats_xmldesc, + dns_sizecounter_in_max, udpinsizestats_index, + udpinsizestat_values, 0)); + + CHECK(dump_counters( + server->sctx->udpoutstats6, isc_statsformat_json, + udpresp6, NULL, udpoutsizestats_xmldesc, + dns_sizecounter_out_max, udpoutsizestats_index, + udpoutsizestat_values, 0)); + + CHECK(dump_counters( + server->sctx->tcpinstats6, isc_statsformat_json, + tcpreq6, NULL, tcpinsizestats_xmldesc, + dns_sizecounter_in_max, tcpinsizestats_index, + tcpinsizestat_values, 0)); + + CHECK(dump_counters( + server->sctx->tcpoutstats6, isc_statsformat_json, + tcpresp6, NULL, tcpoutsizestats_xmldesc, + dns_sizecounter_out_max, tcpoutsizestats_index, + tcpoutsizestat_values, 0)); + + json_object_object_add(traffic, + "dns-udp-requests-sizes-received-ipv4", + udpreq4); + json_object_object_add( + traffic, "dns-udp-responses-sizes-sent-ipv4", udpresp4); + json_object_object_add(traffic, + "dns-tcp-requests-sizes-received-ipv4", + tcpreq4); + json_object_object_add( + traffic, "dns-tcp-responses-sizes-sent-ipv4", tcpresp4); + json_object_object_add(traffic, + "dns-udp-requests-sizes-received-ipv6", + udpreq6); + json_object_object_add( + traffic, "dns-udp-responses-sizes-sent-ipv6", udpresp6); + json_object_object_add(traffic, + "dns-tcp-requests-sizes-received-ipv6", + tcpreq6); + json_object_object_add( + traffic, "dns-tcp-responses-sizes-sent-ipv6", tcpresp6); + json_object_object_add(bindstats, "traffic", traffic); + udpreq4 = NULL; + udpresp4 = NULL; + tcpreq4 = NULL; + tcpresp4 = NULL; + udpreq6 = NULL; + udpresp6 = NULL; + tcpreq6 = NULL; + tcpresp6 = NULL; + traffic = NULL; + } + + *msg = json_object_to_json_string_ext(bindstats, + JSON_C_TO_STRING_PRETTY); + *msglen = strlen(*msg); + + if (rootp != NULL) { + *rootp = bindstats; + bindstats = NULL; + } + + result = ISC_R_SUCCESS; + +error: + if (udpreq4 != NULL) { + json_object_put(udpreq4); + } + if (udpresp4 != NULL) { + json_object_put(udpresp4); + } + if (tcpreq4 != NULL) { + json_object_put(tcpreq4); + } + if (tcpresp4 != NULL) { + json_object_put(tcpresp4); + } + if (udpreq6 != NULL) { + json_object_put(udpreq6); + } + if (udpresp6 != NULL) { + json_object_put(udpresp6); + } + if (tcpreq6 != NULL) { + json_object_put(tcpreq6); + } + if (tcpresp6 != NULL) { + json_object_put(tcpresp6); + } + if (traffic != NULL) { + json_object_put(traffic); + } + if (bindstats != NULL) { + json_object_put(bindstats); + } + + return (result); +} + +static isc_result_t +render_json(uint32_t flags, const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, const char **mimetype, + isc_buffer_t *b, isc_httpdfree_t **freecb, void **freecb_args) { + isc_result_t result; + json_object *bindstats = NULL; + named_server_t *server = arg; + const char *msg = NULL; + size_t msglen = 0; + char *p; + + UNUSED(url); + UNUSED(urlinfo); + UNUSED(headers); + UNUSED(querystring); + + result = generatejson(server, &msglen, &msg, &bindstats, flags); + if (result == ISC_R_SUCCESS) { + *retcode = 200; + *retmsg = "OK"; + *mimetype = "application/json"; + DE_CONST(msg, p); + isc_buffer_reinit(b, p, msglen); + isc_buffer_add(b, msglen); + *freecb = wrap_jsonfree; + *freecb_args = bindstats; + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed at rendering JSON()"); + } + + return (result); +} + +static isc_result_t +render_json_all(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_json(STATS_JSON_ALL, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_json_status(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_json(STATS_JSON_STATUS, url, urlinfo, querystring, + headers, arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_json_server(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_json(STATS_JSON_SERVER, url, urlinfo, querystring, + headers, arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_json_zones(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_json(STATS_JSON_ZONES, url, urlinfo, querystring, + headers, arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_json_mem(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_json(STATS_JSON_MEM, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_json_tasks(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_json(STATS_JSON_TASKS, url, urlinfo, querystring, + headers, arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_json_net(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_json(STATS_JSON_NET, url, urlinfo, querystring, headers, + arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +static isc_result_t +render_json_traffic(const char *url, isc_httpdurl_t *urlinfo, + const char *querystring, const char *headers, void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + return (render_json(STATS_JSON_TRAFFIC, url, urlinfo, querystring, + headers, arg, retcode, retmsg, mimetype, b, freecb, + freecb_args)); +} + +#endif /* HAVE_JSON_C */ + +static isc_result_t +render_xsl(const char *url, isc_httpdurl_t *urlinfo, const char *querystring, + const char *headers, void *args, unsigned int *retcode, + const char **retmsg, const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) { + isc_result_t result; + char *_headers = NULL; + + UNUSED(url); + UNUSED(querystring); + UNUSED(args); + + *freecb = NULL; + *freecb_args = NULL; + *mimetype = "text/xslt+xml"; + + if (urlinfo->isstatic) { + isc_time_t when; + char *line, *saveptr; + const char *if_modified_since = "If-Modified-Since: "; + _headers = strdup(headers); + + if (_headers == NULL) { + goto send; + } + + saveptr = NULL; + for (line = strtok_r(_headers, "\n", &saveptr); line; + line = strtok_r(NULL, "\n", &saveptr)) + { + if (strncasecmp(line, if_modified_since, + strlen(if_modified_since)) == 0) + { + time_t t1, t2; + line += strlen(if_modified_since); + result = isc_time_parsehttptimestamp(line, + &when); + if (result != ISC_R_SUCCESS) { + goto send; + } + + result = isc_time_secondsastimet(&when, &t1); + if (result != ISC_R_SUCCESS) { + goto send; + } + + result = isc_time_secondsastimet( + &urlinfo->loadtime, &t2); + if (result != ISC_R_SUCCESS) { + goto send; + } + + if (t1 < t2) { + goto send; + } + + *retcode = 304; + *retmsg = "Not modified"; + goto end; + } + } + } + +send: + *retcode = 200; + *retmsg = "OK"; + isc_buffer_reinit(b, xslmsg, strlen(xslmsg)); + isc_buffer_add(b, strlen(xslmsg)); +end: + free(_headers); + return (ISC_R_SUCCESS); +} + +static void +shutdown_listener(named_statschannel_t *listener) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format(&listener->address, socktext, sizeof(socktext)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE, + "stopping statistics channel on %s", socktext); + + isc_httpdmgr_shutdown(&listener->httpdmgr); +} + +static bool +client_ok(const isc_sockaddr_t *fromaddr, void *arg) { + named_statschannel_t *listener = arg; + dns_aclenv_t *env = + ns_interfacemgr_getaclenv(named_g_server->interfacemgr); + isc_netaddr_t netaddr; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + int match; + + REQUIRE(listener != NULL); + + isc_netaddr_fromsockaddr(&netaddr, fromaddr); + + LOCK(&listener->lock); + if ((dns_acl_match(&netaddr, NULL, listener->acl, env, &match, NULL) == + ISC_R_SUCCESS) && + match > 0) + { + UNLOCK(&listener->lock); + return (true); + } + UNLOCK(&listener->lock); + + isc_sockaddr_format(fromaddr, socktext, sizeof(socktext)); + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "rejected statistics connection from %s", socktext); + + return (false); +} + +static void +destroy_listener(void *arg) { + named_statschannel_t *listener = arg; + + REQUIRE(listener != NULL); + REQUIRE(!ISC_LINK_LINKED(listener, link)); + + /* We don't have to acquire the lock here since it's already unlinked */ + dns_acl_detach(&listener->acl); + + isc_mutex_destroy(&listener->lock); + isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); +} + +static isc_result_t +add_listener(named_server_t *server, named_statschannel_t **listenerp, + const cfg_obj_t *listen_params, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext) { + isc_result_t result; + named_statschannel_t *listener; + isc_task_t *task = NULL; + isc_socket_t *sock = NULL; + const cfg_obj_t *allow; + dns_acl_t *new_acl = NULL; + + listener = isc_mem_get(server->mctx, sizeof(*listener)); + + listener->httpdmgr = NULL; + listener->address = *addr; + listener->acl = NULL; + listener->mctx = NULL; + ISC_LINK_INIT(listener, link); + + isc_mutex_init(&listener->lock); + + isc_mem_attach(server->mctx, &listener->mctx); + + allow = cfg_tuple_get(listen_params, "allow"); + if (allow != NULL && cfg_obj_islist(allow)) { + result = cfg_acl_fromconfig(allow, config, named_g_lctx, + aclconfctx, listener->mctx, 0, + &new_acl); + } else { + result = dns_acl_any(listener->mctx, &new_acl); + } + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + + result = isc_task_create(named_g_taskmgr, 0, &task); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + isc_task_setname(task, "statchannel", NULL); + + result = isc_socket_create(named_g_socketmgr, isc_sockaddr_pf(addr), + isc_sockettype_tcp, &sock); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + isc_socket_setname(sock, "statchannel", NULL); + +#ifndef ISC_ALLOW_MAPPED + isc_socket_ipv6only(sock, true); +#endif /* ifndef ISC_ALLOW_MAPPED */ + + result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = isc_httpdmgr_create(server->mctx, sock, task, client_ok, + destroy_listener, listener, + named_g_timermgr, &listener->httpdmgr); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + +#ifdef HAVE_LIBXML2 + isc_httpdmgr_addurl(listener->httpdmgr, "/", render_xml_all, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/xml", render_xml_all, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3", render_xml_all, + server); + isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/status", + render_xml_status, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/server", + render_xml_server, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/zones", + render_xml_zones, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/net", render_xml_net, + server); + isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/tasks", + render_xml_tasks, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/mem", render_xml_mem, + server); + isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/traffic", + render_xml_traffic, server); +#endif /* ifdef HAVE_LIBXML2 */ +#ifdef HAVE_JSON_C + isc_httpdmgr_addurl(listener->httpdmgr, "/json", render_json_all, + server); + isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1", render_json_all, + server); + isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/status", + render_json_status, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/server", + render_json_server, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/zones", + render_json_zones, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/tasks", + render_json_tasks, server); + isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/net", render_json_net, + server); + isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/mem", render_json_mem, + server); + isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/traffic", + render_json_traffic, server); +#endif /* ifdef HAVE_JSON_C */ + isc_httpdmgr_addurl2(listener->httpdmgr, "/bind9.xsl", true, render_xsl, + server); + + *listenerp = listener; + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE, + "statistics channel listening on %s", socktext); + +cleanup: + if (result != ISC_R_SUCCESS) { + if (listener->acl != NULL) { + dns_acl_detach(&listener->acl); + } + isc_mutex_destroy(&listener->lock); + isc_mem_putanddetach(&listener->mctx, listener, + sizeof(*listener)); + } + if (task != NULL) { + isc_task_detach(&task); + } + if (sock != NULL) { + isc_socket_detach(&sock); + } + + return (result); +} + +static void +update_listener(named_server_t *server, named_statschannel_t **listenerp, + const cfg_obj_t *listen_params, const cfg_obj_t *config, + isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, + const char *socktext) { + named_statschannel_t *listener; + const cfg_obj_t *allow = NULL; + dns_acl_t *new_acl = NULL; + isc_result_t result = ISC_R_SUCCESS; + + for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL; + listener = ISC_LIST_NEXT(listener, link)) + { + if (isc_sockaddr_equal(addr, &listener->address)) { + break; + } + } + + if (listener == NULL) { + *listenerp = NULL; + return; + } + + /* + * Now, keep the old access list unless a new one can be made. + */ + allow = cfg_tuple_get(listen_params, "allow"); + if (allow != NULL && cfg_obj_islist(allow)) { + result = cfg_acl_fromconfig(allow, config, named_g_lctx, + aclconfctx, listener->mctx, 0, + &new_acl); + } else { + result = dns_acl_any(listener->mctx, &new_acl); + } + + if (result == ISC_R_SUCCESS) { + LOCK(&listener->lock); + + dns_acl_detach(&listener->acl); + dns_acl_attach(new_acl, &listener->acl); + dns_acl_detach(&new_acl); + + UNLOCK(&listener->lock); + } else { + cfg_obj_log(listen_params, named_g_lctx, ISC_LOG_WARNING, + "couldn't install new acl for " + "statistics channel %s: %s", + socktext, isc_result_totext(result)); + } + + *listenerp = listener; +} + +isc_result_t +named_statschannels_configure(named_server_t *server, const cfg_obj_t *config, + cfg_aclconfctx_t *aclconfctx) { + named_statschannel_t *listener, *listener_next; + named_statschannellist_t new_listeners; + const cfg_obj_t *statschannellist = NULL; + const cfg_listelt_t *element, *element2; + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); + + ISC_LIST_INIT(new_listeners); + + /* + * Get the list of named.conf 'statistics-channels' statements. + */ + (void)cfg_map_get(config, "statistics-channels", &statschannellist); + + /* + * Run through the new address/port list, noting sockets that are + * already being listened on and moving them to the new list. + * + * Identifying duplicate addr/port combinations is left to either + * the underlying config code, or to the bind attempt getting an + * address-in-use error. + */ + if (statschannellist != NULL) { +#ifndef EXTENDED_STATS + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "statistics-channels specified but not effective " + "due to missing XML and/or JSON library"); +#else /* EXTENDED_STATS */ +#ifndef HAVE_LIBXML2 + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "statistics-channels: XML library missing, " + "only JSON stats will be available"); +#endif /* !HAVE_LIBXML2 */ +#ifndef HAVE_JSON_C + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "statistics-channels: JSON library missing, " + "only XML stats will be available"); +#endif /* !HAVE_JSON_C */ +#endif /* EXTENDED_STATS */ + + for (element = cfg_list_first(statschannellist); + element != NULL; element = cfg_list_next(element)) + { + const cfg_obj_t *statschannel; + const cfg_obj_t *listenercfg = NULL; + + statschannel = cfg_listelt_value(element); + (void)cfg_map_get(statschannel, "inet", &listenercfg); + if (listenercfg == NULL) { + continue; + } + + for (element2 = cfg_list_first(listenercfg); + element2 != NULL; + element2 = cfg_list_next(element2)) + { + const cfg_obj_t *listen_params; + const cfg_obj_t *obj; + isc_sockaddr_t addr; + + listen_params = cfg_listelt_value(element2); + + obj = cfg_tuple_get(listen_params, "address"); + addr = *cfg_obj_assockaddr(obj); + if (isc_sockaddr_getport(&addr) == 0) { + isc_sockaddr_setport( + &addr, + NAMED_STATSCHANNEL_HTTPPORT); + } + + isc_sockaddr_format(&addr, socktext, + sizeof(socktext)); + + isc_log_write(named_g_lctx, + NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, + ISC_LOG_DEBUG(9), + "processing statistics " + "channel %s", + socktext); + + update_listener(server, &listener, + listen_params, config, &addr, + aclconfctx, socktext); + + if (listener != NULL) { + /* + * Remove the listener from the old + * list, so it won't be shut down. + */ + ISC_LIST_UNLINK(server->statschannels, + listener, link); + } else { + /* + * This is a new listener. + */ + isc_result_t r; + + r = add_listener(server, &listener, + listen_params, config, + &addr, aclconfctx, + socktext); + if (r != ISC_R_SUCCESS) { + cfg_obj_log( + listen_params, + named_g_lctx, + ISC_LOG_WARNING, + "couldn't allocate " + "statistics channel" + " %s: %s", + socktext, + isc_result_totext(r)); + } + } + + if (listener != NULL) { + ISC_LIST_APPEND(new_listeners, listener, + link); + } + } + } + } + + for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL; + listener = listener_next) + { + listener_next = ISC_LIST_NEXT(listener, link); + ISC_LIST_UNLINK(server->statschannels, listener, link); + shutdown_listener(listener); + } + + ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link); + return (ISC_R_SUCCESS); +} + +void +named_statschannels_shutdown(named_server_t *server) { + named_statschannel_t *listener; + + while ((listener = ISC_LIST_HEAD(server->statschannels)) != NULL) { + ISC_LIST_UNLINK(server->statschannels, listener, link); + shutdown_listener(listener); + } +} + +isc_result_t +named_stats_dump(named_server_t *server, FILE *fp) { + isc_stdtime_t now; + isc_result_t result; + dns_view_t *view; + dns_zone_t *zone, *next; + stats_dumparg_t dumparg; + uint64_t nsstat_values[ns_statscounter_max]; + uint64_t resstat_values[dns_resstatscounter_max]; + uint64_t adbstat_values[dns_adbstats_max]; + uint64_t zonestat_values[dns_zonestatscounter_max]; + uint64_t sockstat_values[isc_sockstatscounter_max]; + uint64_t gluecachestats_values[dns_gluecachestatscounter_max]; + + RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); + + /* Set common fields */ + dumparg.type = isc_statsformat_file; + dumparg.arg = fp; + + isc_stdtime_get(&now); + fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); + + fprintf(fp, "++ Incoming Requests ++\n"); + dns_opcodestats_dump(server->sctx->opcodestats, opcodestat_dump, + &dumparg, 0); + + fprintf(fp, "++ Incoming Queries ++\n"); + dns_rdatatypestats_dump(server->sctx->rcvquerystats, rdtypestat_dump, + &dumparg, 0); + + fprintf(fp, "++ Outgoing Rcodes ++\n"); + dns_rcodestats_dump(server->sctx->rcodestats, rcodestat_dump, &dumparg, + 0); + + fprintf(fp, "++ Outgoing Queries ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (view->resquerystats == NULL) { + continue; + } + if (strcmp(view->name, "_default") == 0) { + fprintf(fp, "[View: default]\n"); + } else { + fprintf(fp, "[View: %s]\n", view->name); + } + dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump, + &dumparg, 0); + } + + fprintf(fp, "++ Name Server Statistics ++\n"); + (void)dump_counters(ns_stats_get(server->sctx->nsstats), + isc_statsformat_file, fp, NULL, nsstats_desc, + ns_statscounter_max, nsstats_index, nsstat_values, + 0); + + fprintf(fp, "++ Zone Maintenance Statistics ++\n"); + (void)dump_counters(server->zonestats, isc_statsformat_file, fp, NULL, + zonestats_desc, dns_zonestatscounter_max, + zonestats_index, zonestat_values, 0); + + fprintf(fp, "++ Resolver Statistics ++\n"); + fprintf(fp, "[Common]\n"); + (void)dump_counters(server->resolverstats, isc_statsformat_file, fp, + NULL, resstats_desc, dns_resstatscounter_max, + resstats_index, resstat_values, 0); + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (view->resstats == NULL) { + continue; + } + if (strcmp(view->name, "_default") == 0) { + fprintf(fp, "[View: default]\n"); + } else { + fprintf(fp, "[View: %s]\n", view->name); + } + (void)dump_counters(view->resstats, isc_statsformat_file, fp, + NULL, resstats_desc, + dns_resstatscounter_max, resstats_index, + resstat_values, 0); + } + + fprintf(fp, "++ Cache Statistics ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (strcmp(view->name, "_default") == 0) { + fprintf(fp, "[View: default]\n"); + } else { + fprintf(fp, "[View: %s (Cache: %s)]\n", view->name, + dns_cache_getname(view->cache)); + } + /* + * Avoid dumping redundant statistics when the cache is shared. + */ + if (dns_view_iscacheshared(view)) { + continue; + } + dns_cache_dumpstats(view->cache, fp); + } + + fprintf(fp, "++ Cache DB RRsets ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + dns_stats_t *cacherrstats; + + cacherrstats = dns_db_getrrsetstats(view->cachedb); + if (cacherrstats == NULL) { + continue; + } + if (strcmp(view->name, "_default") == 0) { + fprintf(fp, "[View: default]\n"); + } else { + fprintf(fp, "[View: %s (Cache: %s)]\n", view->name, + dns_cache_getname(view->cache)); + } + if (dns_view_iscacheshared(view)) { + /* + * Avoid dumping redundant statistics when the cache is + * shared. + */ + continue; + } + dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump, + &dumparg, 0); + } + + fprintf(fp, "++ ADB stats ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (view->adbstats == NULL) { + continue; + } + if (strcmp(view->name, "_default") == 0) { + fprintf(fp, "[View: default]\n"); + } else { + fprintf(fp, "[View: %s]\n", view->name); + } + (void)dump_counters(view->adbstats, isc_statsformat_file, fp, + NULL, adbstats_desc, dns_adbstats_max, + adbstats_index, adbstat_values, 0); + } + + fprintf(fp, "++ Socket I/O Statistics ++\n"); + (void)dump_counters(server->sockstats, isc_statsformat_file, fp, NULL, + sockstats_desc, isc_sockstatscounter_max, + sockstats_index, sockstat_values, 0); + + fprintf(fp, "++ Per Zone Query Statistics ++\n"); + zone = NULL; + for (result = dns_zone_first(server->zonemgr, &zone); + result == ISC_R_SUCCESS; + next = NULL, result = dns_zone_next(zone, &next), zone = next) + { + isc_stats_t *zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) { + char zonename[DNS_NAME_FORMATSIZE]; + + view = dns_zone_getview(zone); + if (view == NULL) { + continue; + } + + dns_name_format(dns_zone_getorigin(zone), zonename, + sizeof(zonename)); + fprintf(fp, "[%s", zonename); + if (strcmp(view->name, "_default") != 0) { + fprintf(fp, " (view: %s)", view->name); + } + fprintf(fp, "]\n"); + + (void)dump_counters(zonestats, isc_statsformat_file, fp, + NULL, nsstats_desc, + ns_statscounter_max, nsstats_index, + nsstat_values, 0); + } + } + + fprintf(fp, "++ Per Zone Glue Cache Statistics ++\n"); + zone = NULL; + for (result = dns_zone_first(server->zonemgr, &zone); + result == ISC_R_SUCCESS; + next = NULL, result = dns_zone_next(zone, &next), zone = next) + { + isc_stats_t *gluecachestats = dns_zone_getgluecachestats(zone); + if (gluecachestats != NULL) { + char zonename[DNS_NAME_FORMATSIZE]; + + view = dns_zone_getview(zone); + if (view == NULL) { + continue; + } + + dns_name_format(dns_zone_getorigin(zone), zonename, + sizeof(zonename)); + fprintf(fp, "[%s", zonename); + if (strcmp(view->name, "_default") != 0) { + fprintf(fp, " (view: %s)", view->name); + } + fprintf(fp, "]\n"); + + (void)dump_counters( + gluecachestats, isc_statsformat_file, fp, NULL, + gluecachestats_desc, + dns_gluecachestatscounter_max, + gluecachestats_index, gluecachestats_values, 0); + } + } + + fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); + + return (ISC_R_SUCCESS); /* this function currently always succeeds */ +} diff --git a/bin/named/tkeyconf.c b/bin/named/tkeyconf.c new file mode 100644 index 0000000..03b198b --- /dev/null +++ b/bin/named/tkeyconf.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include + +#include +#include +#include /* Required for HP/UX (and others?) */ + +#include +#include +#include +#include + +#include + +#include + +#include + +#define RETERR(x) \ + do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto failure; \ + } while (0) + +#include +#define LOG(msg) \ + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \ + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, "%s", msg) + +isc_result_t +named_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx, + dns_tkeyctx_t **tctxp) { + isc_result_t result; + dns_tkeyctx_t *tctx = NULL; + const char *s; + uint32_t n; + dns_fixedname_t fname; + dns_name_t *name; + isc_buffer_t b; + const cfg_obj_t *obj; + int type; + + result = dns_tkeyctx_create(mctx, &tctx); + if (result != ISC_R_SUCCESS) { + return (result); + } + + obj = NULL; + result = cfg_map_get(options, "tkey-dhkey", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(cfg_tuple_get(obj, "name")); + n = cfg_obj_asuint32(cfg_tuple_get(obj, "keyid")); + isc_buffer_constinit(&b, s, strlen(s)); + isc_buffer_add(&b, strlen(s)); + name = dns_fixedname_initname(&fname); + RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; + RETERR(dst_key_fromfile(name, (dns_keytag_t)n, DNS_KEYALG_DH, + type, NULL, mctx, &tctx->dhkey)); + } + + obj = NULL; + result = cfg_map_get(options, "tkey-domain", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(obj); + isc_buffer_constinit(&b, s, strlen(s)); + isc_buffer_add(&b, strlen(s)); + name = dns_fixedname_initname(&fname); + RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + tctx->domain = isc_mem_get(mctx, sizeof(dns_name_t)); + dns_name_init(tctx->domain, NULL); + dns_name_dup(name, mctx, tctx->domain); + } + + obj = NULL; + result = cfg_map_get(options, "tkey-gssapi-credential", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(obj); + + isc_buffer_constinit(&b, s, strlen(s)); + isc_buffer_add(&b, strlen(s)); + name = dns_fixedname_initname(&fname); + RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + RETERR(dst_gssapi_acquirecred(name, false, &tctx->gsscred)); + } + + obj = NULL; + result = cfg_map_get(options, "tkey-gssapi-keytab", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(obj); + tctx->gssapi_keytab = isc_mem_strdup(mctx, s); + } + + *tctxp = tctx; + return (ISC_R_SUCCESS); + +failure: + dns_tkeyctx_destroy(&tctx); + return (result); +} diff --git a/bin/named/tsigconf.c b/bin/named/tsigconf.c new file mode 100644 index 0000000..085cc39 --- /dev/null +++ b/bin/named/tsigconf.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +static isc_result_t +add_initial_keys(const cfg_obj_t *list, dns_tsig_keyring_t *ring, + isc_mem_t *mctx) { + dns_tsigkey_t *tsigkey = NULL; + const cfg_listelt_t *element; + const cfg_obj_t *key = NULL; + const char *keyid = NULL; + unsigned char *secret = NULL; + int secretalloc = 0; + int secretlen = 0; + isc_result_t ret; + isc_stdtime_t now; + uint16_t bits; + + for (element = cfg_list_first(list); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *algobj = NULL; + const cfg_obj_t *secretobj = NULL; + dns_name_t keyname; + const dns_name_t *alg; + const char *algstr; + char keynamedata[1024]; + isc_buffer_t keynamesrc, keynamebuf; + const char *secretstr; + isc_buffer_t secretbuf; + + key = cfg_listelt_value(element); + keyid = cfg_obj_asstring(cfg_map_getname(key)); + + algobj = NULL; + secretobj = NULL; + (void)cfg_map_get(key, "algorithm", &algobj); + (void)cfg_map_get(key, "secret", &secretobj); + INSIST(algobj != NULL && secretobj != NULL); + + /* + * Create the key name. + */ + dns_name_init(&keyname, NULL); + isc_buffer_constinit(&keynamesrc, keyid, strlen(keyid)); + isc_buffer_add(&keynamesrc, strlen(keyid)); + isc_buffer_init(&keynamebuf, keynamedata, sizeof(keynamedata)); + ret = dns_name_fromtext(&keyname, &keynamesrc, dns_rootname, + DNS_NAME_DOWNCASE, &keynamebuf); + if (ret != ISC_R_SUCCESS) { + goto failure; + } + + /* + * Create the algorithm. + */ + algstr = cfg_obj_asstring(algobj); + if (named_config_getkeyalgorithm(algstr, &alg, &bits) != + ISC_R_SUCCESS) + { + cfg_obj_log(algobj, named_g_lctx, ISC_LOG_ERROR, + "key '%s': has a " + "unsupported algorithm '%s'", + keyid, algstr); + ret = DNS_R_BADALG; + goto failure; + } + + secretstr = cfg_obj_asstring(secretobj); + secretalloc = secretlen = strlen(secretstr) * 3 / 4; + secret = isc_mem_get(mctx, secretlen); + isc_buffer_init(&secretbuf, secret, secretlen); + ret = isc_base64_decodestring(secretstr, &secretbuf); + if (ret != ISC_R_SUCCESS) { + goto failure; + } + secretlen = isc_buffer_usedlength(&secretbuf); + + isc_stdtime_get(&now); + ret = dns_tsigkey_create(&keyname, alg, secret, secretlen, + false, NULL, now, now, mctx, ring, + &tsigkey); + isc_mem_put(mctx, secret, secretalloc); + secret = NULL; + if (ret != ISC_R_SUCCESS) { + goto failure; + } + /* + * Set digest bits. + */ + dst_key_setbits(tsigkey->key, bits); + dns_tsigkey_detach(&tsigkey); + } + + return (ISC_R_SUCCESS); + +failure: + cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR, + "configuring key '%s': %s", keyid, isc_result_totext(ret)); + + if (secret != NULL) { + isc_mem_put(mctx, secret, secretalloc); + } + return (ret); +} + +isc_result_t +named_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, + isc_mem_t *mctx, dns_tsig_keyring_t **ringp) { + const cfg_obj_t *maps[3]; + const cfg_obj_t *keylist; + dns_tsig_keyring_t *ring = NULL; + isc_result_t result; + int i; + + REQUIRE(ringp != NULL && *ringp == NULL); + + i = 0; + if (config != NULL) { + maps[i++] = config; + } + if (vconfig != NULL) { + maps[i++] = cfg_tuple_get(vconfig, "options"); + } + maps[i] = NULL; + + result = dns_tsigkeyring_create(mctx, &ring); + if (result != ISC_R_SUCCESS) { + return (result); + } + + for (i = 0;; i++) { + if (maps[i] == NULL) { + break; + } + keylist = NULL; + result = cfg_map_get(maps[i], "key", &keylist); + if (result != ISC_R_SUCCESS) { + continue; + } + result = add_initial_keys(keylist, ring, mctx); + if (result != ISC_R_SUCCESS) { + goto failure; + } + } + + *ringp = ring; + return (ISC_R_SUCCESS); + +failure: + dns_tsigkeyring_detach(&ring); + return (result); +} diff --git a/bin/named/unix/Makefile.in b/bin/named/unix/Makefile.in new file mode 100644 index 0000000..21d7bc3 --- /dev/null +++ b/bin/named/unix/Makefile.in @@ -0,0 +1,32 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include -I${srcdir}/../include \ + ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} \ + ${DNS_INCLUDES} ${ISC_INCLUDES} \ + ${OPENSSL_CFLAGS} + +CDEFINES = +CWARNINGS = + +OBJS = os.@O@ dlz_dlopen_driver.@O@ + +SRCS = os.c dlz_dlopen_driver.c + +TARGETS = ${OBJS} + +@BIND9_MAKE_RULES@ diff --git a/bin/named/unix/dlz_dlopen_driver.c b/bin/named/unix/dlz_dlopen_driver.c new file mode 100644 index 0000000..c84df10 --- /dev/null +++ b/bin/named/unix/dlz_dlopen_driver.c @@ -0,0 +1,596 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include +#include +#include +#if HAVE_DLFCN_H +#include +#endif /* if HAVE_DLFCN_H */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef ISC_DLZ_DLOPEN +static dns_sdlzimplementation_t *dlz_dlopen = NULL; + +typedef struct dlopen_data { + isc_mem_t *mctx; + char *dl_path; + char *dlzname; + void *dl_handle; + void *dbdata; + unsigned int flags; + isc_mutex_t lock; + int version; + bool in_configure; + + dlz_dlopen_version_t *dlz_version; + dlz_dlopen_create_t *dlz_create; + dlz_dlopen_findzonedb_t *dlz_findzonedb; + dlz_dlopen_lookup_t *dlz_lookup; + dlz_dlopen_authority_t *dlz_authority; + dlz_dlopen_allnodes_t *dlz_allnodes; + dlz_dlopen_allowzonexfr_t *dlz_allowzonexfr; + dlz_dlopen_newversion_t *dlz_newversion; + dlz_dlopen_closeversion_t *dlz_closeversion; + dlz_dlopen_configure_t *dlz_configure; + dlz_dlopen_ssumatch_t *dlz_ssumatch; + dlz_dlopen_addrdataset_t *dlz_addrdataset; + dlz_dlopen_subrdataset_t *dlz_subrdataset; + dlz_dlopen_delrdataset_t *dlz_delrdataset; + dlz_dlopen_destroy_t *dlz_destroy; +} dlopen_data_t; + +/* Modules can choose whether they are lock-safe or not. */ +#define MAYBE_LOCK(cd) \ + do { \ + if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \ + !cd->in_configure) \ + LOCK(&cd->lock); \ + } while (0) + +#define MAYBE_UNLOCK(cd) \ + do { \ + if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \ + !cd->in_configure) \ + UNLOCK(&cd->lock); \ + } while (0) + +/* + * Log a message at the given level. + */ +static void +dlopen_log(int level, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, + ISC_LOG_DEBUG(level), fmt, ap); + va_end(ap); +} + +/* + * SDLZ methods + */ + +static isc_result_t +dlopen_dlz_allnodes(const char *zone, void *driverarg, void *dbdata, + dns_sdlzallnodes_t *allnodes) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_allnodes == NULL) { + return (ISC_R_NOPERM); + } + + MAYBE_LOCK(cd); + result = cd->dlz_allnodes(zone, cd->dbdata, allnodes); + MAYBE_UNLOCK(cd); + return (result); +} + +static isc_result_t +dlopen_dlz_allowzonexfr(void *driverarg, void *dbdata, const char *name, + const char *client) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_allowzonexfr == NULL) { + return (ISC_R_NOPERM); + } + + MAYBE_LOCK(cd); + result = cd->dlz_allowzonexfr(cd->dbdata, name, client); + MAYBE_UNLOCK(cd); + return (result); +} + +static isc_result_t +dlopen_dlz_authority(const char *zone, void *driverarg, void *dbdata, + dns_sdlzlookup_t *lookup) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_authority == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_authority(zone, cd->dbdata, lookup); + MAYBE_UNLOCK(cd); + return (result); +} + +static isc_result_t +dlopen_dlz_findzonedb(void *driverarg, void *dbdata, const char *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + MAYBE_LOCK(cd); + result = cd->dlz_findzonedb(cd->dbdata, name, methods, clientinfo); + MAYBE_UNLOCK(cd); + return (result); +} + +static isc_result_t +dlopen_dlz_lookup(const char *zone, const char *name, void *driverarg, + void *dbdata, dns_sdlzlookup_t *lookup, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + MAYBE_LOCK(cd); + result = cd->dlz_lookup(zone, name, cd->dbdata, lookup, methods, + clientinfo); + MAYBE_UNLOCK(cd); + return (result); +} + +/* + * Load a symbol from the library + */ +static void * +dl_load_symbol(dlopen_data_t *cd, const char *symbol, bool mandatory) { + void *ptr = dlsym(cd->dl_handle, symbol); + if (ptr == NULL && mandatory) { + dlopen_log(ISC_LOG_ERROR, + "dlz_dlopen: library '%s' is missing " + "required symbol '%s'", + cd->dl_path, symbol); + } + return (ptr); +} + +/* + * Called at startup for each dlopen zone in named.conf + */ +static isc_result_t +dlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[], + void *driverarg, void **dbdata) { + dlopen_data_t *cd; + isc_mem_t *mctx = NULL; + isc_result_t result = ISC_R_FAILURE; + int dlopen_flags = 0; + + UNUSED(driverarg); + + if (argc < 2) { + dlopen_log(ISC_LOG_ERROR, + "dlz_dlopen driver for '%s' needs a path to " + "the shared library", + dlzname); + return (ISC_R_FAILURE); + } + + isc_mem_create(&mctx); + + cd = isc_mem_get(mctx, sizeof(*cd)); + memset(cd, 0, sizeof(*cd)); + + cd->mctx = mctx; + + cd->dl_path = isc_mem_strdup(cd->mctx, argv[1]); + + cd->dlzname = isc_mem_strdup(cd->mctx, dlzname); + + /* Initialize the lock */ + isc_mutex_init(&cd->lock); + + /* Open the library */ + dlopen_flags = RTLD_NOW | RTLD_GLOBAL; + +#if defined(RTLD_DEEPBIND) && !__SANITIZE_ADDRESS__ && !__SANITIZE_THREAD__ + /* + * If RTLD_DEEPBIND is available then use it. This can avoid + * issues with a module using a different version of a system + * library than one that bind9 uses. For example, bind9 may link + * to MIT kerberos, but the module may use Heimdal. If we don't + * use RTLD_DEEPBIND then we could end up with Heimdal functions + * calling MIT functions, which leads to bizarre results (usually + * a segfault). + */ + dlopen_flags |= RTLD_DEEPBIND; +#endif /* if defined(RTLD_DEEPBIND) && !__SANITIZE_ADDRESS__ && \ + !__SANITIZE_THREAD__ */ + + cd->dl_handle = dlopen(cd->dl_path, dlopen_flags); + if (cd->dl_handle == NULL) { + dlopen_log(ISC_LOG_ERROR, + "dlz_dlopen failed to open library '%s' - %s", + cd->dl_path, dlerror()); + result = ISC_R_FAILURE; + goto failed; + } + + /* Find the symbols */ + cd->dlz_version = + (dlz_dlopen_version_t *)dl_load_symbol(cd, "dlz_version", true); + cd->dlz_create = (dlz_dlopen_create_t *)dl_load_symbol(cd, "dlz_create", + true); + cd->dlz_lookup = (dlz_dlopen_lookup_t *)dl_load_symbol(cd, "dlz_lookup", + true); + cd->dlz_findzonedb = (dlz_dlopen_findzonedb_t *)dl_load_symbol( + cd, "dlz_findzonedb", true); + + if (cd->dlz_create == NULL || cd->dlz_version == NULL || + cd->dlz_lookup == NULL || cd->dlz_findzonedb == NULL) + { + /* We're missing a required symbol */ + result = ISC_R_FAILURE; + goto failed; + } + + cd->dlz_allowzonexfr = (dlz_dlopen_allowzonexfr_t *)dl_load_symbol( + cd, "dlz_allowzonexfr", false); + cd->dlz_allnodes = (dlz_dlopen_allnodes_t *)dl_load_symbol( + cd, "dlz_allnodes", (cd->dlz_allowzonexfr != NULL)); + cd->dlz_authority = (dlz_dlopen_authority_t *)dl_load_symbol( + cd, "dlz_authority", false); + cd->dlz_newversion = (dlz_dlopen_newversion_t *)dl_load_symbol( + cd, "dlz_newversion", false); + cd->dlz_closeversion = (dlz_dlopen_closeversion_t *)dl_load_symbol( + cd, "dlz_closeversion", (cd->dlz_newversion != NULL)); + cd->dlz_configure = (dlz_dlopen_configure_t *)dl_load_symbol( + cd, "dlz_configure", false); + cd->dlz_ssumatch = (dlz_dlopen_ssumatch_t *)dl_load_symbol( + cd, "dlz_ssumatch", false); + cd->dlz_addrdataset = (dlz_dlopen_addrdataset_t *)dl_load_symbol( + cd, "dlz_addrdataset", false); + cd->dlz_subrdataset = (dlz_dlopen_subrdataset_t *)dl_load_symbol( + cd, "dlz_subrdataset", false); + cd->dlz_delrdataset = (dlz_dlopen_delrdataset_t *)dl_load_symbol( + cd, "dlz_delrdataset", false); + cd->dlz_destroy = (dlz_dlopen_destroy_t *)dl_load_symbol( + cd, "dlz_destroy", false); + + /* Check the version of the API is the same */ + cd->version = cd->dlz_version(&cd->flags); + if (cd->version < (DLZ_DLOPEN_VERSION - DLZ_DLOPEN_AGE) || + cd->version > DLZ_DLOPEN_VERSION) + { + dlopen_log(ISC_LOG_ERROR, + "dlz_dlopen: %s: incorrect driver API version %d, " + "requires %d", + cd->dl_path, cd->version, DLZ_DLOPEN_VERSION); + result = ISC_R_FAILURE; + goto failed; + } + + /* + * Call the library's create function. Note that this is an + * extended version of dlz create, with the addition of + * named function pointers for helper functions that the + * driver will need. This avoids the need for the backend to + * link the BIND9 libraries + */ + MAYBE_LOCK(cd); + result = cd->dlz_create(dlzname, argc - 1, argv + 1, &cd->dbdata, "log", + dlopen_log, "putrr", dns_sdlz_putrr, + "putnamedrr", dns_sdlz_putnamedrr, + "writeable_zone", dns_dlz_writeablezone, NULL); + MAYBE_UNLOCK(cd); + if (result != ISC_R_SUCCESS) { + goto failed; + } + + *dbdata = cd; + + return (ISC_R_SUCCESS); + +failed: + dlopen_log(ISC_LOG_ERROR, "dlz_dlopen of '%s' failed", dlzname); + if (cd->dl_path != NULL) { + isc_mem_free(mctx, cd->dl_path); + } + if (cd->dlzname != NULL) { + isc_mem_free(mctx, cd->dlzname); + } + if (dlopen_flags != 0) { + isc_mutex_destroy(&cd->lock); + } +#ifdef HAVE_DLCLOSE + if (cd->dl_handle) { + dlclose(cd->dl_handle); + } +#endif /* ifdef HAVE_DLCLOSE */ + isc_mem_put(mctx, cd, sizeof(*cd)); + isc_mem_destroy(&mctx); + return (result); +} + +/* + * Called when bind is shutting down + */ +static void +dlopen_dlz_destroy(void *driverarg, void *dbdata) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_mem_t *mctx; + + UNUSED(driverarg); + + if (cd->dlz_destroy) { + MAYBE_LOCK(cd); + cd->dlz_destroy(cd->dbdata); + MAYBE_UNLOCK(cd); + } + + if (cd->dl_path) { + isc_mem_free(cd->mctx, cd->dl_path); + } + if (cd->dlzname) { + isc_mem_free(cd->mctx, cd->dlzname); + } + +#ifdef HAVE_DLCLOSE + if (cd->dl_handle) { + dlclose(cd->dl_handle); + } +#endif /* ifdef HAVE_DLCLOSE */ + + isc_mutex_destroy(&cd->lock); + + mctx = cd->mctx; + isc_mem_put(mctx, cd, sizeof(*cd)); + isc_mem_destroy(&mctx); +} + +/* + * Called to start a transaction + */ +static isc_result_t +dlopen_dlz_newversion(const char *zone, void *driverarg, void *dbdata, + void **versionp) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_newversion == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_newversion(zone, cd->dbdata, versionp); + MAYBE_UNLOCK(cd); + return (result); +} + +/* + * Called to end a transaction + */ +static void +dlopen_dlz_closeversion(const char *zone, bool commit, void *driverarg, + void *dbdata, void **versionp) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + + UNUSED(driverarg); + + if (cd->dlz_newversion == NULL) { + *versionp = NULL; + return; + } + + MAYBE_LOCK(cd); + cd->dlz_closeversion(zone, commit, cd->dbdata, versionp); + MAYBE_UNLOCK(cd); +} + +/* + * Called on startup to configure any writeable zones + */ +static isc_result_t +dlopen_dlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb, void *driverarg, + void *dbdata) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_configure == NULL) { + return (ISC_R_SUCCESS); + } + + MAYBE_LOCK(cd); + cd->in_configure = true; + result = cd->dlz_configure(view, dlzdb, cd->dbdata); + cd->in_configure = false; + MAYBE_UNLOCK(cd); + + return (result); +} + +/* + * Check for authority to change a name. + */ +static bool +dlopen_dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr, + const char *type, const char *key, uint32_t keydatalen, + unsigned char *keydata, void *driverarg, void *dbdata) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + bool ret; + + UNUSED(driverarg); + + if (cd->dlz_ssumatch == NULL) { + return (false); + } + + MAYBE_LOCK(cd); + ret = cd->dlz_ssumatch(signer, name, tcpaddr, type, key, keydatalen, + keydata, cd->dbdata); + MAYBE_UNLOCK(cd); + + return (ret); +} + +/* + * Add an rdataset. + */ +static isc_result_t +dlopen_dlz_addrdataset(const char *name, const char *rdatastr, void *driverarg, + void *dbdata, void *version) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_addrdataset == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_addrdataset(name, rdatastr, cd->dbdata, version); + MAYBE_UNLOCK(cd); + + return (result); +} + +/* + * Subtract an rdataset. + */ +static isc_result_t +dlopen_dlz_subrdataset(const char *name, const char *rdatastr, void *driverarg, + void *dbdata, void *version) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_subrdataset == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_subrdataset(name, rdatastr, cd->dbdata, version); + MAYBE_UNLOCK(cd); + + return (result); +} + +/* + * Delete a rdataset. + */ +static isc_result_t +dlopen_dlz_delrdataset(const char *name, const char *type, void *driverarg, + void *dbdata, void *version) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_delrdataset == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_delrdataset(name, type, cd->dbdata, version); + MAYBE_UNLOCK(cd); + + return (result); +} + +static dns_sdlzmethods_t dlz_dlopen_methods = { + dlopen_dlz_create, dlopen_dlz_destroy, dlopen_dlz_findzonedb, + dlopen_dlz_lookup, dlopen_dlz_authority, dlopen_dlz_allnodes, + dlopen_dlz_allowzonexfr, dlopen_dlz_newversion, dlopen_dlz_closeversion, + dlopen_dlz_configure, dlopen_dlz_ssumatch, dlopen_dlz_addrdataset, + dlopen_dlz_subrdataset, dlopen_dlz_delrdataset +}; +#endif /* ifdef ISC_DLZ_DLOPEN */ + +/* + * Register driver with BIND + */ +isc_result_t +dlz_dlopen_init(isc_mem_t *mctx) { +#ifndef ISC_DLZ_DLOPEN + UNUSED(mctx); + return (ISC_R_NOTIMPLEMENTED); +#else /* ifndef ISC_DLZ_DLOPEN */ + isc_result_t result; + + dlopen_log(2, "Registering DLZ_dlopen driver"); + + result = dns_sdlzregister("dlopen", &dlz_dlopen_methods, NULL, + DNS_SDLZFLAG_RELATIVEOWNER | + DNS_SDLZFLAG_RELATIVERDATA | + DNS_SDLZFLAG_THREADSAFE, + mctx, &dlz_dlopen); + + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "dns_sdlzregister() failed: %s", + isc_result_totext(result)); + result = ISC_R_UNEXPECTED; + } + + return (result); +#endif /* ifndef ISC_DLZ_DLOPEN */ +} + +/* + * Unregister the driver + */ +void +dlz_dlopen_clear(void) { +#ifdef ISC_DLZ_DLOPEN + dlopen_log(2, "Unregistering DLZ_dlopen driver"); + if (dlz_dlopen != NULL) { + dns_sdlzunregister(&dlz_dlopen); + } +#endif /* ifdef ISC_DLZ_DLOPEN */ +} diff --git a/bin/named/unix/include/.clang-format b/bin/named/unix/include/.clang-format new file mode 120000 index 0000000..e919bba --- /dev/null +++ b/bin/named/unix/include/.clang-format @@ -0,0 +1 @@ +../../../../.clang-format.headers \ No newline at end of file diff --git a/bin/named/unix/include/named/os.h b/bin/named/unix/include/named/os.h new file mode 100644 index 0000000..7f167b1 --- /dev/null +++ b/bin/named/unix/include/named/os.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_OS_H +#define NAMED_OS_H 1 + +/*! \file */ + +#include +#include + +#include + +void +named_os_init(const char *progname); + +void +named_os_daemonize(void); + +void +named_os_opendevnull(void); + +void +named_os_closedevnull(void); + +void +named_os_chroot(const char *root); + +void +named_os_inituserinfo(const char *username); + +void +named_os_changeuser(void); + +uid_t +ns_os_uid(void); + +void +named_os_adjustnofile(void); + +void +named_os_minprivs(void); + +FILE * +named_os_openfile(const char *filename, mode_t mode, bool switch_user); + +void +named_os_writepidfile(const char *filename, bool first_time); + +bool +named_os_issingleton(const char *filename); + +void +named_os_shutdown(void); + +isc_result_t +named_os_gethostname(char *buf, size_t len); + +void +named_os_shutdownmsg(char *command, isc_buffer_t *text); + +void +named_os_tzset(void); + +void +named_os_started(void); + +const char * +named_os_uname(void); + +#endif /* NAMED_OS_H */ diff --git a/bin/named/unix/os.c b/bin/named/unix/os.c new file mode 100644 index 0000000..98c826c --- /dev/null +++ b/bin/named/unix/os.c @@ -0,0 +1,940 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ +#include +#include +#include +#include /* dev_t FreeBSD 2.1 */ +#ifdef HAVE_UNAME +#include +#endif /* ifdef HAVE_UNAME */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_TZSET +#include +#endif /* ifdef HAVE_TZSET */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef HAVE_LIBSCF +#include +#endif /* ifdef HAVE_LIBSCF */ + +static char *pidfile = NULL; +static char *lockfile = NULL; +static int devnullfd = -1; +static int singletonfd = -1; + +#ifndef ISC_FACILITY +#define ISC_FACILITY LOG_DAEMON +#endif /* ifndef ISC_FACILITY */ + +static struct passwd *runas_pw = NULL; +static bool done_setuid = false; +static int dfd[2] = { -1, -1 }; + +#ifdef HAVE_SYS_CAPABILITY_H + +static bool non_root = false; +static bool non_root_caps = false; + +#include +#include + +static void +linux_setcaps(cap_t caps) { + char strbuf[ISC_STRERRORSIZE]; + + if ((getuid() != 0 && !non_root_caps) || non_root) { + return; + } + if (cap_set_proc(caps) < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("cap_set_proc() failed: %s:" + " please ensure that the capset kernel" + " module is loaded. see insmod(8)", + strbuf); + } +} + +#define SET_CAP(flag) \ + do { \ + cap_flag_value_t curval; \ + capval = (flag); \ + err = cap_get_flag(curcaps, capval, CAP_PERMITTED, &curval); \ + if (err != -1 && curval) { \ + err = cap_set_flag(caps, CAP_EFFECTIVE, 1, &capval, \ + CAP_SET); \ + if (err == -1) { \ + strerror_r(errno, strbuf, sizeof(strbuf)); \ + named_main_earlyfatal("cap_set_proc failed: " \ + "%s", \ + strbuf); \ + } \ + \ + err = cap_set_flag(caps, CAP_PERMITTED, 1, &capval, \ + CAP_SET); \ + if (err == -1) { \ + strerror_r(errno, strbuf, sizeof(strbuf)); \ + named_main_earlyfatal("cap_set_proc failed: " \ + "%s", \ + strbuf); \ + } \ + } \ + } while (0) +#define INIT_CAP \ + do { \ + caps = cap_init(); \ + if (caps == NULL) { \ + strerror_r(errno, strbuf, sizeof(strbuf)); \ + named_main_earlyfatal("cap_init failed: %s", strbuf); \ + } \ + curcaps = cap_get_proc(); \ + if (curcaps == NULL) { \ + strerror_r(errno, strbuf, sizeof(strbuf)); \ + named_main_earlyfatal("cap_get_proc failed: %s", \ + strbuf); \ + } \ + } while (0) +#define FREE_CAP \ + { \ + cap_free(caps); \ + cap_free(curcaps); \ + } \ + while (0) + +static void +linux_initialprivs(void) { + cap_t caps; + cap_t curcaps; + cap_value_t capval; + char strbuf[ISC_STRERRORSIZE]; + int err; + + /*% + * We don't need most privileges, so we drop them right away. + * Later on linux_minprivs() will be called, which will drop our + * capabilities to the minimum needed to run the server. + */ + INIT_CAP; + + /* + * We need to be able to bind() to privileged ports, notably port 53! + */ + SET_CAP(CAP_NET_BIND_SERVICE); + + /* + * We need chroot() initially too. + */ + SET_CAP(CAP_SYS_CHROOT); + + /* + * We need setuid() as the kernel supports keeping capabilities after + * setuid(). + */ + SET_CAP(CAP_SETUID); + + /* + * Since we call initgroups, we need this. + */ + SET_CAP(CAP_SETGID); + + /* + * Without this, we run into problems reading a configuration file + * owned by a non-root user and non-world-readable on startup. + */ + SET_CAP(CAP_DAC_READ_SEARCH); + + /* + * XXX We might want to add CAP_SYS_RESOURCE, though it's not + * clear it would work right given the way linuxthreads work. + * XXXDCL But since we need to be able to set the maximum number + * of files, the stack size, data size, and core dump size to + * support named.conf options, this is now being added to test. + */ + SET_CAP(CAP_SYS_RESOURCE); + + /* + * We need to be able to set the ownership of the containing + * directory of the pid file when we create it. + */ + SET_CAP(CAP_CHOWN); + + linux_setcaps(caps); + + FREE_CAP; +} + +static void +linux_minprivs(void) { + cap_t caps; + cap_t curcaps; + cap_value_t capval; + char strbuf[ISC_STRERRORSIZE]; + int err; + + INIT_CAP; + /*% + * Drop all privileges except the ability to bind() to privileged + * ports. + * + * It's important that we drop CAP_SYS_CHROOT. If we didn't, it + * chroot() could be used to escape from the chrooted area. + */ + + SET_CAP(CAP_NET_BIND_SERVICE); + + /* + * XXX We might want to add CAP_SYS_RESOURCE, though it's not + * clear it would work right given the way linuxthreads work. + * XXXDCL But since we need to be able to set the maximum number + * of files, the stack size, data size, and core dump size to + * support named.conf options, this is now being added to test. + */ + SET_CAP(CAP_SYS_RESOURCE); + + linux_setcaps(caps); + + FREE_CAP; +} + +static void +linux_keepcaps(void) { + char strbuf[ISC_STRERRORSIZE]; + /*% + * Ask the kernel to allow us to keep our capabilities after we + * setuid(). + */ + + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { + if (errno != EINVAL) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("prctl() failed: %s", strbuf); + } + } else { + non_root_caps = true; + if (getuid() != 0) { + non_root = true; + } + } +} + +#endif /* HAVE_SYS_CAPABILITY_H */ + +static void +setup_syslog(const char *progname) { + int options; + + options = LOG_PID; +#ifdef LOG_NDELAY + options |= LOG_NDELAY; +#endif /* ifdef LOG_NDELAY */ + openlog(isc_file_basename(progname), options, ISC_FACILITY); +} + +void +named_os_init(const char *progname) { + setup_syslog(progname); +#ifdef HAVE_SYS_CAPABILITY_H + linux_initialprivs(); +#endif /* ifdef HAVE_SYS_CAPABILITY_H */ +#ifdef SIGXFSZ + signal(SIGXFSZ, SIG_IGN); +#endif /* ifdef SIGXFSZ */ +} + +void +named_os_daemonize(void) { + pid_t pid; + char strbuf[ISC_STRERRORSIZE]; + + if (pipe(dfd) == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("pipe(): %s", strbuf); + } + + pid = fork(); + if (pid == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("fork(): %s", strbuf); + } + if (pid != 0) { + int n; + /* + * Wait for the child to finish loading for the first time. + * This would be so much simpler if fork() worked once we + * were multi-threaded. + */ + (void)close(dfd[1]); + do { + char buf; + n = read(dfd[0], &buf, 1); + if (n == 1) { + _exit(0); + } + } while (n == -1 && errno == EINTR); + _exit(1); + } + (void)close(dfd[0]); + + /* + * We're the child. + */ + + if (setsid() == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("setsid(): %s", strbuf); + } + + /* + * Try to set stdin, stdout, and stderr to /dev/null, but press + * on even if it fails. + * + * XXXMLG The close() calls here are unneeded on all but NetBSD, but + * are harmless to include everywhere. dup2() is supposed to close + * the FD if it is in use, but unproven-pthreads-0.16 is broken + * and will end up closing the wrong FD. This will be fixed eventually, + * and these calls will be removed. + */ + if (devnullfd != -1) { + if (devnullfd != STDIN_FILENO) { + (void)close(STDIN_FILENO); + (void)dup2(devnullfd, STDIN_FILENO); + } + if (devnullfd != STDOUT_FILENO) { + (void)close(STDOUT_FILENO); + (void)dup2(devnullfd, STDOUT_FILENO); + } + if (devnullfd != STDERR_FILENO && !named_g_keepstderr) { + (void)close(STDERR_FILENO); + (void)dup2(devnullfd, STDERR_FILENO); + } + } +} + +void +named_os_started(void) { + char buf = 0; + + /* + * Signal to the parent that we started successfully. + */ + if (dfd[0] != -1 && dfd[1] != -1) { + if (write(dfd[1], &buf, 1) != 1) { + named_main_earlyfatal("unable to signal parent that we " + "otherwise started " + "successfully."); + } + close(dfd[1]); + dfd[0] = dfd[1] = -1; + } +} + +void +named_os_opendevnull(void) { + devnullfd = open("/dev/null", O_RDWR, 0); +} + +void +named_os_closedevnull(void) { + if (devnullfd != STDIN_FILENO && devnullfd != STDOUT_FILENO && + devnullfd != STDERR_FILENO) + { + close(devnullfd); + devnullfd = -1; + } +} + +static bool +all_digits(const char *s) { + if (*s == '\0') { + return (false); + } + while (*s != '\0') { + if (!isdigit((unsigned char)(*s))) { + return (false); + } + s++; + } + return (true); +} + +void +named_os_chroot(const char *root) { + char strbuf[ISC_STRERRORSIZE]; +#ifdef HAVE_LIBSCF + named_smf_chroot = 0; +#endif /* ifdef HAVE_LIBSCF */ + if (root != NULL) { +#ifdef HAVE_CHROOT + if (chroot(root) < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("chroot(): %s", strbuf); + } +#else /* ifdef HAVE_CHROOT */ + named_main_earlyfatal("chroot(): disabled"); +#endif /* ifdef HAVE_CHROOT */ + if (chdir("/") < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("chdir(/): %s", strbuf); + } +#ifdef HAVE_LIBSCF + /* Set named_smf_chroot flag on successful chroot. */ + named_smf_chroot = 1; +#endif /* ifdef HAVE_LIBSCF */ + } +} + +void +named_os_inituserinfo(const char *username) { + if (username == NULL) { + return; + } + + if (all_digits(username)) { + runas_pw = getpwuid((uid_t)atoi(username)); + } else { + runas_pw = getpwnam(username); + } + endpwent(); + + if (runas_pw == NULL) { + named_main_earlyfatal("user '%s' unknown", username); + } + + if (getuid() == 0) { + char strbuf[ISC_STRERRORSIZE]; + if (initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("initgroups(): %s", strbuf); + } + } +} + +void +named_os_changeuser(void) { + char strbuf[ISC_STRERRORSIZE]; + if (runas_pw == NULL || done_setuid) { + return; + } + + done_setuid = true; + + if (setgid(runas_pw->pw_gid) < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("setgid(): %s", strbuf); + } + + if (setuid(runas_pw->pw_uid) < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("setuid(): %s", strbuf); + } + +#if defined(HAVE_SYS_CAPABILITY_H) + /* + * Restore the ability of named to drop core after the setuid() + * call has disabled it. + */ + if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("prctl(PR_SET_DUMPABLE) failed: %s", + strbuf); + } + + linux_minprivs(); +#endif /* if defined(HAVE_SYS_CAPABILITY_H) */ +} + +uid_t +ns_os_uid(void) { + if (runas_pw == NULL) { + return (0); + } + return (runas_pw->pw_uid); +} + +void +named_os_adjustnofile(void) { +#if defined(__linux__) || defined(__sun) + isc_result_t result; + isc_resourcevalue_t newvalue; + + /* + * Linux: max number of open files specified by one thread doesn't seem + * to apply to other threads on Linux. + * Sun: restriction needs to be removed sooner when hundreds of CPUs + * are available. + */ + newvalue = ISC_RESOURCE_UNLIMITED; + + result = isc_resource_setlimit(isc_resource_openfiles, newvalue); + if (result != ISC_R_SUCCESS) { + named_main_earlywarning("couldn't adjust limit on open files"); + } +#endif /* if defined(__linux__) || defined(__sun) */ +} + +void +named_os_minprivs(void) { +#if defined(HAVE_SYS_CAPABILITY_H) + linux_keepcaps(); + named_os_changeuser(); + linux_minprivs(); +#endif /* if defined(HAVE_SYS_CAPABILITY_H) */ +} + +static int +safe_open(const char *filename, mode_t mode, bool append) { + int fd; + struct stat sb; + + if (stat(filename, &sb) == -1) { + if (errno != ENOENT) { + return (-1); + } + } else if ((sb.st_mode & S_IFREG) == 0) { + errno = EOPNOTSUPP; + return (-1); + } + + if (append) { + fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, mode); + } else { + if (unlink(filename) < 0 && errno != ENOENT) { + return (-1); + } + fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, mode); + } + return (fd); +} + +static void +cleanup_pidfile(void) { + int n; + if (pidfile != NULL) { + n = unlink(pidfile); + if (n == -1 && errno != ENOENT) { + named_main_earlywarning("unlink '%s': failed", pidfile); + } + free(pidfile); + } + pidfile = NULL; +} + +static void +cleanup_lockfile(void) { + if (singletonfd != -1) { + close(singletonfd); + singletonfd = -1; + } + + if (lockfile != NULL) { + int n = unlink(lockfile); + if (n == -1 && errno != ENOENT) { + named_main_earlywarning("unlink '%s': failed", + lockfile); + } + free(lockfile); + lockfile = NULL; + } +} + +/* + * Ensure that a directory exists. + * NOTE: This function overwrites the '/' characters in 'filename' with + * nulls. The caller should copy the filename to a fresh buffer first. + */ +static int +mkdirpath(char *filename, void (*report)(const char *, ...)) { + char *slash = strrchr(filename, '/'); + char strbuf[ISC_STRERRORSIZE]; + unsigned int mode; + + if (slash != NULL && slash != filename) { + struct stat sb; + *slash = '\0'; + + if (stat(filename, &sb) == -1) { + if (errno != ENOENT) { + strerror_r(errno, strbuf, sizeof(strbuf)); + (*report)("couldn't stat '%s': %s", filename, + strbuf); + goto error; + } + if (mkdirpath(filename, report) == -1) { + goto error; + } + /* + * Handle "//", "/./" and "/../" in path. + */ + if (!strcmp(slash + 1, "") || !strcmp(slash + 1, ".") || + !strcmp(slash + 1, "..")) + { + *slash = '/'; + return (0); + } + mode = S_IRUSR | S_IWUSR | S_IXUSR; /* u=rwx */ + mode |= S_IRGRP | S_IXGRP; /* g=rx */ + mode |= S_IROTH | S_IXOTH; /* o=rx */ + if (mkdir(filename, mode) == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + (*report)("couldn't mkdir '%s': %s", filename, + strbuf); + goto error; + } + if (runas_pw != NULL && + chown(filename, runas_pw->pw_uid, + runas_pw->pw_gid) == -1) + { + strerror_r(errno, strbuf, sizeof(strbuf)); + (*report)("couldn't chown '%s': %s", filename, + strbuf); + } + } + *slash = '/'; + } + return (0); + +error: + *slash = '/'; + return (-1); +} + +#if !HAVE_SYS_CAPABILITY_H +static void +setperms(uid_t uid, gid_t gid) { +#if defined(HAVE_SETEGID) || defined(HAVE_SETRESGID) + char strbuf[ISC_STRERRORSIZE]; +#endif /* if defined(HAVE_SETEGID) || defined(HAVE_SETRESGID) */ +#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) + gid_t oldgid, tmpg; +#endif /* if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */ +#if !defined(HAVE_SETEUID) && defined(HAVE_SETRESUID) + uid_t olduid, tmpu; +#endif /* if !defined(HAVE_SETEUID) && defined(HAVE_SETRESUID) */ +#if defined(HAVE_SETEGID) + if (getegid() != gid && setegid(gid) == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("unable to set effective " + "gid to %ld: %s", + (long)gid, strbuf); + } +#elif defined(HAVE_SETRESGID) + if (getresgid(&tmpg, &oldgid, &tmpg) == -1 || oldgid != gid) { + if (setresgid(-1, gid, -1) == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("unable to set effective " + "gid to %d: %s", + gid, strbuf); + } + } +#endif /* if defined(HAVE_SETEGID) */ + +#if defined(HAVE_SETEUID) + if (geteuid() != uid && seteuid(uid) == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("unable to set effective " + "uid to %ld: %s", + (long)uid, strbuf); + } +#elif defined(HAVE_SETRESUID) + if (getresuid(&tmpu, &olduid, &tmpu) == -1 || olduid != uid) { + if (setresuid(-1, uid, -1) == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("unable to set effective " + "uid to %d: %s", + uid, strbuf); + } + } +#endif /* if defined(HAVE_SETEUID) */ +} +#endif /* HAVE_SYS_CAPABILITY_H */ + +FILE * +named_os_openfile(const char *filename, mode_t mode, bool switch_user) { + char strbuf[ISC_STRERRORSIZE], *f; + FILE *fp; + int fd; + + /* + * Make the containing directory if it doesn't exist. + */ + f = strdup(filename); + if (f == NULL) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("couldn't strdup() '%s': %s", filename, + strbuf); + return (NULL); + } + if (mkdirpath(f, named_main_earlywarning) == -1) { + free(f); + return (NULL); + } + free(f); + + if (switch_user && runas_pw != NULL) { + uid_t olduid = getuid(); + gid_t oldgid = getgid(); +#if HAVE_SYS_CAPABILITY_H + REQUIRE(olduid == runas_pw->pw_uid); + REQUIRE(oldgid == runas_pw->pw_gid); +#else /* HAVE_SYS_CAPABILITY_H */ + /* Set UID/GID to the one we'll be running with eventually */ + setperms(runas_pw->pw_uid, runas_pw->pw_gid); +#endif + fd = safe_open(filename, mode, false); + +#if !HAVE_SYS_CAPABILITY_H + /* Restore UID/GID to previous uid/gid */ + setperms(olduid, oldgid); +#endif + + if (fd == -1) { + fd = safe_open(filename, mode, false); + if (fd != -1) { + named_main_earlywarning("Required root " + "permissions to open " + "'%s'.", + filename); + } else { + named_main_earlywarning("Could not open " + "'%s'.", + filename); + } + named_main_earlywarning("Please check file and " + "directory permissions " + "or reconfigure the filename."); + } + } else { + fd = safe_open(filename, mode, false); + } + + if (fd < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("could not open file '%s': %s", + filename, strbuf); + return (NULL); + } + + fp = fdopen(fd, "w"); + if (fp == NULL) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("could not fdopen() file '%s': %s", + filename, strbuf); + } + + return (fp); +} + +void +named_os_writepidfile(const char *filename, bool first_time) { + FILE *fh; + pid_t pid; + char strbuf[ISC_STRERRORSIZE]; + void (*report)(const char *, ...); + + /* + * The caller must ensure any required synchronization. + */ + + report = first_time ? named_main_earlyfatal : named_main_earlywarning; + + cleanup_pidfile(); + + if (filename == NULL) { + return; + } + + pidfile = strdup(filename); + if (pidfile == NULL) { + strerror_r(errno, strbuf, sizeof(strbuf)); + (*report)("couldn't strdup() '%s': %s", filename, strbuf); + return; + } + + fh = named_os_openfile(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, + first_time); + if (fh == NULL) { + cleanup_pidfile(); + return; + } + pid = getpid(); + if (fprintf(fh, "%ld\n", (long)pid) < 0) { + (*report)("fprintf() to pid file '%s' failed", filename); + (void)fclose(fh); + cleanup_pidfile(); + return; + } + if (fflush(fh) == EOF) { + (*report)("fflush() to pid file '%s' failed", filename); + (void)fclose(fh); + cleanup_pidfile(); + return; + } + (void)fclose(fh); +} + +bool +named_os_issingleton(const char *filename) { + char strbuf[ISC_STRERRORSIZE]; + struct flock lock; + + if (singletonfd != -1) { + return (true); + } + + if (strcasecmp(filename, "none") == 0) { + return (true); + } + + /* + * Make the containing directory if it doesn't exist. + */ + lockfile = strdup(filename); + if (lockfile == NULL) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("couldn't allocate memory for '%s': %s", + filename, strbuf); + } else { + int ret = mkdirpath(lockfile, named_main_earlywarning); + if (ret == -1) { + named_main_earlywarning("couldn't create '%s'", + filename); + cleanup_lockfile(); + return (false); + } + } + + /* + * named_os_openfile() uses safeopen() which removes any existing + * files. We can't use that here. + */ + singletonfd = open(filename, O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (singletonfd == -1) { + cleanup_lockfile(); + return (false); + } + + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + + /* Non-blocking (does not wait for lock) */ + if (fcntl(singletonfd, F_SETLK, &lock) == -1) { + close(singletonfd); + singletonfd = -1; + return (false); + } + + return (true); +} + +void +named_os_shutdown(void) { + closelog(); + cleanup_pidfile(); + cleanup_lockfile(); +} + +isc_result_t +named_os_gethostname(char *buf, size_t len) { + int n; + + n = gethostname(buf, len); + return ((n == 0) ? ISC_R_SUCCESS : ISC_R_FAILURE); +} + +void +named_os_shutdownmsg(char *command, isc_buffer_t *text) { + char *last, *ptr; + pid_t pid; + + /* Skip the command name. */ + if (strtok_r(command, " \t", &last) == NULL) { + return; + } + + if ((ptr = strtok_r(NULL, " \t", &last)) == NULL) { + return; + } + + if (strcmp(ptr, "-p") != 0) { + return; + } + + pid = getpid(); + + (void)isc_buffer_printf(text, "pid: %ld", (long)pid); +} + +void +named_os_tzset(void) { +#ifdef HAVE_TZSET + tzset(); +#endif /* ifdef HAVE_TZSET */ +} + +#ifdef HAVE_UNAME +static char unamebuf[sizeof(struct utsname)]; +#else +static const char unamebuf[] = { "unknown architecture" }; +#endif +static const char *unamep = NULL; + +static void +getuname(void) { +#ifdef HAVE_UNAME + struct utsname uts; + + memset(&uts, 0, sizeof(uts)); + if (uname(&uts) < 0) { + snprintf(unamebuf, sizeof(unamebuf), "unknown architecture"); + return; + } + + snprintf(unamebuf, sizeof(unamebuf), "%s %s %s %s", uts.sysname, + uts.machine, uts.release, uts.version); +#endif /* ifdef HAVE_UNAME */ + unamep = unamebuf; +} + +const char * +named_os_uname(void) { + if (unamep == NULL) { + getuname(); + } + return (unamep); +} diff --git a/bin/named/win32/dlz_dlopen_driver.c b/bin/named/win32/dlz_dlopen_driver.c new file mode 100644 index 0000000..7e41e9c --- /dev/null +++ b/bin/named/win32/dlz_dlopen_driver.c @@ -0,0 +1,578 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef ISC_DLZ_DLOPEN +static dns_sdlzimplementation_t *dlz_dlopen = NULL; + +typedef struct dlopen_data { + isc_mem_t *mctx; + char *dl_path; + char *dlzname; + HMODULE dl_handle; + void *dbdata; + unsigned int flags; + isc_mutex_t lock; + int version; + bool in_configure; + + dlz_dlopen_version_t *dlz_version; + dlz_dlopen_create_t *dlz_create; + dlz_dlopen_findzonedb_t *dlz_findzonedb; + dlz_dlopen_lookup_t *dlz_lookup; + dlz_dlopen_authority_t *dlz_authority; + dlz_dlopen_allnodes_t *dlz_allnodes; + dlz_dlopen_allowzonexfr_t *dlz_allowzonexfr; + dlz_dlopen_newversion_t *dlz_newversion; + dlz_dlopen_closeversion_t *dlz_closeversion; + dlz_dlopen_configure_t *dlz_configure; + dlz_dlopen_ssumatch_t *dlz_ssumatch; + dlz_dlopen_addrdataset_t *dlz_addrdataset; + dlz_dlopen_subrdataset_t *dlz_subrdataset; + dlz_dlopen_delrdataset_t *dlz_delrdataset; + dlz_dlopen_destroy_t *dlz_destroy; +} dlopen_data_t; + +/* Modules can choose whether they are lock-safe or not. */ +#define MAYBE_LOCK(cd) \ + do { \ + if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \ + !cd->in_configure) \ + LOCK(&cd->lock); \ + } while (0) + +#define MAYBE_UNLOCK(cd) \ + do { \ + if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \ + !cd->in_configure) \ + UNLOCK(&cd->lock); \ + } while (0) + +/* + * Log a message at the given level. + */ +static void +dlopen_log(int level, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, + ISC_LOG_DEBUG(level), fmt, ap); + va_end(ap); +} + +/* + * SDLZ methods + */ + +static isc_result_t +dlopen_dlz_allnodes(const char *zone, void *driverarg, void *dbdata, + dns_sdlzallnodes_t *allnodes) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_allnodes == NULL) { + return (ISC_R_NOPERM); + } + + MAYBE_LOCK(cd); + result = cd->dlz_allnodes(zone, cd->dbdata, allnodes); + MAYBE_UNLOCK(cd); + return (result); +} + +static isc_result_t +dlopen_dlz_allowzonexfr(void *driverarg, void *dbdata, const char *name, + const char *client) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_allowzonexfr == NULL) { + return (ISC_R_NOPERM); + } + + MAYBE_LOCK(cd); + result = cd->dlz_allowzonexfr(cd->dbdata, name, client); + MAYBE_UNLOCK(cd); + return (result); +} + +static isc_result_t +dlopen_dlz_authority(const char *zone, void *driverarg, void *dbdata, + dns_sdlzlookup_t *lookup) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_authority == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_authority(zone, cd->dbdata, lookup); + MAYBE_UNLOCK(cd); + return (result); +} + +static isc_result_t +dlopen_dlz_findzonedb(void *driverarg, void *dbdata, const char *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + MAYBE_LOCK(cd); + result = cd->dlz_findzonedb(cd->dbdata, name, methods, clientinfo); + MAYBE_UNLOCK(cd); + return (result); +} + +static isc_result_t +dlopen_dlz_lookup(const char *zone, const char *name, void *driverarg, + void *dbdata, dns_sdlzlookup_t *lookup, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + MAYBE_LOCK(cd); + result = cd->dlz_lookup(zone, name, cd->dbdata, lookup, methods, + clientinfo); + MAYBE_UNLOCK(cd); + return (result); +} + +/* + * Load a symbol from the library + */ +static void * +dl_load_symbol(dlopen_data_t *cd, const char *symbol, bool mandatory) { + void *ptr = GetProcAddress(cd->dl_handle, symbol); + if (ptr == NULL && mandatory) { + dlopen_log(ISC_LOG_ERROR, + "dlz_dlopen: library '%s' is missing " + "required symbol '%s'", + cd->dl_path, symbol); + } + return (ptr); +} + +/* + * Called at startup for each dlopen zone in named.conf + */ +static isc_result_t +dlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[], + void *driverarg, void **dbdata) { + dlopen_data_t *cd; + isc_mem_t *mctx = NULL; + isc_result_t result = ISC_R_FAILURE; + bool triedload = false; + + UNUSED(driverarg); + + if (argc < 2) { + dlopen_log(ISC_LOG_ERROR, + "dlz_dlopen driver for '%s' needs a path to " + "the shared library", + dlzname); + return (ISC_R_FAILURE); + } + + isc_mem_create(&mctx); + + cd = isc_mem_get(mctx, sizeof(*cd)); + memset(cd, 0, sizeof(*cd)); + + cd->mctx = mctx; + + cd->dl_path = isc_mem_strdup(cd->mctx, argv[1]); + + cd->dlzname = isc_mem_strdup(cd->mctx, dlzname); + + triedload = true; + + /* Initialize the lock */ + isc_mutex_init(&cd->lock); + + /* Open the library */ + cd->dl_handle = LoadLibraryA(cd->dl_path); + if (cd->dl_handle == NULL) { + unsigned int error = GetLastError(); + + dlopen_log(ISC_LOG_ERROR, + "dlz_dlopen failed to open library '%s' - %u", + cd->dl_path, error); + result = ISC_R_FAILURE; + goto cleanup_lock; + } + + /* Find the symbols */ + cd->dlz_version = + (dlz_dlopen_version_t *)dl_load_symbol(cd, "dlz_version", true); + cd->dlz_create = (dlz_dlopen_create_t *)dl_load_symbol(cd, "dlz_create", + true); + cd->dlz_lookup = (dlz_dlopen_lookup_t *)dl_load_symbol(cd, "dlz_lookup", + true); + cd->dlz_findzonedb = (dlz_dlopen_findzonedb_t *)dl_load_symbol( + cd, "dlz_findzonedb", true); + + if (cd->dlz_create == NULL || cd->dlz_version == NULL || + cd->dlz_lookup == NULL || cd->dlz_findzonedb == NULL) + { + /* We're missing a required symbol */ + result = ISC_R_FAILURE; + goto cleanup_lock; + } + + cd->dlz_allowzonexfr = (dlz_dlopen_allowzonexfr_t *)dl_load_symbol( + cd, "dlz_allowzonexfr", false); + cd->dlz_allnodes = (dlz_dlopen_allnodes_t *)dl_load_symbol( + cd, "dlz_allnodes", (cd->dlz_allowzonexfr != NULL)); + cd->dlz_authority = (dlz_dlopen_authority_t *)dl_load_symbol( + cd, "dlz_authority", false); + cd->dlz_newversion = (dlz_dlopen_newversion_t *)dl_load_symbol( + cd, "dlz_newversion", false); + cd->dlz_closeversion = (dlz_dlopen_closeversion_t *)dl_load_symbol( + cd, "dlz_closeversion", (cd->dlz_newversion != NULL)); + cd->dlz_configure = (dlz_dlopen_configure_t *)dl_load_symbol( + cd, "dlz_configure", false); + cd->dlz_ssumatch = (dlz_dlopen_ssumatch_t *)dl_load_symbol( + cd, "dlz_ssumatch", false); + cd->dlz_addrdataset = (dlz_dlopen_addrdataset_t *)dl_load_symbol( + cd, "dlz_addrdataset", false); + cd->dlz_subrdataset = (dlz_dlopen_subrdataset_t *)dl_load_symbol( + cd, "dlz_subrdataset", false); + cd->dlz_delrdataset = (dlz_dlopen_delrdataset_t *)dl_load_symbol( + cd, "dlz_delrdataset", false); + + /* Check the version of the API is the same */ + cd->version = cd->dlz_version(&cd->flags); + if (cd->version < (DLZ_DLOPEN_VERSION - DLZ_DLOPEN_AGE) || + cd->version > DLZ_DLOPEN_VERSION) + { + dlopen_log(ISC_LOG_ERROR, + "dlz_dlopen: %s: incorrect driver API version %d, " + "requires %d", + cd->dl_path, cd->version, DLZ_DLOPEN_VERSION); + result = ISC_R_FAILURE; + goto cleanup_lock; + } + + /* + * Call the library's create function. Note that this is an + * extended version of dlz create, with the addition of + * named function pointers for helper functions that the + * driver will need. This avoids the need for the backend to + * link the BIND9 libraries + */ + MAYBE_LOCK(cd); + result = cd->dlz_create(dlzname, argc - 1, argv + 1, &cd->dbdata, "log", + dlopen_log, "putrr", dns_sdlz_putrr, + "putnamedrr", dns_sdlz_putnamedrr, + "writeable_zone", dns_dlz_writeablezone, NULL); + MAYBE_UNLOCK(cd); + if (result != ISC_R_SUCCESS) { + goto cleanup_lock; + } + + *dbdata = cd; + + return (ISC_R_SUCCESS); + +cleanup_lock: + isc_mutex_destroy(&cd->lock); +failed: + dlopen_log(ISC_LOG_ERROR, "dlz_dlopen of '%s' failed", dlzname); + if (cd->dl_path) { + isc_mem_free(mctx, cd->dl_path); + } + if (cd->dlzname) { + isc_mem_free(mctx, cd->dlzname); + } + if (triedload) { + isc_mutex_destroy(&cd->lock); + } + if (cd->dl_handle) { + FreeLibrary(cd->dl_handle); + } + isc_mem_put(mctx, cd, sizeof(*cd)); + isc_mem_destroy(&mctx); + return (result); +} + +/* + * Called when bind is shutting down + */ +static void +dlopen_dlz_destroy(void *driverarg, void *dbdata) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_mem_t *mctx; + + UNUSED(driverarg); + + if (cd->dlz_destroy) { + MAYBE_LOCK(cd); + cd->dlz_destroy(cd->dbdata); + MAYBE_UNLOCK(cd); + } + + if (cd->dl_path) { + isc_mem_free(cd->mctx, cd->dl_path); + } + if (cd->dlzname) { + isc_mem_free(cd->mctx, cd->dlzname); + } + + if (cd->dl_handle) { + FreeLibrary(cd->dl_handle); + } + + isc_mutex_destroy(&cd->lock); + + mctx = cd->mctx; + isc_mem_put(mctx, cd, sizeof(*cd)); + isc_mem_destroy(&mctx); +} + +/* + * Called to start a transaction + */ +static isc_result_t +dlopen_dlz_newversion(const char *zone, void *driverarg, void *dbdata, + void **versionp) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_newversion == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_newversion(zone, cd->dbdata, versionp); + MAYBE_UNLOCK(cd); + return (result); +} + +/* + * Called to end a transaction + */ +static void +dlopen_dlz_closeversion(const char *zone, bool commit, void *driverarg, + void *dbdata, void **versionp) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + + UNUSED(driverarg); + + if (cd->dlz_newversion == NULL) { + *versionp = NULL; + return; + } + + MAYBE_LOCK(cd); + cd->dlz_closeversion(zone, commit, cd->dbdata, versionp); + MAYBE_UNLOCK(cd); +} + +/* + * Called on startup to configure any writeable zones + */ +static isc_result_t +dlopen_dlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb, void *driverarg, + void *dbdata) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_configure == NULL) { + return (ISC_R_SUCCESS); + } + + MAYBE_LOCK(cd); + cd->in_configure = true; + result = cd->dlz_configure(view, dlzdb, cd->dbdata); + cd->in_configure = false; + MAYBE_UNLOCK(cd); + + return (result); +} + +/* + * Check for authority to change a name + */ +static bool +dlopen_dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr, + const char *type, const char *key, uint32_t keydatalen, + unsigned char *keydata, void *driverarg, void *dbdata) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + bool ret; + + UNUSED(driverarg); + + if (cd->dlz_ssumatch == NULL) { + return (false); + } + + MAYBE_LOCK(cd); + ret = cd->dlz_ssumatch(signer, name, tcpaddr, type, key, keydatalen, + keydata, cd->dbdata); + MAYBE_UNLOCK(cd); + + return (ret); +} + +/* + * Add an rdataset + */ +static isc_result_t +dlopen_dlz_addrdataset(const char *name, const char *rdatastr, void *driverarg, + void *dbdata, void *version) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_addrdataset == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_addrdataset(name, rdatastr, cd->dbdata, version); + MAYBE_UNLOCK(cd); + + return (result); +} + +/* + * Subtract an rdataset + */ +static isc_result_t +dlopen_dlz_subrdataset(const char *name, const char *rdatastr, void *driverarg, + void *dbdata, void *version) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_subrdataset == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_subrdataset(name, rdatastr, cd->dbdata, version); + MAYBE_UNLOCK(cd); + + return (result); +} + +/* + * delete a rdataset + */ +static isc_result_t +dlopen_dlz_delrdataset(const char *name, const char *type, void *driverarg, + void *dbdata, void *version) { + dlopen_data_t *cd = (dlopen_data_t *)dbdata; + isc_result_t result; + + UNUSED(driverarg); + + if (cd->dlz_delrdataset == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + MAYBE_LOCK(cd); + result = cd->dlz_delrdataset(name, type, cd->dbdata, version); + MAYBE_UNLOCK(cd); + + return (result); +} + +static dns_sdlzmethods_t dlz_dlopen_methods = { + dlopen_dlz_create, dlopen_dlz_destroy, dlopen_dlz_findzonedb, + dlopen_dlz_lookup, dlopen_dlz_authority, dlopen_dlz_allnodes, + dlopen_dlz_allowzonexfr, dlopen_dlz_newversion, dlopen_dlz_closeversion, + dlopen_dlz_configure, dlopen_dlz_ssumatch, dlopen_dlz_addrdataset, + dlopen_dlz_subrdataset, dlopen_dlz_delrdataset +}; +#endif /* ifdef ISC_DLZ_DLOPEN */ + +/* + * Register driver with BIND + */ +isc_result_t +dlz_dlopen_init(isc_mem_t *mctx) { +#ifndef ISC_DLZ_DLOPEN + UNUSED(mctx); + return (ISC_R_NOTIMPLEMENTED); +#else /* ifndef ISC_DLZ_DLOPEN */ + isc_result_t result; + + dlopen_log(2, "Registering DLZ_dlopen driver"); + + result = dns_sdlzregister("dlopen", &dlz_dlopen_methods, NULL, + DNS_SDLZFLAG_RELATIVEOWNER | + DNS_SDLZFLAG_RELATIVERDATA | + DNS_SDLZFLAG_THREADSAFE, + mctx, &dlz_dlopen); + + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "dns_sdlzregister() failed: %s", + isc_result_totext(result)); + result = ISC_R_UNEXPECTED; + } + + return (result); +#endif /* ifndef ISC_DLZ_DLOPEN */ +} + +/* + * Unregister the driver + */ +void +dlz_dlopen_clear(void) { +#ifdef ISC_DLZ_DLOPEN + dlopen_log(2, "Unregistering DLZ_dlopen driver"); + if (dlz_dlopen != NULL) { + dns_sdlzunregister(&dlz_dlopen); + } +#endif /* ifdef ISC_DLZ_DLOPEN */ +} diff --git a/bin/named/win32/include/.clang-format b/bin/named/win32/include/.clang-format new file mode 120000 index 0000000..e919bba --- /dev/null +++ b/bin/named/win32/include/.clang-format @@ -0,0 +1 @@ +../../../../.clang-format.headers \ No newline at end of file diff --git a/bin/named/win32/include/named/ntservice.h b/bin/named/win32/include/named/ntservice.h new file mode 100644 index 0000000..0b380e5 --- /dev/null +++ b/bin/named/win32/include/named/ntservice.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NTSERVICE_H +#define NTSERVICE_H + +#include + +#define BIND_DISPLAY_NAME "ISC BIND" +#define BIND_SERVICE_NAME "named" + +void + ntservice_init(); +void UpdateSCM(DWORD); +void +ServiceControl(DWORD dwCtrlCode); +void +ntservice_shutdown(); +BOOL +ntservice_isservice(); +#endif /* ifndef NTSERVICE_H */ diff --git a/bin/named/win32/include/named/os.h b/bin/named/win32/include/named/os.h new file mode 100644 index 0000000..696465b --- /dev/null +++ b/bin/named/win32/include/named/os.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef NAMED_OS_H +#define NAMED_OS_H 1 + +#include + +#include + +void +named_os_init(const char *progname); + +void +named_os_daemonize(void); + +void +named_os_opendevnull(void); + +void +named_os_closedevnull(void); + +void +named_os_chroot(const char *root); + +void +named_os_inituserinfo(const char *username); + +void +named_os_changeuser(void); + +unsigned int +ns_os_uid(void); + +void +named_os_adjustnofile(void); + +void +named_os_minprivs(void); + +FILE * +named_os_openfile(const char *filename, int mode, bool switch_user); + +void +named_os_writepidfile(const char *filename, bool first_time); + +bool +named_os_issingleton(const char *filename); + +void +named_os_shutdown(void); + +isc_result_t +named_os_gethostname(char *buf, size_t len); + +void +named_os_shutdownmsg(char *command, isc_buffer_t *text); + +void +named_os_tzset(void); + +void +named_os_started(void); + +const char * +named_os_uname(void); + +#endif /* NAMED_OS_H */ diff --git a/bin/named/win32/named.vcxproj.filters.in b/bin/named/win32/named.vcxproj.filters.in new file mode 100644 index 0000000..60b2ec2 --- /dev/null +++ b/bin/named/win32/named.vcxproj.filters.in @@ -0,0 +1,121 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + +@IF GEOIP + + Source Files + +@END GEOIP + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + +@IF GEOIP + + Header Files + +@END GEOIP + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + diff --git a/bin/named/win32/named.vcxproj.in b/bin/named/win32/named.vcxproj.in new file mode 100644 index 0000000..f470085 --- /dev/null +++ b/bin/named/win32/named.vcxproj.in @@ -0,0 +1,156 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {723C65DA-A96C-4BA3-A34E-44F11CA346F9} + Win32Proj + named + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;@USE_GSSAPI@BUILDER="Visual Studio";_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + @LIBUV_INC@@OPENSSL_INC@@GSSAPI_INC@@GEOIP_INC@.\;..\..\..\;@LIBXML2_INC@..\win32\include;..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\isccc\include;..\..\..\lib\isccfg\include;..\..\..\lib\bind9\include;..\..\..\lib\ns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);..\..\..\lib\ns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @LIBUV_LIB@@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBXML2_LIB@@GSSAPI_LIB@@GEOIP_LIB@libisc.lib;libdns.lib;libisccc.lib;libisccfg.lib;libbind9.lib;libns.lib;version.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;@USE_GSSAPI@BUILDER="Visual Studio";NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + @LIBUV_INC@@OPENSSL_INC@@GSSAPI_INC@@GEOIP_INC@.\;..\..\..\;@LIBXML2_INC@..\win32\include;..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\isccc\include;..\..\..\lib\isccfg\include;..\..\..\lib\bind9\include;..\..\..\lib\ns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);..\..\..\lib\ns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @LIBUV_LIB@@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBXML2_LIB@@GSSAPI_LIB@@GEOIP_LIB@libisc.lib;libdns.lib;libisccc.lib;libisccfg.lib;libbind9.lib;libns.lib;version.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + +@IF GEOIP + +@END GEOIP + + + + + + + + + + + + + + + + +@IF GEOIP + +@END GEOIP + + + + + + + + + + + + + + + + + diff --git a/bin/named/win32/named.vcxproj.user b/bin/named/win32/named.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/named/win32/named.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/named/win32/ntservice.c b/bin/named/win32/ntservice.c new file mode 100644 index 0000000..5c5c40f --- /dev/null +++ b/bin/named/win32/ntservice.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Handle to SCM for updating service status */ +static SERVICE_STATUS_HANDLE hServiceStatus = 0; +static BOOL foreground = FALSE; +static char ConsoleTitle[128]; + +/* + * Forward declarations + */ +static int +bindmain_service_wrapper(int argc, char *argv[]); +void +ServiceControl(DWORD dwCtrlCode); +int +bindmain(int, char *[]); /* From main.c */ + +/* + * Initialize the ISC library running as a Windows Service before calling + * bindmain() + */ +static int +bindmain_service_wrapper(int argc, char *argv[]) { + return (isc_lib_ntservice(bindmain, argc, argv)); +} + +/* + * Initialize the Service by registering it. + */ +void +ntservice_init(void) { + if (!foreground) { + /* Register handler with the SCM */ + hServiceStatus = RegisterServiceCtrlHandler( + BIND_SERVICE_NAME, (LPHANDLER_FUNCTION)ServiceControl); + if (!hServiceStatus) { + named_main_earlyfatal("could not register service " + "control handler"); + } + UpdateSCM(SERVICE_RUNNING); + } else { + strlcpy(ConsoleTitle, "BIND Version ", sizeof(ConsoleTitle)); + strlcat(ConsoleTitle, VERSION, sizeof(ConsoleTitle)); + SetConsoleTitle(ConsoleTitle); + } +} + +void +ntservice_shutdown(void) { + UpdateSCM(SERVICE_STOPPED); +} + +/* + * Routine to check if this is a service or a foreground program + */ +BOOL +ntservice_isservice(void) { + return (!foreground); +} + +/* + * ServiceControl(): Handles requests from the SCM and passes them on + * to named. + */ +void +ServiceControl(DWORD dwCtrlCode) { + /* Handle the requested control code */ + switch (dwCtrlCode) { + case SERVICE_CONTROL_INTERROGATE: + UpdateSCM(0); + break; + + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + named_server_flushonshutdown(named_g_server, true); + isc_app_shutdown(); + UpdateSCM(SERVICE_STOP_PENDING); + break; + default: + break; + } +} + +/* + * Tell the Service Control Manager the state of the service. + */ +void +UpdateSCM(DWORD state) { + SERVICE_STATUS ss; + static DWORD dwState = SERVICE_STOPPED; + + if (hServiceStatus) { + if (state) { + dwState = state; + } + + memset(&ss, 0, sizeof(SERVICE_STATUS)); + ss.dwServiceType |= SERVICE_WIN32_OWN_PROCESS; + ss.dwCurrentState = dwState; + ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_SHUTDOWN; + ss.dwCheckPoint = 0; + ss.dwServiceSpecificExitCode = 0; + ss.dwWin32ExitCode = NO_ERROR; + ss.dwWaitHint = dwState == SERVICE_STOP_PENDING ? 10000 : 1000; + + if (!SetServiceStatus(hServiceStatus, &ss)) { + ss.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(hServiceStatus, &ss); + } + } +} + +/* unhook main */ + +#undef main + +/* + * This is the entry point for the executable + * We can now call bindmain() explicitly or via StartServiceCtrlDispatcher() + * as we need to. + */ +int +main(int argc, char *argv[]) { + int rc, ch; + + /* Command line users should put -f in the options. */ + isc_commandline_errprint = false; + while ((ch = isc_commandline_parse(argc, argv, NAMED_MAIN_ARGS)) != -1) + { + switch (ch) { + case 'f': + case 'g': + case 'v': + case 'V': + foreground = TRUE; + break; + default: + break; + } + } + isc_commandline_reset = true; + + if (foreground) { + /* run in console window */ + exit(bindmain(argc, argv)); + } else { + /* Start up as service */ + char *SERVICE_NAME = BIND_SERVICE_NAME; + + SERVICE_TABLE_ENTRY dispatchTable[] = { + { TEXT(SERVICE_NAME), + (LPSERVICE_MAIN_FUNCTION)bindmain_service_wrapper }, + { NULL, NULL } + }; + + rc = StartServiceCtrlDispatcher(dispatchTable); + if (!rc) { + fprintf(stderr, "Use -f to run from the command " + "line.\n"); + /* will be 1063 when launched as a console app */ + exit(GetLastError()); + } + } + exit(0); +} diff --git a/bin/named/win32/os.c b/bin/named/win32/os.c new file mode 100644 index 0000000..5503d95 --- /dev/null +++ b/bin/named/win32/os.c @@ -0,0 +1,473 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static char *lockfile = NULL; +static char *pidfile = NULL; +static int devnullfd = -1; +static int lockfilefd = -1; + +static BOOL Initialized = FALSE; + +static char *version_error = "named requires Windows 2000 Service Pack 2 or " + "later to run correctly"; + +void +named_paths_init(void) { + if (!Initialized) { + isc_ntpaths_init(); + } + + named_g_conffile = isc_ntpaths_get(NAMED_CONF_PATH); + named_g_defaultpidfile = isc_ntpaths_get(NAMED_PID_PATH); + named_g_defaultlockfile = isc_ntpaths_get(NAMED_LOCK_PATH); + named_g_keyfile = isc_ntpaths_get(RNDC_KEY_PATH); + named_g_defaultsessionkeyfile = isc_ntpaths_get(SESSION_KEY_PATH); + named_g_defaultbindkeys = isc_ntpaths_get(BIND_KEYS_PATH); + + Initialized = TRUE; +} + +/* + * Due to Knowledge base article Q263823 we need to make sure that + * Windows 2000 systems have Service Pack 2 or later installed and + * warn when it isn't. + */ +static void +version_check(const char *progname) { + if ((isc_win32os_versioncheck(4, 0, 0, 0) >= 0) && + (isc_win32os_versioncheck(5, 0, 0, 0) < 0)) + { + return; /* No problem with Version 4.0 */ + } + if (isc_win32os_versioncheck(5, 0, 2, 0) < 0) { + if (ntservice_isservice()) { + NTReportError(progname, version_error); + } else { + fprintf(stderr, "%s\n", version_error); + } + } +} + +static void +setup_syslog(const char *progname) { + int options; + + options = LOG_PID; +#ifdef LOG_NDELAY + options |= LOG_NDELAY; +#endif /* ifdef LOG_NDELAY */ + + openlog(progname, options, LOG_DAEMON); +} + +void +named_os_init(const char *progname) { + named_paths_init(); + setup_syslog(progname); + /* + * XXXMPA. We may need to split ntservice_init() in two and + * just mark as running in named_os_started(). If we do that + * this is where the first part of ntservice_init() should be + * called from. + * + * XXX970 Remove comment if no problems by 9.7.0. + * + * ntservice_init(); + */ + version_check(progname); + /* + * If running in a Cygwin environment, clear the SEM_NOGPFAULTERRORBOX + * bit in the process error mode to prevent Cygwin from concealing + * non-abort() crashes, giving Windows Error Reporting a chance to + * handle such crashes. This is done to ensure all crashes triggered + * by system tests can be detected. + */ + if (getenv("CYGWIN") != NULL) { + SetErrorMode(GetErrorMode() & ~SEM_NOGPFAULTERRORBOX); + } +} + +void +named_os_daemonize(void) { + /* + * Try to set stdin, stdout, and stderr to /dev/null, but press + * on even if it fails. + */ + if (devnullfd != -1) { + if (devnullfd != _fileno(stdin)) { + close(_fileno(stdin)); + (void)_dup2(devnullfd, _fileno(stdin)); + } + if (devnullfd != _fileno(stdout)) { + close(_fileno(stdout)); + (void)_dup2(devnullfd, _fileno(stdout)); + } + if (devnullfd != _fileno(stderr)) { + close(_fileno(stderr)); + (void)_dup2(devnullfd, _fileno(stderr)); + } + } +} + +void +named_os_opendevnull(void) { + devnullfd = open("NUL", O_RDWR, 0); +} + +void +named_os_closedevnull(void) { + if (devnullfd != _fileno(stdin) && devnullfd != _fileno(stdout) && + devnullfd != _fileno(stderr)) + { + close(devnullfd); + devnullfd = -1; + } +} + +void +named_os_chroot(const char *root) { + if (root != NULL) { + named_main_earlyfatal("chroot(): isn't supported by Win32 API"); + } +} + +void +named_os_inituserinfo(const char *username) {} + +void +named_os_changeuser(void) {} + +unsigned int +ns_os_uid(void) { + return (0); +} + +void +named_os_adjustnofile(void) {} + +void +named_os_minprivs(void) {} + +static int +safe_open(const char *filename, int mode, bool append) { + int fd; + struct stat sb; + + if (stat(filename, &sb) == -1) { + if (errno != ENOENT) { + return (-1); + } + } else if ((sb.st_mode & S_IFREG) == 0) { + return (-1); + } + + if (append) { + fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, mode); + } else { + (void)unlink(filename); + fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, mode); + } + return (fd); +} + +static void +cleanup_pidfile(void) { + if (pidfile != NULL) { + (void)unlink(pidfile); + free(pidfile); + } + pidfile = NULL; +} + +static void +cleanup_lockfile(void) { + if (lockfilefd != -1) { + close(lockfilefd); + lockfilefd = -1; + } + + if (lockfile != NULL) { + int n = unlink(lockfile); + if (n == -1 && errno != ENOENT) { + named_main_earlywarning("unlink '%s': failed", + lockfile); + } + free(lockfile); + lockfile = NULL; + } +} + +FILE * +named_os_openfile(const char *filename, int mode, bool switch_user) { + char strbuf[ISC_STRERRORSIZE]; + FILE *fp; + int fd; + + UNUSED(switch_user); + fd = safe_open(filename, mode, false); + if (fd < 0) { + strerror_s(strbuf, sizeof(strbuf), errno); + named_main_earlywarning("could not open file '%s': %s", + filename, strbuf); + return (NULL); + } + + fp = fdopen(fd, "w"); + if (fp == NULL) { + strerror_s(strbuf, sizeof(strbuf), errno); + named_main_earlywarning("could not fdopen() file '%s': %s", + filename, strbuf); + close(fd); + } + + return (fp); +} + +void +named_os_writepidfile(const char *filename, bool first_time) { + FILE *pidlockfile; + pid_t pid; + char strbuf[ISC_STRERRORSIZE]; + void (*report)(const char *, ...); + + /* + * The caller must ensure any required synchronization. + */ + + report = first_time ? named_main_earlyfatal : named_main_earlywarning; + + cleanup_pidfile(); + + if (filename == NULL) { + return; + } + + pidfile = strdup(filename); + if (pidfile == NULL) { + strerror_s(strbuf, sizeof(strbuf), errno); + (*report)("couldn't strdup() '%s': %s", filename, strbuf); + return; + } + + pidlockfile = named_os_openfile( + filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, false); + if (pidlockfile == NULL) { + free(pidfile); + pidfile = NULL; + return; + } + + pid = getpid(); + + if (fprintf(pidlockfile, "%ld\n", (long)pid) < 0) { + (*report)("fprintf() to pid file '%s' failed", filename); + (void)fclose(pidlockfile); + cleanup_pidfile(); + return; + } + if (fflush(pidlockfile) == EOF) { + (*report)("fflush() to pid file '%s' failed", filename); + (void)fclose(pidlockfile); + cleanup_pidfile(); + return; + } + (void)fclose(pidlockfile); +} + +bool +named_os_issingleton(const char *filename) { + char strbuf[ISC_STRERRORSIZE]; + OVERLAPPED o; + + if (lockfilefd != -1) { + return (true); + } + + if (strcasecmp(filename, "none") == 0) { + return (true); + } + + lockfile = strdup(filename); + if (lockfile == NULL) { + strerror_s(strbuf, sizeof(strbuf), errno); + named_main_earlyfatal("couldn't allocate memory for '%s': %s", + filename, strbuf); + } + + /* + * named_os_openfile() uses safeopen() which removes any existing + * files. We can't use that here. + */ + lockfilefd = open(filename, O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (lockfilefd == -1) { + cleanup_lockfile(); + return (false); + } + + memset(&o, 0, sizeof(o)); + /* Expect ERROR_LOCK_VIOLATION if already locked */ + if (!LockFileEx((HANDLE)_get_osfhandle(lockfilefd), + LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, + 0, 1, &o)) + { + cleanup_lockfile(); + return (false); + } + + return (true); +} + +void +named_os_shutdown(void) { + closelog(); + cleanup_pidfile(); + + if (lockfilefd != -1) { + (void)UnlockFile((HANDLE)_get_osfhandle(lockfilefd), 0, 0, 0, + 1); + } + cleanup_lockfile(); + + ntservice_shutdown(); /* This MUST be the last thing done */ +} + +isc_result_t +named_os_gethostname(char *buf, size_t len) { + int n; + + n = gethostname(buf, (int)len); + return ((n == 0) ? ISC_R_SUCCESS : ISC_R_FAILURE); +} + +void +named_os_shutdownmsg(char *command, isc_buffer_t *text) { + UNUSED(command); + UNUSED(text); +} + +void +named_os_tzset(void) { +#ifdef HAVE_TZSET + tzset(); +#endif /* ifdef HAVE_TZSET */ +} + +void +named_os_started(void) { + ntservice_init(); +} + +static char unamebuf[BUFSIZ]; +static const char *unamep = NULL; + +static void +getuname(void) { + DWORD fvilen; + char *fvi; + VS_FIXEDFILEINFO *ffi; + UINT ffilen; + SYSTEM_INFO sysinfo; + char *arch; + + fvi = NULL; + fvilen = GetFileVersionInfoSize("kernel32.dll", 0); + if (fvilen == 0) { + goto err; + } + fvi = (char *)malloc(fvilen); + if (fvi == NULL) { + goto err; + } + memset(fvi, 0, fvilen); + if (GetFileVersionInfo("kernel32.dll", 0, fvilen, fvi) == 0) { + goto err; + } + ffi = NULL; + ffilen = 0; + if ((VerQueryValue(fvi, "\\", &ffi, &ffilen) == 0) || (ffi == NULL) || + (ffilen == 0)) + { + goto err; + } + memset(&sysinfo, 0, sizeof(sysinfo)); + GetSystemInfo(&sysinfo); + switch (sysinfo.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_INTEL: + arch = "x86"; + break; + case PROCESSOR_ARCHITECTURE_ARM: + arch = "arm"; + break; + case PROCESSOR_ARCHITECTURE_IA64: + arch = "ia64"; + break; + case PROCESSOR_ARCHITECTURE_AMD64: + arch = "x64"; + break; + default: + arch = "unknown architecture"; + break; + } + + snprintf(unamebuf, sizeof(unamebuf), + "Windows %d %d build %d %d for %s\n", + (ffi->dwProductVersionMS >> 16) & 0xffff, + ffi->dwProductVersionMS & 0xffff, + (ffi->dwProductVersionLS >> 16) & 0xffff, + ffi->dwProductVersionLS & 0xffff, arch); + +err: + if (fvi != NULL) { + free(fvi); + } + unamep = unamebuf; +} + +/* + * GetVersionEx() returns 6.2 (aka Windows 8.1) since it was obsoleted + * so we had to switch to the recommended way to get the Windows version. + */ +const char * +named_os_uname(void) { + if (unamep == NULL) { + getuname(); + } + return (unamep); +} diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c new file mode 100644 index 0000000..2e614aa --- /dev/null +++ b/bin/named/zoneconf.c @@ -0,0 +1,2173 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* ACLs associated with zone */ +typedef enum { + allow_notify, + allow_query, + allow_query_on, + allow_transfer, + allow_update, + allow_update_forwarding +} acl_type_t; + +#define RETERR(x) \ + do { \ + isc_result_t _r = (x); \ + if (_r != ISC_R_SUCCESS) \ + return ((_r)); \ + } while (0) + +#define CHECK(x) \ + do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +/*% + * Convenience function for configuring a single zone ACL. + */ +static isc_result_t +configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, + const cfg_obj_t *config, acl_type_t acltype, + cfg_aclconfctx_t *actx, dns_zone_t *zone, + void (*setzacl)(dns_zone_t *, dns_acl_t *), + void (*clearzacl)(dns_zone_t *)) { + isc_result_t result; + const cfg_obj_t *maps[5] = { NULL, NULL, NULL, NULL, NULL }; + const cfg_obj_t *aclobj = NULL; + int i = 0; + dns_acl_t **aclp = NULL, *acl = NULL; + const char *aclname; + dns_view_t *view; + + view = dns_zone_getview(zone); + + switch (acltype) { + case allow_notify: + if (view != NULL) { + aclp = &view->notifyacl; + } + aclname = "allow-notify"; + break; + case allow_query: + if (view != NULL) { + aclp = &view->queryacl; + } + aclname = "allow-query"; + break; + case allow_query_on: + if (view != NULL) { + aclp = &view->queryonacl; + } + aclname = "allow-query-on"; + break; + case allow_transfer: + if (view != NULL) { + aclp = &view->transferacl; + } + aclname = "allow-transfer"; + break; + case allow_update: + if (view != NULL) { + aclp = &view->updateacl; + } + aclname = "allow-update"; + break; + case allow_update_forwarding: + if (view != NULL) { + aclp = &view->upfwdacl; + } + aclname = "allow-update-forwarding"; + break; + default: + UNREACHABLE(); + } + + /* First check to see if ACL is defined within the zone */ + if (zconfig != NULL) { + maps[0] = cfg_tuple_get(zconfig, "options"); + (void)named_config_get(maps, aclname, &aclobj); + if (aclobj != NULL) { + aclp = NULL; + goto parse_acl; + } + } + + /* Failing that, see if there's a default ACL already in the view */ + if (aclp != NULL && *aclp != NULL) { + (*setzacl)(zone, *aclp); + return (ISC_R_SUCCESS); + } + + /* Check for default ACLs that haven't been parsed yet */ + if (vconfig != NULL) { + const cfg_obj_t *options = cfg_tuple_get(vconfig, "options"); + if (options != NULL) { + maps[i++] = options; + } + } + if (config != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) { + maps[i++] = options; + } + } + maps[i++] = named_g_defaults; + maps[i] = NULL; + + (void)named_config_get(maps, aclname, &aclobj); + if (aclobj == NULL) { + (*clearzacl)(zone); + return (ISC_R_SUCCESS); + } + +parse_acl: + result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, + named_g_mctx, 0, &acl); + if (result != ISC_R_SUCCESS) { + return (result); + } + (*setzacl)(zone, acl); + + /* Set the view default now */ + if (aclp != NULL) { + dns_acl_attach(acl, aclp); + } + + dns_acl_detach(&acl); + return (ISC_R_SUCCESS); +} + +/*% + * Parse the zone update-policy statement. + */ +static isc_result_t +configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone, + const char *zname) { + const cfg_obj_t *updatepolicy = NULL; + const cfg_listelt_t *element, *element2; + dns_ssutable_t *table = NULL; + isc_mem_t *mctx = dns_zone_getmctx(zone); + bool autoddns = false; + isc_result_t result; + + (void)cfg_map_get(zconfig, "update-policy", &updatepolicy); + + if (updatepolicy == NULL) { + dns_zone_setssutable(zone, NULL); + return (ISC_R_SUCCESS); + } + + if (cfg_obj_isstring(updatepolicy) && + strcmp("local", cfg_obj_asstring(updatepolicy)) == 0) + { + autoddns = true; + updatepolicy = NULL; + } + + result = dns_ssutable_create(mctx, &table); + if (result != ISC_R_SUCCESS) { + return (result); + } + + for (element = cfg_list_first(updatepolicy); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *stmt = cfg_listelt_value(element); + const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode"); + const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity"); + const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype"); + const cfg_obj_t *dname = cfg_tuple_get(stmt, "name"); + const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types"); + const char *str; + bool grant = false; + bool usezone = false; + dns_ssumatchtype_t mtype = dns_ssumatchtype_name; + dns_fixedname_t fname, fident; + isc_buffer_t b; + dns_rdatatype_t *types; + unsigned int i, n; + + str = cfg_obj_asstring(mode); + if (strcasecmp(str, "grant") == 0) { + grant = true; + } else if (strcasecmp(str, "deny") == 0) { + grant = false; + } else { + UNREACHABLE(); + } + + str = cfg_obj_asstring(matchtype); + CHECK(dns_ssu_mtypefromstring(str, &mtype)); + if (mtype == dns_ssumatchtype_subdomain && + strcasecmp(str, "zonesub") == 0) + { + usezone = true; + } + + dns_fixedname_init(&fident); + str = cfg_obj_asstring(identity); + isc_buffer_constinit(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(dns_fixedname_name(&fident), &b, + dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(identity, named_g_lctx, ISC_LOG_ERROR, + "'%s' is not a valid name", str); + goto cleanup; + } + + dns_fixedname_init(&fname); + if (usezone) { + dns_name_copynf(dns_zone_getorigin(zone), + dns_fixedname_name(&fname)); + } else { + str = cfg_obj_asstring(dname); + isc_buffer_constinit(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(dns_fixedname_name(&fname), + &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(identity, named_g_lctx, + ISC_LOG_ERROR, + "'%s' is not a valid name", str); + goto cleanup; + } + } + + n = named_config_listcount(typelist); + if (n == 0) { + types = NULL; + } else { + types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t)); + } + + i = 0; + for (element2 = cfg_list_first(typelist); element2 != NULL; + element2 = cfg_list_next(element2)) + { + const cfg_obj_t *typeobj; + isc_textregion_t r; + + INSIST(i < n); + + typeobj = cfg_listelt_value(element2); + str = cfg_obj_asstring(typeobj); + DE_CONST(str, r.base); + r.length = strlen(str); + + result = dns_rdatatype_fromtext(&types[i++], &r); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(identity, named_g_lctx, + ISC_LOG_ERROR, + "'%s' is not a valid type", str); + isc_mem_put(mctx, types, + n * sizeof(dns_rdatatype_t)); + goto cleanup; + } + } + INSIST(i == n); + + result = dns_ssutable_addrule( + table, grant, dns_fixedname_name(&fident), mtype, + dns_fixedname_name(&fname), n, types); + if (types != NULL) { + isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t)); + } + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } + + /* + * If "update-policy local;" and a session key exists, + * then use the default policy, which is equivalent to: + * update-policy { grant zonesub any; }; + */ + if (autoddns) { + dns_rdatatype_t any = dns_rdatatype_any; + + if (named_g_server->session_keyname == NULL) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed to enable auto DDNS policy " + "for zone %s: session key not found", + zname); + result = ISC_R_NOTFOUND; + goto cleanup; + } + + result = dns_ssutable_addrule( + table, true, named_g_server->session_keyname, + dns_ssumatchtype_local, dns_zone_getorigin(zone), 1, + &any); + + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } + + result = ISC_R_SUCCESS; + dns_zone_setssutable(zone, table); + +cleanup: + dns_ssutable_detach(&table); + return (result); +} + +/* + * This is the TTL used for internally generated RRsets for static-stub zones. + * The value doesn't matter because the mapping is static, but needs to be + * defined for the sake of implementation. + */ +#define STATICSTUB_SERVER_TTL 86400 + +/*% + * Configure an apex NS with glues for a static-stub zone. + * For example, for the zone named "example.com", the following RRs will be + * added to the zone DB: + * example.com. NS example.com. + * example.com. A 192.0.2.1 + * example.com. AAAA 2001:db8::1 + */ +static isc_result_t +configure_staticstub_serveraddrs(const cfg_obj_t *zconfig, dns_zone_t *zone, + dns_rdatalist_t *rdatalist_ns, + dns_rdatalist_t *rdatalist_a, + dns_rdatalist_t *rdatalist_aaaa) { + const cfg_listelt_t *element; + isc_mem_t *mctx = dns_zone_getmctx(zone); + isc_region_t region, sregion; + dns_rdata_t *rdata; + isc_result_t result = ISC_R_SUCCESS; + + for (element = cfg_list_first(zconfig); element != NULL; + element = cfg_list_next(element)) + { + const isc_sockaddr_t *sa; + isc_netaddr_t na; + const cfg_obj_t *address = cfg_listelt_value(element); + dns_rdatalist_t *rdatalist; + + sa = cfg_obj_assockaddr(address); + if (isc_sockaddr_getport(sa) != 0) { + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "port is not configurable for " + "static stub server-addresses"); + return (ISC_R_FAILURE); + } + isc_netaddr_fromsockaddr(&na, sa); + if (isc_netaddr_getzone(&na) != 0) { + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "scoped address is not allowed " + "for static stub " + "server-addresses"); + return (ISC_R_FAILURE); + } + + switch (na.family) { + case AF_INET: + region.length = sizeof(na.type.in); + rdatalist = rdatalist_a; + break; + default: + INSIST(na.family == AF_INET6); + region.length = sizeof(na.type.in6); + rdatalist = rdatalist_aaaa; + break; + } + + rdata = isc_mem_get(mctx, sizeof(*rdata) + region.length); + region.base = (unsigned char *)(rdata + 1); + memmove(region.base, &na.type, region.length); + dns_rdata_init(rdata); + dns_rdata_fromregion(rdata, dns_zone_getclass(zone), + rdatalist->type, ®ion); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + } + + /* + * If no address is specified (unlikely in this context, but possible), + * there's nothing to do anymore. + */ + if (ISC_LIST_EMPTY(rdatalist_a->rdata) && + ISC_LIST_EMPTY(rdatalist_aaaa->rdata)) + { + return (ISC_R_SUCCESS); + } + + /* Add to the list an apex NS with the ns name being the origin name */ + dns_name_toregion(dns_zone_getorigin(zone), &sregion); + rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length); + region.length = sregion.length; + region.base = (unsigned char *)(rdata + 1); + memmove(region.base, sregion.base, region.length); + dns_rdata_init(rdata); + dns_rdata_fromregion(rdata, dns_zone_getclass(zone), dns_rdatatype_ns, + ®ion); + ISC_LIST_APPEND(rdatalist_ns->rdata, rdata, link); + + return (result); +} + +/*% + * Configure an apex NS with an out-of-zone NS names for a static-stub zone. + * For example, for the zone named "example.com", something like the following + * RRs will be added to the zone DB: + * example.com. NS ns.example.net. + */ +static isc_result_t +configure_staticstub_servernames(const cfg_obj_t *zconfig, dns_zone_t *zone, + dns_rdatalist_t *rdatalist, + const char *zname) { + const cfg_listelt_t *element; + isc_mem_t *mctx = dns_zone_getmctx(zone); + dns_rdata_t *rdata; + isc_region_t sregion, region; + isc_result_t result = ISC_R_SUCCESS; + + for (element = cfg_list_first(zconfig); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *obj; + const char *str; + dns_fixedname_t fixed_name; + dns_name_t *nsname; + isc_buffer_t b; + + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(obj); + + nsname = dns_fixedname_initname(&fixed_name); + + isc_buffer_constinit(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(nsname, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "server-name '%s' is not a valid " + "name", + str); + return (result); + } + if (dns_name_issubdomain(nsname, dns_zone_getorigin(zone))) { + cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR, + "server-name '%s' must not be a " + "subdomain of zone name '%s'", + str, zname); + return (ISC_R_FAILURE); + } + + dns_name_toregion(nsname, &sregion); + rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length); + region.length = sregion.length; + region.base = (unsigned char *)(rdata + 1); + memmove(region.base, sregion.base, region.length); + dns_rdata_init(rdata); + dns_rdata_fromregion(rdata, dns_zone_getclass(zone), + dns_rdatatype_ns, ®ion); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + } + + return (result); +} + +/*% + * Configure static-stub zone. + */ +static isc_result_t +configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone, + const char *zname, const char *dbtype) { + int i = 0; + const cfg_obj_t *obj; + isc_mem_t *mctx = dns_zone_getmctx(zone); + dns_db_t *db = NULL; + dns_dbversion_t *dbversion = NULL; + dns_dbnode_t *apexnode = NULL; + dns_name_t apexname; + isc_result_t result; + dns_rdataset_t rdataset; + dns_rdatalist_t rdatalist_ns, rdatalist_a, rdatalist_aaaa; + dns_rdatalist_t *rdatalists[] = { &rdatalist_ns, &rdatalist_a, + &rdatalist_aaaa, NULL }; + dns_rdata_t *rdata; + isc_region_t region; + + /* Create the DB beforehand */ + RETERR(dns_db_create(mctx, dbtype, dns_zone_getorigin(zone), + dns_dbtype_stub, dns_zone_getclass(zone), 0, NULL, + &db)); + + dns_rdataset_init(&rdataset); + + dns_rdatalist_init(&rdatalist_ns); + rdatalist_ns.rdclass = dns_zone_getclass(zone); + rdatalist_ns.type = dns_rdatatype_ns; + rdatalist_ns.ttl = STATICSTUB_SERVER_TTL; + + dns_rdatalist_init(&rdatalist_a); + rdatalist_a.rdclass = dns_zone_getclass(zone); + rdatalist_a.type = dns_rdatatype_a; + rdatalist_a.ttl = STATICSTUB_SERVER_TTL; + + dns_rdatalist_init(&rdatalist_aaaa); + rdatalist_aaaa.rdclass = dns_zone_getclass(zone); + rdatalist_aaaa.type = dns_rdatatype_aaaa; + rdatalist_aaaa.ttl = STATICSTUB_SERVER_TTL; + + /* Prepare zone RRs from the configuration */ + obj = NULL; + result = cfg_map_get(zconfig, "server-addresses", &obj); + if (result == ISC_R_SUCCESS) { + INSIST(obj != NULL); + CHECK(configure_staticstub_serveraddrs(obj, zone, &rdatalist_ns, + &rdatalist_a, + &rdatalist_aaaa)); + } + + obj = NULL; + result = cfg_map_get(zconfig, "server-names", &obj); + if (result == ISC_R_SUCCESS) { + INSIST(obj != NULL); + CHECK(configure_staticstub_servernames(obj, zone, &rdatalist_ns, + zname)); + } + + /* + * Sanity check: there should be at least one NS RR at the zone apex + * to trigger delegation. + */ + if (ISC_LIST_EMPTY(rdatalist_ns.rdata)) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "No NS record is configured for a " + "static-stub zone '%s'", + zname); + result = ISC_R_FAILURE; + goto cleanup; + } + + /* + * Now add NS and glue A/AAAA RRsets to the zone DB. + * First open a new version for the add operation and get a pointer + * to the apex node (all RRs are of the apex name). + */ + CHECK(dns_db_newversion(db, &dbversion)); + + dns_name_init(&apexname, NULL); + dns_name_clone(dns_zone_getorigin(zone), &apexname); + CHECK(dns_db_findnode(db, &apexname, false, &apexnode)); + + /* Add NS RRset */ + RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_ns, &rdataset) == + ISC_R_SUCCESS); + CHECK(dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, 0, + NULL)); + dns_rdataset_disassociate(&rdataset); + + /* Add glue A RRset, if any */ + if (!ISC_LIST_EMPTY(rdatalist_a.rdata)) { + RUNTIME_CHECK( + dns_rdatalist_tordataset(&rdatalist_a, &rdataset) == + ISC_R_SUCCESS); + CHECK(dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, + 0, NULL)); + dns_rdataset_disassociate(&rdataset); + } + + /* Add glue AAAA RRset, if any */ + if (!ISC_LIST_EMPTY(rdatalist_aaaa.rdata)) { + RUNTIME_CHECK( + dns_rdatalist_tordataset(&rdatalist_aaaa, &rdataset) == + ISC_R_SUCCESS); + CHECK(dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, + 0, NULL)); + dns_rdataset_disassociate(&rdataset); + } + + dns_db_closeversion(db, &dbversion, true); + dns_zone_setdb(zone, db); + + result = ISC_R_SUCCESS; + +cleanup: + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + if (apexnode != NULL) { + dns_db_detachnode(db, &apexnode); + } + if (dbversion != NULL) { + dns_db_closeversion(db, &dbversion, false); + } + if (db != NULL) { + dns_db_detach(&db); + } + for (i = 0; rdatalists[i] != NULL; i++) { + while ((rdata = ISC_LIST_HEAD(rdatalists[i]->rdata)) != NULL) { + ISC_LIST_UNLINK(rdatalists[i]->rdata, rdata, link); + dns_rdata_toregion(rdata, ®ion); + isc_mem_put(mctx, rdata, + sizeof(*rdata) + region.length); + } + } + + INSIST(dbversion == NULL); + + return (result); +} + +/*% + * Convert a config file zone type into a server zone type. + */ +static dns_zonetype_t +zonetype_fromconfig(const cfg_obj_t *map) { + const cfg_obj_t *obj = NULL; + isc_result_t result; + + result = cfg_map_get(map, "type", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + return (named_config_getzonetype(obj)); +} + +/*% + * Helper function for strtoargv(). Pardon the gratuitous recursion. + */ +static isc_result_t +strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp, + unsigned int n) { + isc_result_t result; + + /* Discard leading whitespace. */ + while (*s == ' ' || *s == '\t') { + s++; + } + + if (*s == '\0') { + /* We have reached the end of the string. */ + *argcp = n; + *argvp = isc_mem_get(mctx, n * sizeof(char *)); + } else { + char *p = s; + while (*p != ' ' && *p != '\t' && *p != '\0') { + p++; + } + if (*p != '\0') { + *p++ = '\0'; + } + + result = strtoargvsub(mctx, p, argcp, argvp, n + 1); + if (result != ISC_R_SUCCESS) { + return (result); + } + (*argvp)[n] = s; + } + return (ISC_R_SUCCESS); +} + +/*% + * Tokenize the string "s" into whitespace-separated words, + * return the number of words in '*argcp' and an array + * of pointers to the words in '*argvp'. The caller + * must free the array using isc_mem_put(). The string + * is modified in-place. + */ +static isc_result_t +strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) { + return (strtoargvsub(mctx, s, argcp, argvp, 0)); +} + +static const char *const primary_synonyms[] = { "primary", "master", NULL }; + +static const char *const secondary_synonyms[] = { "secondary", "slave", NULL }; + +static void +checknames(dns_zonetype_t ztype, const cfg_obj_t **maps, + const cfg_obj_t **objp) { + isc_result_t result; + + switch (ztype) { + case dns_zone_secondary: + case dns_zone_mirror: + result = named_checknames_get(maps, secondary_synonyms, objp); + break; + case dns_zone_primary: + result = named_checknames_get(maps, primary_synonyms, objp); + break; + default: + UNREACHABLE(); + } + + INSIST(result == ISC_R_SUCCESS && objp != NULL && *objp != NULL); +} + +/* + * Callback to see if a non-recursive query coming from 'srcaddr' to + * 'destaddr', with optional key 'mykey' for class 'rdclass' would be + * delivered to 'myview'. + * + * We run this unlocked as both the view list and the interface list + * are updated when the appropriate task has exclusivity. + */ +static bool +isself(dns_view_t *myview, dns_tsigkey_t *mykey, const isc_sockaddr_t *srcaddr, + const isc_sockaddr_t *dstaddr, dns_rdataclass_t rdclass, void *arg) { + ns_interfacemgr_t *interfacemgr = (ns_interfacemgr_t *)arg; + dns_aclenv_t *env = ns_interfacemgr_getaclenv(interfacemgr); + dns_view_t *view; + dns_tsigkey_t *key = NULL; + isc_netaddr_t netsrc; + isc_netaddr_t netdst; + + if (interfacemgr == NULL) { + return (true); + } + + if (!ns_interfacemgr_listeningon(interfacemgr, dstaddr)) { + return (false); + } + + isc_netaddr_fromsockaddr(&netsrc, srcaddr); + isc_netaddr_fromsockaddr(&netdst, dstaddr); + + for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + const dns_name_t *tsig = NULL; + + if (view->matchrecursiveonly) { + continue; + } + + if (rdclass != view->rdclass) { + continue; + } + + if (mykey != NULL) { + bool match; + isc_result_t result; + + result = dns_view_gettsig(view, &mykey->name, &key); + if (result != ISC_R_SUCCESS) { + continue; + } + match = dst_key_compare(mykey->key, key->key); + dns_tsigkey_detach(&key); + if (!match) { + continue; + } + tsig = dns_tsigkey_identity(mykey); + } + + if (dns_acl_allowed(&netsrc, tsig, view->matchclients, env) && + dns_acl_allowed(&netdst, tsig, view->matchdestinations, + env)) + { + break; + } + } + return (view == myview); +} + +/*% + * For mirror zones, change "notify yes;" to "notify explicit;", informing the + * user only if "notify" was explicitly configured rather than inherited from + * default configuration. + */ +static dns_notifytype_t +process_notifytype(dns_notifytype_t ntype, dns_zonetype_t ztype, + const char *zname, const cfg_obj_t **maps) { + const cfg_obj_t *obj = NULL; + + /* + * Return the original setting if this is not a mirror zone or if the + * zone is configured with something else than "notify yes;". + */ + if (ztype != dns_zone_mirror || ntype != dns_notifytype_yes) { + return (ntype); + } + + /* + * Only log a message if "notify" was set in the configuration + * hierarchy supplied in 'maps'. + */ + if (named_config_get(maps, "notify", &obj) == ISC_R_SUCCESS) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO, + "'notify explicit;' will be used for mirror zone " + "'%s'", + zname); + } + + return (dns_notifytype_explicit); +} + +isc_result_t +named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, + const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac, + dns_kasplist_t *kasplist, dns_zone_t *zone, + dns_zone_t *raw) { + isc_result_t result; + const char *zname; + dns_rdataclass_t zclass; + dns_rdataclass_t vclass; + const cfg_obj_t *maps[5]; + const cfg_obj_t *nodefault[4]; + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *options = NULL; + const cfg_obj_t *obj; + const char *filename = NULL; + const char *kaspname = NULL; + const char *dupcheck; + dns_notifytype_t notifytype = dns_notifytype_yes; + uint32_t count; + unsigned int dbargc; + char **dbargv; + static char default_dbtype[] = "rbt"; + static char dlz_dbtype[] = "dlz"; + char *cpval = default_dbtype; + isc_mem_t *mctx = dns_zone_getmctx(zone); + dns_dialuptype_t dialup = dns_dialuptype_no; + dns_zonetype_t ztype; + int i; + int32_t journal_size; + bool multi; + bool alt; + dns_view_t *view = NULL; + dns_kasp_t *kasp = NULL; + bool check = false, fail = false; + bool warn = false, ignore = false; + bool ixfrdiff; + bool use_kasp = false; + dns_masterformat_t masterformat; + const dns_master_style_t *masterstyle = &dns_master_style_default; + isc_stats_t *zoneqrystats; + dns_stats_t *rcvquerystats; + dns_stats_t *dnssecsignstats; + dns_zonestat_level_t statlevel = dns_zonestat_none; + int seconds; + dns_ttl_t maxttl = 0; /* unlimited */ + dns_zone_t *mayberaw = (raw != NULL) ? raw : zone; + isc_dscp_t dscp; + + i = 0; + if (zconfig != NULL) { + zoptions = cfg_tuple_get(zconfig, "options"); + nodefault[i] = maps[i] = zoptions; + i++; + } + if (vconfig != NULL) { + nodefault[i] = maps[i] = cfg_tuple_get(vconfig, "options"); + i++; + } + if (config != NULL) { + (void)cfg_map_get(config, "options", &options); + if (options != NULL) { + nodefault[i] = maps[i] = options; + i++; + } + } + nodefault[i] = NULL; + maps[i++] = named_g_defaults; + maps[i] = NULL; + + if (vconfig != NULL) { + CHECK(named_config_getclass(cfg_tuple_get(vconfig, "class"), + dns_rdataclass_in, &vclass)); + } else { + vclass = dns_rdataclass_in; + } + + /* + * Configure values common to all zone types. + */ + + zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + + CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"), vclass, + &zclass)); + dns_zone_setclass(zone, zclass); + if (raw != NULL) { + dns_zone_setclass(raw, zclass); + } + + ztype = zonetype_fromconfig(zoptions); + if (raw != NULL) { + dns_zone_settype(raw, ztype); + dns_zone_settype(zone, dns_zone_primary); + } else { + dns_zone_settype(zone, ztype); + } + + obj = NULL; + result = cfg_map_get(zoptions, "database", &obj); + if (result == ISC_R_SUCCESS) { + cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); + } + if (cpval == NULL) { + CHECK(ISC_R_NOMEMORY); + } + + obj = NULL; + result = cfg_map_get(zoptions, "dlz", &obj); + if (result == ISC_R_SUCCESS) { + const char *dlzname = cfg_obj_asstring(obj); + size_t len; + + if (cpval != default_dbtype) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "zone '%s': both 'database' and 'dlz' " + "specified", + zname); + CHECK(ISC_R_FAILURE); + } + + len = strlen(dlzname) + 5; + cpval = isc_mem_allocate(mctx, len); + snprintf(cpval, len, "dlz %s", dlzname); + } + + result = strtoargv(mctx, cpval, &dbargc, &dbargv); + if (result != ISC_R_SUCCESS && cpval != default_dbtype) { + isc_mem_free(mctx, cpval); + CHECK(result); + } + + /* + * ANSI C is strange here. There is no logical reason why (char **) + * cannot be promoted automatically to (const char * const *) by the + * compiler w/o generating a warning. + */ + dns_zone_setdbtype(zone, dbargc, (const char *const *)dbargv); + isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv)); + if (cpval != default_dbtype && cpval != dlz_dbtype) { + isc_mem_free(mctx, cpval); + } + + obj = NULL; + result = cfg_map_get(zoptions, "file", &obj); + if (result == ISC_R_SUCCESS) { + filename = cfg_obj_asstring(obj); + } + + /* + * Unless we're using some alternative database, a master zone + * will be needing a master file. + */ + if (ztype == dns_zone_primary && cpval == default_dbtype && + filename == NULL) + { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "zone '%s': 'file' not specified", zname); + CHECK(ISC_R_FAILURE); + } + + if (ztype == dns_zone_secondary || ztype == dns_zone_mirror) { + masterformat = dns_masterformat_raw; + } else { + masterformat = dns_masterformat_text; + } + obj = NULL; + result = named_config_get(maps, "masterfile-format", &obj); + if (result == ISC_R_SUCCESS) { + const char *masterformatstr = cfg_obj_asstring(obj); + + if (strcasecmp(masterformatstr, "text") == 0) { + masterformat = dns_masterformat_text; + } else if (strcasecmp(masterformatstr, "raw") == 0) { + masterformat = dns_masterformat_raw; + } else if (strcasecmp(masterformatstr, "map") == 0) { + masterformat = dns_masterformat_map; + cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, + "masterfile-format: format 'map' is " + "deprecated"); + } else { + UNREACHABLE(); + } + } + + obj = NULL; + result = named_config_get(maps, "masterfile-style", &obj); + if (result == ISC_R_SUCCESS) { + const char *masterstylestr = cfg_obj_asstring(obj); + + if (masterformat != dns_masterformat_text) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "zone '%s': 'masterfile-style' " + "can only be used with " + "'masterfile-format text'", + zname); + CHECK(ISC_R_FAILURE); + } + + if (strcasecmp(masterstylestr, "full") == 0) { + masterstyle = &dns_master_style_full; + } else if (strcasecmp(masterstylestr, "relative") == 0) { + masterstyle = &dns_master_style_default; + } else { + UNREACHABLE(); + } + } + + obj = NULL; + result = named_config_get(maps, "max-records", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setmaxrecords(mayberaw, cfg_obj_asuint32(obj)); + if (zone != mayberaw) { + dns_zone_setmaxrecords(zone, 0); + } + + if (raw != NULL && filename != NULL) { +#define SIGNED ".signed" + size_t signedlen = strlen(filename) + sizeof(SIGNED); + char *signedname; + + CHECK(dns_zone_setfile(raw, filename, masterformat, + masterstyle)); + signedname = isc_mem_get(mctx, signedlen); + + (void)snprintf(signedname, signedlen, "%s" SIGNED, filename); + result = dns_zone_setfile(zone, signedname, + dns_masterformat_raw, NULL); + isc_mem_put(mctx, signedname, signedlen); + CHECK(result); + } else { + CHECK(dns_zone_setfile(zone, filename, masterformat, + masterstyle)); + } + + obj = NULL; + result = cfg_map_get(zoptions, "journal", &obj); + if (result == ISC_R_SUCCESS) { + CHECK(dns_zone_setjournal(mayberaw, cfg_obj_asstring(obj))); + } + + /* + * Notify messages are processed by the raw zone if it exists. + */ + if (ztype == dns_zone_secondary || ztype == dns_zone_mirror) { + CHECK(configure_zone_acl(zconfig, vconfig, config, allow_notify, + ac, mayberaw, dns_zone_setnotifyacl, + dns_zone_clearnotifyacl)); + } + + /* + * XXXAG This probably does not make sense for stubs. + */ + CHECK(configure_zone_acl(zconfig, vconfig, config, allow_query, ac, + zone, dns_zone_setqueryacl, + dns_zone_clearqueryacl)); + + CHECK(configure_zone_acl(zconfig, vconfig, config, allow_query_on, ac, + zone, dns_zone_setqueryonacl, + dns_zone_clearqueryonacl)); + + obj = NULL; + result = named_config_get(maps, "dialup", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) { + dialup = dns_dialuptype_yes; + } else { + dialup = dns_dialuptype_no; + } + } else { + const char *dialupstr = cfg_obj_asstring(obj); + if (strcasecmp(dialupstr, "notify") == 0) { + dialup = dns_dialuptype_notify; + } else if (strcasecmp(dialupstr, "notify-passive") == 0) { + dialup = dns_dialuptype_notifypassive; + } else if (strcasecmp(dialupstr, "refresh") == 0) { + dialup = dns_dialuptype_refresh; + } else if (strcasecmp(dialupstr, "passive") == 0) { + dialup = dns_dialuptype_passive; + } else { + UNREACHABLE(); + } + } + if (raw != NULL) { + dns_zone_setdialup(raw, dialup); + } + dns_zone_setdialup(zone, dialup); + + obj = NULL; + result = named_config_get(maps, "zone-statistics", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) { + statlevel = dns_zonestat_full; + } else { + statlevel = dns_zonestat_none; + } + } else { + const char *levelstr = cfg_obj_asstring(obj); + if (strcasecmp(levelstr, "full") == 0) { + statlevel = dns_zonestat_full; + } else if (strcasecmp(levelstr, "terse") == 0) { + statlevel = dns_zonestat_terse; + } else if (strcasecmp(levelstr, "none") == 0) { + statlevel = dns_zonestat_none; + } else { + UNREACHABLE(); + } + } + dns_zone_setstatlevel(zone, statlevel); + + zoneqrystats = NULL; + rcvquerystats = NULL; + dnssecsignstats = NULL; + if (statlevel == dns_zonestat_full) { + CHECK(isc_stats_create(mctx, &zoneqrystats, + ns_statscounter_max)); + CHECK(dns_rdatatypestats_create(mctx, &rcvquerystats)); + CHECK(dns_dnssecsignstats_create(mctx, &dnssecsignstats)); + } + dns_zone_setrequeststats(zone, zoneqrystats); + dns_zone_setrcvquerystats(zone, rcvquerystats); + dns_zone_setdnssecsignstats(zone, dnssecsignstats); + + if (zoneqrystats != NULL) { + isc_stats_detach(&zoneqrystats); + } + + if (rcvquerystats != NULL) { + dns_stats_detach(&rcvquerystats); + } + + if (dnssecsignstats != NULL) { + dns_stats_detach(&dnssecsignstats); + } + + /* + * Configure master functionality. This applies + * to primary servers (type "primary") and secondaries + * acting as primaries (type "secondary"), but not to stubs. + */ + if (ztype != dns_zone_stub && ztype != dns_zone_staticstub && + ztype != dns_zone_redirect) + { + obj = NULL; + result = named_config_get(maps, "dnssec-policy", &obj); + if (result == ISC_R_SUCCESS) { + kaspname = cfg_obj_asstring(obj); + if (strcmp(kaspname, "none") != 0) { + result = dns_kasplist_find(kasplist, kaspname, + &kasp); + if (result != ISC_R_SUCCESS) { + cfg_obj_log( + obj, named_g_lctx, + ISC_LOG_ERROR, + "dnssec-policy '%s' not found ", + kaspname); + CHECK(result); + } + dns_zone_setkasp(zone, kasp); + use_kasp = true; + } + } + if (!use_kasp) { + dns_zone_setkasp(zone, NULL); + } + + obj = NULL; + result = named_config_get(maps, "notify", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) { + notifytype = dns_notifytype_yes; + } else { + notifytype = dns_notifytype_no; + } + } else { + const char *str = cfg_obj_asstring(obj); + if (strcasecmp(str, "explicit") == 0) { + notifytype = dns_notifytype_explicit; + } else if (strcasecmp(str, "master-only") == 0 || + strcasecmp(str, "primary-only") == 0) + { + notifytype = dns_notifytype_masteronly; + } else { + UNREACHABLE(); + } + } + notifytype = process_notifytype(notifytype, ztype, zname, + nodefault); + if (raw != NULL) { + dns_zone_setnotifytype(raw, dns_notifytype_no); + } + dns_zone_setnotifytype(zone, notifytype); + + obj = NULL; + result = named_config_get(maps, "also-notify", &obj); + if (result == ISC_R_SUCCESS && + (notifytype == dns_notifytype_yes || + notifytype == dns_notifytype_explicit || + (notifytype == dns_notifytype_masteronly && + ztype == dns_zone_primary))) + { + dns_ipkeylist_t ipkl; + dns_ipkeylist_init(&ipkl); + + CHECK(named_config_getipandkeylist(config, "primaries", + obj, mctx, &ipkl)); + result = dns_zone_setalsonotifydscpkeys( + zone, ipkl.addrs, ipkl.dscps, ipkl.keys, + ipkl.count); + dns_ipkeylist_clear(mctx, &ipkl); + CHECK(result); + } else { + CHECK(dns_zone_setalsonotify(zone, NULL, 0)); + } + + obj = NULL; + result = named_config_get(maps, "parental-source", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + CHECK(dns_zone_setparentalsrc4(zone, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) { + dscp = named_g_dscp; + } + CHECK(dns_zone_setparentalsrc4dscp(zone, dscp)); + named_add_reserved_dispatch(named_g_server, + cfg_obj_assockaddr(obj)); + + obj = NULL; + result = named_config_get(maps, "parental-source-v6", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + CHECK(dns_zone_setparentalsrc6(zone, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) { + dscp = named_g_dscp; + } + CHECK(dns_zone_setparentalsrc6dscp(zone, dscp)); + named_add_reserved_dispatch(named_g_server, + cfg_obj_assockaddr(obj)); + + obj = NULL; + result = named_config_get(maps, "notify-source", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + CHECK(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) { + dscp = named_g_dscp; + } + CHECK(dns_zone_setnotifysrc4dscp(zone, dscp)); + named_add_reserved_dispatch(named_g_server, + cfg_obj_assockaddr(obj)); + + obj = NULL; + result = named_config_get(maps, "notify-source-v6", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + CHECK(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) { + dscp = named_g_dscp; + } + CHECK(dns_zone_setnotifysrc6dscp(zone, dscp)); + named_add_reserved_dispatch(named_g_server, + cfg_obj_assockaddr(obj)); + + obj = NULL; + result = named_config_get(maps, "notify-to-soa", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA, + cfg_obj_asboolean(obj)); + + dns_zone_setisself(zone, isself, named_g_server->interfacemgr); + + CHECK(configure_zone_acl( + zconfig, vconfig, config, allow_transfer, ac, zone, + dns_zone_setxfracl, dns_zone_clearxfracl)); + + obj = NULL; + result = named_config_get(maps, "max-transfer-time-out", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = named_config_get(maps, "max-transfer-idle-out", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = named_config_get(maps, "max-journal-size", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (raw != NULL) { + dns_zone_setjournalsize(raw, -1); + } + dns_zone_setjournalsize(zone, -1); + if (cfg_obj_isstring(obj)) { + const char *str = cfg_obj_asstring(obj); + if (strcasecmp(str, "unlimited") == 0) { + journal_size = DNS_JOURNAL_SIZE_MAX; + } else { + INSIST(strcasecmp(str, "default") == 0); + journal_size = -1; + } + } else { + isc_resourcevalue_t value; + value = cfg_obj_asuint64(obj); + if (value > DNS_JOURNAL_SIZE_MAX) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "'max-journal-size " + "%" PRId64 "' " + "is too large", + value); + CHECK(ISC_R_RANGE); + } + journal_size = (uint32_t)value; + } + if (raw != NULL) { + dns_zone_setjournalsize(raw, journal_size); + } + dns_zone_setjournalsize(zone, journal_size); + + obj = NULL; + result = named_config_get(maps, "ixfr-from-differences", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (cfg_obj_isboolean(obj)) { + ixfrdiff = cfg_obj_asboolean(obj); + } else if ((strcasecmp(cfg_obj_asstring(obj), "primary") == 0 || + strcasecmp(cfg_obj_asstring(obj), "master") == 0) && + ztype == dns_zone_primary) + { + ixfrdiff = true; + } else if ((strcasecmp(cfg_obj_asstring(obj), "secondary") == + 0 || + strcasecmp(cfg_obj_asstring(obj), "slave") == 0) && + ztype == dns_zone_secondary) + { + ixfrdiff = true; + } else { + ixfrdiff = false; + } + if (raw != NULL) { + dns_zone_setoption(raw, DNS_ZONEOPT_IXFRFROMDIFFS, + true); + dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, + false); + } else { + dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, + ixfrdiff); + } + + obj = NULL; + result = named_config_get(maps, "max-ixfr-ratio", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (cfg_obj_isstring(obj)) { + dns_zone_setixfrratio(zone, 0); + } else { + dns_zone_setixfrratio(zone, cfg_obj_aspercentage(obj)); + } + + obj = NULL; + result = named_config_get(maps, "request-expire", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setrequestexpire(zone, cfg_obj_asboolean(obj)); + + obj = NULL; + result = named_config_get(maps, "request-ixfr", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setrequestixfr(zone, cfg_obj_asboolean(obj)); + + obj = NULL; + checknames(ztype, maps, &obj); + INSIST(obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + fail = false; + check = true; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + fail = check = true; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + fail = check = false; + } else { + UNREACHABLE(); + } + if (raw != NULL) { + dns_zone_setoption(raw, DNS_ZONEOPT_CHECKNAMES, check); + dns_zone_setoption(raw, DNS_ZONEOPT_CHECKNAMESFAIL, + fail); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, false); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, + false); + } else { + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, + fail); + } + + obj = NULL; + result = named_config_get(maps, "notify-delay", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "check-sibling", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING, + cfg_obj_asboolean(obj)); + + obj = NULL; + result = named_config_get(maps, "check-spf", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + check = true; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + check = false; + } else { + UNREACHABLE(); + } + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSPF, check); + + obj = NULL; + result = named_config_get(maps, "zero-no-soa-ttl", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj)); + + obj = NULL; + result = named_config_get(maps, "nsec3-test-zone", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE, + cfg_obj_asboolean(obj)); + } else if (ztype == dns_zone_redirect) { + dns_zone_setnotifytype(zone, dns_notifytype_no); + + obj = NULL; + result = named_config_get(maps, "max-journal-size", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setjournalsize(zone, -1); + if (cfg_obj_isstring(obj)) { + const char *str = cfg_obj_asstring(obj); + if (strcasecmp(str, "unlimited") == 0) { + journal_size = DNS_JOURNAL_SIZE_MAX; + } else { + INSIST(strcasecmp(str, "default") == 0); + journal_size = -1; + } + } else { + isc_resourcevalue_t value; + value = cfg_obj_asuint64(obj); + if (value > DNS_JOURNAL_SIZE_MAX) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "'max-journal-size " + "%" PRId64 "' " + "is too large", + value); + CHECK(ISC_R_RANGE); + } + journal_size = (uint32_t)value; + } + dns_zone_setjournalsize(zone, journal_size); + } + + if (use_kasp) { + maxttl = dns_kasp_zonemaxttl(dns_zone_getkasp(zone)); + } else { + obj = NULL; + result = named_config_get(maps, "max-zone-ttl", &obj); + if (result == ISC_R_SUCCESS) { + if (cfg_obj_isduration(obj)) { + maxttl = cfg_obj_asduration(obj); + } + } + } + dns_zone_setmaxttl(zone, maxttl); + if (raw != NULL) { + dns_zone_setmaxttl(raw, maxttl); + } + + /* + * Configure update-related options. These apply to + * primary servers only. + */ + if (ztype == dns_zone_primary) { + dns_acl_t *updateacl; + + CHECK(configure_zone_acl(zconfig, vconfig, config, allow_update, + ac, mayberaw, dns_zone_setupdateacl, + dns_zone_clearupdateacl)); + + updateacl = dns_zone_getupdateacl(mayberaw); + if (updateacl != NULL && dns_acl_isinsecure(updateacl)) { + isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "zone '%s' allows unsigned updates " + "from remote hosts, which is insecure", + zname); + } + + CHECK(configure_zone_ssutable(zoptions, mayberaw, zname)); + } + + /* + * Configure DNSSEC signing. These apply to primary zones or zones that + * use inline-signing (raw != NULL). + */ + if (ztype == dns_zone_primary || raw != NULL) { + const cfg_obj_t *validity, *resign; + bool allow = false, maint = false; + bool sigvalinsecs; + + if (use_kasp) { + if (dns_kasp_nsec3(kasp)) { + result = dns_zone_setnsec3param( + zone, 1, dns_kasp_nsec3flags(kasp), + dns_kasp_nsec3iter(kasp), + dns_kasp_nsec3saltlen(kasp), NULL, true, + false); + } else { + result = dns_zone_setnsec3param( + zone, 0, 0, 0, 0, NULL, true, false); + } + INSIST(result == ISC_R_SUCCESS); + } + + if (use_kasp) { + seconds = (uint32_t)dns_kasp_sigvalidity_dnskey(kasp); + } else { + obj = NULL; + result = named_config_get(maps, "dnskey-sig-validity", + &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + seconds = cfg_obj_asuint32(obj) * 86400; + } + dns_zone_setkeyvalidityinterval(zone, seconds); + + if (use_kasp) { + seconds = (uint32_t)dns_kasp_sigvalidity(kasp); + dns_zone_setsigvalidityinterval(zone, seconds); + seconds = (uint32_t)dns_kasp_sigrefresh(kasp); + dns_zone_setsigresigninginterval(zone, seconds); + } else { + obj = NULL; + result = named_config_get(maps, "sig-validity-interval", + &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + + sigvalinsecs = ns_server_getoption( + named_g_server->sctx, NS_SERVER_SIGVALINSECS); + validity = cfg_tuple_get(obj, "validity"); + seconds = cfg_obj_asuint32(validity); + if (!sigvalinsecs) { + seconds *= 86400; + } + dns_zone_setsigvalidityinterval(zone, seconds); + + resign = cfg_tuple_get(obj, "re-sign"); + if (cfg_obj_isvoid(resign)) { + seconds /= 4; + } else if (!sigvalinsecs) { + uint32_t r = cfg_obj_asuint32(resign); + if (seconds > 7 * 86400) { + seconds = r * 86400; + } else { + seconds = r * 3600; + } + } else { + seconds = cfg_obj_asuint32(resign); + } + dns_zone_setsigresigninginterval(zone, seconds); + } + + obj = NULL; + result = named_config_get(maps, "key-directory", &obj); + if (result == ISC_R_SUCCESS) { + filename = cfg_obj_asstring(obj); + CHECK(dns_zone_setkeydirectory(zone, filename)); + } + + obj = NULL; + result = named_config_get(maps, "sig-signing-signatures", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setsignatures(zone, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "sig-signing-nodes", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setnodes(zone, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "sig-signing-type", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "update-check-ksk", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK, + cfg_obj_asboolean(obj)); + /* + * This setting will be ignored if dnssec-policy is used. + * named-checkconf will error if both are configured. + */ + + obj = NULL; + result = named_config_get(maps, "dnssec-dnskey-kskonly", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY, + cfg_obj_asboolean(obj)); + /* + * This setting will be ignored if dnssec-policy is used. + * named-checkconf will error if both are configured. + */ + + obj = NULL; + result = named_config_get(maps, "dnssec-loadkeys-interval", + &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + CHECK(dns_zone_setrefreshkeyinterval(zone, + cfg_obj_asuint32(obj))); + + obj = NULL; + result = cfg_map_get(zoptions, "auto-dnssec", &obj); + if (kasp != NULL) { + bool s2i = (strcmp(dns_kasp_getname(kasp), + "insecure") != 0); + dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, true); + dns_zone_setkeyopt(zone, DNS_ZONEKEY_CREATE, !s2i); + dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, true); + } else if (result == ISC_R_SUCCESS) { + const char *arg = cfg_obj_asstring(obj); + if (strcasecmp(arg, "allow") == 0) { + allow = true; + } else if (strcasecmp(arg, "maintain") == 0) { + allow = maint = true; + } else if (strcasecmp(arg, "off") == 0) { + /* Default */ + } else { + UNREACHABLE(); + } + dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow); + dns_zone_setkeyopt(zone, DNS_ZONEKEY_CREATE, false); + dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint); + } + } + + if (ztype == dns_zone_secondary || ztype == dns_zone_mirror) { + CHECK(configure_zone_acl(zconfig, vconfig, config, + allow_update_forwarding, ac, mayberaw, + dns_zone_setforwardacl, + dns_zone_clearforwardacl)); + } + + /*% + * Configure parental agents, applies to primary and secondary zones. + */ + if (ztype == dns_zone_primary || ztype == dns_zone_secondary) { + obj = NULL; + (void)cfg_map_get(zoptions, "parental-agents", &obj); + if (obj != NULL) { + dns_ipkeylist_t ipkl; + dns_ipkeylist_init(&ipkl); + CHECK(named_config_getipandkeylist( + config, "parental-agents", obj, mctx, &ipkl)); + result = dns_zone_setparentals(zone, ipkl.addrs, + ipkl.keys, ipkl.count); + dns_ipkeylist_clear(mctx, &ipkl); + CHECK(result); + } else { + CHECK(dns_zone_setparentals(zone, NULL, NULL, 0)); + } + } + + /*% + * Primary master functionality. + */ + if (ztype == dns_zone_primary) { + obj = NULL; + result = named_config_get(maps, "check-wildcard", &obj); + if (result == ISC_R_SUCCESS) { + check = cfg_obj_asboolean(obj); + } else { + check = false; + } + dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKWILDCARD, check); + + /* + * With map files, the default is ignore duplicate + * records. With other master formats, the default is + * taken from the global configuration. + */ + obj = NULL; + if (masterformat != dns_masterformat_map) { + result = named_config_get(maps, "check-dup-records", + &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dupcheck = cfg_obj_asstring(obj); + } else { + result = named_config_get(nodefault, + "check-dup-records", &obj); + if (result == ISC_R_SUCCESS) { + dupcheck = cfg_obj_asstring(obj); + } else { + dupcheck = "ignore"; + } + } + if (strcasecmp(dupcheck, "warn") == 0) { + fail = false; + check = true; + } else if (strcasecmp(dupcheck, "fail") == 0) { + fail = check = true; + } else if (strcasecmp(dupcheck, "ignore") == 0) { + fail = check = false; + } else { + UNREACHABLE(); + } + dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKDUPRR, check); + dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKDUPRRFAIL, fail); + + obj = NULL; + result = named_config_get(maps, "check-mx", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + fail = false; + check = true; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + fail = check = true; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + fail = check = false; + } else { + UNREACHABLE(); + } + dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKMX, check); + dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKMXFAIL, fail); + + /* + * With map files, the default is *not* to check + * integrity. With other master formats, the default is + * taken from the global configuration. + */ + obj = NULL; + if (masterformat != dns_masterformat_map) { + result = named_config_get(maps, "check-integrity", + &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKINTEGRITY, + cfg_obj_asboolean(obj)); + } else { + check = false; + result = named_config_get(nodefault, "check-integrity", + &obj); + if (result == ISC_R_SUCCESS) { + check = cfg_obj_asboolean(obj); + } + dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKINTEGRITY, + check); + } + + obj = NULL; + result = named_config_get(maps, "check-mx-cname", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + warn = true; + ignore = false; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + warn = ignore = false; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + warn = ignore = true; + } else { + UNREACHABLE(); + } + dns_zone_setoption(mayberaw, DNS_ZONEOPT_WARNMXCNAME, warn); + dns_zone_setoption(mayberaw, DNS_ZONEOPT_IGNOREMXCNAME, ignore); + + obj = NULL; + result = named_config_get(maps, "check-srv-cname", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + warn = true; + ignore = false; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + warn = ignore = false; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + warn = ignore = true; + } else { + UNREACHABLE(); + } + dns_zone_setoption(mayberaw, DNS_ZONEOPT_WARNSRVCNAME, warn); + dns_zone_setoption(mayberaw, DNS_ZONEOPT_IGNORESRVCNAME, + ignore); + + obj = NULL; + result = named_config_get(maps, "dnssec-secure-to-insecure", + &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setoption(mayberaw, DNS_ZONEOPT_SECURETOINSECURE, + cfg_obj_asboolean(obj)); + + obj = NULL; + result = cfg_map_get(zoptions, "dnssec-update-mode", &obj); + if (result == ISC_R_SUCCESS) { + const char *arg = cfg_obj_asstring(obj); + if (strcasecmp(arg, "no-resign") == 0) { + dns_zone_setkeyopt(zone, DNS_ZONEKEY_NORESIGN, + true); + } else if (strcasecmp(arg, "maintain") == 0) { + /* Default */ + } else { + UNREACHABLE(); + } + } + + obj = NULL; + result = named_config_get(maps, "serial-update-method", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "unixtime") == 0) { + dns_zone_setserialupdatemethod( + zone, dns_updatemethod_unixtime); + } else if (strcasecmp(cfg_obj_asstring(obj), "date") == 0) { + dns_zone_setserialupdatemethod(zone, + dns_updatemethod_date); + } else { + dns_zone_setserialupdatemethod( + zone, dns_updatemethod_increment); + } + } + + /* + * Configure slave functionality. + */ + switch (ztype) { + case dns_zone_mirror: + /* + * Disable outgoing zone transfers for mirror zones unless they + * are explicitly enabled by zone configuration. + */ + obj = NULL; + (void)cfg_map_get(zoptions, "allow-transfer", &obj); + if (obj == NULL) { + dns_acl_t *none; + CHECK(dns_acl_none(mctx, &none)); + dns_zone_setxfracl(zone, none); + dns_acl_detach(&none); + } + FALLTHROUGH; + case dns_zone_secondary: + case dns_zone_stub: + case dns_zone_redirect: + count = 0; + obj = NULL; + (void)cfg_map_get(zoptions, "primaries", &obj); + if (obj == NULL) { + (void)cfg_map_get(zoptions, "masters", &obj); + } + + /* + * Use the built-in primary server list if one was not + * explicitly specified and this is a root zone mirror. + */ + if (obj == NULL && ztype == dns_zone_mirror && + dns_name_equal(dns_zone_getorigin(zone), dns_rootname)) + { + result = named_config_getremotesdef( + named_g_config, "primaries", + DEFAULT_IANA_ROOT_ZONE_PRIMARIES, &obj); + CHECK(result); + } + if (obj != NULL) { + dns_ipkeylist_t ipkl; + dns_ipkeylist_init(&ipkl); + + CHECK(named_config_getipandkeylist(config, "primaries", + obj, mctx, &ipkl)); + result = dns_zone_setprimarieswithkeys( + mayberaw, ipkl.addrs, ipkl.keys, ipkl.count); + count = ipkl.count; + dns_ipkeylist_clear(mctx, &ipkl); + CHECK(result); + } else { + result = dns_zone_setprimaries(mayberaw, NULL, 0); + } + CHECK(result); + + multi = false; + if (count > 1) { + obj = NULL; + result = named_config_get(maps, "multi-master", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + multi = cfg_obj_asboolean(obj); + } + dns_zone_setoption(mayberaw, DNS_ZONEOPT_MULTIMASTER, multi); + + obj = NULL; + result = named_config_get(maps, "max-transfer-time-in", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setmaxxfrin(mayberaw, cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = named_config_get(maps, "max-transfer-idle-in", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setidlein(mayberaw, cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = named_config_get(maps, "max-refresh-time", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setmaxrefreshtime(mayberaw, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "min-refresh-time", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setminrefreshtime(mayberaw, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "max-retry-time", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setmaxretrytime(mayberaw, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "min-retry-time", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + dns_zone_setminretrytime(mayberaw, cfg_obj_asuint32(obj)); + + obj = NULL; + result = named_config_get(maps, "transfer-source", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + CHECK(dns_zone_setxfrsource4(mayberaw, + cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) { + dscp = named_g_dscp; + } + CHECK(dns_zone_setxfrsource4dscp(mayberaw, dscp)); + named_add_reserved_dispatch(named_g_server, + cfg_obj_assockaddr(obj)); + + obj = NULL; + result = named_config_get(maps, "transfer-source-v6", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + CHECK(dns_zone_setxfrsource6(mayberaw, + cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) { + dscp = named_g_dscp; + } + CHECK(dns_zone_setxfrsource6dscp(mayberaw, dscp)); + named_add_reserved_dispatch(named_g_server, + cfg_obj_assockaddr(obj)); + + obj = NULL; + result = named_config_get(maps, "alt-transfer-source", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + CHECK(dns_zone_setaltxfrsource4(mayberaw, + cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) { + dscp = named_g_dscp; + } + CHECK(dns_zone_setaltxfrsource4dscp(mayberaw, dscp)); + + obj = NULL; + result = named_config_get(maps, "alt-transfer-source-v6", &obj); + INSIST(result == ISC_R_SUCCESS && obj != NULL); + CHECK(dns_zone_setaltxfrsource6(mayberaw, + cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) { + dscp = named_g_dscp; + } + CHECK(dns_zone_setaltxfrsource6dscp(mayberaw, dscp)); + + obj = NULL; + (void)named_config_get(maps, "use-alt-transfer-source", &obj); + if (obj == NULL) { + /* + * Default off when views are in use otherwise + * on for BIND 8 compatibility. + */ + view = dns_zone_getview(zone); + if (view != NULL && strcmp(view->name, "_default") == 0) + { + alt = true; + } else { + alt = false; + } + } else { + alt = cfg_obj_asboolean(obj); + } + dns_zone_setoption(mayberaw, DNS_ZONEOPT_USEALTXFRSRC, alt); + + obj = NULL; + (void)named_config_get(maps, "try-tcp-refresh", &obj); + dns_zone_setoption(mayberaw, DNS_ZONEOPT_TRYTCPREFRESH, + cfg_obj_asboolean(obj)); + break; + + case dns_zone_staticstub: + CHECK(configure_staticstub(zoptions, zone, zname, + default_dbtype)); + break; + + default: + break; + } + + result = ISC_R_SUCCESS; + +cleanup: + if (kasp != NULL) { + dns_kasp_detach(&kasp); + } + return (result); +} + +/* + * Set up a DLZ zone as writeable + */ +isc_result_t +named_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone, + dns_rdataclass_t rdclass, dns_name_t *name) { + dns_db_t *db = NULL; + isc_time_t now; + isc_result_t result; + + TIME_NOW(&now); + + dns_zone_settype(zone, dns_zone_dlz); + result = dns_sdlz_setdb(dlzdatabase, rdclass, name, &db); + if (result != ISC_R_SUCCESS) { + return (result); + } + result = dns_zone_dlzpostload(zone, db); + dns_db_detach(&db); + return (result); +} + +bool +named_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) { + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *obj = NULL; + const char *cfilename; + const char *zfilename; + dns_zone_t *raw = NULL; + bool has_raw, inline_signing; + dns_zonetype_t ztype; + + zoptions = cfg_tuple_get(zconfig, "options"); + + /* + * We always reconfigure a static-stub zone for simplicity, assuming + * the amount of data to be loaded is small. + */ + if (zonetype_fromconfig(zoptions) == dns_zone_staticstub) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "not reusable: staticstub"); + return (false); + } + + /* If there's a raw zone, use that for filename and type comparison */ + dns_zone_getraw(zone, &raw); + if (raw != NULL) { + zfilename = dns_zone_getfile(raw); + ztype = dns_zone_gettype(raw); + dns_zone_detach(&raw); + has_raw = true; + } else { + zfilename = dns_zone_getfile(zone); + ztype = dns_zone_gettype(zone); + has_raw = false; + } + + inline_signing = named_zone_inlinesigning(zconfig); + if (!inline_signing && has_raw) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "not reusable: old zone was inline-signing"); + return (false); + } else if (inline_signing && !has_raw) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "not reusable: old zone was not inline-signing"); + return (false); + } + + if (zonetype_fromconfig(zoptions) != ztype) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "not reusable: type mismatch"); + return (false); + } + + obj = NULL; + (void)cfg_map_get(zoptions, "file", &obj); + if (obj != NULL) { + cfilename = cfg_obj_asstring(obj); + } else { + cfilename = NULL; + } + if (!((cfilename == NULL && zfilename == NULL) || + (cfilename != NULL && zfilename != NULL && + strcmp(cfilename, zfilename) == 0))) + { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "not reusable: filename mismatch"); + return (false); + } + + return (true); +} + +bool +named_zone_inlinesigning(const cfg_obj_t *zconfig) { + const cfg_obj_t *zoptions = NULL; + const cfg_obj_t *signing = NULL; + bool inline_signing = false; + + zoptions = cfg_tuple_get(zconfig, "options"); + inline_signing = (cfg_map_get(zoptions, "inline-signing", &signing) == + ISC_R_SUCCESS && + cfg_obj_asboolean(signing)); + + return (inline_signing); +} diff --git a/bin/nsupdate/Makefile.in b/bin/nsupdate/Makefile.in new file mode 100644 index 0000000..37d5cb3 --- /dev/null +++ b/bin/nsupdate/Makefile.in @@ -0,0 +1,86 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +READLINE_LIB = @READLINE_LIB@ + +DST_GSSAPI_INC = @DST_GSSAPI_INC@ + +CINCLUDES = ${DNS_INCLUDES} ${BIND9_INCLUDES} ${ISC_INCLUDES} \ + ${ISCCFG_INCLUDES} ${IRS_INCLUDES} ${DST_GSSAPI_INC} \ + ${OPENSSL_CFLAGS} + +CDEFINES = -DVERSION=\"${VERSION}\" @USE_GSSAPI@ +CWARNINGS = + +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +BIND9LIBS = ../../lib/bind9/libbind9.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +IRSLIBS = ../../lib/irs/libirs.@A@ + +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ +IRSDEPLIBS = ../../lib/irs/libirs.@A@ + +DEPLIBS = ${DNSDEPLIBS} ${IRSDEPLIBS} ${BIND9DEPLIBS} \ + ${ISCDEPLIBS} ${ISCCFGDEPLIBS} + +LIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCLIBS} ${GSSAPI_LIBS} \ + @LIBS@ + +NOSYMLIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCNOSYMLIBS} @LIBS@ + +SUBDIRS = + +TARGETS = nsupdate@EXEEXT@ + +OBJS = nsupdate.@O@ + +UOBJS = + +SRCS = nsupdate.c + +@BIND9_MAKE_RULES@ + +nsupdate.@O@: nsupdate.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DSESSION_KEYFILE=\"${localstatedir}/run/named/session.key\" \ + -c ${srcdir}/nsupdate.c + +nsupdate@EXEEXT@: nsupdate.@O@ ${UOBJS} ${DEPLIBS} + export BASEOBJS="nsupdate.@O@ ${READLINE_LIB} ${UOBJS}"; \ + export LIBS0="${DNSLIBS} ${IRSLIBS}"; \ + ${FINALBUILDCMD} + +clean distclean:: + rm -f ${TARGETS} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${bindir} + +install:: nsupdate@EXEEXT@ installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} nsupdate@EXEEXT@ ${DESTDIR}${bindir} + +uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${bindir}/nsupdate@EXEEXT@ diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c new file mode 100644 index 0000000..6c93a03 --- /dev/null +++ b/bin/nsupdate/nsupdate.c @@ -0,0 +1,3491 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#ifdef GSSAPI +#include +#ifdef WIN32 +#include +#include +#include +#else /* ifdef WIN32 */ +#include ISC_PLATFORM_GSSAPIHEADER +#ifdef ISC_PLATFORM_GSSAPI_KRB5_HEADER +#include ISC_PLATFORM_GSSAPI_KRB5_HEADER +#endif /* ifdef ISC_PLATFORM_GSSAPI_KRB5_HEADER */ +#include ISC_PLATFORM_KRB5HEADER +#endif /* ifdef WIN32 */ +#endif /* ifdef GSSAPI */ +#include + +#if defined(HAVE_READLINE) +#if defined(HAVE_EDIT_READLINE_READLINE_H) +#include +#if defined(HAVE_EDIT_READLINE_HISTORY_H) +#include +#endif /* if defined(HAVE_EDIT_READLINE_HISTORY_H) */ +#elif defined(HAVE_EDITLINE_READLINE_H) +#include +#else /* if defined(HAVE_EDIT_READLINE_READLINE_H) */ +/* Prevent deprecated functions being declared. */ +#define _FUNCTION_DEF 1 +/* Ensure rl_message() gets prototype. */ +#define USE_VARARGS 1 +#define PREFER_STDARG 1 +#include +#include +#endif /* if defined(HAVE_EDIT_READLINE_READLINE_H) */ +#endif /* if defined(HAVE_READLINE) */ + +#define MAXCMD (128 * 1024) +#define MAXWIRE (64 * 1024) +#define PACKETSIZE ((64 * 1024) - 1) +#define INITTEXT (2 * 1024) +#define MAXTEXT (128 * 1024) +#define FIND_TIMEOUT 5 +#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */ + +#define DNSDEFAULTPORT 53 + +/* Number of addresses to request from bind9_getaddresses() */ +#define MAX_SERVERADDRS 4 + +static uint16_t dnsport = DNSDEFAULTPORT; + +#ifndef RESOLV_CONF +#define RESOLV_CONF "/etc/resolv.conf" +#endif /* ifndef RESOLV_CONF */ + +static bool debugging = false, ddebugging = false; +static bool memdebugging = false; +static bool have_ipv4 = false; +static bool have_ipv6 = false; +static bool is_dst_up = false; +static bool usevc = false; +static bool usegsstsig = false; +static bool use_win2k_gsstsig = false; +static bool tried_other_gsstsig = false; +static bool local_only = false; +static isc_nm_t *netmgr = NULL; +static isc_taskmgr_t *taskmgr = NULL; +static isc_task_t *global_task = NULL; +static isc_event_t *global_event = NULL; +static isc_log_t *glctx = NULL; +static isc_mem_t *gmctx = NULL; +static dns_dispatchmgr_t *dispatchmgr = NULL; +static dns_requestmgr_t *requestmgr = NULL; +static isc_socketmgr_t *socketmgr = NULL; +static isc_timermgr_t *timermgr = NULL; +static dns_dispatch_t *dispatchv4 = NULL; +static dns_dispatch_t *dispatchv6 = NULL; +static dns_message_t *updatemsg = NULL; +static dns_fixedname_t fuserzone; +static dns_fixedname_t fzname; +static dns_name_t *userzone = NULL; +static dns_name_t *zname = NULL; +static dns_name_t tmpzonename = DNS_NAME_INITEMPTY; +static dns_name_t restart_master = DNS_NAME_INITEMPTY; +static dns_tsig_keyring_t *gssring = NULL; +static dns_tsigkey_t *tsigkey = NULL; +static dst_key_t *sig0key = NULL; +static isc_sockaddr_t *servers = NULL; +static isc_sockaddr_t *master_servers = NULL; +static bool default_servers = true; +static int ns_inuse = 0; +static int master_inuse = 0; +static int ns_total = 0; +static int ns_alloc = 0; +static int master_total = 0; +static int master_alloc = 0; +static isc_sockaddr_t *localaddr4 = NULL; +static isc_sockaddr_t *localaddr6 = NULL; +static const char *keyfile = NULL; +static char *keystr = NULL; +static bool shuttingdown = false; +static FILE *input; +static bool interactive = true; +static bool seenerror = false; +static const dns_master_style_t *style; +static int requests = 0; +static unsigned int logdebuglevel = 0; +static unsigned int timeout = 300; +static unsigned int udp_timeout = 3; +static unsigned int udp_retries = 3; +static dns_rdataclass_t defaultclass = dns_rdataclass_in; +static dns_rdataclass_t zoneclass = dns_rdataclass_none; +static isc_mutex_t answer_lock; +static dns_message_t *answer = NULL; +static uint32_t default_ttl = 0; +static bool default_ttl_set = false; +static bool checknames = true; + +typedef struct nsu_requestinfo { + dns_message_t *msg; + isc_sockaddr_t *addr; +} nsu_requestinfo_t; + +static void +sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg, + dns_request_t **request); +static void +send_update(dns_name_t *zonename, isc_sockaddr_t *master); + +ISC_PLATFORM_NORETURN_PRE static void +fatal(const char *format, ...) + ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; + +static void +debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +static void +ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +#ifdef GSSAPI +static dns_fixedname_t fkname; +static isc_sockaddr_t *kserver = NULL; +static char *realm = NULL; +static char servicename[DNS_NAME_FORMATSIZE]; +static dns_name_t *keyname; +typedef struct nsu_gssinfo { + dns_message_t *msg; + isc_sockaddr_t *addr; + dns_gss_ctx_id_t context; +} nsu_gssinfo_t; + +static void +failed_gssrequest(); +static void +start_gssrequest(dns_name_t *master); +static void +send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg, + dns_request_t **request, dns_gss_ctx_id_t context); +static void +recvgss(isc_task_t *task, isc_event_t *event); +#endif /* GSSAPI */ + +static void +error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +#define STATUS_MORE (uint16_t)0 +#define STATUS_SEND (uint16_t)1 +#define STATUS_QUIT (uint16_t)2 +#define STATUS_SYNTAX (uint16_t)3 + +static void +master_from_servers(void) { + if (master_servers != NULL && master_servers != servers) { + isc_mem_put(gmctx, master_servers, + master_alloc * sizeof(isc_sockaddr_t)); + } + master_servers = servers; + master_total = ns_total; + master_alloc = ns_alloc; + master_inuse = ns_inuse; +} + +static dns_rdataclass_t +getzoneclass(void) { + if (zoneclass == dns_rdataclass_none) { + zoneclass = defaultclass; + } + return (zoneclass); +} + +static bool +setzoneclass(dns_rdataclass_t rdclass) { + if (zoneclass == dns_rdataclass_none || rdclass == dns_rdataclass_none) + { + zoneclass = rdclass; + } + if (zoneclass != rdclass) { + return (false); + } + return (true); +} + +static void +fatal(const char *format, ...) { + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + exit(1); +} + +static void +error(const char *format, ...) { + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); +} + +static void +debug(const char *format, ...) { + va_list args; + + if (debugging) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + } +} + +static void +ddebug(const char *format, ...) { + va_list args; + + if (ddebugging) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + } +} + +static void +check_result(isc_result_t result, const char *msg) { + if (result != ISC_R_SUCCESS) { + fatal("%s: %s", msg, isc_result_totext(result)); + } +} + +static char * +nsu_strsep(char **stringp, const char *delim) { + char *string = *stringp; + *stringp = NULL; + char *s; + const char *d; + char sc, dc; + + if (string == NULL) { + return (NULL); + } + + for (; *string != '\0'; string++) { + sc = *string; + for (d = delim; (dc = *d) != '\0'; d++) { + if (sc == dc) { + break; + } + } + if (dc == 0) { + break; + } + } + + for (s = string; *s != '\0'; s++) { + sc = *s; + for (d = delim; (dc = *d) != '\0'; d++) { + if (sc == dc) { + *s++ = '\0'; + *stringp = s; + return (string); + } + } + } + return (string); +} + +static void +reset_system(void) { + ddebug("reset_system()"); + /* If the update message is still around, destroy it */ + if (updatemsg != NULL) { + dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER); + } else { + dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER, &updatemsg); + } + updatemsg->opcode = dns_opcode_update; + if (usegsstsig) { + if (tsigkey != NULL) { + dns_tsigkey_detach(&tsigkey); + } + if (gssring != NULL) { + dns_tsigkeyring_detach(&gssring); + } + tried_other_gsstsig = false; + } +} + +static bool +parse_hmac(const dns_name_t **hmac, const char *hmacstr, size_t len, + uint16_t *digestbitsp) { + uint16_t digestbits = 0; + isc_result_t result; + char buf[20]; + + REQUIRE(hmac != NULL && *hmac == NULL); + REQUIRE(hmacstr != NULL); + + if (len >= sizeof(buf)) { + error("unknown key type '%.*s'", (int)(len), hmacstr); + return (false); + } + + /* Copy len bytes and NUL terminate. */ + strlcpy(buf, hmacstr, ISC_MIN(len + 1, sizeof(buf))); + + if (strcasecmp(buf, "hmac-md5") == 0) { + *hmac = DNS_TSIG_HMACMD5_NAME; + } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) { + *hmac = DNS_TSIG_HMACMD5_NAME; + result = isc_parse_uint16(&digestbits, &buf[9], 10); + if (result != ISC_R_SUCCESS || digestbits > 128) { + error("digest-bits out of range [0..128]"); + return (false); + } + *digestbitsp = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha1") == 0) { + *hmac = DNS_TSIG_HMACSHA1_NAME; + } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) { + *hmac = DNS_TSIG_HMACSHA1_NAME; + result = isc_parse_uint16(&digestbits, &buf[10], 10); + if (result != ISC_R_SUCCESS || digestbits > 160) { + error("digest-bits out of range [0..160]"); + return (false); + } + *digestbitsp = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha224") == 0) { + *hmac = DNS_TSIG_HMACSHA224_NAME; + } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA224_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 224) { + error("digest-bits out of range [0..224]"); + return (false); + } + *digestbitsp = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha256") == 0) { + *hmac = DNS_TSIG_HMACSHA256_NAME; + } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA256_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 256) { + error("digest-bits out of range [0..256]"); + return (false); + } + *digestbitsp = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha384") == 0) { + *hmac = DNS_TSIG_HMACSHA384_NAME; + } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA384_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 384) { + error("digest-bits out of range [0..384]"); + return (false); + } + *digestbitsp = (digestbits + 7) & ~0x7U; + } else if (strcasecmp(buf, "hmac-sha512") == 0) { + *hmac = DNS_TSIG_HMACSHA512_NAME; + } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) { + *hmac = DNS_TSIG_HMACSHA512_NAME; + result = isc_parse_uint16(&digestbits, &buf[12], 10); + if (result != ISC_R_SUCCESS || digestbits > 512) { + error("digest-bits out of range [0..512]"); + return (false); + } + *digestbitsp = (digestbits + 7) & ~0x7U; + } else { + error("unknown key type '%s'", buf); + return (false); + } + return (true); +} + +static int +basenamelen(const char *file) { + int len = strlen(file); + + if (len > 1 && file[len - 1] == '.') { + len -= 1; + } else if (len > 8 && strcmp(file + len - 8, ".private") == 0) { + len -= 8; + } else if (len > 4 && strcmp(file + len - 4, ".key") == 0) { + len -= 4; + } + return (len); +} + +static void +setup_keystr(void) { + unsigned char *secret = NULL; + int secretlen; + isc_buffer_t secretbuf; + isc_result_t result; + isc_buffer_t keynamesrc; + char *secretstr; + char *s, *n; + dns_fixedname_t fkeyname; + dns_name_t *mykeyname; + char *name; + const dns_name_t *hmacname = NULL; + uint16_t digestbits = 0; + + mykeyname = dns_fixedname_initname(&fkeyname); + + debug("Creating key..."); + + s = strchr(keystr, ':'); + if (s == NULL || s == keystr || s[1] == 0) { + fatal("key option must specify [hmac:]keyname:secret"); + } + secretstr = s + 1; + n = strchr(secretstr, ':'); + if (n != NULL) { + if (n == secretstr || n[1] == 0) { + fatal("key option must specify [hmac:]keyname:secret"); + } + name = secretstr; + secretstr = n + 1; + if (!parse_hmac(&hmacname, keystr, s - keystr, &digestbits)) { + exit(1); + } + } else { + hmacname = DNS_TSIG_HMACMD5_NAME; + name = keystr; + n = s; + } + + isc_buffer_init(&keynamesrc, name, (unsigned int)(n - name)); + isc_buffer_add(&keynamesrc, (unsigned int)(n - name)); + + debug("namefromtext"); + result = dns_name_fromtext(mykeyname, &keynamesrc, dns_rootname, 0, + NULL); + check_result(result, "dns_name_fromtext"); + + secretlen = strlen(secretstr) * 3 / 4; + secret = isc_mem_allocate(gmctx, secretlen); + + isc_buffer_init(&secretbuf, secret, secretlen); + result = isc_base64_decodestring(secretstr, &secretbuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", keystr, + isc_result_totext(result)); + goto failure; + } + + secretlen = isc_buffer_usedlength(&secretbuf); + + debug("keycreate"); + result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen, + false, NULL, 0, 0, gmctx, NULL, &tsigkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", keystr, + dns_result_totext(result)); + } else { + dst_key_setbits(tsigkey->key, digestbits); + } +failure: + if (secret != NULL) { + isc_mem_free(gmctx, secret); + } +} + +/* + * Get a key from a named.conf format keyfile + */ +static isc_result_t +read_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) { + cfg_parser_t *pctx = NULL; + cfg_obj_t *sessionkey = NULL; + const cfg_obj_t *key = NULL; + const cfg_obj_t *secretobj = NULL; + const cfg_obj_t *algorithmobj = NULL; + const char *mykeyname; + const char *secretstr; + const char *algorithm; + isc_result_t result; + int len; + + if (!isc_file_exists(keyfile)) { + return (ISC_R_FILENOTFOUND); + } + + result = cfg_parser_create(mctx, lctx, &pctx); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey, + &sessionkey); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = cfg_map_get(sessionkey, "key", &key); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + (void)cfg_map_get(key, "secret", &secretobj); + (void)cfg_map_get(key, "algorithm", &algorithmobj); + if (secretobj == NULL || algorithmobj == NULL) { + fatal("key must have algorithm and secret"); + } + + mykeyname = cfg_obj_asstring(cfg_map_getname(key)); + secretstr = cfg_obj_asstring(secretobj); + algorithm = cfg_obj_asstring(algorithmobj); + + len = strlen(algorithm) + strlen(mykeyname) + strlen(secretstr) + 3; + keystr = isc_mem_allocate(mctx, len); + snprintf(keystr, len, "%s:%s:%s", algorithm, mykeyname, secretstr); + setup_keystr(); + +cleanup: + if (pctx != NULL) { + if (sessionkey != NULL) { + cfg_obj_destroy(pctx, &sessionkey); + } + cfg_parser_destroy(&pctx); + } + + if (keystr != NULL) { + isc_mem_free(mctx, keystr); + } + + return (result); +} + +static void +setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) { + dst_key_t *dstkey = NULL; + isc_result_t result; + const dns_name_t *hmacname = NULL; + + debug("Creating key..."); + + if (sig0key != NULL) { + dst_key_free(&sig0key); + } + + /* Try reading the key from a K* pair */ + result = dst_key_fromnamedfile( + keyfile, NULL, DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, &dstkey); + + /* If that didn't work, try reading it as a session.key keyfile */ + if (result != ISC_R_SUCCESS) { + result = read_sessionkey(mctx, lctx); + if (result == ISC_R_SUCCESS) { + return; + } + } + + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "could not read key from %.*s.{private,key}: " + "%s\n", + basenamelen(keyfile), keyfile, + isc_result_totext(result)); + return; + } + + switch (dst_key_alg(dstkey)) { + case DST_ALG_HMACMD5: + hmacname = DNS_TSIG_HMACMD5_NAME; + break; + case DST_ALG_HMACSHA1: + hmacname = DNS_TSIG_HMACSHA1_NAME; + break; + case DST_ALG_HMACSHA224: + hmacname = DNS_TSIG_HMACSHA224_NAME; + break; + case DST_ALG_HMACSHA256: + hmacname = DNS_TSIG_HMACSHA256_NAME; + break; + case DST_ALG_HMACSHA384: + hmacname = DNS_TSIG_HMACSHA384_NAME; + break; + case DST_ALG_HMACSHA512: + hmacname = DNS_TSIG_HMACSHA512_NAME; + break; + } + if (hmacname != NULL) { + result = dns_tsigkey_createfromkey( + dst_key_name(dstkey), hmacname, dstkey, false, NULL, 0, + 0, mctx, NULL, &tsigkey); + dst_key_free(&dstkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", + keyfile, isc_result_totext(result)); + return; + } + } else { + dst_key_attach(dstkey, &sig0key); + dst_key_free(&dstkey); + } +} + +static void +doshutdown(void) { + isc_task_detach(&global_task); + + /* + * The isc_mem_put of master_servers must be before the + * isc_mem_put of servers as it sets the servers pointer + * to NULL. + */ + if (master_servers != NULL && master_servers != servers) { + isc_mem_put(gmctx, master_servers, + master_alloc * sizeof(isc_sockaddr_t)); + } + + if (servers != NULL) { + isc_mem_put(gmctx, servers, ns_alloc * sizeof(isc_sockaddr_t)); + } + + if (localaddr4 != NULL) { + isc_mem_put(gmctx, localaddr4, sizeof(isc_sockaddr_t)); + } + + if (localaddr6 != NULL) { + isc_mem_put(gmctx, localaddr6, sizeof(isc_sockaddr_t)); + } + + if (tsigkey != NULL) { + ddebug("Freeing TSIG key"); + dns_tsigkey_detach(&tsigkey); + } + + if (sig0key != NULL) { + ddebug("Freeing SIG(0) key"); + dst_key_free(&sig0key); + } + + if (updatemsg != NULL) { + dns_message_detach(&updatemsg); + } + + if (is_dst_up) { + ddebug("Destroy DST lib"); + dst_lib_destroy(); + is_dst_up = false; + } + + ddebug("Destroying request manager"); + dns_requestmgr_detach(&requestmgr); + + ddebug("Freeing the dispatchers"); + if (have_ipv4) { + dns_dispatch_detach(&dispatchv4); + } + if (have_ipv6) { + dns_dispatch_detach(&dispatchv6); + } + + ddebug("Shutting down dispatch manager"); + dns_dispatchmgr_destroy(&dispatchmgr); +} + +static void +maybeshutdown(void) { + /* when called from getinput, doshutdown might be already finished */ + if (requestmgr == NULL) { + return; + } + + ddebug("Shutting down request manager"); + dns_requestmgr_shutdown(requestmgr); + + if (requests != 0) { + return; + } + + doshutdown(); +} + +static void +shutdown_program(isc_task_t *task, isc_event_t *event) { + REQUIRE(task == global_task); + UNUSED(task); + + ddebug("shutdown_program()"); + isc_event_free(&event); + + shuttingdown = true; + maybeshutdown(); +} + +/* + * Try honoring the operating system's preferred ephemeral port range. + */ +static void +set_source_ports(dns_dispatchmgr_t *manager) { + isc_portset_t *v4portset = NULL, *v6portset = NULL; + in_port_t udpport_low, udpport_high; + isc_result_t result; + + result = isc_portset_create(gmctx, &v4portset); + check_result(result, "isc_portset_create (v4)"); + result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high); + check_result(result, "isc_net_getudpportrange (v4)"); + isc_portset_addrange(v4portset, udpport_low, udpport_high); + + result = isc_portset_create(gmctx, &v6portset); + check_result(result, "isc_portset_create (v6)"); + result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high); + check_result(result, "isc_net_getudpportrange (v6)"); + isc_portset_addrange(v6portset, udpport_low, udpport_high); + + result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset); + check_result(result, "dns_dispatchmgr_setavailports"); + + isc_portset_destroy(gmctx, &v4portset); + isc_portset_destroy(gmctx, &v6portset); +} + +static void +setup_system(void) { + isc_result_t result; + isc_sockaddr_t bind_any, bind_any6; + unsigned int attrs, attrmask; + isc_sockaddrlist_t *nslist; + isc_logconfig_t *logconfig = NULL; + irs_resconf_t *resconf = NULL; + + ddebug("setup_system()"); + + dns_result_register(); + + isc_log_create(gmctx, &glctx, &logconfig); + isc_log_setcontext(glctx); + dns_log_init(glctx); + dns_log_setcontext(glctx); + + result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL); + check_result(result, "isc_log_usechannel"); + + isc_log_setdebuglevel(glctx, logdebuglevel); + + result = irs_resconf_load(gmctx, RESOLV_CONF, &resconf); + if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) { + fatal("parse of %s failed", RESOLV_CONF); + } + + nslist = irs_resconf_getnameservers(resconf); + + if (servers != NULL) { + if (master_servers == servers) { + master_servers = NULL; + } + isc_mem_put(gmctx, servers, ns_alloc * sizeof(isc_sockaddr_t)); + } + + ns_inuse = 0; + if (local_only || ISC_LIST_EMPTY(*nslist)) { + struct in_addr in; + struct in6_addr in6; + + if (local_only && keyfile == NULL) { + keyfile = SESSION_KEYFILE; + } + + default_servers = !local_only; + + ns_total = ns_alloc = (have_ipv4 ? 1 : 0) + (have_ipv6 ? 1 : 0); + servers = isc_mem_get(gmctx, ns_alloc * sizeof(isc_sockaddr_t)); + + if (have_ipv6) { + memset(&in6, 0, sizeof(in6)); + in6.s6_addr[15] = 1; + isc_sockaddr_fromin6(&servers[0], &in6, dnsport); + } + if (have_ipv4) { + in.s_addr = htonl(INADDR_LOOPBACK); + isc_sockaddr_fromin(&servers[(have_ipv6 ? 1 : 0)], &in, + dnsport); + } + } else { + isc_sockaddr_t *sa; + int i; + + /* + * Count the nameservers (skipping any that we can't use + * because of address family restrictions) and allocate + * the servers array. + */ + ns_total = 0; + for (sa = ISC_LIST_HEAD(*nslist); sa != NULL; + sa = ISC_LIST_NEXT(sa, link)) + { + switch (sa->type.sa.sa_family) { + case AF_INET: + if (have_ipv4) { + ns_total++; + } + break; + case AF_INET6: + if (have_ipv6) { + ns_total++; + } + break; + default: + fatal("bad family"); + } + } + + ns_alloc = ns_total; + servers = isc_mem_get(gmctx, ns_alloc * sizeof(isc_sockaddr_t)); + + i = 0; + for (sa = ISC_LIST_HEAD(*nslist); sa != NULL; + sa = ISC_LIST_NEXT(sa, link)) + { + switch (sa->type.sa.sa_family) { + case AF_INET: + if (have_ipv4) { + sa->type.sin.sin_port = htons(dnsport); + } else { + continue; + } + break; + case AF_INET6: + if (have_ipv6) { + sa->type.sin6.sin6_port = + htons(dnsport); + } else { + continue; + } + break; + default: + fatal("bad family"); + } + INSIST(i < ns_alloc); + servers[i++] = *sa; + } + } + + irs_resconf_destroy(&resconf); + + result = dns_dispatchmgr_create(gmctx, &dispatchmgr); + check_result(result, "dns_dispatchmgr_create"); + + result = isc_socketmgr_create(gmctx, &socketmgr); + check_result(result, "dns_socketmgr_create"); + + result = isc_timermgr_create(gmctx, &timermgr); + check_result(result, "dns_timermgr_create"); + + result = isc_managers_create(gmctx, 1, 0, &netmgr, &taskmgr); + check_result(result, "isc_managers_create"); + + result = isc_task_create(taskmgr, 0, &global_task); + check_result(result, "isc_task_create"); + + result = isc_task_onshutdown(global_task, shutdown_program, NULL); + check_result(result, "isc_task_onshutdown"); + + result = dst_lib_init(gmctx, NULL); + check_result(result, "dst_lib_init"); + is_dst_up = true; + + set_source_ports(dispatchmgr); + + attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; + attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; + + if (have_ipv6) { + attrs = DNS_DISPATCHATTR_UDP; + attrs |= DNS_DISPATCHATTR_MAKEQUERY; + attrs |= DNS_DISPATCHATTR_IPV6; + isc_sockaddr_any6(&bind_any6); + result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, + &bind_any6, PACKETSIZE, 4, 2, 3, 5, + attrs, attrmask, &dispatchv6); + check_result(result, "dns_dispatch_getudp (v6)"); + } + + if (have_ipv4) { + attrs = DNS_DISPATCHATTR_UDP; + attrs |= DNS_DISPATCHATTR_MAKEQUERY; + attrs |= DNS_DISPATCHATTR_IPV4; + isc_sockaddr_any(&bind_any); + result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, + &bind_any, PACKETSIZE, 4, 2, 3, 5, + attrs, attrmask, &dispatchv4); + check_result(result, "dns_dispatch_getudp (v4)"); + } + + result = dns_requestmgr_create(gmctx, timermgr, socketmgr, taskmgr, + dispatchmgr, dispatchv4, dispatchv6, + &requestmgr); + check_result(result, "dns_requestmgr_create"); + + if (keystr != NULL) { + setup_keystr(); + } else if (local_only) { + result = read_sessionkey(gmctx, glctx); + if (result != ISC_R_SUCCESS) { + fatal("can't read key from %s: %s\n", keyfile, + isc_result_totext(result)); + } + } else if (keyfile != NULL) { + setup_keyfile(gmctx, glctx); + } + + isc_mutex_init(&answer_lock); +} + +static int +get_addresses(char *host, in_port_t port, isc_sockaddr_t *sockaddr, + int naddrs) { + int count = 0; + isc_result_t result; + + isc_app_block(); + result = bind9_getaddresses(host, port, sockaddr, naddrs, &count); + isc_app_unblock(); + if (result != ISC_R_SUCCESS) { + error("couldn't get address for '%s': %s", host, + isc_result_totext(result)); + } + return (count); +} + +static void +version(void) { + fputs("nsupdate " VERSION "\n", stderr); +} + +#define PARSE_ARGS_FMT "46dDML:y:ghilovk:p:Pr:R::t:Tu:V" + +static void +pre_parse_args(int argc, char **argv) { + dns_rdatatype_t t; + int ch; + char buf[100]; + bool doexit = false; + bool ipv4only = false, ipv6only = false; + + while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { + switch (ch) { + case 'M': /* was -dm */ + debugging = true; + ddebugging = true; + memdebugging = true; + isc_mem_debugging = ISC_MEM_DEBUGTRACE | + ISC_MEM_DEBUGRECORD; + break; + + case '4': + if (ipv6only) { + fatal("only one of -4 and -6 allowed"); + } + ipv4only = true; + break; + + case '6': + if (ipv4only) { + fatal("only one of -4 and -6 allowed"); + } + ipv6only = true; + break; + + case '?': + case 'h': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + argv[0], isc_commandline_option); + } + fprintf(stderr, "usage: nsupdate [-dDi] [-L level] [-l]" + "[-g | -o | -y keyname:secret | -k " + "keyfile] " + "[-v] [-V] [-P] [-T] [-4 | -6] " + "[filename]\n"); + exit(1); + + case 'P': + for (t = 0xff00; t <= 0xfffe; t++) { + if (dns_rdatatype_ismeta(t)) { + continue; + } + dns_rdatatype_format(t, buf, sizeof(buf)); + if (strncmp(buf, "TYPE", 4) != 0) { + fprintf(stdout, "%s\n", buf); + } + } + doexit = true; + break; + + case 'T': + for (t = 1; t <= 0xfeff; t++) { + if (dns_rdatatype_ismeta(t)) { + continue; + } + dns_rdatatype_format(t, buf, sizeof(buf)); + if (strncmp(buf, "TYPE", 4) != 0) { + fprintf(stdout, "%s\n", buf); + } + } + doexit = true; + break; + + case 'V': + version(); + doexit = true; + break; + + default: + break; + } + } + if (doexit) { + exit(0); + } + isc_commandline_reset = true; + isc_commandline_index = 1; +} + +static void +parse_args(int argc, char **argv) { + int ch; + uint32_t i; + isc_result_t result; + bool force_interactive = false; + + debug("parse_args"); + while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { + switch (ch) { + case '4': + if (have_ipv4) { + isc_net_disableipv6(); + have_ipv6 = false; + } else { + fatal("can't find IPv4 networking"); + } + break; + case '6': + if (have_ipv6) { + isc_net_disableipv4(); + have_ipv4 = false; + } else { + fatal("can't find IPv6 networking"); + } + break; + case 'd': + debugging = true; + break; + case 'D': /* was -dd */ + debugging = true; + ddebugging = true; + break; + case 'M': + break; + case 'i': + force_interactive = true; + interactive = true; + break; + case 'l': + local_only = true; + break; + case 'L': + result = isc_parse_uint32(&i, isc_commandline_argument, + 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "bad library debug value " + "'%s'\n", + isc_commandline_argument); + exit(1); + } + logdebuglevel = i; + break; + case 'y': + keystr = isc_commandline_argument; + break; + case 'v': + usevc = true; + break; + case 'k': + keyfile = isc_commandline_argument; + break; + case 'g': + usegsstsig = true; + use_win2k_gsstsig = false; + break; + case 'o': + usegsstsig = true; + use_win2k_gsstsig = true; + break; + case 'p': + result = isc_parse_uint16(&dnsport, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "bad port number " + "'%s'\n", + isc_commandline_argument); + exit(1); + } + break; + case 't': + result = isc_parse_uint32(&timeout, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad timeout '%s'\n", + isc_commandline_argument); + exit(1); + } + if (timeout == 0) { + timeout = UINT_MAX; + } + break; + case 'u': + result = isc_parse_uint32(&udp_timeout, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad udp timeout '%s'\n", + isc_commandline_argument); + exit(1); + } + if (udp_timeout == 0) { + udp_timeout = UINT_MAX; + } + break; + case 'r': + result = isc_parse_uint32(&udp_retries, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad udp retries '%s'\n", + isc_commandline_argument); + exit(1); + } + break; + + case 'R': + fatal("The -R options has been deprecated.\n"); + break; + + default: + fprintf(stderr, "%s: unhandled option: %c\n", argv[0], + isc_commandline_option); + exit(1); + } + } + if (keyfile != NULL && keystr != NULL) { + fprintf(stderr, "%s: cannot specify both -k and -y\n", argv[0]); + exit(1); + } + +#ifdef GSSAPI + if (usegsstsig && (keyfile != NULL || keystr != NULL)) { + fprintf(stderr, "%s: cannot specify -g with -k or -y\n", + argv[0]); + exit(1); + } +#else /* ifdef GSSAPI */ + if (usegsstsig) { + fprintf(stderr, + "%s: cannot specify -g or -o, " + "program not linked with GSS API Library\n", + argv[0]); + exit(1); + } +#endif /* ifdef GSSAPI */ + + if (argv[isc_commandline_index] != NULL) { + if (strcmp(argv[isc_commandline_index], "-") == 0) { + input = stdin; + } else { + result = isc_stdio_open(argv[isc_commandline_index], + "r", &input); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not open '%s': %s\n", + argv[isc_commandline_index], + isc_result_totext(result)); + exit(1); + } + } + if (!force_interactive) { + interactive = false; + } + } +} + +static uint16_t +parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) { + isc_result_t result; + char *word; + isc_buffer_t source; + + word = nsu_strsep(cmdlinep, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read owner name\n"); + return (STATUS_SYNTAX); + } + + result = dns_message_gettempname(msg, namep); + check_result(result, "dns_message_gettempname"); + isc_buffer_init(&source, word, strlen(word)); + isc_buffer_add(&source, strlen(word)); + result = dns_name_fromtext(*namep, &source, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + error("invalid owner name: %s", isc_result_totext(result)); + isc_buffer_invalidate(&source); + dns_message_puttempname(msg, namep); + return (STATUS_SYNTAX); + } + isc_buffer_invalidate(&source); + return (STATUS_MORE); +} + +static uint16_t +parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass, + dns_rdatatype_t rdatatype, dns_message_t *msg, dns_rdata_t *rdata) { + char *cmdline = *cmdlinep; + isc_buffer_t source, *buf = NULL, *newbuf = NULL; + isc_region_t r; + isc_lex_t *lex = NULL; + dns_rdatacallbacks_t callbacks; + isc_result_t result; + + if (cmdline == NULL) { + rdata->flags = DNS_RDATA_UPDATE; + return (STATUS_MORE); + } + + while (*cmdline != 0 && isspace((unsigned char)*cmdline)) { + cmdline++; + } + + if (*cmdline != 0) { + dns_rdatacallbacks_init(&callbacks); + result = isc_lex_create(gmctx, strlen(cmdline), &lex); + check_result(result, "isc_lex_create"); + isc_buffer_init(&source, cmdline, strlen(cmdline)); + isc_buffer_add(&source, strlen(cmdline)); + result = isc_lex_openbuffer(lex, &source); + check_result(result, "isc_lex_openbuffer"); + isc_buffer_allocate(gmctx, &buf, MAXWIRE); + result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex, + dns_rootname, 0, gmctx, buf, + &callbacks); + isc_lex_destroy(&lex); + if (result == ISC_R_SUCCESS) { + isc_buffer_usedregion(buf, &r); + isc_buffer_allocate(gmctx, &newbuf, r.length); + isc_buffer_putmem(newbuf, r.base, r.length); + isc_buffer_usedregion(newbuf, &r); + dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r); + isc_buffer_free(&buf); + dns_message_takebuffer(msg, &newbuf); + } else { + fprintf(stderr, "invalid rdata format: %s\n", + isc_result_totext(result)); + isc_buffer_free(&buf); + return (STATUS_SYNTAX); + } + } else { + rdata->flags = DNS_RDATA_UPDATE; + } + *cmdlinep = cmdline; + return (STATUS_MORE); +} + +static uint16_t +make_prereq(char *cmdline, bool ispositive, bool isrrset) { + isc_result_t result; + char *word; + dns_name_t *name = NULL; + isc_textregion_t region; + dns_rdataset_t *rdataset = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdataclass_t rdataclass; + dns_rdatatype_t rdatatype; + dns_rdata_t *rdata = NULL; + uint16_t retval; + + ddebug("make_prereq()"); + + /* + * Read the owner name + */ + retval = parse_name(&cmdline, updatemsg, &name); + if (retval != STATUS_MORE) { + return (retval); + } + + /* + * If this is an rrset prereq, read the class or type. + */ + if (isrrset) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read class or type\n"); + goto failure; + } + region.base = word; + region.length = strlen(word); + result = dns_rdataclass_fromtext(&rdataclass, ®ion); + if (result == ISC_R_SUCCESS) { + if (!setzoneclass(rdataclass)) { + fprintf(stderr, "class mismatch: %s\n", word); + goto failure; + } + /* + * Now read the type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read type\n"); + goto failure; + } + region.base = word; + region.length = strlen(word); + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "invalid type: %s\n", word); + goto failure; + } + } else { + rdataclass = getzoneclass(); + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "invalid type: %s\n", word); + goto failure; + } + } + } else { + rdatatype = dns_rdatatype_any; + } + + result = dns_message_gettemprdata(updatemsg, &rdata); + check_result(result, "dns_message_gettemprdata"); + + dns_rdata_init(rdata); + + if (isrrset && ispositive) { + retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, + rdata); + if (retval != STATUS_MORE) { + goto failure; + } + } else { + rdata->flags = DNS_RDATA_UPDATE; + } + + result = dns_message_gettemprdatalist(updatemsg, &rdatalist); + check_result(result, "dns_message_gettemprdatalist"); + result = dns_message_gettemprdataset(updatemsg, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + rdatalist->type = rdatatype; + if (ispositive) { + if (isrrset && rdata->data != NULL) { + rdatalist->rdclass = rdataclass; + } else { + rdatalist->rdclass = dns_rdataclass_any; + } + } else { + rdatalist->rdclass = dns_rdataclass_none; + } + rdata->rdclass = rdatalist->rdclass; + rdata->type = rdatatype; + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + dns_rdatalist_tordataset(rdatalist, rdataset); + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE); + return (STATUS_MORE); + +failure: + if (name != NULL) { + dns_message_puttempname(updatemsg, &name); + } + return (STATUS_SYNTAX); +} + +static uint16_t +evaluate_prereq(char *cmdline) { + char *word; + bool ispositive, isrrset; + + ddebug("evaluate_prereq()"); + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read operation code\n"); + return (STATUS_SYNTAX); + } + if (strcasecmp(word, "nxdomain") == 0) { + ispositive = false; + isrrset = false; + } else if (strcasecmp(word, "yxdomain") == 0) { + ispositive = true; + isrrset = false; + } else if (strcasecmp(word, "nxrrset") == 0) { + ispositive = false; + isrrset = true; + } else if (strcasecmp(word, "yxrrset") == 0) { + ispositive = true; + isrrset = true; + } else { + fprintf(stderr, "incorrect operation code: %s\n", word); + return (STATUS_SYNTAX); + } + return (make_prereq(cmdline, ispositive, isrrset)); +} + +static uint16_t +evaluate_server(char *cmdline) { + char *word, *server; + long port; + + if (local_only) { + fprintf(stderr, "cannot reset server in localhost-only mode\n"); + return (STATUS_SYNTAX); + } + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read server name\n"); + return (STATUS_SYNTAX); + } + server = word; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + port = dnsport; + } else { + char *endp; + port = strtol(word, &endp, 10); + if (*endp != 0) { + fprintf(stderr, "port '%s' is not numeric\n", word); + return (STATUS_SYNTAX); + } else if (port < 1 || port > 65535) { + fprintf(stderr, + "port '%s' is out of range " + "(1 to 65535)\n", + word); + return (STATUS_SYNTAX); + } + } + + if (servers != NULL) { + if (master_servers == servers) { + master_servers = NULL; + } + isc_mem_put(gmctx, servers, ns_alloc * sizeof(isc_sockaddr_t)); + } + + default_servers = false; + + ns_alloc = MAX_SERVERADDRS; + ns_inuse = 0; + servers = isc_mem_get(gmctx, ns_alloc * sizeof(isc_sockaddr_t)); + + memset(servers, 0, ns_alloc * sizeof(isc_sockaddr_t)); + ns_total = get_addresses(server, (in_port_t)port, servers, ns_alloc); + if (ns_total == 0) { + return (STATUS_SYNTAX); + } + + return (STATUS_MORE); +} + +static uint16_t +evaluate_local(char *cmdline) { + char *word, *local; + long port; + struct in_addr in4; + struct in6_addr in6; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read server name\n"); + return (STATUS_SYNTAX); + } + local = word; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + port = 0; + } else { + char *endp; + port = strtol(word, &endp, 10); + if (*endp != 0) { + fprintf(stderr, "port '%s' is not numeric\n", word); + return (STATUS_SYNTAX); + } else if (port < 1 || port > 65535) { + fprintf(stderr, + "port '%s' is out of range " + "(1 to 65535)\n", + word); + return (STATUS_SYNTAX); + } + } + + if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) { + if (localaddr6 == NULL) { + localaddr6 = isc_mem_get(gmctx, sizeof(isc_sockaddr_t)); + } + isc_sockaddr_fromin6(localaddr6, &in6, (in_port_t)port); + } else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) { + if (localaddr4 == NULL) { + localaddr4 = isc_mem_get(gmctx, sizeof(isc_sockaddr_t)); + } + isc_sockaddr_fromin(localaddr4, &in4, (in_port_t)port); + } else { + fprintf(stderr, "invalid address %s", local); + return (STATUS_SYNTAX); + } + + return (STATUS_MORE); +} + +static uint16_t +evaluate_key(char *cmdline) { + char *namestr; + char *secretstr; + isc_buffer_t b; + isc_result_t result; + dns_fixedname_t fkeyname; + dns_name_t *mykeyname; + int secretlen; + unsigned char *secret = NULL; + isc_buffer_t secretbuf; + const dns_name_t *hmacname = NULL; + uint16_t digestbits = 0; + char *n; + + namestr = nsu_strsep(&cmdline, " \t\r\n"); + if (namestr == NULL || *namestr == 0) { + fprintf(stderr, "could not read key name\n"); + return (STATUS_SYNTAX); + } + + mykeyname = dns_fixedname_initname(&fkeyname); + + n = strchr(namestr, ':'); + if (n != NULL) { + if (!parse_hmac(&hmacname, namestr, n - namestr, &digestbits)) { + return (STATUS_SYNTAX); + } + namestr = n + 1; + } else { + hmacname = DNS_TSIG_HMACMD5_NAME; + } + + isc_buffer_init(&b, namestr, strlen(namestr)); + isc_buffer_add(&b, strlen(namestr)); + result = dns_name_fromtext(mykeyname, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not parse key name\n"); + return (STATUS_SYNTAX); + } + + secretstr = nsu_strsep(&cmdline, "\r\n"); + if (secretstr == NULL || *secretstr == 0) { + fprintf(stderr, "could not read key secret\n"); + return (STATUS_SYNTAX); + } + secretlen = strlen(secretstr) * 3 / 4; + secret = isc_mem_allocate(gmctx, secretlen); + + isc_buffer_init(&secretbuf, secret, secretlen); + result = isc_base64_decodestring(secretstr, &secretbuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", secretstr, + isc_result_totext(result)); + isc_mem_free(gmctx, secret); + return (STATUS_SYNTAX); + } + secretlen = isc_buffer_usedlength(&secretbuf); + + if (tsigkey != NULL) { + dns_tsigkey_detach(&tsigkey); + } + result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen, + false, NULL, 0, 0, gmctx, NULL, &tsigkey); + isc_mem_free(gmctx, secret); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s %s: %s\n", + namestr, secretstr, dns_result_totext(result)); + return (STATUS_SYNTAX); + } + dst_key_setbits(tsigkey->key, digestbits); + return (STATUS_MORE); +} + +static uint16_t +evaluate_zone(char *cmdline) { + char *word; + isc_buffer_t b; + isc_result_t result; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read zone name\n"); + return (STATUS_SYNTAX); + } + + userzone = dns_fixedname_initname(&fuserzone); + isc_buffer_init(&b, word, strlen(word)); + isc_buffer_add(&b, strlen(word)); + result = dns_name_fromtext(userzone, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + userzone = NULL; /* Lest it point to an invalid name */ + fprintf(stderr, "could not parse zone name\n"); + return (STATUS_SYNTAX); + } + + return (STATUS_MORE); +} + +static uint16_t +evaluate_realm(char *cmdline) { +#ifdef GSSAPI + char *word; + char buf[1024]; + int n; + + if (realm != NULL) { + isc_mem_free(gmctx, realm); + realm = NULL; + } + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + return (STATUS_MORE); + } + + n = snprintf(buf, sizeof(buf), "@%s", word); + if (n < 0 || (size_t)n >= sizeof(buf)) { + error("realm is too long"); + return (STATUS_SYNTAX); + } + realm = isc_mem_strdup(gmctx, buf); + return (STATUS_MORE); +#else /* ifdef GSSAPI */ + UNUSED(cmdline); + return (STATUS_SYNTAX); +#endif /* ifdef GSSAPI */ +} + +static uint16_t +evaluate_ttl(char *cmdline) { + char *word; + isc_result_t result; + uint32_t ttl; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read ttl\n"); + return (STATUS_SYNTAX); + } + + if (!strcasecmp(word, "none")) { + default_ttl = 0; + default_ttl_set = false; + return (STATUS_MORE); + } + + result = isc_parse_uint32(&ttl, word, 10); + if (result != ISC_R_SUCCESS) { + return (STATUS_SYNTAX); + } + + if (ttl > TTL_MAX) { + fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", word, + TTL_MAX); + return (STATUS_SYNTAX); + } + default_ttl = ttl; + default_ttl_set = true; + + return (STATUS_MORE); +} + +static uint16_t +evaluate_class(char *cmdline) { + char *word; + isc_textregion_t r; + isc_result_t result; + dns_rdataclass_t rdclass; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read class name\n"); + return (STATUS_SYNTAX); + } + + r.base = word; + r.length = strlen(word); + result = dns_rdataclass_fromtext(&rdclass, &r); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not parse class name: %s\n", word); + return (STATUS_SYNTAX); + } + switch (rdclass) { + case dns_rdataclass_none: + case dns_rdataclass_any: + case dns_rdataclass_reserved0: + fprintf(stderr, "bad default class: %s\n", word); + return (STATUS_SYNTAX); + default: + defaultclass = rdclass; + } + + return (STATUS_MORE); +} + +static uint16_t +update_addordelete(char *cmdline, bool isdelete) { + isc_result_t result; + dns_name_t *name = NULL; + uint32_t ttl; + char *word; + dns_rdataclass_t rdataclass; + dns_rdatatype_t rdatatype; + dns_rdata_t *rdata = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdataset_t *rdataset = NULL; + isc_textregion_t region; + uint16_t retval; + + ddebug("update_addordelete()"); + + /* + * Read the owner name. + */ + retval = parse_name(&cmdline, updatemsg, &name); + if (retval != STATUS_MORE) { + return (retval); + } + + result = dns_message_gettemprdata(updatemsg, &rdata); + check_result(result, "dns_message_gettemprdata"); + + dns_rdata_init(rdata); + + /* + * If this is an add, read the TTL and verify that it's in range. + * If it's a delete, ignore a TTL if present (for compatibility). + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + if (!isdelete) { + fprintf(stderr, "could not read owner ttl\n"); + goto failure; + } else { + ttl = 0; + rdataclass = dns_rdataclass_any; + rdatatype = dns_rdatatype_any; + rdata->flags = DNS_RDATA_UPDATE; + goto doneparsing; + } + } + result = isc_parse_uint32(&ttl, word, 10); + if (result != ISC_R_SUCCESS) { + if (isdelete) { + ttl = 0; + goto parseclass; + } else if (default_ttl_set) { + ttl = default_ttl; + goto parseclass; + } else { + fprintf(stderr, "ttl '%s': %s\n", word, + isc_result_totext(result)); + goto failure; + } + } + + if (isdelete) { + ttl = 0; + } else if (ttl > TTL_MAX) { + fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", word, + TTL_MAX); + goto failure; + } + + /* + * Read the class or type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); +parseclass: + if (word == NULL || *word == 0) { + if (isdelete) { + rdataclass = dns_rdataclass_any; + rdatatype = dns_rdatatype_any; + rdata->flags = DNS_RDATA_UPDATE; + goto doneparsing; + } else { + fprintf(stderr, "could not read class or type\n"); + goto failure; + } + } + region.base = word; + region.length = strlen(word); + rdataclass = dns_rdataclass_any; + result = dns_rdataclass_fromtext(&rdataclass, ®ion); + if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) { + if (!setzoneclass(rdataclass)) { + fprintf(stderr, "class mismatch: %s\n", word); + goto failure; + } + /* + * Now read the type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + if (isdelete) { + rdataclass = dns_rdataclass_any; + rdatatype = dns_rdatatype_any; + rdata->flags = DNS_RDATA_UPDATE; + goto doneparsing; + } else { + fprintf(stderr, "could not read type\n"); + goto failure; + } + } + region.base = word; + region.length = strlen(word); + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "'%s' is not a valid type: %s\n", word, + isc_result_totext(result)); + goto failure; + } + } else { + rdataclass = getzoneclass(); + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "'%s' is not a valid class or type: " + "%s\n", + word, isc_result_totext(result)); + goto failure; + } + } + + retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, rdata); + if (retval != STATUS_MORE) { + goto failure; + } + + if (isdelete) { + if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { + rdataclass = dns_rdataclass_any; + } else { + rdataclass = dns_rdataclass_none; + } + } else { + if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { + fprintf(stderr, "could not read rdata\n"); + goto failure; + } + } + + if (!isdelete && checknames) { + dns_fixedname_t fixed; + dns_name_t *bad; + + if (!dns_rdata_checkowner(name, rdata->rdclass, rdata->type, + true)) + { + char namebuf[DNS_NAME_FORMATSIZE]; + + dns_name_format(name, namebuf, sizeof(namebuf)); + fprintf(stderr, "check-names failed: bad owner '%s'\n", + namebuf); + goto failure; + } + + bad = dns_fixedname_initname(&fixed); + if (!dns_rdata_checknames(rdata, name, bad)) { + char namebuf[DNS_NAME_FORMATSIZE]; + + dns_name_format(bad, namebuf, sizeof(namebuf)); + fprintf(stderr, "check-names failed: bad name '%s'\n", + namebuf); + goto failure; + } + } + + if (!isdelete && rdata->type == dns_rdatatype_nsec3param) { + dns_rdata_nsec3param_t nsec3param; + + result = dns_rdata_tostruct(rdata, &nsec3param, NULL); + check_result(result, "dns_rdata_tostruct"); + if (nsec3param.iterations > dns_nsec3_maxiterations()) { + fprintf(stderr, + "NSEC3PARAM has excessive iterations (> %u)\n", + dns_nsec3_maxiterations()); + goto failure; + } + } + +doneparsing: + + result = dns_message_gettemprdatalist(updatemsg, &rdatalist); + check_result(result, "dns_message_gettemprdatalist"); + result = dns_message_gettemprdataset(updatemsg, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + rdatalist->type = rdatatype; + rdatalist->rdclass = rdataclass; + rdatalist->covers = rdatatype; + rdatalist->ttl = (dns_ttl_t)ttl; + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + dns_rdatalist_tordataset(rdatalist, rdataset); + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE); + return (STATUS_MORE); + +failure: + if (name != NULL) { + dns_message_puttempname(updatemsg, &name); + } + dns_message_puttemprdata(updatemsg, &rdata); + return (STATUS_SYNTAX); +} + +static uint16_t +evaluate_update(char *cmdline) { + char *word; + bool isdelete; + + ddebug("evaluate_update()"); + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read operation code\n"); + return (STATUS_SYNTAX); + } + if (strcasecmp(word, "delete") == 0) { + isdelete = true; + } else if (strcasecmp(word, "del") == 0) { + isdelete = true; + } else if (strcasecmp(word, "add") == 0) { + isdelete = false; + } else { + fprintf(stderr, "incorrect operation code: %s\n", word); + return (STATUS_SYNTAX); + } + return (update_addordelete(cmdline, isdelete)); +} + +static uint16_t +evaluate_checknames(char *cmdline) { + char *word; + + ddebug("evaluate_checknames()"); + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read check-names directive\n"); + return (STATUS_SYNTAX); + } + if (strcasecmp(word, "yes") == 0 || strcasecmp(word, "true") == 0 || + strcasecmp(word, "on") == 0) + { + checknames = true; + } else if (strcasecmp(word, "no") == 0 || + strcasecmp(word, "false") == 0 || + strcasecmp(word, "off") == 0) + { + checknames = false; + } else { + fprintf(stderr, "incorrect check-names directive: %s\n", word); + return (STATUS_SYNTAX); + } + return (STATUS_MORE); +} + +static void +setzone(dns_name_t *zonename) { + isc_result_t result; + dns_name_t *name = NULL; + dns_rdataset_t *rdataset = NULL; + + result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE); + if (result == ISC_R_SUCCESS) { + dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name); + dns_message_removename(updatemsg, name, DNS_SECTION_ZONE); + for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; + rdataset = ISC_LIST_HEAD(name->list)) + { + ISC_LIST_UNLINK(name->list, rdataset, link); + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(updatemsg, &rdataset); + } + dns_message_puttempname(updatemsg, &name); + } + + if (zonename != NULL) { + result = dns_message_gettempname(updatemsg, &name); + check_result(result, "dns_message_gettempname"); + dns_name_clone(zonename, name); + result = dns_message_gettemprdataset(updatemsg, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + dns_rdataset_makequestion(rdataset, getzoneclass(), + dns_rdatatype_soa); + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(updatemsg, name, DNS_SECTION_ZONE); + } +} + +static void +show_message(FILE *stream, dns_message_t *msg, const char *description) { + isc_result_t result; + isc_buffer_t *buf = NULL; + int bufsz; + + ddebug("show_message()"); + + setzone(userzone); + + bufsz = INITTEXT; + do { + if (bufsz > MAXTEXT) { + fprintf(stderr, "could not allocate large enough " + "buffer to display message\n"); + exit(1); + } + if (buf != NULL) { + isc_buffer_free(&buf); + } + isc_buffer_allocate(gmctx, &buf, bufsz); + result = dns_message_totext(msg, style, 0, buf); + bufsz *= 2; + } while (result == ISC_R_NOSPACE); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not convert message to text format.\n"); + isc_buffer_free(&buf); + return; + } + fprintf(stream, "%s\n%.*s", description, + (int)isc_buffer_usedlength(buf), (char *)isc_buffer_base(buf)); + fflush(stream); + isc_buffer_free(&buf); +} + +static uint16_t +do_next_command(char *cmdline) { + char *word; + + ddebug("do_next_command()"); + word = nsu_strsep(&cmdline, " \t\r\n"); + + if (word == NULL || *word == 0) { + return (STATUS_SEND); + } + if (word[0] == ';') { + return (STATUS_MORE); + } + if (strcasecmp(word, "quit") == 0) { + return (STATUS_QUIT); + } + if (strcasecmp(word, "prereq") == 0) { + return (evaluate_prereq(cmdline)); + } + if (strcasecmp(word, "nxdomain") == 0) { + return (make_prereq(cmdline, false, false)); + } + if (strcasecmp(word, "yxdomain") == 0) { + return (make_prereq(cmdline, true, false)); + } + if (strcasecmp(word, "nxrrset") == 0) { + return (make_prereq(cmdline, false, true)); + } + if (strcasecmp(word, "yxrrset") == 0) { + return (make_prereq(cmdline, true, true)); + } + if (strcasecmp(word, "update") == 0) { + return (evaluate_update(cmdline)); + } + if (strcasecmp(word, "delete") == 0) { + return (update_addordelete(cmdline, true)); + } + if (strcasecmp(word, "del") == 0) { + return (update_addordelete(cmdline, true)); + } + if (strcasecmp(word, "add") == 0) { + return (update_addordelete(cmdline, false)); + } + if (strcasecmp(word, "server") == 0) { + return (evaluate_server(cmdline)); + } + if (strcasecmp(word, "local") == 0) { + return (evaluate_local(cmdline)); + } + if (strcasecmp(word, "zone") == 0) { + return (evaluate_zone(cmdline)); + } + if (strcasecmp(word, "class") == 0) { + return (evaluate_class(cmdline)); + } + if (strcasecmp(word, "send") == 0) { + return (STATUS_SEND); + } + if (strcasecmp(word, "debug") == 0) { + if (debugging) { + ddebugging = true; + } else { + debugging = true; + } + return (STATUS_MORE); + } + if (strcasecmp(word, "ttl") == 0) { + return (evaluate_ttl(cmdline)); + } + if (strcasecmp(word, "show") == 0) { + show_message(stdout, updatemsg, "Outgoing update query:"); + return (STATUS_MORE); + } + if (strcasecmp(word, "answer") == 0) { + LOCK(&answer_lock); + if (answer != NULL) { + show_message(stdout, answer, "Answer:"); + } + UNLOCK(&answer_lock); + return (STATUS_MORE); + } + if (strcasecmp(word, "key") == 0) { + usegsstsig = false; + return (evaluate_key(cmdline)); + } + if (strcasecmp(word, "realm") == 0) { + return (evaluate_realm(cmdline)); + } + if (strcasecmp(word, "check-names") == 0 || + strcasecmp(word, "checknames") == 0) + { + return (evaluate_checknames(cmdline)); + } + if (strcasecmp(word, "gsstsig") == 0) { +#ifdef GSSAPI + usegsstsig = true; + use_win2k_gsstsig = false; +#else /* ifdef GSSAPI */ + fprintf(stderr, "gsstsig not supported\n"); +#endif /* ifdef GSSAPI */ + return (STATUS_MORE); + } + if (strcasecmp(word, "oldgsstsig") == 0) { +#ifdef GSSAPI + usegsstsig = true; + use_win2k_gsstsig = true; +#else /* ifdef GSSAPI */ + fprintf(stderr, "gsstsig not supported\n"); +#endif /* ifdef GSSAPI */ + return (STATUS_MORE); + } + if (strcasecmp(word, "help") == 0) { + fprintf(stdout, "nsupdate " VERSION ":\n" + "local address [port] (set local " + "resolver)\n" + "server address [port] (set master server " + "for zone)\n" + "send (send the update " + "request)\n" + "show (show the update " + "request)\n" + "answer (show the answer to " + "the last request)\n" + "quit (quit, any pending " + "update is not sent)\n" + "help (display this " + "message)\n" + "key [hmac:]keyname secret (use TSIG to sign " + "the request)\n" + "gsstsig (use GSS_TSIG to " + "sign the request)\n" + "oldgsstsig (use Microsoft's " + "GSS_TSIG to sign the request)\n" + "zone name (set the zone to be " + "updated)\n" + "class CLASS (set the zone's DNS " + "class, e.g. IN (default), CH)\n" + "check-names { on | off } (enable / disable " + "check-names)\n" + "[prereq] nxdomain name (require that this " + "name does not exist)\n" + "[prereq] yxdomain name (require that this " + "name exists)\n" + "[prereq] nxrrset .... (require that this " + "RRset does not exist)\n" + "[prereq] yxrrset .... (require that this " + "RRset exists)\n" + "[update] add .... (add the given " + "record to the zone)\n" + "[update] del[ete] .... (remove the given " + "record(s) from the zone)\n"); + return (STATUS_MORE); + } + if (strcasecmp(word, "version") == 0) { + fprintf(stdout, "nsupdate " VERSION "\n"); + return (STATUS_MORE); + } + fprintf(stderr, "incorrect section name: %s\n", word); + return (STATUS_SYNTAX); +} + +static uint16_t +get_next_command(void) { + uint16_t result = STATUS_QUIT; + char cmdlinebuf[MAXCMD]; + char *cmdline; + + isc_app_block(); + if (interactive) { +#ifdef HAVE_READLINE + cmdline = readline("> "); + if (cmdline != NULL) { + add_history(cmdline); + } +#else /* ifdef HAVE_READLINE */ + fprintf(stdout, "> "); + fflush(stdout); + cmdline = fgets(cmdlinebuf, MAXCMD, input); +#endif /* ifdef HAVE_READLINE */ + } else { + cmdline = fgets(cmdlinebuf, MAXCMD, input); + } + isc_app_unblock(); + + if (cmdline != NULL) { + char *tmp = cmdline; + + /* + * Normalize input by removing any eol as readline() + * removes eol but fgets doesn't. + */ + (void)nsu_strsep(&tmp, "\r\n"); + result = do_next_command(cmdline); + } +#ifdef HAVE_READLINE + if (interactive) { + free(cmdline); + } +#endif /* ifdef HAVE_READLINE */ + return (result); +} + +static bool +user_interaction(void) { + uint16_t result = STATUS_MORE; + + ddebug("user_interaction()"); + while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) { + result = get_next_command(); + if (!interactive && result == STATUS_SYNTAX) { + fatal("syntax error"); + } + } + if (result == STATUS_SEND) { + return (true); + } + return (false); +} + +static void +done_update(void) { + isc_event_t *event = global_event; + ddebug("done_update()"); + isc_task_send(global_task, &event); +} + +static void +check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_any_tsig_t tsig; + + result = dns_rdataset_first(rdataset); + check_result(result, "dns_rdataset_first"); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &tsig, NULL); + check_result(result, "dns_rdata_tostruct"); + if (tsig.error != 0) { + if (isc_buffer_remaininglength(b) < 1) { + check_result(ISC_R_NOSPACE, "isc_buffer_" + "remaininglength"); + } + isc_buffer_putstr(b, "(" /*)*/); + result = dns_tsigrcode_totext(tsig.error, b); + check_result(result, "dns_tsigrcode_totext"); + if (isc_buffer_remaininglength(b) < 1) { + check_result(ISC_R_NOSPACE, "isc_buffer_" + "remaininglength"); + } + isc_buffer_putstr(b, /*(*/ ")"); + } +} + +static bool +next_master(const char *caller, isc_sockaddr_t *addr, isc_result_t eresult) { + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); + fprintf(stderr, "; Communication with %s failed: %s\n", addrbuf, + isc_result_totext(eresult)); + if (++master_inuse >= master_total) { + return (false); + } + ddebug("%s: trying next server", caller); + return (true); +} + +static void +update_completed(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = NULL; + isc_result_t result; + dns_request_t *request; + + UNUSED(task); + + ddebug("update_completed()"); + + requests--; + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + + if (shuttingdown) { + dns_request_destroy(&request); + isc_event_free(&event); + maybeshutdown(); + return; + } + + if (reqev->result != ISC_R_SUCCESS) { + if (!next_master("update_completed", + &master_servers[master_inuse], reqev->result)) + { + seenerror = true; + goto done; + } + + ddebug("Destroying request [%p]", request); + dns_request_destroy(&request); + dns_message_renderreset(updatemsg); + dns_message_settsigkey(updatemsg, NULL); + send_update(zname, &master_servers[master_inuse]); + isc_event_free(&event); + return; + } + + LOCK(&answer_lock); + dns_message_create(gmctx, DNS_MESSAGE_INTENTPARSE, &answer); + result = dns_request_getresponse(request, answer, + DNS_MESSAGEPARSE_PRESERVEORDER); + switch (result) { + case ISC_R_SUCCESS: + if (answer->verify_attempted) { + ddebug("tsig verification successful"); + } + break; + case DNS_R_CLOCKSKEW: + case DNS_R_EXPECTEDTSIG: + case DNS_R_TSIGERRORSET: + case DNS_R_TSIGVERIFYFAILURE: + case DNS_R_UNEXPECTEDTSIG: + case ISC_R_FAILURE: +#if 0 + if (usegsstsig && answer->rcode == dns_rcode_noerror) { + /* + * For MS DNS that violates RFC 2845, section 4.2 + */ + break; + } +#endif /* if 0 */ + fprintf(stderr, "; TSIG error with server: %s\n", + isc_result_totext(result)); + seenerror = true; + break; + default: + check_result(result, "dns_request_getresponse"); + } + + if (answer->opcode != dns_opcode_update) { + fatal("invalid OPCODE in response to UPDATE request"); + } + + if (answer->rcode != dns_rcode_noerror) { + seenerror = true; + if (!debugging) { + char buf[64]; + isc_buffer_t b; + dns_rdataset_t *rds; + + isc_buffer_init(&b, buf, sizeof(buf) - 1); + result = dns_rcode_totext(answer->rcode, &b); + check_result(result, "dns_rcode_totext"); + rds = dns_message_gettsig(answer, NULL); + if (rds != NULL) { + check_tsig_error(rds, &b); + } + fprintf(stderr, "update failed: %.*s\n", + (int)isc_buffer_usedlength(&b), buf); + } + } + if (debugging) { + show_message(stderr, answer, "\nReply from update query:"); + } + UNLOCK(&answer_lock); + +done: + dns_request_destroy(&request); + if (usegsstsig) { + dns_name_free(&tmpzonename, gmctx); + dns_name_free(&restart_master, gmctx); + dns_name_init(&tmpzonename, 0); + dns_name_init(&restart_master, 0); + } + isc_event_free(&event); + done_update(); +} + +static void +send_update(dns_name_t *zone, isc_sockaddr_t *master) { + isc_result_t result; + dns_request_t *request = NULL; + unsigned int options = DNS_REQUESTOPT_CASE; + isc_sockaddr_t *srcaddr; + + ddebug("send_update()"); + + setzone(zone); + + if (usevc) { + options |= DNS_REQUESTOPT_TCP; + } + if (tsigkey == NULL && sig0key != NULL) { + result = dns_message_setsig0key(updatemsg, sig0key); + check_result(result, "dns_message_setsig0key"); + } + if (debugging) { + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(master, addrbuf, sizeof(addrbuf)); + fprintf(stderr, "Sending update to %s\n", addrbuf); + } + + if (isc_sockaddr_pf(master) == AF_INET6) { + srcaddr = localaddr6; + } else { + srcaddr = localaddr4; + } + + /* Windows doesn't like the tsig name to be compressed. */ + if (updatemsg->tsigname) { + updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; + } + + result = dns_request_createvia(requestmgr, updatemsg, srcaddr, master, + -1, options, tsigkey, timeout, + udp_timeout, udp_retries, global_task, + update_completed, NULL, &request); + check_result(result, "dns_request_createvia"); + + if (debugging) { + show_message(stdout, updatemsg, "Outgoing update query:"); + } + + requests++; +} + +static void +next_server(const char *caller, isc_sockaddr_t *addr, isc_result_t eresult) { + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); + fprintf(stderr, "; Communication with %s failed: %s\n", addrbuf, + isc_result_totext(eresult)); + if (++ns_inuse >= ns_total) { + fatal("could not reach any name server"); + } else { + ddebug("%s: trying next server", caller); + } +} + +static void +recvsoa(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = NULL; + dns_request_t *request = NULL; + isc_result_t result, eresult; + dns_message_t *rcvmsg = NULL; + dns_section_t section; + dns_name_t *name = NULL; + dns_rdataset_t *soaset = NULL; + dns_rdata_soa_t soa; + dns_rdata_t soarr = DNS_RDATA_INIT; + int pass = 0; + dns_name_t master; + nsu_requestinfo_t *reqinfo; + dns_message_t *soaquery = NULL; + isc_sockaddr_t *addr; + isc_sockaddr_t *srcaddr; + bool seencname = false; + dns_name_t tname; + unsigned int nlabels; + + UNUSED(task); + + ddebug("recvsoa()"); + + requests--; + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + eresult = reqev->result; + reqinfo = reqev->ev_arg; + soaquery = reqinfo->msg; + addr = reqinfo->addr; + + if (shuttingdown) { + dns_request_destroy(&request); + dns_message_detach(&soaquery); + isc_mem_put(gmctx, reqinfo, sizeof(nsu_requestinfo_t)); + isc_event_free(&event); + maybeshutdown(); + return; + } + + if (eresult != ISC_R_SUCCESS) { + next_server("recvsoa", addr, eresult); + ddebug("Destroying request [%p]", request); + dns_request_destroy(&request); + dns_message_renderreset(soaquery); + dns_message_settsigkey(soaquery, NULL); + sendrequest(&servers[ns_inuse], soaquery, &request); + isc_mem_put(gmctx, reqinfo, sizeof(nsu_requestinfo_t)); + isc_event_free(&event); + setzoneclass(dns_rdataclass_none); + return; + } + + isc_mem_put(gmctx, reqinfo, sizeof(nsu_requestinfo_t)); + reqinfo = NULL; + isc_event_free(&event); + reqev = NULL; + + ddebug("About to create rcvmsg"); + dns_message_create(gmctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); + result = dns_request_getresponse(request, rcvmsg, + DNS_MESSAGEPARSE_PRESERVEORDER); + if (result == DNS_R_TSIGERRORSET && servers != NULL) { + dns_message_detach(&rcvmsg); + ddebug("Destroying request [%p]", request); + dns_request_destroy(&request); + reqinfo = isc_mem_get(gmctx, sizeof(nsu_requestinfo_t)); + reqinfo->msg = soaquery; + reqinfo->addr = addr; + dns_message_renderreset(soaquery); + ddebug("retrying soa request without TSIG"); + + if (isc_sockaddr_pf(addr) == AF_INET6) { + srcaddr = localaddr6; + } else { + srcaddr = localaddr4; + } + + result = dns_request_createvia( + requestmgr, soaquery, srcaddr, addr, -1, 0, NULL, + FIND_TIMEOUT * 20, FIND_TIMEOUT, 3, global_task, + recvsoa, reqinfo, &request); + check_result(result, "dns_request_createvia"); + requests++; + return; + } + check_result(result, "dns_request_getresponse"); + + if (rcvmsg->rcode == dns_rcode_refused) { + next_server("recvsoa", addr, DNS_R_REFUSED); + dns_message_detach(&rcvmsg); + dns_request_destroy(&request); + dns_message_renderreset(soaquery); + dns_message_settsigkey(soaquery, NULL); + sendrequest(&servers[ns_inuse], soaquery, &request); + return; + } + + section = DNS_SECTION_ANSWER; + POST(section); + if (debugging) { + show_message(stderr, rcvmsg, "Reply from SOA query:"); + } + + if (rcvmsg->opcode != dns_opcode_query) { + fatal("invalid OPCODE in response to SOA query"); + } + + if (rcvmsg->rcode != dns_rcode_noerror && + rcvmsg->rcode != dns_rcode_nxdomain) + { + fatal("response to SOA query was unsuccessful"); + } + + if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(userzone, namebuf, sizeof(namebuf)); + error("specified zone '%s' does not exist (NXDOMAIN)", namebuf); + dns_message_detach(&rcvmsg); + dns_request_destroy(&request); + dns_message_detach(&soaquery); + ddebug("Out of recvsoa"); + seenerror = true; + done_update(); + return; + } + +lookforsoa: + if (pass == 0) { + section = DNS_SECTION_ANSWER; + } else if (pass == 1) { + section = DNS_SECTION_AUTHORITY; + } else { + goto droplabel; + } + + result = dns_message_firstname(rcvmsg, section); + if (result != ISC_R_SUCCESS) { + pass++; + goto lookforsoa; + } + while (result == ISC_R_SUCCESS) { + name = NULL; + dns_message_currentname(rcvmsg, section, &name); + soaset = NULL; + result = dns_message_findtype(name, dns_rdatatype_soa, 0, + &soaset); + if (result == ISC_R_SUCCESS) { + break; + } + if (section == DNS_SECTION_ANSWER) { + dns_rdataset_t *tset = NULL; + if (dns_message_findtype(name, dns_rdatatype_cname, 0, + &tset) == ISC_R_SUCCESS || + dns_message_findtype(name, dns_rdatatype_dname, 0, + &tset) == ISC_R_SUCCESS) + { + seencname = true; + break; + } + } + + result = dns_message_nextname(rcvmsg, section); + } + + if (soaset == NULL && !seencname) { + pass++; + goto lookforsoa; + } + + if (seencname) { + goto droplabel; + } + + if (debugging) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + fprintf(stderr, "Found zone name: %s\n", namestr); + } + + result = dns_rdataset_first(soaset); + check_result(result, "dns_rdataset_first"); + + dns_rdata_init(&soarr); + dns_rdataset_current(soaset, &soarr); + result = dns_rdata_tostruct(&soarr, &soa, NULL); + check_result(result, "dns_rdata_tostruct"); + + dns_name_init(&master, NULL); + dns_name_clone(&soa.origin, &master); + + if (userzone != NULL) { + zname = userzone; + } else { + /* + * Save the zone name in case we need to try a second + * address. + */ + zname = dns_fixedname_initname(&fzname); + dns_name_copynf(name, zname); + } + + if (debugging) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(&master, namestr, sizeof(namestr)); + fprintf(stderr, "The master is: %s\n", namestr); + } + + if (default_servers) { + char serverstr[DNS_NAME_MAXTEXT + 1]; + isc_buffer_t buf; + size_t size; + + isc_buffer_init(&buf, serverstr, sizeof(serverstr)); + result = dns_name_totext(&master, true, &buf); + check_result(result, "dns_name_totext"); + serverstr[isc_buffer_usedlength(&buf)] = 0; + + if (master_servers != NULL && master_servers != servers) { + isc_mem_put(gmctx, master_servers, + master_alloc * sizeof(isc_sockaddr_t)); + } + master_alloc = MAX_SERVERADDRS; + size = master_alloc * sizeof(isc_sockaddr_t); + master_servers = isc_mem_get(gmctx, size); + + memset(master_servers, 0, size); + master_total = get_addresses(serverstr, dnsport, master_servers, + master_alloc); + if (master_total == 0) { + seenerror = true; + dns_rdata_freestruct(&soa); + dns_message_detach(&soaquery); + dns_request_destroy(&request); + dns_message_detach(&rcvmsg); + ddebug("Out of recvsoa"); + done_update(); + return; + } + master_inuse = 0; + } else { + master_from_servers(); + } + dns_rdata_freestruct(&soa); + +#ifdef GSSAPI + if (usegsstsig) { + dns_name_init(&tmpzonename, NULL); + dns_name_dup(zname, gmctx, &tmpzonename); + dns_name_init(&restart_master, NULL); + dns_name_dup(&master, gmctx, &restart_master); + start_gssrequest(&master); + } else { + send_update(zname, &master_servers[master_inuse]); + setzoneclass(dns_rdataclass_none); + } +#else /* ifdef GSSAPI */ + send_update(zname, &master_servers[master_inuse]); + setzoneclass(dns_rdataclass_none); +#endif /* ifdef GSSAPI */ + + dns_message_detach(&soaquery); + dns_request_destroy(&request); + +out: + dns_message_detach(&rcvmsg); + ddebug("Out of recvsoa"); + return; + +droplabel: + result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); + INSIST(result == ISC_R_SUCCESS); + name = NULL; + dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); + nlabels = dns_name_countlabels(name); + if (nlabels == 1) { + fatal("could not find enclosing zone"); + } + dns_name_init(&tname, NULL); + dns_name_getlabelsequence(name, 1, nlabels - 1, &tname); + dns_name_clone(&tname, name); + dns_request_destroy(&request); + dns_message_renderreset(soaquery); + dns_message_settsigkey(soaquery, NULL); + sendrequest(&servers[ns_inuse], soaquery, &request); + goto out; +} + +static void +sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg, + dns_request_t **request) { + isc_result_t result; + nsu_requestinfo_t *reqinfo; + isc_sockaddr_t *srcaddr; + + reqinfo = isc_mem_get(gmctx, sizeof(nsu_requestinfo_t)); + reqinfo->msg = msg; + reqinfo->addr = destaddr; + + if (isc_sockaddr_pf(destaddr) == AF_INET6) { + srcaddr = localaddr6; + } else { + srcaddr = localaddr4; + } + + result = dns_request_createvia(requestmgr, msg, srcaddr, destaddr, -1, + 0, default_servers ? NULL : tsigkey, + FIND_TIMEOUT * 20, FIND_TIMEOUT, 3, + global_task, recvsoa, reqinfo, request); + check_result(result, "dns_request_createvia"); + requests++; +} + +#ifdef GSSAPI + +/* + * Get the realm from the users kerberos ticket if possible + */ +static void +get_ticket_realm(isc_mem_t *mctx) { + krb5_context ctx; + krb5_error_code rc; + krb5_ccache ccache; + krb5_principal princ; + char *name; + const char *ticket_realm; + + rc = krb5_init_context(&ctx); + if (rc != 0) { + return; + } + + rc = krb5_cc_default(ctx, &ccache); + if (rc != 0) { + krb5_free_context(ctx); + return; + } + + rc = krb5_cc_get_principal(ctx, ccache, &princ); + if (rc != 0) { + krb5_cc_close(ctx, ccache); + krb5_free_context(ctx); + return; + } + + rc = krb5_unparse_name(ctx, princ, &name); + if (rc != 0) { + krb5_free_principal(ctx, princ); + krb5_cc_close(ctx, ccache); + krb5_free_context(ctx); + return; + } + + ticket_realm = strrchr(name, '@'); + if (ticket_realm != NULL) { + realm = isc_mem_strdup(mctx, ticket_realm); + } + + free(name); + krb5_free_principal(ctx, princ); + krb5_cc_close(ctx, ccache); + krb5_free_context(ctx); + if (realm != NULL && debugging) { + fprintf(stderr, "Found realm from ticket: %s\n", realm + 1); + } +} + +static void +failed_gssrequest() { + seenerror = true; + + dns_name_free(&tmpzonename, gmctx); + dns_name_free(&restart_master, gmctx); + dns_name_init(&tmpzonename, NULL); + dns_name_init(&restart_master, NULL); + + done_update(); +} + +static void +start_gssrequest(dns_name_t *master) { + dns_gss_ctx_id_t context; + isc_buffer_t buf; + isc_result_t result; + uint32_t val = 0; + dns_message_t *rmsg = NULL; + dns_request_t *request = NULL; + dns_name_t *servname; + dns_fixedname_t fname; + char namestr[DNS_NAME_FORMATSIZE]; + char mykeystr[DNS_NAME_FORMATSIZE]; + char *err_message = NULL; + + debug("start_gssrequest"); + usevc = true; + + if (gssring != NULL) { + dns_tsigkeyring_detach(&gssring); + } + gssring = NULL; + result = dns_tsigkeyring_create(gmctx, &gssring); + + if (result != ISC_R_SUCCESS) { + fatal("dns_tsigkeyring_create failed: %s", + isc_result_totext(result)); + } + + dns_name_format(master, namestr, sizeof(namestr)); + if (kserver == NULL) { + kserver = isc_mem_get(gmctx, sizeof(isc_sockaddr_t)); + } + + memmove(kserver, &master_servers[master_inuse], sizeof(isc_sockaddr_t)); + + servname = dns_fixedname_initname(&fname); + + if (realm == NULL) { + get_ticket_realm(gmctx); + } + + result = snprintf(servicename, sizeof(servicename), "DNS/%s%s", namestr, + realm ? realm : ""); + RUNTIME_CHECK(result < sizeof(servicename)); + isc_buffer_init(&buf, servicename, strlen(servicename)); + isc_buffer_add(&buf, strlen(servicename)); + result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fatal("dns_name_fromtext(servname) failed: %s", + isc_result_totext(result)); + } + + keyname = dns_fixedname_initname(&fkname); + + isc_nonce_buf(&val, sizeof(val)); + + result = snprintf(mykeystr, sizeof(mykeystr), "%u.sig-%s", val, + namestr); + RUNTIME_CHECK(result <= sizeof(mykeystr)); + + isc_buffer_init(&buf, mykeystr, strlen(mykeystr)); + isc_buffer_add(&buf, strlen(mykeystr)); + + result = dns_name_fromtext(keyname, &buf, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fatal("dns_name_fromtext(keyname) failed: %s", + isc_result_totext(result)); + } + + /* Windows doesn't recognize name compression in the key name. */ + keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS; + + rmsg = NULL; + dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER, &rmsg); + + /* Build first request. */ + context = GSS_C_NO_CONTEXT; + result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0, + &context, use_win2k_gsstsig, gmctx, + &err_message); + if (result == ISC_R_FAILURE) { + fprintf(stderr, "tkey query failed: %s\n", + err_message != NULL ? err_message : "unknown error"); + goto failure; + } + if (result != ISC_R_SUCCESS) { + fatal("dns_tkey_buildgssquery failed: %s", + isc_result_totext(result)); + } + + send_gssrequest(kserver, rmsg, &request, context); + return; + +failure: + if (rmsg != NULL) { + dns_message_detach(&rmsg); + } + if (err_message != NULL) { + isc_mem_free(gmctx, err_message); + } + failed_gssrequest(); +} + +static void +send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg, + dns_request_t **request, dns_gss_ctx_id_t context) { + isc_result_t result; + nsu_gssinfo_t *reqinfo; + unsigned int options = 0; + isc_sockaddr_t *srcaddr; + + debug("send_gssrequest"); + REQUIRE(destaddr != NULL); + + reqinfo = isc_mem_get(gmctx, sizeof(nsu_gssinfo_t)); + reqinfo->msg = msg; + reqinfo->addr = destaddr; + reqinfo->context = context; + + options |= DNS_REQUESTOPT_TCP; + + if (isc_sockaddr_pf(destaddr) == AF_INET6) { + srcaddr = localaddr6; + } else { + srcaddr = localaddr4; + } + + result = dns_request_createvia(requestmgr, msg, srcaddr, destaddr, -1, + options, tsigkey, FIND_TIMEOUT * 20, + FIND_TIMEOUT, 3, global_task, recvgss, + reqinfo, request); + check_result(result, "dns_request_createvia"); + if (debugging) { + show_message(stdout, msg, "Outgoing update query:"); + } + requests++; +} + +static void +recvgss(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = NULL; + dns_request_t *request = NULL; + isc_result_t result, eresult; + dns_message_t *rcvmsg = NULL; + nsu_gssinfo_t *reqinfo; + dns_message_t *tsigquery = NULL; + isc_sockaddr_t *addr; + dns_gss_ctx_id_t context; + isc_buffer_t buf; + dns_name_t *servname; + dns_fixedname_t fname; + char *err_message = NULL; + + UNUSED(task); + + ddebug("recvgss()"); + + requests--; + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + eresult = reqev->result; + reqinfo = reqev->ev_arg; + tsigquery = reqinfo->msg; + context = reqinfo->context; + addr = reqinfo->addr; + + if (shuttingdown) { + dns_request_destroy(&request); + dns_message_detach(&tsigquery); + isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t)); + isc_event_free(&event); + maybeshutdown(); + return; + } + + if (eresult != ISC_R_SUCCESS) { + ddebug("Destroying request [%p]", request); + dns_request_destroy(&request); + if (!next_master("recvgss", addr, eresult)) { + dns_message_detach(&tsigquery); + failed_gssrequest(); + } else { + dns_message_renderreset(tsigquery); + memmove(kserver, &master_servers[master_inuse], + sizeof(isc_sockaddr_t)); + send_gssrequest(kserver, tsigquery, &request, context); + } + isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t)); + isc_event_free(&event); + return; + } + isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t)); + + isc_event_free(&event); + reqev = NULL; + + ddebug("recvgss creating rcvmsg"); + dns_message_create(gmctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); + + result = dns_request_getresponse(request, rcvmsg, + DNS_MESSAGEPARSE_PRESERVEORDER); + check_result(result, "dns_request_getresponse"); + + if (debugging) { + show_message(stderr, rcvmsg, + "recvmsg reply from GSS-TSIG query"); + } + + if (rcvmsg->opcode != dns_opcode_query) { + fatal("invalid OPCODE in response to GSS-TSIG query"); + } + + if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) { + ddebug("recvgss trying %s GSS-TSIG", + use_win2k_gsstsig ? "Standard" : "Win2k"); + if (use_win2k_gsstsig) { + use_win2k_gsstsig = false; + } else { + use_win2k_gsstsig = true; + } + tried_other_gsstsig = true; + start_gssrequest(&restart_master); + goto done; + } + + if (rcvmsg->rcode != dns_rcode_noerror && + rcvmsg->rcode != dns_rcode_nxdomain) + { + fatal("response to GSS-TSIG query was unsuccessful"); + } + + servname = dns_fixedname_initname(&fname); + isc_buffer_init(&buf, servicename, strlen(servicename)); + isc_buffer_add(&buf, strlen(servicename)); + result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL); + check_result(result, "dns_name_fromtext"); + + tsigkey = NULL; + result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname, &context, + &tsigkey, gssring, use_win2k_gsstsig, + &err_message); + switch (result) { + case DNS_R_CONTINUE: + dns_message_detach(&rcvmsg); + dns_request_destroy(&request); + send_gssrequest(kserver, tsigquery, &request, context); + ddebug("Out of recvgss"); + return; + + case ISC_R_SUCCESS: + /* + * XXXSRA Waaay too much fun here. There's no good + * reason why we need a TSIG here (the people who put + * it into the spec admitted at the time that it was + * not a security issue), and Windows clients don't + * seem to work if named complies with the spec and + * includes the gratuitous TSIG. So we're in the + * bizarre situation of having to choose between + * complying with a useless requirement in the spec + * and interoperating. This is nuts. If we can + * confirm this behavior, we should ask the WG to + * consider removing the requirement for the + * gratuitous TSIG here. For the moment, we ignore + * the TSIG -- this too is a spec violation, but it's + * the least insane thing to do. + */ +#if 0 + /* + * Verify the signature. + */ + rcvmsg->state = DNS_SECTION_ANY; + dns_message_setquerytsig(rcvmsg, NULL); + result = dns_message_settsigkey(rcvmsg, tsigkey); + check_result(result, "dns_message_settsigkey"); + result = dns_message_checksig(rcvmsg, NULL); + ddebug("tsig verification: %s", dns_result_totext(result)); + check_result(result, "dns_message_checksig"); +#endif /* 0 */ + + send_update(&tmpzonename, &master_servers[master_inuse]); + setzoneclass(dns_rdataclass_none); + break; + + default: + fatal("dns_tkey_gssnegotiate: %s %s", isc_result_totext(result), + err_message != NULL ? err_message : ""); + } + +done: + dns_request_destroy(&request); + dns_message_detach(&tsigquery); + + dns_message_detach(&rcvmsg); + ddebug("Out of recvgss"); +} +#endif /* ifdef GSSAPI */ + +static void +start_update(void) { + isc_result_t result; + dns_rdataset_t *rdataset = NULL; + dns_name_t *name = NULL; + dns_request_t *request = NULL; + dns_message_t *soaquery = NULL; + dns_name_t *firstname; + dns_section_t section = DNS_SECTION_UPDATE; + + ddebug("start_update()"); + + LOCK(&answer_lock); + if (answer != NULL) { + dns_message_detach(&answer); + } + UNLOCK(&answer_lock); + + /* + * If we have both the zone and the servers we have enough information + * to send the update straight away otherwise we need to discover + * the zone and / or the master server. + */ + if (userzone != NULL && !default_servers && !usegsstsig) { + master_from_servers(); + send_update(userzone, &master_servers[master_inuse]); + setzoneclass(dns_rdataclass_none); + return; + } + + dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER, &soaquery); + + if (default_servers) { + soaquery->flags |= DNS_MESSAGEFLAG_RD; + } + + result = dns_message_gettempname(soaquery, &name); + check_result(result, "dns_message_gettempname"); + + result = dns_message_gettemprdataset(soaquery, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + + dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa); + + if (userzone != NULL) { + dns_name_clone(userzone, name); + } else { + dns_rdataset_t *tmprdataset; + result = dns_message_firstname(updatemsg, section); + if (result == ISC_R_NOMORE) { + section = DNS_SECTION_PREREQUISITE; + result = dns_message_firstname(updatemsg, section); + } + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(soaquery, &name); + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(soaquery, &rdataset); + dns_message_detach(&soaquery); + done_update(); + return; + } + firstname = NULL; + dns_message_currentname(updatemsg, section, &firstname); + dns_name_clone(firstname, name); + /* + * Looks to see if the first name references a DS record + * and if that name is not the root remove a label as DS + * records live in the parent zone so we need to start our + * search one label up. + */ + tmprdataset = ISC_LIST_HEAD(firstname->list); + if (section == DNS_SECTION_UPDATE && + !dns_name_equal(firstname, dns_rootname) && + tmprdataset->type == dns_rdatatype_ds) + { + unsigned int labels = dns_name_countlabels(name); + dns_name_getlabelsequence(name, 1, labels - 1, name); + } + } + + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); + + ns_inuse = 0; + sendrequest(&servers[ns_inuse], soaquery, &request); +} + +static void +cleanup(void) { + ddebug("cleanup()"); + + LOCK(&answer_lock); + if (answer != NULL) { + dns_message_detach(&answer); + } + UNLOCK(&answer_lock); + +#ifdef GSSAPI + if (tsigkey != NULL) { + ddebug("detach tsigkey x%p", tsigkey); + dns_tsigkey_detach(&tsigkey); + } + if (gssring != NULL) { + ddebug("Detaching GSS-TSIG keyring"); + dns_tsigkeyring_detach(&gssring); + } +#endif /* ifdef GSSAPI */ + + if (sig0key != NULL) { + dst_key_free(&sig0key); + } + + ddebug("Shutting down task manager"); + isc_managers_destroy(&netmgr, &taskmgr); + + ddebug("Destroying event"); + isc_event_free(&global_event); + + ddebug("Shutting down socket manager"); + isc_socketmgr_destroy(&socketmgr); + + ddebug("Shutting down timer manager"); + isc_timermgr_destroy(&timermgr); + +#ifdef GSSAPI + /* + * Cleanup GSSAPI resources after taskmgr has been destroyed. + */ + if (kserver != NULL) { + isc_mem_put(gmctx, kserver, sizeof(isc_sockaddr_t)); + kserver = NULL; + } + if (realm != NULL) { + isc_mem_free(gmctx, realm); + realm = NULL; + } + if (dns_name_dynamic(&tmpzonename)) { + dns_name_free(&tmpzonename, gmctx); + } + if (dns_name_dynamic(&restart_master)) { + dns_name_free(&restart_master, gmctx); + } +#endif /* ifdef GSSAPI */ + + ddebug("Removing log context"); + isc_log_destroy(&glctx); + + ddebug("Destroying memory context"); + if (memdebugging) { + isc_mem_stats(gmctx, stderr); + } + isc_mem_destroy(&gmctx); + + isc_mutex_destroy(&answer_lock); +} + +static void +getinput(isc_task_t *task, isc_event_t *event) { + bool more; + + UNUSED(task); + + if (shuttingdown) { + maybeshutdown(); + return; + } + + if (global_event == NULL) { + global_event = event; + } + + reset_system(); + more = user_interaction(); + if (!more) { + isc_app_shutdown(); + return; + } + start_update(); + return; +} + +int +main(int argc, char **argv) { + isc_result_t result; + style = &dns_master_style_debug; + + input = stdin; + + interactive = isatty(0); + + isc_app_start(); + + if (isc_net_probeipv4() == ISC_R_SUCCESS) { + have_ipv4 = true; + } + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + have_ipv6 = true; + } + if (!have_ipv4 && !have_ipv6) { + fatal("could not find either IPv4 or IPv6"); + } + + pre_parse_args(argc, argv); + + isc_mem_create(&gmctx); + + parse_args(argc, argv); + + setup_system(); + + result = isc_app_onrun(gmctx, global_task, getinput, NULL); + check_result(result, "isc_app_onrun"); + + (void)isc_app_run(); + + cleanup(); + + isc_app_finish(); + + if (seenerror) { + return (2); + } else { + return (0); + } +} diff --git a/bin/nsupdate/nsupdate.rst b/bin/nsupdate/nsupdate.rst new file mode 100644 index 0000000..aad9b02 --- /dev/null +++ b/bin/nsupdate/nsupdate.rst @@ -0,0 +1,357 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_nsupdate: + +nsupdate - dynamic DNS update utility +------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`nsupdate` [**-d**] [**-D**] [**-i**] [**-L** level] [ [**-g**] | [**-o**] | [**-l**] | [**-y** [hmac:]keyname:secret] | [**-k** keyfile] ] [**-t** timeout] [**-u** udptimeout] [**-r** udpretries] [**-v**] [**-T**] [**-P**] [**-V**] [ [**-4**] | [**-6**] ] [filename] + +Description +~~~~~~~~~~~ + +``nsupdate`` is used to submit Dynamic DNS Update requests, as defined in +:rfc:`2136`, to a name server. This allows resource records to be added or +removed from a zone without manually editing the zone file. A single +update request can contain requests to add or remove more than one +resource record. + +Zones that are under dynamic control via ``nsupdate`` or a DHCP server +should not be edited by hand. Manual edits could conflict with dynamic +updates and cause data to be lost. + +The resource records that are dynamically added or removed with +``nsupdate`` must be in the same zone. Requests are sent to the +zone's primary server, which is identified by the MNAME field of the +zone's SOA record. + +Transaction signatures can be used to authenticate the Dynamic DNS +updates. These use the TSIG resource record type described in :rfc:`2845`, +the SIG(0) record described in :rfc:`2535` and :rfc:`2931`, or GSS-TSIG as +described in :rfc:`3645`. + +TSIG relies on a shared secret that should only be known to ``nsupdate`` +and the name server. For instance, suitable ``key`` and ``server`` +statements are added to ``/etc/named.conf`` so that the name server +can associate the appropriate secret key and algorithm with the IP +address of the client application that is using TSIG +authentication. ``ddns-confgen`` can generate suitable +configuration fragments. ``nsupdate`` uses the ``-y`` or ``-k`` options +to provide the TSIG shared secret; these options are mutually exclusive. + +SIG(0) uses public key cryptography. To use a SIG(0) key, the public key +must be stored in a KEY record in a zone served by the name server. + +GSS-TSIG uses Kerberos credentials. Standard GSS-TSIG mode is switched +on with the ``-g`` flag. A non-standards-compliant variant of GSS-TSIG +used by Windows 2000 can be switched on with the ``-o`` flag. + +Options +~~~~~~~ + +``-4`` + This option sets use of IPv4 only. + +``-6`` + This option sets use of IPv6 only. + +``-d`` + This option sets debug mode, which provides tracing information about the update + requests that are made and the replies received from the name server. + +``-D`` + This option sets extra debug mode. + +``-i`` + This option forces interactive mode, even when standard input is not a terminal. + +``-k keyfile`` + This option indicates the file containing the TSIG authentication key. Keyfiles may be in + two formats: a single file containing a ``named.conf``-format ``key`` + statement, which may be generated automatically by ``ddns-confgen``; + or a pair of files whose names are of the format + ``K{name}.+157.+{random}.key`` and + ``K{name}.+157.+{random}.private``, which can be generated by + ``dnssec-keygen``. The ``-k`` option can also be used to specify a SIG(0) + key used to authenticate Dynamic DNS update requests. In this case, + the key specified is not an HMAC-MD5 key. + +``-l`` + This option sets local-host only mode, which sets the server address to localhost + (disabling the ``server`` so that the server address cannot be + overridden). Connections to the local server use a TSIG key + found in ``/var/run/named/session.key``, which is automatically + generated by ``named`` if any local ``primary`` zone has set + ``update-policy`` to ``local``. The location of this key file can be + overridden with the ``-k`` option. + +``-L level`` + This option sets the logging debug level. If zero, logging is disabled. + +``-p port`` + This option sets the port to use for connections to a name server. The default is + 53. + +``-P`` + This option prints the list of private BIND-specific resource record types whose + format is understood by ``nsupdate``. See also the ``-T`` option. + +``-r udpretries`` + This option sets the number of UDP retries. The default is 3. If zero, only one update + request is made. + +``-t timeout`` + This option sets the maximum time an update request can take before it is aborted. The + default is 300 seconds. If zero, the timeout is disabled. + +``-T`` + This option prints the list of IANA standard resource record types whose format is + understood by ``nsupdate``. ``nsupdate`` exits after the lists + are printed. The ``-T`` option can be combined with the ``-P`` + option. + + Other types can be entered using ``TYPEXXXXX`` where ``XXXXX`` is the + decimal value of the type with no leading zeros. The rdata, if + present, is parsed using the UNKNOWN rdata format, ( + ). + +``-u udptimeout`` + This option sets the UDP retry interval. The default is 3 seconds. If zero, the + interval is computed from the timeout interval and number of UDP + retries. + +``-v`` + This option specifies that TCP should be used even for small update requests. By default, ``nsupdate`` uses + UDP to send update requests to the name server unless they are too + large to fit in a UDP request, in which case TCP is used. TCP may + be preferable when a batch of update requests is made. + +``-V`` + This option prints the version number and exits. + +``-y [hmac:]keyname:secret`` + This option sets the literal TSIG authentication key. ``keyname`` is the name of the key, + and ``secret`` is the base64 encoded shared secret. ``hmac`` is the + name of the key algorithm; valid choices are ``hmac-md5``, + ``hmac-sha1``, ``hmac-sha224``, ``hmac-sha256``, ``hmac-sha384``, or + ``hmac-sha512``. If ``hmac`` is not specified, the default is + ``hmac-md5``, or if MD5 was disabled, ``hmac-sha256``. + + NOTE: Use of the ``-y`` option is discouraged because the shared + secret is supplied as a command-line argument in clear text. This may + be visible in the output from ps1 or in a history file maintained by + the user's shell. + +Input Format +~~~~~~~~~~~~ + +``nsupdate`` reads input from ``filename`` or standard input. Each +command is supplied on exactly one line of input. Some commands are for +administrative purposes; others are either update instructions or +prerequisite checks on the contents of the zone. These checks set +conditions that some name or set of resource records (RRset) either +exists or is absent from the zone. These conditions must be met if the +entire update request is to succeed. Updates are rejected if the +tests for the prerequisite conditions fail. + +Every update request consists of zero or more prerequisites and zero or +more updates. This allows a suitably authenticated update request to +proceed if some specified resource records are either present or missing from +the zone. A blank input line (or the ``send`` command) causes the +accumulated commands to be sent as one Dynamic DNS update request to the +name server. + +The command formats and their meanings are as follows: + +``server servername port`` + This command sends all dynamic update requests to the name server ``servername``. + When no server statement is provided, ``nsupdate`` sends updates + to the primary server of the correct zone. The MNAME field of that + zone's SOA record identify the primary server for that zone. + ``port`` is the port number on ``servername`` where the dynamic + update requests are sent. If no port number is specified, the default + DNS port number of 53 is used. + + .. note:: This command has no effect when GSS-TSIG is in use. + +``local address port`` + This command sends all dynamic update requests using the local ``address``. When + no local statement is provided, ``nsupdate`` sends updates using + an address and port chosen by the system. ``port`` can also + be used to force requests to come from a specific port. If no port number + is specified, the system assigns one. + +``zone zonename`` + This command specifies that all updates are to be made to the zone ``zonename``. + If no ``zone`` statement is provided, ``nsupdate`` attempts to + determine the correct zone to update based on the rest of the input. + +``class classname`` + This command specifies the default class. If no ``class`` is specified, the default + class is ``IN``. + +``ttl seconds`` + This command specifies the default time-to-live, in seconds, for records to be added. The value + ``none`` clears the default TTL. + +``key hmac:keyname secret`` + This command specifies that all updates are to be TSIG-signed using the + ``keyname``-``secret`` pair. If ``hmac`` is specified, it sets + the signing algorithm in use. The default is ``hmac-md5``; if MD5 + was disabled, the default is ``hmac-sha256``. The ``key`` command overrides any key + specified on the command line via ``-y`` or ``-k``. + +``gsstsig`` + This command uses GSS-TSIG to sign the updates. This is equivalent to specifying + ``-g`` on the command line. + +``oldgsstsig`` + This command uses the Windows 2000 version of GSS-TSIG to sign the updates. This is + equivalent to specifying ``-o`` on the command line. + +``realm [realm_name]`` + When using GSS-TSIG, this command specifies the use of ``realm_name`` rather than the default realm + in ``krb5.conf``. If no realm is specified, the saved realm is + cleared. + +``check-names [yes_or_no]`` + This command turns on or off check-names processing on records to be added. + Check-names has no effect on prerequisites or records to be deleted. + By default check-names processing is on. If check-names processing + fails, the record is not added to the UPDATE message. + +``prereq nxdomain domain-name`` + This command requires that no resource record of any type exist with the name + ``domain-name``. + +``prereq yxdomain domain-name`` + This command requires that ``domain-name`` exist (as at least one resource + record, of any type). + +``prereq nxrrset domain-name class type`` + This command requires that no resource record exist of the specified ``type``, + ``class``, and ``domain-name``. If ``class`` is omitted, IN (Internet) + is assumed. + +``prereq yxrrset domain-name class type`` + This command requires that a resource record of the specified ``type``, + ``class`` and ``domain-name`` exist. If ``class`` is omitted, IN + (internet) is assumed. + +``prereq yxrrset domain-name class type data`` + With this command, the ``data`` from each set of prerequisites of this form sharing a + common ``type``, ``class``, and ``domain-name`` are combined to form + a set of RRs. This set of RRs must exactly match the set of RRs + existing in the zone at the given ``type``, ``class``, and + ``domain-name``. The ``data`` are written in the standard text + representation of the resource record's RDATA. + +``update delete domain-name ttl class type data`` + This command deletes any resource records named ``domain-name``. If ``type`` and + ``data`` are provided, only matching resource records are removed. + The Internet class is assumed if ``class`` is not supplied. The + ``ttl`` is ignored, and is only allowed for compatibility. + +``update add domain-name ttl class type data`` + This command adds a new resource record with the specified ``ttl``, ``class``, and + ``data``. + +``show`` + This command displays the current message, containing all of the prerequisites and + updates specified since the last send. + +``send`` + This command sends the current message. This is equivalent to entering a blank + line. + +``answer`` + This command displays the answer. + +``debug`` + This command turns on debugging. + +``version`` + This command prints the version number. + +``help`` + This command prints a list of commands. + +Lines beginning with a semicolon (;) are comments and are ignored. + +Examples +~~~~~~~~ + +The examples below show how ``nsupdate`` can be used to insert and +delete resource records from the ``example.com`` zone. Notice that the +input in each example contains a trailing blank line, so that a group of +commands is sent as one dynamic update request to the primary name +server for ``example.com``. + +:: + + # nsupdate + > update delete oldhost.example.com A + > update add newhost.example.com 86400 A 172.16.1.1 + > send + +Any A records for ``oldhost.example.com`` are deleted, and an A record +for ``newhost.example.com`` with IP address 172.16.1.1 is added. The +newly added record has a TTL of 1 day (86400 seconds). + +:: + + # nsupdate + > prereq nxdomain nickname.example.com + > update add nickname.example.com 86400 CNAME somehost.example.com + > send + +The prerequisite condition tells the name server to verify that there are +no resource records of any type for ``nickname.example.com``. If there +are, the update request fails. If this name does not exist, a CNAME for +it is added. This ensures that when the CNAME is added, it cannot +conflict with the long-standing rule in :rfc:`1034` that a name must not +exist as any other record type if it exists as a CNAME. (The rule has +been updated for DNSSEC in :rfc:`2535` to allow CNAMEs to have RRSIG, +DNSKEY, and NSEC records.) + +Files +~~~~~ + +``/etc/resolv.conf`` + Used to identify the default name server + +``/var/run/named/session.key`` + Sets the default TSIG key for use in local-only mode + +``K{name}.+157.+{random}.key`` + Base-64 encoding of the HMAC-MD5 key created by ``dnssec-keygen``. + +``K{name}.+157.+{random}.private`` + Base-64 encoding of the HMAC-MD5 key created by ``dnssec-keygen``. + +See Also +~~~~~~~~ + +:rfc:`2136`, :rfc:`3007`, :rfc:`2104`, :rfc:`2845`, :rfc:`1034`, :rfc:`2535`, :rfc:`2931`, +:manpage:`named(8)`, :manpage:`ddns-confgen(8)`, :manpage:`dnssec-keygen(8)`. + +Bugs +~~~~ + +The TSIG key is redundantly stored in two separate files. This is a +consequence of ``nsupdate`` using the DST library for its cryptographic +operations, and may change in future releases. diff --git a/bin/nsupdate/win32/nsupdate.vcxproj.filters.in b/bin/nsupdate/win32/nsupdate.vcxproj.filters.in new file mode 100644 index 0000000..477847e --- /dev/null +++ b/bin/nsupdate/win32/nsupdate.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/nsupdate/win32/nsupdate.vcxproj.in b/bin/nsupdate/win32/nsupdate.vcxproj.in new file mode 100644 index 0000000..572d939 --- /dev/null +++ b/bin/nsupdate/win32/nsupdate.vcxproj.in @@ -0,0 +1,119 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {C41266C7-E27E-4D60-9815-82D3B32BF82F} + Win32Proj + nsupdate + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;@USE_GSSAPI@USE_READLINE_STATIC;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\include;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@GSSAPI_INC@@READLINE_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\irs\include;..\..\..\lib\irs\win32\include;..\..\..\lib\bind9\include;..\..\..\lib\isccfg\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@READLINE_LIBD@@GSSAPI_LIB@@KRB5_LIB@libisc.lib;libdns.lib;libbind9.lib;libisccfg.lib;libirs.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;@USE_GSSAPI@USE_READLINE_STATIC;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\include;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@GSSAPI_INC@@READLINE_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\irs\include;..\..\..\lib\irs\win32\include;..\..\..\lib\bind9\include;..\..\..\lib\isccfg\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\irs\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@READLINE_LIB@@GSSAPI_LIB@@KRB5_LIB@libisc.lib;libdns.lib;libbind9.lib;libisccfg.lib;libirs.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/nsupdate/win32/nsupdate.vcxproj.user b/bin/nsupdate/win32/nsupdate.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/nsupdate/win32/nsupdate.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/pkcs11/Makefile.in b/bin/pkcs11/Makefile.in new file mode 100644 index 0000000..ad0da42 --- /dev/null +++ b/bin/pkcs11/Makefile.in @@ -0,0 +1,82 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = ${ISC_INCLUDES} + +CDEFINES = + +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ + +ISCDEPLIBS = ../../lib/isc/libisc.@A@ + +DEPLIBS = ${ISCDEPLIBS} + +# if FORCE_STATIC_PROVIDER: LIBS += ${PROVIDER} +LIBS = ${ISCLIBS} @LIBS@ + +SUBDIRS = benchmarks + +TARGETS = pkcs11-list@EXEEXT@ pkcs11-destroy@EXEEXT@ \ + pkcs11-keygen@EXEEXT@ pkcs11-tokens@EXEEXT@ +SRCS = pkcs11-list.c pkcs11-destroy.c \ + pkcs11-keygen.c pkcs11-tokens.c +OBJS = pkcs11-list.@O@ pkcs11-destroy.@O@ \ + pkcs11-keygen.@O@ pkcs11-tokens.@O@ + +@BIND9_MAKE_RULES@ + +pkcs11-list@EXEEXT@: pkcs11-list.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ pkcs11-list.@O@ ${LIBS} + +pkcs11-destroy@EXEEXT@: pkcs11-destroy.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ pkcs11-destroy.@O@ ${LIBS} + +pkcs11-keygen@EXEEXT@: pkcs11-keygen.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ pkcs11-keygen.@O@ ${LIBS} + +pkcs11-tokens@EXEEXT@: pkcs11-tokens.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ pkcs11-tokens.@O@ ${LIBS} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} + +install:: ${TARGETS} installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-list@EXEEXT@ \ + ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-destroy@EXEEXT@ \ + ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-keygen@EXEEXT@ \ + ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-tokens@EXEEXT@ \ + ${DESTDIR}${sbindir} + +uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f / + ${DESTDIR}${sbindir}/pkcs11-tokens@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f / + ${DESTDIR}${sbindir}/pkcs11-keygen@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f / + ${DESTDIR}${sbindir}/pkcs11-destroy@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f / + ${DESTDIR}${sbindir}/pkcs11-list@EXEEXT@ + +clean distclean:: + rm -f ${OBJS} ${TARGETS} diff --git a/bin/pkcs11/pkcs11-destroy.c b/bin/pkcs11/pkcs11-destroy.c new file mode 100644 index 0000000..04f9682 --- /dev/null +++ b/bin/pkcs11/pkcs11-destroy.c @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2009, 2015 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * pkcs11-destroy [-m module] [-s $slot] [-i $id | -l $label] + * [-p $pin] [ -w $wait ] + */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#ifdef WIN32 +#define sleep(x) Sleep(x) +#endif /* ifdef WIN32 */ + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession; + CK_BYTE attr_id[2]; + CK_OBJECT_HANDLE akey[50]; + pk11_context_t pctx; + char *lib_name = NULL; + char *label = NULL; + char *pin = NULL; + int error = 0; + unsigned int id = 0, i = 0, wait = 5; + int c, errflg = 0; + CK_ULONG ulObjectCount; + CK_ATTRIBUTE search_template[] = { { CKA_ID, &attr_id, + sizeof(attr_id) } }; + unsigned int j, len; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:i:l:p:w:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + break; + case 'i': + id = atoi(isc_commandline_argument); + id &= 0xffff; + break; + case 'l': + label = isc_commandline_argument; + break; + case 'p': + pin = isc_commandline_argument; + break; + case 'w': + wait = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg || (id && (label != NULL))) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tpkcs11-destroy [-m module] [-s slot] " + "{-i id | -l label} [-p pin] [-w waittime]\n"); + exit(1); + } + + if (id) { + attr_id[0] = (id >> 8) & 0xff; + attr_id[1] = id & 0xff; + } else if (label) { + search_template[0].type = CKA_LABEL; + search_template[0].pValue = label; + search_template[0].ulValueLen = strlen(label); + } + + pk11_result_register(); + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, OP_ANY, false, true, true, + (const char *)pin, slot); + if (result == PK11_R_NORANDOMSERVICE || + result == PK11_R_NODIGESTSERVICE || result == PK11_R_NOAESSERVICE) + { + fprintf(stderr, "Warning: %s\n", isc_result_totext(result)); + fprintf(stderr, "This HSM will not work with BIND 9 " + "using native PKCS#11.\n"); + } else if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "Unrecoverable error initializing " + "PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + memset(pin, 0, strlen(pin)); + + hSession = pctx.session; + + rv = pkcs_C_FindObjectsInit(hSession, search_template, + ((id != 0) || (label != NULL)) ? 1 : 0); + + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv); + error = 1; + goto exit_session; + } + + rv = pkcs_C_FindObjects(hSession, akey, 50, &ulObjectCount); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv); + error = 1; + goto exit_search; + } + + if (ulObjectCount == 0) { + printf("No matching key objects found.\n"); + goto exit_search; + } else { + printf("Key object%s found:\n", ulObjectCount > 1 ? "s" : ""); + } + + for (i = 0; i < ulObjectCount; i++) { + CK_OBJECT_CLASS oclass = 0; + CK_BYTE labelbuf[64 + 1]; + CK_BYTE idbuf[64]; + CK_ATTRIBUTE attr_template[] = { + { CKA_CLASS, &oclass, sizeof(oclass) }, + { CKA_LABEL, labelbuf, sizeof(labelbuf) - 1 }, + { CKA_ID, idbuf, sizeof(idbuf) } + }; + + memset(labelbuf, 0, sizeof(labelbuf)); + memset(idbuf, 0, sizeof(idbuf)); + + rv = pkcs_C_GetAttributeValue(hSession, akey[i], attr_template, + 3); + if (rv != CKR_OK) { + fprintf(stderr, + "C_GetAttributeValue[%u]: rv = 0x%.8lX\n", i, + rv); + error = 1; + goto exit_search; + } + len = attr_template[2].ulValueLen; + printf(" object[%u]: class %lu, label '%s', id[%lu] ", i, + oclass, labelbuf, attr_template[2].ulValueLen); + if (len > 4) { + len = 4; + } + if (len > 0) { + printf("0x"); + } + for (j = 0; j < len; j++) { + printf("%02x", idbuf[j]); + } + if (attr_template[2].ulValueLen > len) { + printf("...\n"); + } else { + printf("\n"); + } + } + + if (wait != 0) { + printf("WARNING: This action is irreversible! " + "Destroying key objects in %u seconds\n ", + wait); + for (i = 0; i < wait; i++) { + printf("."); + fflush(stdout); + sleep(1); + } + printf("\n"); + } + + for (i = 0; i < ulObjectCount; i++) { + rv = pkcs_C_DestroyObject(hSession, akey[i]); + if (rv != CKR_OK) { + fprintf(stderr, + "C_DestroyObject[%u] failed: rv = 0x%.8lX\n", i, + rv); + error = 1; + } + } + + if (error == 0) { + printf("Destruction complete.\n"); + } + +exit_search: + rv = pkcs_C_FindObjectsFinal(hSession); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv); + error = 1; + } + +exit_session: + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/pkcs11/pkcs11-destroy.rst b/bin/pkcs11/pkcs11-destroy.rst new file mode 100644 index 0000000..bad150c --- /dev/null +++ b/bin/pkcs11/pkcs11-destroy.rst @@ -0,0 +1,61 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_pkcs11-destroy: + +pkcs11-destroy - destroy PKCS#11 objects + +Synopsis +~~~~~~~~ + +:program:`pkcs11-destroy` [**-m** module] [**-s** slot] [**-i** ID] [**-l** label] [**-p** PIN] [**-w** seconds] + +Description +~~~~~~~~~~~ + +``pkcs11-destroy`` destroys keys stored in a PKCS#11 device, identified +by their ``ID`` or ``label``. + +Matching keys are displayed before being destroyed. By default, there is +a five-second delay to allow the user to interrupt the process before +the destruction takes place. + +Options +~~~~~~~ + +``-m module`` + This option specifies the PKCS#11 provider module. This must be the full path to a + shared library object implementing the PKCS#11 API for the device. + +``-s slot`` + This option opens the session with the given PKCS#11 slot. The default is slot 0. + +``-i ID`` + This option destroys keys with the given object ID. + +``-l label`` + This option destroys keys with the given label. + +``-p PIN`` + This option specifies the ``PIN`` for the device. If no ``PIN`` is provided on the command + line, ``pkcs11-destroy`` prompts for it. + +``-w seconds`` + This option specifies how long, in seconds, to pause before carrying out key destruction. The + default is 5 seconds. If set to ``0``, destruction is + immediate. + +See Also +~~~~~~~~ + +:manpage:`pkcs11-keygen(8)`, :manpage:`pkcs11-list(8)`, :manpage:`pkcs11-tokens(8)` diff --git a/bin/pkcs11/pkcs11-keygen.c b/bin/pkcs11/pkcs11-keygen.c new file mode 100644 index 0000000..e1859b2 --- /dev/null +++ b/bin/pkcs11/pkcs11-keygen.c @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2009, 2012, 2015 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* pkcs11-keygen - PKCS#11 key generator + * + * Create a key in the keystore of an HSM + * + * The calculation of key tag is left to the script + * that converts the key into a DNSKEY RR and inserts + * it into a zone file. + * + * usage: + * pkcs11-keygen [-P] [-m module] [-s slot] [-e] [-b keysize] + * [-i id] [-p pin] -l label + * + */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Define static key template values */ +static CK_BBOOL truevalue = TRUE; +static CK_BBOOL falsevalue = FALSE; + +/* Static arrays of data used for key template initialization */ +static CK_BYTE pk11_ecc_prime256v1[] = PK11_ECC_PRIME256V1; +static CK_BYTE pk11_ecc_secp384r1[] = PK11_ECC_SECP384R1; +static CK_BYTE pk11_ecx_ed25519[] = PK11_ECX_ED25519; +static CK_BYTE pk11_ecx_ed448[] = PK11_ECX_ED448; + +/* Key class: RSA, ECC, ECX, or unknown */ +typedef enum { key_unknown, key_rsa, key_ecc, key_ecx } key_class_t; + +/* + * Private key template + */ +#define PRIVATE_LABEL 0 +#define PRIVATE_SIGN 1 +#define PRIVATE_TOKEN 2 +#define PRIVATE_PRIVATE 3 +#define PRIVATE_SENSITIVE 4 +#define PRIVATE_EXTRACTABLE 5 +#define PRIVATE_ID 6 +#define PRIVATE_ATTRS 7 +static CK_ATTRIBUTE private_template[] = { + { CKA_LABEL, NULL_PTR, 0 }, + { CKA_SIGN, &truevalue, sizeof(truevalue) }, + { CKA_TOKEN, &truevalue, sizeof(truevalue) }, + { CKA_PRIVATE, &truevalue, sizeof(truevalue) }, + { CKA_SENSITIVE, &truevalue, sizeof(truevalue) }, + { CKA_EXTRACTABLE, &falsevalue, sizeof(falsevalue) }, + { CKA_ID, NULL_PTR, 0 } +}; + +/* + * Public key template for RSA keys + */ +#define RSA_LABEL 0 +#define RSA_VERIFY 1 +#define RSA_TOKEN 2 +#define RSA_PRIVATE 3 +#define RSA_MODULUS_BITS 4 +#define RSA_PUBLIC_EXPONENT 5 +#define RSA_ID 6 +#define RSA_ATTRS 7 +static CK_ATTRIBUTE rsa_template[] = { + { CKA_LABEL, NULL_PTR, 0 }, + { CKA_VERIFY, &truevalue, sizeof(truevalue) }, + { CKA_TOKEN, &truevalue, sizeof(truevalue) }, + { CKA_PRIVATE, &falsevalue, sizeof(falsevalue) }, + { CKA_MODULUS_BITS, NULL_PTR, 0 }, + { CKA_PUBLIC_EXPONENT, NULL_PTR, 0 }, + { CKA_ID, NULL_PTR, 0 } +}; + +/* + * Public key template for ECC/ECX keys + */ +#define ECC_LABEL 0 +#define ECC_VERIFY 1 +#define ECC_TOKEN 2 +#define ECC_PRIVATE 3 +#define ECC_PARAMS 4 +#define ECC_ID 5 +#define ECC_ATTRS 6 +static CK_ATTRIBUTE ecc_template[] = { + { CKA_LABEL, NULL_PTR, 0 }, + { CKA_VERIFY, &truevalue, sizeof(truevalue) }, + { CKA_TOKEN, &truevalue, sizeof(truevalue) }, + { CKA_PRIVATE, &falsevalue, sizeof(falsevalue) }, + { CKA_EC_PARAMS, NULL_PTR, 0 }, + { CKA_ID, NULL_PTR, 0 } +}; + +/* + * Convert from text to key class. Accepts the names of DNSSEC + * signing algorithms, so e.g., ECDSAP256SHA256 maps to ECC and + * NSEC3RSASHA1 maps to RSA. + */ +static key_class_t +keyclass_fromtext(const char *name) { + if (name == NULL) { + return (key_unknown); + } + + if (strncasecmp(name, "rsa", 3) == 0 || + strncasecmp(name, "nsec3rsa", 8) == 0) + { + return (key_rsa); + } else if (strncasecmp(name, "ecc", 3) == 0 || + strncasecmp(name, "ecdsa", 5) == 0) + { + return (key_ecc); + } else if (strncasecmp(name, "ecx", 3) == 0 || + strncasecmp(name, "ed", 2) == 0) + { + return (key_ecx); + } else { + return (key_unknown); + } +} + +static void +usage(void) { + fprintf(stderr, "Usage:\n" + "\tpkcs11-keygen -a algorithm -b keysize -l label\n" + "\t [-P] [-m module] " + "[-s slot] [-e] [-S] [-i id] [-p PIN]\n"); + exit(2); +} + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_MECHANISM mech; + CK_SESSION_HANDLE hSession; + char *lib_name = NULL; + char *pin = NULL; + CK_ULONG bits = 0; + CK_CHAR *label = NULL; + CK_OBJECT_HANDLE privatekey, publickey; + CK_BYTE exponent[5]; + CK_ULONG expsize = 0; + pk11_context_t pctx; + int error = 0; + int c, errflg = 0; + int hide = 1, quiet = 0; + int idlen = 0, id_offset = 0; + unsigned long id = 0; + CK_BYTE idbuf[4]; + CK_ULONG ulObjectCount; + CK_ATTRIBUTE search_template[] = { { CKA_LABEL, NULL_PTR, 0 } }; + CK_ATTRIBUTE *public_template = NULL; + CK_ULONG public_attrcnt = 0, private_attrcnt = PRIVATE_ATTRS; + key_class_t keyclass = key_rsa; + pk11_optype_t op_type = OP_ANY; + +#define OPTIONS ":a:b:ei:l:m:Pp:qSs:" + while ((c = isc_commandline_parse(argc, argv, OPTIONS)) != -1) { + switch (c) { + case 'a': + keyclass = keyclass_fromtext(isc_commandline_argument); + break; + case 'P': + hide = 0; + break; + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + break; + case 'e': + expsize = 5; + break; + case 'b': + bits = atoi(isc_commandline_argument); + break; + case 'l': + /* -l option is retained for backward compatibility * */ + label = (CK_CHAR *)isc_commandline_argument; + break; + case 'i': + id = strtoul(isc_commandline_argument, NULL, 0); + idlen = 4; + break; + case 'p': + pin = isc_commandline_argument; + break; + case 'q': + quiet = 1; + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (label == NULL && isc_commandline_index < argc) { + label = (CK_CHAR *)argv[isc_commandline_index]; + } + + if (errflg || (label == NULL)) { + usage(); + } + + if (expsize != 0 && keyclass != key_rsa) { + fprintf(stderr, "The -e option is only compatible " + "with RSA key generation\n"); + exit(2); + } + + switch (keyclass) { + case key_rsa: + op_type = OP_RSA; + if (expsize == 0) { + expsize = 3; + } + if (bits == 0) { + usage(); + } + + mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + public_template = rsa_template; + public_attrcnt = RSA_ATTRS; + id_offset = RSA_ID; + + /* Set public exponent to F4 or F5 */ + exponent[0] = 0x01; + exponent[1] = 0x00; + if (expsize == 3) { + exponent[2] = 0x01; + } else { + exponent[2] = 0x00; + exponent[3] = 0x00; + exponent[4] = 0x01; + } + + public_template[RSA_MODULUS_BITS].pValue = &bits; + public_template[RSA_MODULUS_BITS].ulValueLen = sizeof(bits); + public_template[RSA_PUBLIC_EXPONENT].pValue = &exponent; + public_template[RSA_PUBLIC_EXPONENT].ulValueLen = expsize; + break; + case key_ecc: + op_type = OP_ECDSA; + if (bits == 0) { + bits = 256; + } else if (bits != 256 && bits != 384) { + fprintf(stderr, "ECC keys only support bit sizes of " + "256 and 384\n"); + exit(2); + } + + mech.mechanism = CKM_EC_KEY_PAIR_GEN; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + public_template = ecc_template; + public_attrcnt = ECC_ATTRS; + id_offset = ECC_ID; + + if (bits == 256) { + public_template[4].pValue = pk11_ecc_prime256v1; + public_template[4].ulValueLen = + sizeof(pk11_ecc_prime256v1); + } else { + public_template[4].pValue = pk11_ecc_secp384r1; + public_template[4].ulValueLen = + sizeof(pk11_ecc_secp384r1); + } + + break; + case key_ecx: + op_type = OP_EDDSA; + if (bits == 0) { + bits = 256; + } else if (bits != 256 && bits != 456) { + fprintf(stderr, "ECX keys only support bit sizes of " + "256 and 456\n"); + exit(2); + } + + mech.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + public_template = ecc_template; + public_attrcnt = ECC_ATTRS; + id_offset = ECC_ID; + + if (bits == 256) { + public_template[4].pValue = pk11_ecx_ed25519; + public_template[4].ulValueLen = + sizeof(pk11_ecx_ed25519); + } else { + public_template[4].pValue = pk11_ecx_ed448; + public_template[4].ulValueLen = sizeof(pk11_ecx_ed448); + } + + break; + case key_unknown: + usage(); + } + + search_template[0].pValue = label; + search_template[0].ulValueLen = strlen((char *)label); + public_template[0].pValue = label; + public_template[0].ulValueLen = strlen((char *)label); + private_template[0].pValue = label; + private_template[0].ulValueLen = strlen((char *)label); + + if (idlen == 0) { + public_attrcnt--; + private_attrcnt--; + } else { + if (id <= 0xffff) { + idlen = 2; + idbuf[0] = (CK_BYTE)(id >> 8); + idbuf[1] = (CK_BYTE)id; + } else { + idbuf[0] = (CK_BYTE)(id >> 24); + idbuf[1] = (CK_BYTE)(id >> 16); + idbuf[2] = (CK_BYTE)(id >> 8); + idbuf[3] = (CK_BYTE)id; + } + + public_template[id_offset].pValue = idbuf; + public_template[id_offset].ulValueLen = idlen; + private_template[PRIVATE_ID].pValue = idbuf; + private_template[PRIVATE_ID].ulValueLen = idlen; + } + + pk11_result_register(); + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, op_type, false, true, true, + (const char *)pin, slot); + if (result == PK11_R_NORANDOMSERVICE || + result == PK11_R_NODIGESTSERVICE || result == PK11_R_NOAESSERVICE) + { + fprintf(stderr, "Warning: %s\n", isc_result_totext(result)); + fprintf(stderr, "This HSM will not work with BIND 9 " + "using native PKCS#11.\n"); + } else if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "Unrecoverable error initializing " + "PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + memset(pin, 0, strlen(pin)); + + hSession = pctx.session; + + /* check if a key with the same id already exists */ + rv = pkcs_C_FindObjectsInit(hSession, search_template, 1); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv); + error = 1; + goto exit_session; + } + rv = pkcs_C_FindObjects(hSession, &privatekey, 1, &ulObjectCount); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv); + error = 1; + goto exit_search; + } + if (ulObjectCount != 0) { + fprintf(stderr, "Key already exists.\n"); + error = 1; + goto exit_search; + } + + /* Set attributes if the key is not to be hidden */ + if (!hide) { + private_template[4].pValue = &falsevalue; + private_template[5].pValue = &truevalue; + } + + /* Generate Key pair for signing/verifying */ + rv = pkcs_C_GenerateKeyPair(hSession, &mech, public_template, + public_attrcnt, private_template, + private_attrcnt, &publickey, &privatekey); + + if (rv != CKR_OK) { + fprintf(stderr, "C_GenerateKeyPair: Error = 0x%.8lX\n", rv); + error = 1; + } else if (!quiet) { + printf("Key pair generation complete.\n"); + } + +exit_search: + rv = pkcs_C_FindObjectsFinal(hSession); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv); + error = 1; + } + +exit_session: + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/pkcs11/pkcs11-keygen.rst b/bin/pkcs11/pkcs11-keygen.rst new file mode 100644 index 0000000..9ce2fba --- /dev/null +++ b/bin/pkcs11/pkcs11-keygen.rst @@ -0,0 +1,80 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_pkcs11-keygen: + +pkcs11-keygen - generate keys on a PKCS#11 device +------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`pkcs11-keygen` [**-a** algorithm] [**-b** keysize] [**-e**] [**-i** id] [**-m** module] [**-P**] [**-p** PIN] [**-q**] [**-S**] [**-s** slot] label + +Description +~~~~~~~~~~~ + +``pkcs11-keygen`` causes a PKCS#11 device to generate a new key pair +with the given ``label`` (which must be unique) and with ``keysize`` +bits of prime. + +Options +~~~~~~~ + +``-a algorithm`` + This option specifies the key algorithm class: supported classes are RSA, DSA, DH, + ECC, and ECX. In addition to these strings, the ``algorithm`` can be + specified as a DNSSEC signing algorithm to be used with this + key; for example, NSEC3RSASHA1 maps to RSA, ECDSAP256SHA256 maps to + ECC, and ED25519 to ECX. The default class is ``RSA``. + +``-b keysize`` + This option creates the key pair with ``keysize`` bits of prime. For ECC keys, the + only valid values are 256 and 384, and the default is 256. For ECX + keys, the only valid values are 256 and 456, and the default is 256. + +``-e`` + For RSA keys only, this option specifies use of a large exponent. + +``-i id`` + This option creates key objects with ``id``. The ID is either an unsigned short 2-byte + or an unsigned long 4-byte number. + +``-m module`` + This option specifies the PKCS#11 provider module. This must be the full path to a + shared library object implementing the PKCS#11 API for the device. + +``-P`` + This option sets the new private key to be non-sensitive and extractable, and + allows the private key data to be read from the PKCS#11 device. The + default is for private keys to be sensitive and non-extractable. + +``-p PIN`` + This option specifies the ``PIN`` for the device. If no ``PIN`` is provided on the command + line, ``pkcs11-keygen`` prompts for it. + +``-q`` + This option sets quiet mode, which suppresses unnecessary output. + +``-S`` + For Diffie-Hellman (DH) keys only, this option specifies use of a special prime of 768-, 1024-, + or 1536-bit size and base (AKA generator) 2. If not specified, bit + size defaults to 1024. + +``-s slot`` + This option opens the session with the given PKCS#11 slot. The default is slot 0. + +See Also +~~~~~~~~ + +:manpage:`pkcs11-destroy(8)`, :manpage:`pkcs11-list(8)`, :manpage:`pkcs11-tokens(8)`, :manpage:`dnssec-keyfromlabel(8)` diff --git a/bin/pkcs11/pkcs11-list.c b/bin/pkcs11/pkcs11-list.c new file mode 100644 index 0000000..1fdd8a8 --- /dev/null +++ b/bin/pkcs11/pkcs11-list.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* pkcs11-list [-P] [-m module] [-s slot] [-i $id | -l $label] [-p $pin] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession; + CK_BYTE attr_id[2]; + CK_OBJECT_HANDLE akey[50]; + pk11_context_t pctx; + char *lib_name = NULL; + char *label = NULL; + char *pin = NULL; + bool error = false, logon = true, all = false; + unsigned int i = 0, id = 0; + int c, errflg = 0; + CK_ULONG ulObjectCount; + CK_ATTRIBUTE search_template[] = { { CKA_ID, &attr_id, + sizeof(attr_id) } }; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:i:l:p:P")) != -1) { + switch (c) { + case 'P': + logon = false; + break; + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + break; + case 'i': + id = atoi(isc_commandline_argument); + id &= 0xffff; + break; + case 'l': + label = isc_commandline_argument; + break; + case 'p': + pin = isc_commandline_argument; + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tpkcs11-list [-P] [-m module] [-s slot] " + "[-i id | -l label] [-p pin]\n"); + exit(1); + } + + if (!id && (label == NULL)) { + all = true; + } + + if (slot) { + printf("slot %lu\n", slot); + } + + if (id) { + printf("id %u\n", id); + attr_id[0] = (id >> 8) & 0xff; + attr_id[1] = id & 0xff; + } else if (label != NULL) { + printf("label %s\n", label); + search_template[0].type = CKA_LABEL; + search_template[0].pValue = label; + search_template[0].ulValueLen = strlen(label); + } + + pk11_result_register(); + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (logon && pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, OP_ANY, false, false, logon, pin, + slot); + if (result == PK11_R_NORANDOMSERVICE || + result == PK11_R_NODIGESTSERVICE || result == PK11_R_NOAESSERVICE) + { + fprintf(stderr, "Warning: %s\n", isc_result_totext(result)); + fprintf(stderr, "This HSM will not work with BIND 9 " + "using native PKCS#11.\n"); + } else if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "Unrecoverable error initializing " + "PKCS#11: %s\n", + isc_result_totext(result)); + fprintf(stderr, + "Unrecoverable error initializing " + "PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + if (pin != NULL) { + memset(pin, 0, strlen(pin)); + } + + hSession = pctx.session; + + rv = pkcs_C_FindObjectsInit(hSession, search_template, all ? 0 : 1); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv); + error = 1; + goto exit_session; + } + + ulObjectCount = 1; + while (ulObjectCount) { + rv = pkcs_C_FindObjects(hSession, akey, 50, &ulObjectCount); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv); + error = 1; + goto exit_search; + } + for (i = 0; i < ulObjectCount; i++) { + unsigned int j, len; + + CK_OBJECT_CLASS oclass = 0; + CK_BYTE labelbuf[64 + 1]; + CK_BYTE idbuf[64]; + CK_BBOOL extract = TRUE; + CK_BBOOL never = FALSE; + CK_ATTRIBUTE template[] = { + { CKA_CLASS, &oclass, sizeof(oclass) }, + { CKA_LABEL, labelbuf, sizeof(labelbuf) - 1 }, + { CKA_ID, idbuf, sizeof(idbuf) } + }; + CK_ATTRIBUTE priv_template[] = { + { CKA_EXTRACTABLE, &extract, sizeof(extract) }, + { CKA_NEVER_EXTRACTABLE, &never, sizeof(never) } + }; + + memset(labelbuf, 0, sizeof(labelbuf)); + memset(idbuf, 0, sizeof(idbuf)); + + rv = pkcs_C_GetAttributeValue(hSession, akey[i], + template, 3); + if (rv != CKR_OK) { + fprintf(stderr, + "C_GetAttributeValue[%u]: " + "rv = 0x%.8lX\n", + i, rv); + if (rv == CKR_BUFFER_TOO_SMALL) { + fprintf(stderr, + "%u too small: %lu %lu %lu\n", + i, template[0].ulValueLen, + template[1].ulValueLen, + template[2].ulValueLen); + } + error = 1; + continue; + } + + len = template[2].ulValueLen; + printf("object[%u]: handle %lu class %lu " + "label[%lu] '%s' id[%lu] ", + i, akey[i], oclass, template[1].ulValueLen, + labelbuf, template[2].ulValueLen); + if (len == 2) { + id = (idbuf[0] << 8) & 0xff00; + id |= idbuf[1] & 0xff; + printf("%u", id); + } else { + if (len > 8) { + len = 8; + } + if (len > 0) { + printf("0x"); + } + for (j = 0; j < len; j++) { + printf("%02x", idbuf[j]); + } + if (template[2].ulValueLen > len) { + printf("..."); + } + } + if ((oclass == CKO_PRIVATE_KEY || + oclass == CKO_SECRET_KEY) && + pkcs_C_GetAttributeValue(hSession, akey[i], + priv_template, + 2) == CKR_OK) + { + printf(" E:%s", + extract ? "true" + : (never ? "never" : "false")); + } + printf("\n"); + } + } + +exit_search: + rv = pkcs_C_FindObjectsFinal(hSession); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv); + error = 1; + } + +exit_session: + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/pkcs11/pkcs11-list.rst b/bin/pkcs11/pkcs11-list.rst new file mode 100644 index 0000000..5cfe2da --- /dev/null +++ b/bin/pkcs11/pkcs11-list.rst @@ -0,0 +1,56 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_pkcs11-list: + +pkcs11-list - list PKCS#11 objects +---------------------------------- + +:program:`pkcs11-list` [**-P**] [**-m** module] [**-s** slot] [**-i** ID **] [-l** label] [**-p** PIN] + +Description +~~~~~~~~~~~ + +``pkcs11-list`` lists the PKCS#11 objects with ``ID`` or ``label`` or, by +default, all objects. The object class, label, and ID are displayed for +all keys. For private or secret keys, the extractability attribute is +also displayed, as either ``true``, ``false``, or ``never``. + +Options +~~~~~~~ + +``-P`` + This option lists only the public objects. (Note that on some PKCS#11 devices, all + objects are private.) + +``-m module`` + This option specifies the PKCS#11 provider module. This must be the full path to a + shared library object implementing the PKCS#11 API for the device. + +``-s slot`` + This option opens the session with the given PKCS#11 slot. The default is slot 0. + +``-i ID`` + This option lists only key objects with the given object ID. + +``-l label`` + This option lists only key objects with the given label. + +``-p PIN`` + This option specifies the ``PIN`` for the device. If no ``PIN`` is provided on the command + line, ``pkcs11-list`` prompts for it. + +See Also +~~~~~~~~ + +:manpage:`pkcs11-destroy(8)`, :manpage:`pkcs11-keygen(8)`, :manpage:`pkcs11-tokens(8)` diff --git a/bin/pkcs11/pkcs11-tokens.c b/bin/pkcs11/pkcs11-tokens.c new file mode 100644 index 0000000..e95fa4c --- /dev/null +++ b/bin/pkcs11/pkcs11-tokens.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* pkcs11-tokens [-m module] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +int +main(int argc, char *argv[]) { + isc_result_t result; + char *lib_name = NULL; + int c, errflg = 0; + isc_mem_t *mctx = NULL; + pk11_context_t pctx; + + while ((c = isc_commandline_parse(argc, argv, ":m:v")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 'v': + pk11_verbose_init = true; + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tpkcs11-tokens [-v] [-m module]\n"); + exit(1); + } + + isc_mem_create(&mctx); + + pk11_result_register(); + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + result = pk11_get_session(&pctx, OP_ANY, true, false, false, NULL, 0); + if (result == PK11_R_NORANDOMSERVICE || + result == PK11_R_NODIGESTSERVICE || result == PK11_R_NOAESSERVICE) + { + fprintf(stderr, "Warning: %s\n", isc_result_totext(result)); + fprintf(stderr, "This HSM will not work with BIND 9 " + "using native PKCS#11.\n\n"); + } else if ((result != ISC_R_SUCCESS) && (result != ISC_R_NOTFOUND)) { + fprintf(stderr, + "Unrecoverable error initializing " + "PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + pk11_dump_tokens(); + + if (pctx.handle != NULL) { + pk11_return_session(&pctx); + } + (void)pk11_finalize(); + + isc_mem_destroy(&mctx); + + exit(0); +} diff --git a/bin/pkcs11/pkcs11-tokens.rst b/bin/pkcs11/pkcs11-tokens.rst new file mode 100644 index 0000000..3612105 --- /dev/null +++ b/bin/pkcs11/pkcs11-tokens.rst @@ -0,0 +1,43 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_pkcs11-tokens: + +pkcs11-tokens - list PKCS#11 available tokens +--------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`pkcs11-tokens` [**-m** module] [**-v**] + +Description +~~~~~~~~~~~ + +``pkcs11-tokens`` lists the PKCS#11 available tokens with defaults from +the slot/token scan performed at application initialization. + +Options +~~~~~~~ + +``-m module`` + This option specifies the PKCS#11 provider module. This must be the full path to a + shared library object implementing the PKCS#11 API for the device. + +``-v`` + This option makes the PKCS#11 libisc initialization verbose. + +See Also +~~~~~~~~ + +:manpage:`pkcs11-destroy(8)`, :manpage:`pkcs11-keygen(8)`, :manpage:`pkcs11-list(8)` diff --git a/bin/pkcs11/win32/pk11destroy.vcxproj.filters.in b/bin/pkcs11/win32/pk11destroy.vcxproj.filters.in new file mode 100644 index 0000000..bdcc431 --- /dev/null +++ b/bin/pkcs11/win32/pk11destroy.vcxproj.filters.in @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/pkcs11/win32/pk11destroy.vcxproj.in b/bin/pkcs11/win32/pk11destroy.vcxproj.in new file mode 100644 index 0000000..4e006d5 --- /dev/null +++ b/bin/pkcs11/win32/pk11destroy.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {5B3137E5-7E1F-49AA-8810-A09AA417D326} + Win32Proj + pk11destroy + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + pkcs11-destroy + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + pkcs11-destroy + + + + + + Level4 + false + Disabled + WIN32;@PK11_LIB_LOCATION@_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;@PK11_LIB_LOCATION@NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/pkcs11/win32/pk11destroy.vcxproj.user b/bin/pkcs11/win32/pk11destroy.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/pkcs11/win32/pk11destroy.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/pkcs11/win32/pk11keygen.vcxproj.filters.in b/bin/pkcs11/win32/pk11keygen.vcxproj.filters.in new file mode 100644 index 0000000..412ff86 --- /dev/null +++ b/bin/pkcs11/win32/pk11keygen.vcxproj.filters.in @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/pkcs11/win32/pk11keygen.vcxproj.in b/bin/pkcs11/win32/pk11keygen.vcxproj.in new file mode 100644 index 0000000..137d251 --- /dev/null +++ b/bin/pkcs11/win32/pk11keygen.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {5042D371-0402-4FA3-A52A-769708694422} + Win32Proj + pk11keygen + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + pkcs11-keygen + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + pkcs11-keygen + + + + + + Level4 + false + Disabled + WIN32;@PK11_LIB_LOCATION@_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;@PK11_LIB_LOCATION@NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/pkcs11/win32/pk11keygen.vcxproj.user b/bin/pkcs11/win32/pk11keygen.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/pkcs11/win32/pk11keygen.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/pkcs11/win32/pk11list.vcxproj.filters.in b/bin/pkcs11/win32/pk11list.vcxproj.filters.in new file mode 100644 index 0000000..6944afd --- /dev/null +++ b/bin/pkcs11/win32/pk11list.vcxproj.filters.in @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/pkcs11/win32/pk11list.vcxproj.in b/bin/pkcs11/win32/pk11list.vcxproj.in new file mode 100644 index 0000000..52c6f02 --- /dev/null +++ b/bin/pkcs11/win32/pk11list.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {C663B088-F7BC-4C8C-8D06-A76636EED651} + Win32Proj + pk11list + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + pkcs11-list + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + pkcs11-list + + + + + + Level4 + false + Disabled + WIN32;@PK11_LIB_LOCATION@_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;@PK11_LIB_LOCATION@NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/pkcs11/win32/pk11list.vcxproj.user b/bin/pkcs11/win32/pk11list.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/pkcs11/win32/pk11list.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/pkcs11/win32/pk11tokens.vcxproj.filters.in b/bin/pkcs11/win32/pk11tokens.vcxproj.filters.in new file mode 100644 index 0000000..7c3b8ed --- /dev/null +++ b/bin/pkcs11/win32/pk11tokens.vcxproj.filters.in @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/pkcs11/win32/pk11tokens.vcxproj.in b/bin/pkcs11/win32/pk11tokens.vcxproj.in new file mode 100644 index 0000000..7bb41cb --- /dev/null +++ b/bin/pkcs11/win32/pk11tokens.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {403FD4B1-A4F9-4159-9013-5860E3A4417D} + Win32Proj + pk11tokens + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + pkcs11-tokens + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + pkcs11-tokens + + + + + + Level4 + false + Disabled + WIN32;@PK11_LIB_LOCATION@_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;@PK11_LIB_LOCATION@NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/pkcs11/win32/pk11tokens.vcxproj.user b/bin/pkcs11/win32/pk11tokens.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/pkcs11/win32/pk11tokens.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/plugins/Makefile.in b/bin/plugins/Makefile.in new file mode 100644 index 0000000..4bd606a --- /dev/null +++ b/bin/plugins/Makefile.in @@ -0,0 +1,67 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ + ${NS_INCLUDES} ${DNS_INCLUDES} \ + ${ISCCFG_INCLUDES} ${ISC_INCLUDES} + +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +NSLIBS = ../../lib/ns/libns.@A@ + +LIBS = + +SO_TARGETS = lib/filter-aaaa.@SO@ +SO_INSTALL = filter-aaaa.@SO@ +TARGETS = @SO_TARGETS@ + +SO_OBJS = filter-aaaa.@O@ +SO_SRCS = filter-aaaa.c + +CFLAGS = @CFLAGS@ @SO_CFLAGS@ +SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@ + +@BIND9_MAKE_RULES@ + +lib/filter-aaaa.@SO@: filter-aaaa.@SO@ + $(SHELL) ${top_srcdir}/mkinstalldirs `pwd`/lib + ${LIBTOOL_MODE_INSTALL} ${INSTALL} filter-aaaa.@SO@ `pwd`/lib + +filter-aaaa.@SO@: filter-aaaa.@O@ + ${LIBTOOL_MODE_LINK} @SO_LD@ ${SO_LDFLAGS} -o $@ \ + filter-aaaa.@O@ ${LIBS} + +clean distclean:: + rm -f filter-aaaa.so + rm -f ${TARGETS} ${OBJS} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${plugindir} + +install:: @SO_TARGETS@ installdirs + for i in ${SO_INSTALL} ; \ + do \ + if test -f $$i ; \ + then \ + ${LIBTOOL_MODE_INSTALL} ${INSTALL_LIBRARY} $$i \ + ${DESTDIR}${plugindir}; \ + fi \ + done + +uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${plugindir}/filter-aaaa.@SO@ diff --git a/bin/plugins/filter-aaaa.c b/bin/plugins/filter-aaaa.c new file mode 100644 index 0000000..265da26 --- /dev/null +++ b/bin/plugins/filter-aaaa.c @@ -0,0 +1,881 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define CHECK(op) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) { \ + goto cleanup; \ + } \ + } while (0) + +/* + * Possible values for the settings of filter-aaaa-on-v4 and + * filter-aaaa-on-v6: "no" is NONE, "yes" is FILTER, "break-dnssec" + * is BREAK_DNSSEC. + */ +typedef enum { NONE = 0, FILTER = 1, BREAK_DNSSEC = 2 } filter_aaaa_t; + +/* + * Persistent data for use by this module. This will be associated + * with client object address in the hash table, and will remain + * accessible until the client object is detached. + */ +typedef struct filter_data { + filter_aaaa_t mode; + uint32_t flags; +} filter_data_t; + +typedef struct filter_instance { + ns_plugin_t *module; + isc_mem_t *mctx; + + /* + * Hash table associating a client object with its persistent data. + */ + isc_ht_t *ht; + isc_mutex_t hlock; + + /* + * Values configured when the module is loaded. + */ + filter_aaaa_t v4_aaaa; + filter_aaaa_t v6_aaaa; + dns_acl_t *aaaa_acl; +} filter_instance_t; + +/* + * Per-client flags set by this module + */ +#define FILTER_AAAA_RECURSING 0x0001 /* Recursing for A */ +#define FILTER_AAAA_FILTERED 0x0002 /* AAAA was removed from answer */ + +/* + * Client attribute tests. + */ +#define WANTDNSSEC(c) (((c)->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0) +#define RECURSIONOK(c) (((c)->query.attributes & NS_QUERYATTR_RECURSIONOK) != 0) + +/* + * Forward declarations of functions referenced in install_hooks(). + */ +static ns_hookresult_t +filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp); +static ns_hookresult_t +filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp); +static ns_hookresult_t +filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp); +static ns_hookresult_t +filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp); +static ns_hookresult_t +filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp); +static ns_hookresult_t +filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp); + +/*% + * Register the functions to be called at each hook point in 'hooktable', using + * memory context 'mctx' for allocating copies of stack-allocated structures + * passed to ns_hook_add(). Make sure 'inst' will be passed as the 'cbdata' + * argument to every callback. + */ +static void +install_hooks(ns_hooktable_t *hooktable, isc_mem_t *mctx, + filter_instance_t *inst) { + const ns_hook_t filter_init = { + .action = filter_qctx_initialize, + .action_data = inst, + }; + + const ns_hook_t filter_respbegin = { + .action = filter_respond_begin, + .action_data = inst, + }; + + const ns_hook_t filter_respanyfound = { + .action = filter_respond_any_found, + .action_data = inst, + }; + + const ns_hook_t filter_prepresp = { + .action = filter_prep_response_begin, + .action_data = inst, + }; + + const ns_hook_t filter_donesend = { + .action = filter_query_done_send, + .action_data = inst, + }; + + const ns_hook_t filter_destroy = { + .action = filter_qctx_destroy, + .action_data = inst, + }; + + ns_hook_add(hooktable, mctx, NS_QUERY_QCTX_INITIALIZED, &filter_init); + ns_hook_add(hooktable, mctx, NS_QUERY_RESPOND_BEGIN, &filter_respbegin); + ns_hook_add(hooktable, mctx, NS_QUERY_RESPOND_ANY_FOUND, + &filter_respanyfound); + ns_hook_add(hooktable, mctx, NS_QUERY_PREP_RESPONSE_BEGIN, + &filter_prepresp); + ns_hook_add(hooktable, mctx, NS_QUERY_DONE_SEND, &filter_donesend); + ns_hook_add(hooktable, mctx, NS_QUERY_QCTX_DESTROYED, &filter_destroy); +} + +/** +** Support for parsing of parameters and configuration of the module. +**/ + +/* + * Support for parsing of parameters. + */ +static const char *filter_aaaa_enums[] = { "break-dnssec", NULL }; + +static isc_result_t +parse_filter_aaaa(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); +} + +static void +doc_filter_aaaa(cfg_printer_t *pctx, const cfg_type_t *type) { + cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); +} + +static cfg_type_t cfg_type_filter_aaaa = { + "filter_aaaa", parse_filter_aaaa, cfg_print_ustring, + doc_filter_aaaa, &cfg_rep_string, filter_aaaa_enums, +}; + +static cfg_clausedef_t param_clauses[] = { + { "filter-aaaa", &cfg_type_bracketed_aml, 0 }, + { "filter-aaaa-on-v4", &cfg_type_filter_aaaa, 0 }, + { "filter-aaaa-on-v6", &cfg_type_filter_aaaa, 0 }, +}; + +static cfg_clausedef_t *param_clausesets[] = { param_clauses, NULL }; + +static cfg_type_t cfg_type_parameters = { + "filter-aaaa-params", cfg_parse_mapbody, cfg_print_mapbody, + cfg_doc_mapbody, &cfg_rep_map, param_clausesets +}; + +static isc_result_t +parse_filter_aaaa_on(const cfg_obj_t *param_obj, const char *param_name, + filter_aaaa_t *dstp) { + const cfg_obj_t *obj = NULL; + isc_result_t result; + + result = cfg_map_get(param_obj, param_name, &obj); + if (result != ISC_R_SUCCESS) { + return (ISC_R_SUCCESS); + } + + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) { + *dstp = FILTER; + } else { + *dstp = NONE; + } + } else if (strcasecmp(cfg_obj_asstring(obj), "break-dnssec") == 0) { + *dstp = BREAK_DNSSEC; + } else { + result = ISC_R_UNEXPECTED; + } + + return (result); +} + +static isc_result_t +check_syntax(cfg_obj_t *fmap, const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, + void *actx) { + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *aclobj = NULL; + dns_acl_t *acl = NULL; + filter_aaaa_t f4 = NONE, f6 = NONE; + + cfg_map_get(fmap, "filter-aaaa", &aclobj); + if (aclobj == NULL) { + return (result); + } + + CHECK(cfg_acl_fromconfig(aclobj, (const cfg_obj_t *)cfg, lctx, + (cfg_aclconfctx_t *)actx, mctx, 0, &acl)); + + CHECK(parse_filter_aaaa_on(fmap, "filter-aaaa-on-v4", &f4)); + CHECK(parse_filter_aaaa_on(fmap, "filter-aaaa-on-v6", &f6)); + + if ((f4 != NONE || f6 != NONE) && dns_acl_isnone(acl)) { + cfg_obj_log(aclobj, lctx, ISC_LOG_WARNING, + "\"filter-aaaa\" is 'none;' but " + "either filter-aaaa-on-v4 or filter-aaaa-on-v6 " + "is enabled"); + result = ISC_R_FAILURE; + } else if (f4 == NONE && f6 == NONE && !dns_acl_isnone(acl)) { + cfg_obj_log(aclobj, lctx, ISC_LOG_WARNING, + "\"filter-aaaa\" is set but " + "neither filter-aaaa-on-v4 or filter-aaaa-on-v6 " + "is enabled"); + result = ISC_R_FAILURE; + } + +cleanup: + if (acl != NULL) { + dns_acl_detach(&acl); + } + + return (result); +} + +static isc_result_t +parse_parameters(filter_instance_t *inst, const char *parameters, + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx) { + isc_result_t result = ISC_R_SUCCESS; + cfg_parser_t *parser = NULL; + cfg_obj_t *param_obj = NULL; + const cfg_obj_t *obj = NULL; + isc_buffer_t b; + + CHECK(cfg_parser_create(mctx, lctx, &parser)); + + isc_buffer_constinit(&b, parameters, strlen(parameters)); + isc_buffer_add(&b, strlen(parameters)); + CHECK(cfg_parse_buffer(parser, &b, cfg_file, cfg_line, + &cfg_type_parameters, 0, ¶m_obj)); + + CHECK(check_syntax(param_obj, cfg, mctx, lctx, actx)); + + CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4", + &inst->v4_aaaa)); + CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v6", + &inst->v6_aaaa)); + + result = cfg_map_get(param_obj, "filter-aaaa", &obj); + if (result == ISC_R_SUCCESS) { + CHECK(cfg_acl_fromconfig(obj, (const cfg_obj_t *)cfg, lctx, + (cfg_aclconfctx_t *)actx, mctx, 0, + &inst->aaaa_acl)); + } else { + CHECK(dns_acl_any(mctx, &inst->aaaa_acl)); + } + +cleanup: + if (param_obj != NULL) { + cfg_obj_destroy(parser, ¶m_obj); + } + if (parser != NULL) { + cfg_parser_destroy(&parser); + } + return (result); +} + +/** +** Mandatory plugin API functions: +** +** - plugin_destroy +** - plugin_register +** - plugin_version +** - plugin_check +**/ + +/* + * Called by ns_plugin_register() to initialize the plugin and + * register hook functions into the view hook table. + */ +isc_result_t +plugin_register(const char *parameters, const void *cfg, const char *cfg_file, + unsigned long cfg_line, isc_mem_t *mctx, isc_log_t *lctx, + void *actx, ns_hooktable_t *hooktable, void **instp) { + filter_instance_t *inst = NULL; + isc_result_t result = ISC_R_SUCCESS; + + isc_log_write(lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, + ISC_LOG_INFO, + "registering 'filter-aaaa' " + "module from %s:%lu, %s parameters", + cfg_file, cfg_line, parameters != NULL ? "with" : "no"); + + inst = isc_mem_get(mctx, sizeof(*inst)); + memset(inst, 0, sizeof(*inst)); + isc_mem_attach(mctx, &inst->mctx); + + if (parameters != NULL) { + CHECK(parse_parameters(inst, parameters, cfg, cfg_file, + cfg_line, mctx, lctx, actx)); + } + + isc_ht_init(&inst->ht, mctx, 16); + isc_mutex_init(&inst->hlock); + + /* + * Set hook points in the view's hooktable. + */ + install_hooks(hooktable, mctx, inst); + + *instp = inst; + +cleanup: + if (result != ISC_R_SUCCESS && inst != NULL) { + plugin_destroy((void **)&inst); + } + + return (result); +} + +isc_result_t +plugin_check(const char *parameters, const void *cfg, const char *cfg_file, + unsigned long cfg_line, isc_mem_t *mctx, isc_log_t *lctx, + void *actx) { + isc_result_t result = ISC_R_SUCCESS; + cfg_parser_t *parser = NULL; + cfg_obj_t *param_obj = NULL; + isc_buffer_t b; + + CHECK(cfg_parser_create(mctx, lctx, &parser)); + + isc_buffer_constinit(&b, parameters, strlen(parameters)); + isc_buffer_add(&b, strlen(parameters)); + CHECK(cfg_parse_buffer(parser, &b, cfg_file, cfg_line, + &cfg_type_parameters, 0, ¶m_obj)); + + CHECK(check_syntax(param_obj, cfg, mctx, lctx, actx)); + +cleanup: + if (param_obj != NULL) { + cfg_obj_destroy(parser, ¶m_obj); + } + if (parser != NULL) { + cfg_parser_destroy(&parser); + } + return (result); +} + +/* + * Called by ns_plugins_free(); frees memory allocated by + * the module when it was registered. + */ +void +plugin_destroy(void **instp) { + filter_instance_t *inst = (filter_instance_t *)*instp; + + if (inst->ht != NULL) { + isc_ht_destroy(&inst->ht); + isc_mutex_destroy(&inst->hlock); + } + if (inst->aaaa_acl != NULL) { + dns_acl_detach(&inst->aaaa_acl); + } + + isc_mem_putanddetach(&inst->mctx, inst, sizeof(*inst)); + *instp = NULL; + + return; +} + +/* + * Returns plugin API version for compatibility checks. + */ +int +plugin_version(void) { + return (NS_PLUGIN_VERSION); +} + +/** +** "filter-aaaa" feature implementation begins here. +**/ + +/*% + * Structure describing the filtering to be applied by process_section(). + */ +typedef struct section_filter { + query_ctx_t *qctx; + filter_aaaa_t mode; + dns_section_t section; + const dns_name_t *name; + dns_rdatatype_t type; + bool only_if_a_exists; +} section_filter_t; + +/* + * Check whether this is an IPv4 client. + */ +static bool +is_v4_client(ns_client_t *client) { + if (isc_sockaddr_pf(&client->peeraddr) == AF_INET) { + return (true); + } + if (isc_sockaddr_pf(&client->peeraddr) == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&client->peeraddr.type.sin6.sin6_addr)) + { + return (true); + } + return (false); +} + +/* + * Check whether this is an IPv6 client. + */ +static bool +is_v6_client(ns_client_t *client) { + if (isc_sockaddr_pf(&client->peeraddr) == AF_INET6 && + !IN6_IS_ADDR_V4MAPPED(&client->peeraddr.type.sin6.sin6_addr)) + { + return (true); + } + return (false); +} + +static filter_data_t * +client_state_get(const query_ctx_t *qctx, filter_instance_t *inst) { + filter_data_t *client_state = NULL; + isc_result_t result; + + LOCK(&inst->hlock); + result = isc_ht_find(inst->ht, (const unsigned char *)&qctx->client, + sizeof(qctx->client), (void **)&client_state); + UNLOCK(&inst->hlock); + + return (result == ISC_R_SUCCESS ? client_state : NULL); +} + +static void +client_state_create(const query_ctx_t *qctx, filter_instance_t *inst) { + filter_data_t *client_state; + isc_result_t result; + + client_state = isc_mem_get(inst->mctx, sizeof(*client_state)); + + client_state->mode = NONE; + client_state->flags = 0; + + LOCK(&inst->hlock); + result = isc_ht_add(inst->ht, (const unsigned char *)&qctx->client, + sizeof(qctx->client), client_state); + UNLOCK(&inst->hlock); + RUNTIME_CHECK(result == ISC_R_SUCCESS); +} + +static void +client_state_destroy(const query_ctx_t *qctx, filter_instance_t *inst) { + filter_data_t *client_state = client_state_get(qctx, inst); + isc_result_t result; + + if (client_state == NULL) { + return; + } + + LOCK(&inst->hlock); + result = isc_ht_delete(inst->ht, (const unsigned char *)&qctx->client, + sizeof(qctx->client)); + UNLOCK(&inst->hlock); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + isc_mem_put(inst->mctx, client_state, sizeof(*client_state)); +} + +/*% + * Mark 'rdataset' and 'sigrdataset' as rendered, gracefully handling NULL + * pointers and non-associated rdatasets. + */ +static void +mark_as_rendered(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { + if (rdataset != NULL && dns_rdataset_isassociated(rdataset)) { + rdataset->attributes |= DNS_RDATASETATTR_RENDERED; + } + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { + sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; + } +} + +/*% + * Check whether an RRset of given 'type' is present at given 'name'. If + * it is found and either it is not signed or the combination of query + * flags and configured processing 'mode' allows it, mark the RRset and its + * associated signatures as already rendered to prevent them from appearing + * in the response message stored in 'qctx'. If 'only_if_a_exists' is + * true, an RRset of type A must also exist at 'name' in order for the + * above processing to happen. + */ +static bool +process_name(query_ctx_t *qctx, filter_aaaa_t mode, const dns_name_t *name, + dns_rdatatype_t type, bool only_if_a_exists) { + dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; + isc_result_t result; + bool modified = false; + + if (only_if_a_exists) { + CHECK(dns_message_findtype(name, dns_rdatatype_a, 0, NULL)); + } + + (void)dns_message_findtype(name, type, 0, &rdataset); + (void)dns_message_findtype(name, dns_rdatatype_rrsig, type, + &sigrdataset); + + if (rdataset != NULL && + (sigrdataset == NULL || !WANTDNSSEC(qctx->client) || + mode == BREAK_DNSSEC)) + { + /* + * An RRset of given 'type' was found at 'name' and at least + * one of the following is true: + * + * - the RRset is not signed, + * - the client did not set the DO bit in its request, + * - configuration allows us to tamper with signed responses. + * + * This means it is okay to filter out this RRset and its + * signatures, if any, from the response. + */ + mark_as_rendered(rdataset, sigrdataset); + modified = true; + } + +cleanup: + return (modified); +} + +/*% + * Apply the requested section filter, i.e. prevent (when possible, as + * determined by process_name()) RRsets of given 'type' from being rendered + * in the given 'section' of the response message stored in 'qctx'. Clear + * the AD bit if the answer and/or authority section was modified. If + * 'name' is NULL, all names in the given 'section' are processed; + * otherwise, only 'name' is. 'only_if_a_exists' is passed through to + * process_name(). + */ +static void +process_section(const section_filter_t *filter) { + query_ctx_t *qctx = filter->qctx; + filter_aaaa_t mode = filter->mode; + dns_section_t section = filter->section; + const dns_name_t *name = filter->name; + dns_rdatatype_t type = filter->type; + bool only_if_a_exists = filter->only_if_a_exists; + + dns_message_t *message = qctx->client->message; + isc_result_t result; + + for (result = dns_message_firstname(message, section); + result == ISC_R_SUCCESS; + result = dns_message_nextname(message, section)) + { + dns_name_t *cur = NULL; + dns_message_currentname(message, section, &cur); + if (name != NULL && !dns_name_equal(name, cur)) { + /* + * We only want to process 'name' and this is not it. + */ + continue; + } + + if (!process_name(qctx, mode, cur, type, only_if_a_exists)) { + /* + * Response was not modified, do not touch the AD bit. + */ + continue; + } + + if (section == DNS_SECTION_ANSWER || + section == DNS_SECTION_AUTHORITY) + { + message->flags &= ~DNS_MESSAGEFLAG_AD; + } + } +} + +/* + * Initialize filter state, fetching it from a memory pool and storing it + * in a hash table keyed according to the client object; this enables us to + * retrieve persistent data related to a client query for as long as the + * object persists. + */ +static ns_hookresult_t +filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *)arg; + filter_instance_t *inst = (filter_instance_t *)cbdata; + filter_data_t *client_state; + + *resp = ISC_R_UNSET; + + client_state = client_state_get(qctx, inst); + if (client_state == NULL) { + client_state_create(qctx, inst); + } + + return (NS_HOOK_CONTINUE); +} + +/* + * Determine whether this client should have AAAA filtered or not, based on + * the client address family and the settings of filter-aaaa-on-v4 and + * filter-aaaa-on-v6. + */ +static ns_hookresult_t +filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *)arg; + filter_instance_t *inst = (filter_instance_t *)cbdata; + filter_data_t *client_state = client_state_get(qctx, inst); + isc_result_t result; + + *resp = ISC_R_UNSET; + + if (client_state == NULL) { + return (NS_HOOK_CONTINUE); + } + + if (inst->v4_aaaa != NONE || inst->v6_aaaa != NONE) { + result = ns_client_checkaclsilent(qctx->client, NULL, + inst->aaaa_acl, true); + if (result == ISC_R_SUCCESS && inst->v4_aaaa != NONE && + is_v4_client(qctx->client)) + { + client_state->mode = inst->v4_aaaa; + } else if (result == ISC_R_SUCCESS && inst->v6_aaaa != NONE && + is_v6_client(qctx->client)) + { + client_state->mode = inst->v6_aaaa; + } + } + + return (NS_HOOK_CONTINUE); +} + +/* + * Hide AAAA rrsets if there is a matching A. Trigger recursion if + * necessary to find out whether an A exists. + * + * (This version is for processing answers to explicit AAAA queries; ANY + * queries are handled in filter_respond_any_found().) + */ +static ns_hookresult_t +filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *)arg; + filter_instance_t *inst = (filter_instance_t *)cbdata; + filter_data_t *client_state = client_state_get(qctx, inst); + isc_result_t result = ISC_R_UNSET; + + *resp = ISC_R_UNSET; + + if (client_state == NULL) { + return (NS_HOOK_CONTINUE); + } + + if (client_state->mode != BREAK_DNSSEC && + (client_state->mode != FILTER || + (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && + dns_rdataset_isassociated(qctx->sigrdataset)))) + { + return (NS_HOOK_CONTINUE); + } + + if (qctx->qtype == dns_rdatatype_aaaa) { + dns_rdataset_t *trdataset; + trdataset = ns_client_newrdataset(qctx->client); + result = dns_db_findrdataset( + qctx->db, qctx->node, qctx->version, dns_rdatatype_a, 0, + qctx->client->now, trdataset, NULL); + if (dns_rdataset_isassociated(trdataset)) { + dns_rdataset_disassociate(trdataset); + } + ns_client_putrdataset(qctx->client, &trdataset); + + /* + * We found an AAAA. If we also found an A, then the AAAA + * must not be rendered. + * + * If the A is not in our cache, then any result other than + * DNS_R_DELEGATION or ISC_R_NOTFOUND means there is no A, + * and so AAAAs are okay. + * + * We assume there is no A if we can't recurse for this + * client. That might be the wrong answer, but what else + * can we do? Besides, the fact that we have the AAAA and + * are using this mechanism in the first place suggests + * that we care more about As than AAAAs, and would have + * cached an A if it existed. + */ + if (result == ISC_R_SUCCESS) { + mark_as_rendered(qctx->rdataset, qctx->sigrdataset); + qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; + client_state->flags |= FILTER_AAAA_FILTERED; + } else if (!qctx->authoritative && RECURSIONOK(qctx->client) && + (result == DNS_R_DELEGATION || + result == ISC_R_NOTFOUND)) + { + /* + * This is an ugly kludge to recurse + * for the A and discard the result. + * + * Continue to add the AAAA now. + * We'll make a note to not render it + * if the recursion for the A succeeds. + */ + result = ns_query_recurse(qctx->client, dns_rdatatype_a, + qctx->client->query.qname, + NULL, NULL, qctx->resuming); + if (result == ISC_R_SUCCESS) { + client_state->flags |= FILTER_AAAA_RECURSING; + qctx->client->query.attributes |= + NS_QUERYATTR_RECURSING; + } + } + } else if (qctx->qtype == dns_rdatatype_a && + (client_state->flags & FILTER_AAAA_RECURSING) != 0) + { + const section_filter_t filter_answer = { + .qctx = qctx, + .mode = client_state->mode, + .section = DNS_SECTION_ANSWER, + .name = qctx->fname, + .type = dns_rdatatype_aaaa, + }; + process_section(&filter_answer); + + client_state->flags &= ~FILTER_AAAA_RECURSING; + + result = ns_query_done(qctx); + + *resp = result; + + return (NS_HOOK_RETURN); + } + + *resp = result; + return (NS_HOOK_CONTINUE); +} + +/* + * When answering an ANY query, remove AAAA if A is present. + */ +static ns_hookresult_t +filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *)arg; + filter_instance_t *inst = (filter_instance_t *)cbdata; + filter_data_t *client_state = client_state_get(qctx, inst); + + *resp = ISC_R_UNSET; + + if (client_state != NULL && client_state->mode != NONE) { + /* + * If we are authoritative, require an A record to be + * present before filtering out AAAA records; otherwise, + * just assume an A record exists even if it was not in the + * cache (and therefore is not in the response message), + * thus proceeding with filtering out AAAA records. + */ + const section_filter_t filter_answer = { + .qctx = qctx, + .mode = client_state->mode, + .section = DNS_SECTION_ANSWER, + .name = qctx->tname, + .type = dns_rdatatype_aaaa, + .only_if_a_exists = qctx->authoritative, + }; + process_section(&filter_answer); + } + + return (NS_HOOK_CONTINUE); +} + +/* + * Hide AAAA rrsets in the additional section if there is a matching A, and + * hide NS in the authority section if AAAA was filtered in the answer + * section. + */ +static ns_hookresult_t +filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *)arg; + filter_instance_t *inst = (filter_instance_t *)cbdata; + filter_data_t *client_state = client_state_get(qctx, inst); + + *resp = ISC_R_UNSET; + + if (client_state != NULL && client_state->mode != NONE) { + const section_filter_t filter_additional = { + .qctx = qctx, + .mode = client_state->mode, + .section = DNS_SECTION_ADDITIONAL, + .type = dns_rdatatype_aaaa, + .only_if_a_exists = true, + }; + process_section(&filter_additional); + + if ((client_state->flags & FILTER_AAAA_FILTERED) != 0) { + const section_filter_t filter_authority = { + .qctx = qctx, + .mode = client_state->mode, + .section = DNS_SECTION_AUTHORITY, + .type = dns_rdatatype_ns, + }; + process_section(&filter_authority); + } + } + + return (NS_HOOK_CONTINUE); +} + +/* + * If the client is being detached, then we can delete our persistent data + * from hash table and return it to the memory pool. + */ +static ns_hookresult_t +filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *)arg; + filter_instance_t *inst = (filter_instance_t *)cbdata; + + *resp = ISC_R_UNSET; + + if (!qctx->detach_client) { + return (NS_HOOK_CONTINUE); + } + + client_state_destroy(qctx, inst); + + return (NS_HOOK_CONTINUE); +} diff --git a/bin/plugins/filter-aaaa.rst b/bin/plugins/filter-aaaa.rst new file mode 100644 index 0000000..1696101 --- /dev/null +++ b/bin/plugins/filter-aaaa.rst @@ -0,0 +1,89 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_filter-aaaa: + +filter-aaaa.so - filter AAAA in DNS responses when A is present +--------------------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`plugin query` "filter-aaaa.so" [{ parameters }]; + +Description +~~~~~~~~~~~ + +``filter-aaaa.so`` is a query plugin module for ``named``, enabling +``named`` to omit some IPv6 addresses when responding to clients. + +Until BIND 9.12, this feature was implemented natively in ``named`` and +enabled with the ``filter-aaaa`` ACL and the ``filter-aaaa-on-v4`` and +``filter-aaaa-on-v6`` options. These options are now deprecated in +``named.conf`` but can be passed as parameters to the +``filter-aaaa.so`` plugin, for example: + +:: + + plugin query "/usr/local/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa-on-v6 yes; + filter-aaaa { 192.0.2.1; 2001:db8:2::1; }; + }; + +This module is intended to aid transition from IPv4 to IPv6 by +withholding IPv6 addresses from DNS clients which are not connected to +the IPv6 Internet, when the name being looked up has an IPv4 address +available. Use of this module is not recommended unless absolutely +necessary. + +Note: This mechanism can erroneously cause other servers not to give +AAAA records to their clients. If a recursing server with both IPv6 and +IPv4 network connections queries an authoritative server using this +mechanism via IPv4, it is denied AAAA records even if its client is +using IPv6. + +Options +~~~~~~~ + +``filter-aaaa`` + This option specifies a list of client addresses for which AAAA filtering is to + be applied. The default is ``any``. + +``filter-aaaa-on-v4`` + If set to ``yes``, this option indicates that the DNS client is at an IPv4 address, in + ``filter-aaaa``. If the response does not include DNSSEC + signatures, then all AAAA records are deleted from the response. This + filtering applies to all responses, not only authoritative + ones. + + If set to ``break-dnssec``, then AAAA records are deleted even when + DNSSEC is enabled. As suggested by the name, this causes the response + to fail to verify, because the DNSSEC protocol is designed to detect + deletions. + + This mechanism can erroneously cause other servers not to give AAAA + records to their clients. If a recursing server with both IPv6 and IPv4 + network connections queries an authoritative server using this + mechanism via IPv4, it is denied AAAA records even if its client is + using IPv6. + +``filter-aaaa-on-v6`` + This option is identical to ``filter-aaaa-on-v4``, except that it filters AAAA responses + to queries from IPv6 clients instead of IPv4 clients. To filter all + responses, set both options to ``yes``. + +See Also +~~~~~~~~ + +BIND 9 Administrator Reference Manual. diff --git a/bin/python/Makefile.in b/bin/python/Makefile.in new file mode 100644 index 0000000..dc1af40 --- /dev/null +++ b/bin/python/Makefile.in @@ -0,0 +1,66 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +PYTHON = @PYTHON@ + +SUBDIRS = isc + +TARGETS = dnssec-checkds dnssec-coverage dnssec-keymgr +PYSRCS = dnssec-checkds.py dnssec-coverage.py dnssec-keymgr.py + +@BIND9_MAKE_RULES@ + +dnssec-checkds: dnssec-checkds.py + cp -f dnssec-checkds.py dnssec-checkds + chmod +x dnssec-checkds + +dnssec-coverage: dnssec-coverage.py + cp -f dnssec-coverage.py dnssec-coverage + chmod +x dnssec-coverage + +dnssec-keymgr: dnssec-keymgr.py + cp -f dnssec-keymgr.py dnssec-keymgr + chmod +x dnssec-keymgr + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} + +install:: ${TARGETS} installdirs + ${INSTALL_SCRIPT} dnssec-checkds ${DESTDIR}${sbindir} + ${INSTALL_SCRIPT} dnssec-coverage ${DESTDIR}${sbindir} + ${INSTALL_SCRIPT} dnssec-keymgr ${DESTDIR}${sbindir} + if test -n "${PYTHON}" ; then \ + if test -n "${DESTDIR}" ; then \ + ${PYTHON} ${srcdir}/setup.py install --root=${DESTDIR} --prefix=${prefix} @PYTHON_INSTALL_LIB@ ; \ + else \ + ${PYTHON} ${srcdir}/setup.py install --prefix=${prefix} @PYTHON_INSTALL_LIB@ ; \ + fi ; \ + rm -rf build ; \ + fi + +uninstall:: + rm -f ${DESTDIR}${sbindir}/dnssec-keymgr + rm -f ${DESTDIR}${sbindir}/dnssec-coverage + rm -f ${DESTDIR}${sbindir}/dnssec-checkds + # only manually uninstall for the python package itself + +clean distclean:: + rm -f ${TARGETS} + rm -rf build + +distclean:: + rm -f dnssec-checkds.py dnssec-coverage.py dnssec-keymgr.py diff --git a/bin/python/dnssec-checkds.py.in b/bin/python/dnssec-checkds.py.in new file mode 100644 index 0000000..3ec15e2 --- /dev/null +++ b/bin/python/dnssec-checkds.py.in @@ -0,0 +1,32 @@ +#!@PYTHON@ + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import os +import sys + +sys.path.insert(0, os.path.dirname(sys.argv[0])) +if os.name != "nt": + if "@PYTHON_INSTALL_DIR@": # value of --with-python-install-dir + sys.path.insert(1, "@PYTHON_INSTALL_DIR@") + else: + sys.path.insert( + 1, + os.path.join( + "@prefix@", "lib", "python" + sys.version[:3], "site-packages" + ), + ) + +import isc.checkds + +if __name__ == "__main__": + isc.checkds.main() diff --git a/bin/python/dnssec-checkds.rst b/bin/python/dnssec-checkds.rst new file mode 100644 index 0000000..aa239fa --- /dev/null +++ b/bin/python/dnssec-checkds.rst @@ -0,0 +1,68 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-checkds: + +dnssec-checkds - DNSSEC delegation consistency checking tool +------------------------------------------------------------ + +Synopsis +~~~~~~~~ + +``dnssec-checkds`` [**-d**\ *dig path*] [**-D**\ *dsfromkey path*] +[**-f**\ *file*] [**-l**\ *domain*] [**-s**\ *file*] {zone} + +Description +~~~~~~~~~~~ + +``dnssec-checkds`` verifies the correctness of Delegation Signer (DS) +resource records for keys in a specified zone. + +Options +~~~~~~~ + +**-a** *algorithm* + + Specify a digest algorithm to use when converting the zones DNSKEY + records to expected DS records. This option can be repeated, so that + multiple records are checked for each DNSKEY record. + + The *algorithm* must be one of SHA-1, SHA-256, or SHA-384. These + values are case insensitive, and the hyphen may be omitted. If no + algorithm is specified, the default is SHA-256. + +**-f** *file* + + If a ``file`` is specified, then the zone is read from that file to + find the DNSKEY records. If not, then the DNSKEY records for the zone + are looked up in the DNS. + +**-s** *file* + + Specifies a prepared dsset file, such as would be generated by + ``dnssec-signzone``, to use as a source for the DS RRset instead of + querying the parent. + +**-d** *dig path* + + Specifies a path to a ``dig`` binary. Used for testing. + +**-D** *dsfromkey path* + + Specifies a path to a ``dnssec-dsfromkey`` binary. Used for testing. + +See Also +~~~~~~~~ + +``dnssec-dsfromkey``\ (8), ``dnssec-keygen``\ (8), +``dnssec-signzone``\ (8), diff --git a/bin/python/dnssec-coverage.py.in b/bin/python/dnssec-coverage.py.in new file mode 100644 index 0000000..a82dfe3 --- /dev/null +++ b/bin/python/dnssec-coverage.py.in @@ -0,0 +1,32 @@ +#!@PYTHON@ + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import os +import sys + +sys.path.insert(0, os.path.dirname(sys.argv[0])) +if os.name != "nt": + if "@PYTHON_INSTALL_DIR@": # value of --with-python-install-dir + sys.path.insert(1, "@PYTHON_INSTALL_DIR@") + else: + sys.path.insert( + 1, + os.path.join( + "@prefix@", "lib", "python" + sys.version[:3], "site-packages" + ), + ) + +import isc.coverage + +if __name__ == "__main__": + isc.coverage.main() diff --git a/bin/python/dnssec-coverage.rst b/bin/python/dnssec-coverage.rst new file mode 100644 index 0000000..e2658cb --- /dev/null +++ b/bin/python/dnssec-coverage.rst @@ -0,0 +1,152 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-coverage: + +dnssec-coverage - checks future DNSKEY coverage for a zone +---------------------------------------------------------- + +Synopsis +~~~~~~~~ + +``dnssec-coverage`` [**-K**\ *directory*] [**-l**\ *length*] +[**-f**\ *file*] [**-d**\ *DNSKEY TTL*] [**-m**\ *max TTL*] +[**-r**\ *interval*] [**-c**\ *compilezone path*] [**-k**] [**-z**] +[zone...] + +Description +~~~~~~~~~~~ + +``dnssec-coverage`` verifies that the DNSSEC keys for a given zone or a +set of zones have timing metadata set properly to ensure no future +lapses in DNSSEC coverage. + +If ``zone`` is specified, then keys found in the key repository matching +that zone are scanned, and an ordered list is generated of the events +scheduled for that key (i.e., publication, activation, inactivation, +deletion). The list of events is walked in order of occurrence. Warnings +are generated if any event is scheduled which could cause the zone to +enter a state in which validation failures might occur: for example, if +the number of published or active keys for a given algorithm drops to +zero, or if a key is deleted from the zone too soon after a new key is +rolled, and cached data signed by the prior key has not had time to +expire from resolver caches. + +If ``zone`` is not specified, then all keys in the key repository will +be scanned, and all zones for which there are keys will be analyzed. +(Note: This method of reporting is only accurate if all the zones that +have keys in a given repository share the same TTL parameters.) + +Options +~~~~~~~ + +**-K** *directory* + + Sets the directory in which keys can be found. Defaults to the + current working directory. + +**-f** *file* + + If a ``file`` is specified, then the zone is read from that file; the + largest TTL and the DNSKEY TTL are determined directly from the zone + data, and the ``-m`` and ``-d`` options do not need to be specified + on the command line. + +**-l** *duration* + + The length of time to check for DNSSEC coverage. Key events scheduled + further into the future than ``duration`` will be ignored, and + assumed to be correct. + + The value of ``duration`` can be set in seconds, or in larger units + of time by adding a suffix: mi for minutes, h for hours, d for days, + w for weeks, mo for months, y for years. + +**-m** *maximum TTL* + + Sets the value to be used as the maximum TTL for the zone or zones + being analyzed when determining whether there is a possibility of + validation failure. When a zone-signing key is deactivated, there + must be enough time for the record in the zone with the longest TTL + to have expired from resolver caches before that key can be purged + from the DNSKEY RRset. If that condition does not apply, a warning + will be generated. + + The length of the TTL can be set in seconds, or in larger units of + time by adding a suffix: mi for minutes, h for hours, d for days, w + for weeks, mo for months, y for years. + + This option is not necessary if the ``-f`` has been used to specify a + zone file. If ``-f`` has been specified, this option may still be + used; it will override the value found in the file. + + If this option is not used and the maximum TTL cannot be retrieved + from a zone file, a warning is generated and a default value of 1 + week is used. + +**-d** *DNSKEY TTL* + + Sets the value to be used as the DNSKEY TTL for the zone or zones + being analyzed when determining whether there is a possibility of + validation failure. When a key is rolled (that is, replaced with a + new key), there must be enough time for the old DNSKEY RRset to have + expired from resolver caches before the new key is activated and + begins generating signatures. If that condition does not apply, a + warning will be generated. + + The length of the TTL can be set in seconds, or in larger units of + time by adding a suffix: mi for minutes, h for hours, d for days, w + for weeks, mo for months, y for years. + + This option is not necessary if ``-f`` has been used to specify a + zone file from which the TTL of the DNSKEY RRset can be read, or if a + default key TTL was set using ith the ``-L`` to ``dnssec-keygen``. If + either of those is true, this option may still be used; it will + override the values found in the zone file or the key file. + + If this option is not used and the key TTL cannot be retrieved from + the zone file or the key file, then a warning is generated and a + default value of 1 day is used. + +**-r** *resign interval* + + Sets the value to be used as the resign interval for the zone or + zones being analyzed when determining whether there is a possibility + of validation failure. This value defaults to 22.5 days, which is + also the default in ``named``. However, if it has been changed by the + ``sig-validity-interval`` option in named.conf, then it should also + be changed here. + + The length of the interval can be set in seconds, or in larger units + of time by adding a suffix: mi for minutes, h for hours, d for days, + w for weeks, mo for months, y for years. + +**-k** + + Only check KSK coverage; ignore ZSK events. Cannot be used with + ``-z``. + +**-z** + + Only check ZSK coverage; ignore KSK events. Cannot be used with + ``-k``. + +**-c** *compilezone path* + + Specifies a path to a ``named-compilezone`` binary. Used for testing. + +See Also +~~~~~~~~ + +``dnssec-checkds``\ (8), ``dnssec-dsfromkey``\ (8), +``dnssec-keygen``\ (8), ``dnssec-signzone``\ (8) diff --git a/bin/python/dnssec-keymgr.py.in b/bin/python/dnssec-keymgr.py.in new file mode 100644 index 0000000..f8ee013 --- /dev/null +++ b/bin/python/dnssec-keymgr.py.in @@ -0,0 +1,32 @@ +#!@PYTHON@ + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import os +import sys + +sys.path.insert(0, os.path.dirname(sys.argv[0])) +if os.name != "nt": + if "@PYTHON_INSTALL_DIR@": # value of --with-python-install-dir + sys.path.insert(1, "@PYTHON_INSTALL_DIR@") + else: + sys.path.insert( + 1, + os.path.join( + "@prefix@", "lib", "python" + sys.version[:3], "site-packages" + ), + ) + +import isc.keymgr + +if __name__ == "__main__": + isc.keymgr.main() diff --git a/bin/python/dnssec-keymgr.rst b/bin/python/dnssec-keymgr.rst new file mode 100644 index 0000000..4320541 --- /dev/null +++ b/bin/python/dnssec-keymgr.rst @@ -0,0 +1,223 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_dnssec-keymgr: + +dnssec-keymgr - Ensures correct DNSKEY coverage based on a defined policy +------------------------------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`dnssec-keymgr` [**-K**\ *directory*] [**-c**\ *file*] [**-f**] [**-k**] [**-q**] [**-v**] [**-z**] [**-g**\ *path*] [**-s**\ *path*] [zone...] + +Description +~~~~~~~~~~~ + +``dnssec-keymgr`` is a high level Python wrapper to facilitate the key +rollover process for zones handled by BIND. It uses the BIND commands +for manipulating DNSSEC key metadata: ``dnssec-keygen`` and +``dnssec-settime``. + +DNSSEC policy can be read from a configuration file (default +/etc/dnssec-policy.conf), from which the key parameters, publication and +rollover schedule, and desired coverage duration for any given zone can +be determined. This file may be used to define individual DNSSEC +policies on a per-zone basis, or to set a "default" policy used for all +zones. + +When ``dnssec-keymgr`` runs, it examines the DNSSEC keys for one or more +zones, comparing their timing metadata against the policies for those +zones. If key settings do not conform to the DNSSEC policy (for example, +because the policy has been changed), they are automatically corrected. + +A zone policy can specify a duration for which we want to ensure the key +correctness (``coverage``). It can also specify a rollover period +(``roll-period``). If policy indicates that a key should roll over +before the coverage period ends, then a successor key will automatically +be created and added to the end of the key series. + +If zones are specified on the command line, ``dnssec-keymgr`` will +examine only those zones. If a specified zone does not already have keys +in place, then keys will be generated for it according to policy. + +If zones are *not* specified on the command line, then ``dnssec-keymgr`` +will search the key directory (either the current working directory or +the directory set by the ``-K`` option), and check the keys for all the +zones represented in the directory. + +Key times that are in the past will not be updated unless the ``-f`` is +used (see below). Key inactivation and deletion times that are less than +five minutes in the future will be delayed by five minutes. + +It is expected that this tool will be run automatically and unattended +(for example, by ``cron``). + +Options +~~~~~~~ + +**-c** *file* + + If ``-c`` is specified, then the DNSSEC policy is read from ``file``. + (If not specified, then the policy is read from + /etc/dnssec-policy.conf; if that file doesnt exist, a built-in global + default policy is used.) + +**-f** + + Force: allow updating of key events even if they are already in the + past. This is not recommended for use with zones in which keys have + already been published. However, if a set of keys has been generated + all of which have publication and activation dates in the past, but + the keys have not been published in a zone as yet, then this option + can be used to clean them up and turn them into a proper series of + keys with appropriate rollover intervals. + +**-g** *keygen-path* + + Specifies a path to a ``dnssec-keygen`` binary. Used for testing. See + also the ``-s`` option. + +**-h** + + Print the ``dnssec-keymgr`` help summary and exit. + +**-K** *directory* + + Sets the directory in which keys can be found. Defaults to the + current working directory. + +**-k** + + Only apply policies to KSK keys. See also the ``-z`` option. + +**-q** + + Quiet: suppress printing of ``dnssec-keygen`` and ``dnssec-settime``. + +**-s** *settime-path* + + Specifies a path to a ``dnssec-settime`` binary. Used for testing. + See also the ``-g`` option. + +**-v** + + Print the ``dnssec-keymgr`` version and exit. + +**-z** + + Only apply policies to ZSK keys. See also the ``-k`` option. + +Policy Configuration +~~~~~~~~~~~~~~~~~~~~ + +The dnssec-policy.conf file can specify three kinds of policies: + + · *Policy classes* (``policy``\ *name*\ ``{ ... };``) can be + inherited by zone policies or other policy classes; these can be used + to create sets of different security profiles. For example, a policy + class ``normal`` might specify 1024-bit key sizes, but a class + ``extra`` might specify 2048 bits instead; ``extra`` would be used + for zones that had unusually high security needs. + +.. + + · *Algorithm policies:* (``algorithm-policy``\ *algorithm*\ ``{ ... + };`` ) override default per-algorithm settings. For example, by + default, RSASHA256 keys use 2048-bit key sizes for both KSK and ZSK. + This can be modified using ``algorithm-policy``, and the new key + sizes would then be used for any key of type RSASHA256. + + · *Zone policies:* (``zone``\ *name*\ ``{ ... };`` ) set policy for a + single zone by name. A zone policy can inherit a policy class by + including a ``policy`` option. Zone names beginning with digits + (i.e., 0-9) must be quoted. If a zone does not have its own policy + then the "default" policy applies. + +Options that can be specified in policies: + +``algorithm`` *name*; + + The key algorithm. If no policy is defined, the default is RSASHA256. + +``coverage`` *duration*; + + The length of time to ensure that keys will be correct; no action + will be taken to create new keys to be activated after this time. + This can be represented as a number of seconds, or as a duration + using human-readable units (examples: "1y" or "6 months"). A default + value for this option can be set in algorithm policies as well as in + policy classes or zone policies. If no policy is configured, the + default is six months. + +``directory`` *path*; + + Specifies the directory in which keys should be stored. + +``key-size`` *keytype* *size*; + + Specifies the number of bits to use in creating keys. The keytype is + either "zsk" or "ksk". A default value for this option can be set in + algorithm policies as well as in policy classes or zone policies. If + no policy is configured, the default is 2048 bits for RSA keys. + +``keyttl`` *duration*; + + The key TTL. If no policy is defined, the default is one hour. + +``post-publish`` *keytype* *duration*; + + How long after inactivation a key should be deleted from the zone. + Note: If ``roll-period`` is not set, this value is ignored. The + keytype is either "zsk" or "ksk". A default duration for this option + can be set in algorithm policies as well as in policy classes or zone + policies. The default is one month. + +``pre-publish`` *keytype* *duration*; + + How long before activation a key should be published. Note: If + ``roll-period`` is not set, this value is ignored. The keytype is + either "zsk" or "ksk". A default duration for this option can be set + in algorithm policies as well as in policy classes or zone policies. + The default is one month. + +``roll-period`` *keytype* *duration*; + + How frequently keys should be rolled over. The keytype is either + "zsk" or "ksk". A default duration for this option can be set in + algorithm policies as well as in policy classes or zone policies. If + no policy is configured, the default is one year for ZSKs. KSKs do + not roll over by default. + +``standby`` *keytype* *number*; + + Not yet implemented. + +Remaining Work +~~~~~~~~~~~~~~ + + · Enable scheduling of KSK rollovers using the ``-P sync`` and ``-D + sync`` options to ``dnssec-keygen`` and ``dnssec-settime``. Check the + parent zone (as in ``dnssec-checkds``) to determine when its safe for + the key to roll. + +.. + + · Allow configuration of standby keys and use of the REVOKE bit, for + keys that use RFC 5011 semantics. + +See Also +~~~~~~~~ + +``dnssec-coverage``\ (8), ``dnssec-keygen``\ (8), +``dnssec-settime``\ (8), ``dnssec-checkds``\ (8) diff --git a/bin/python/isc/Makefile.in b/bin/python/isc/Makefile.in new file mode 100644 index 0000000..f175c6c --- /dev/null +++ b/bin/python/isc/Makefile.in @@ -0,0 +1,45 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +SUBDIRS = tests + +PYTHON = @PYTHON@ + +PYSRCS = __init__.py checkds.py coverage.py dnskey.py eventlist.py \ + keydict.py keyevent.py keymgr.py keyseries.py keyzone.py \ + policy.py rndc.py utils.py + +TARGETS = parsetab.py + +@BIND9_MAKE_RULES@ + +.SUFFIXES: .py .pyc +.py.pyc: + $(PYTHON) -m compileall . + +parsetab.py: policy.py + $(PYTHON) policy.py parse /dev/null > /dev/null + PYTHONPATH=${srcdir} $(PYTHON) -m parsetab + +check test: subdirs + +clean distclean:: + rm -f *.pyc parser.out parsetab.py + rm -rf __pycache__ build + +distclean:: + rm -rf ${PYSRCS} diff --git a/bin/python/isc/__init__.py.in b/bin/python/isc/__init__.py.in new file mode 100644 index 0000000..405c3d7 --- /dev/null +++ b/bin/python/isc/__init__.py.in @@ -0,0 +1,38 @@ +#!/usr/bin/python3 + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +__all__ = [ + "checkds", + "coverage", + "keymgr", + "dnskey", + "eventlist", + "keydict", + "keyevent", + "keyseries", + "keyzone", + "policy", + "parsetab", + "rndc", + "utils", +] + +from isc.dnskey import * +from isc.eventlist import * +from isc.keydict import * +from isc.keyevent import * +from isc.keyseries import * +from isc.keyzone import * +from isc.policy import * +from isc.rndc import * +from isc.utils import * diff --git a/bin/python/isc/checkds.py.in b/bin/python/isc/checkds.py.in new file mode 100644 index 0000000..f2e6562 --- /dev/null +++ b/bin/python/isc/checkds.py.in @@ -0,0 +1,226 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import argparse +import os +import sys +from subprocess import Popen, PIPE + +from isc.utils import prefix, version + +prog = "dnssec-checkds" + + +############################################################################ +# SECRR class: +# Class for DS resource record +############################################################################ +class SECRR: + hashalgs = {1: "SHA-1", 2: "SHA-256", 3: "GOST", 4: "SHA-384"} + rrname = "" + rrclass = "IN" + keyid = None + keyalg = None + hashalg = None + digest = "" + ttl = 0 + + def __init__(self, rrtext): + if not rrtext: + raise Exception + + # 'str' does not have decode method in python3 + if type(rrtext) is not str: + fields = rrtext.decode("ascii").split() + else: + fields = rrtext.split() + if len(fields) < 7: + raise Exception + + self.rrtype = "DS" + self.rrname = fields[0].lower() + + fields = fields[1:] + if fields[0].upper() in ["IN", "CH", "HS"]: + self.rrclass = fields[0].upper() + fields = fields[1:] + else: + self.ttl = int(fields[0]) + self.rrclass = fields[1].upper() + fields = fields[2:] + + if fields[0].upper() != self.rrtype: + raise Exception("%s does not match %s" % (fields[0].upper(), self.rrtype)) + + self.keyid, self.keyalg, self.hashalg = map(int, fields[1:4]) + self.digest = "".join(fields[4:]).upper() + + def __repr__(self): + return "%s %s %s %d %d %d %s" % ( + self.rrname, + self.rrclass, + self.rrtype, + self.keyid, + self.keyalg, + self.hashalg, + self.digest, + ) + + def __eq__(self, other): + return self.__repr__() == other.__repr__() + + +############################################################################ +# check: +# Fetch DS RRset for the given zone from the DNS; fetch DNSKEY +# RRset from the masterfile if specified, or from DNS if not. +# Generate a set of expected DS records from the DNSKEY RRset, +# and report on congruency. +############################################################################ +def check(zone, args): + rrlist = [] + if args.dssetfile: + fp = open(args.dssetfile).read() + else: + cmd = [args.dig, "+noall", "+answer", "-t", "ds", "-q", zone] + fp, _ = Popen(cmd, stdout=PIPE).communicate() + + for line in fp.splitlines(): + if type(line) is not str: + line = line.decode("ascii") + rrlist.append(SECRR(line)) + rrlist = sorted(rrlist, key=lambda rr: (rr.keyid, rr.keyalg, rr.hashalg)) + + klist = [] + + cmd = [args.dsfromkey] + for algo in args.algo: + cmd += ["-a", algo] + + if args.masterfile: + cmd += ["-f", args.masterfile, zone] + fp, _ = Popen(cmd, stdout=PIPE).communicate() + else: + intods, _ = Popen( + [args.dig, "+noall", "+answer", "-t", "dnskey", "-q", zone], stdout=PIPE + ).communicate() + cmd += ["-f", "-", zone] + fp, _ = Popen(cmd, stdin=PIPE, stdout=PIPE).communicate(intods) + + for line in fp.splitlines(): + if type(line) is not str: + line = line.decode("ascii") + klist.append(SECRR(line)) + + if len(klist) < 1: + print("No DNSKEY records found in zone apex") + return False + + match = True + for rr in rrlist: + if rr not in klist: + print( + "KSK for %s %s/%03d/%05d (%s) missing from child" + % ( + rr.rrtype, + rr.rrname.strip("."), + rr.keyalg, + rr.keyid, + SECRR.hashalgs[rr.hashalg], + ) + ) + match = False + for rr in klist: + if rr not in rrlist: + print( + "%s for KSK %s/%03d/%05d (%s) missing from parent" + % ( + rr.rrtype, + rr.rrname.strip("."), + rr.keyalg, + rr.keyid, + SECRR.hashalgs[rr.hashalg], + ) + ) + match = False + for rr in klist: + if rr in rrlist: + print( + "%s for KSK %s/%03d/%05d (%s) found in parent" + % ( + rr.rrtype, + rr.rrname.strip("."), + rr.keyalg, + rr.keyid, + SECRR.hashalgs[rr.hashalg], + ) + ) + + return match + + +############################################################################ +# parse_args: +# Read command line arguments, set global 'args' structure +############################################################################ +def parse_args(): + parser = argparse.ArgumentParser(description=prog + ": checks DS coverage") + + bindir = "bin" + sbindir = "bin" if os.name == "nt" else "sbin" + + parser.add_argument("zone", type=str, help="zone to check") + parser.add_argument( + "-a", + "--algo", + dest="algo", + action="append", + default=[], + type=str, + help="DS digest algorithm", + ) + parser.add_argument( + "-d", + "--dig", + dest="dig", + default=os.path.join(prefix(bindir), "dig"), + type=str, + help="path to 'dig'", + ) + parser.add_argument( + "-D", + "--dsfromkey", + dest="dsfromkey", + default=os.path.join(prefix(sbindir), "dnssec-dsfromkey"), + type=str, + help="path to 'dnssec-dsfromkey'", + ) + parser.add_argument( + "-f", "--file", dest="masterfile", type=str, help="zone master file" + ) + parser.add_argument( + "-s", "--dsset", dest="dssetfile", type=str, help="prepared DSset file" + ) + parser.add_argument("-v", "--version", action="version", version=version) + args = parser.parse_args() + + args.zone = args.zone.strip(".") + + return args + + +############################################################################ +# Main +############################################################################ +def main(): + args = parse_args() + match = check(args.zone, args) + exit(0 if match else 1) diff --git a/bin/python/isc/coverage.py.in b/bin/python/isc/coverage.py.in new file mode 100644 index 0000000..e9be265 --- /dev/null +++ b/bin/python/isc/coverage.py.in @@ -0,0 +1,333 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +from __future__ import print_function +import os +import sys +import argparse +import glob +import re +import time +import calendar +import pprint +from collections import defaultdict + +prog = "dnssec-coverage" + +from isc import dnskey, eventlist, keydict, keyevent, keyzone, utils + + +############################################################################ +# print a fatal error and exit +############################################################################ +def fatal(*args, **kwargs): + print(*args, **kwargs) + sys.exit(1) + + +############################################################################ +# output: +############################################################################ +_firstline = True + + +def output(*args, **kwargs): + """output text, adding a vertical space this is *not* the first + first section being printed since a call to vreset()""" + global _firstline + if "skip" in kwargs: + skip = kwargs["skip"] + kwargs.pop("skip", None) + else: + skip = True + if _firstline: + _firstline = False + elif skip: + print("") + if args: + print(*args, **kwargs) + + +def vreset(): + """reset vertical spacing""" + global _firstline + _firstline = True + + +############################################################################ +# parse_time +############################################################################ +def parse_time(s): + """convert a formatted time (e.g., 1y, 6mo, 15mi, etc) into seconds + :param s: String with some text representing a time interval + :return: Integer with the number of seconds in the time interval + """ + s = s.strip() + + # if s is an integer, we're done already + try: + return int(s) + except ValueError: + pass + + # try to parse as a number with a suffix indicating unit of time + r = re.compile(r"([0-9][0-9]*)\s*([A-Za-z]*)") + m = r.match(s) + if not m: + raise ValueError("Cannot parse %s" % s) + n, unit = m.groups() + n = int(n) + unit = unit.lower() + if unit.startswith("y"): + return n * 31536000 + elif unit.startswith("mo"): + return n * 2592000 + elif unit.startswith("w"): + return n * 604800 + elif unit.startswith("d"): + return n * 86400 + elif unit.startswith("h"): + return n * 3600 + elif unit.startswith("mi"): + return n * 60 + elif unit.startswith("s"): + return n + else: + raise ValueError("Invalid suffix %s" % unit) + + +############################################################################ +# set_path: +############################################################################ +def set_path(command, default=None): + """find the location of a specified command. if a default is supplied + and it works, we use it; otherwise we search PATH for a match. + :param command: string with a command to look for in the path + :param default: default location to use + :return: detected location for the desired command + """ + + fpath = default + if not fpath or not os.path.isfile(fpath) or not os.access(fpath, os.X_OK): + path = os.environ["PATH"] + if not path: + path = os.path.defpath + for directory in path.split(os.pathsep): + fpath = os.path.join(directory, command) + if os.path.isfile(fpath) and os.access(fpath, os.X_OK): + break + fpath = None + + return fpath + + +############################################################################ +# parse_args: +############################################################################ +def parse_args(): + """Read command line arguments, set global 'args' structure""" + compilezone = set_path( + "named-compilezone", os.path.join(utils.prefix("sbin"), "named-compilezone") + ) + + parser = argparse.ArgumentParser( + description=prog + ": checks future " + "DNSKEY coverage for a zone" + ) + + parser.add_argument( + "zone", + type=str, + nargs="*", + default=None, + help="zone(s) to check" + "(default: all zones in the directory)", + ) + parser.add_argument( + "-K", + dest="path", + default=".", + type=str, + help="a directory containing keys to process", + metavar="dir", + ) + parser.add_argument( + "-f", dest="filename", type=str, help="zone master file", metavar="file" + ) + parser.add_argument( + "-m", + dest="maxttl", + type=str, + help="the longest TTL in the zone(s)", + metavar="time", + ) + parser.add_argument( + "-d", dest="keyttl", type=str, help="the DNSKEY TTL", metavar="time" + ) + parser.add_argument( + "-r", + dest="resign", + default="1944000", + type=str, + help="the RRSIG refresh interval " "in seconds [default: 22.5 days]", + metavar="time", + ) + parser.add_argument( + "-c", + dest="compilezone", + default=compilezone, + type=str, + help="path to 'named-compilezone'", + metavar="path", + ) + parser.add_argument( + "-l", + dest="checklimit", + type=str, + default="0", + help="Length of time to check for " "DNSSEC coverage [default: 0 (unlimited)]", + metavar="time", + ) + parser.add_argument( + "-z", + dest="no_ksk", + action="store_true", + default=False, + help="Only check zone-signing keys (ZSKs)", + ) + parser.add_argument( + "-k", + dest="no_zsk", + action="store_true", + default=False, + help="Only check key-signing keys (KSKs)", + ) + parser.add_argument( + "-D", + "--debug", + dest="debug_mode", + action="store_true", + default=False, + help="Turn on debugging output", + ) + parser.add_argument("-v", "--version", action="version", version=utils.version) + + args = parser.parse_args() + + if args.no_zsk and args.no_ksk: + fatal("ERROR: -z and -k cannot be used together.") + elif args.no_zsk or args.no_ksk: + args.keytype = "KSK" if args.no_zsk else "ZSK" + else: + args.keytype = None + + if args.filename and len(args.zone) > 1: + fatal("ERROR: -f can only be used with one zone.") + + # strip trailing dots if any + args.zone = [x[:-1] if (len(x) > 1 and x[-1] == ".") else x for x in args.zone] + + # convert from time arguments to seconds + try: + if args.maxttl: + m = parse_time(args.maxttl) + args.maxttl = m + except ValueError: + pass + + try: + if args.keyttl: + k = parse_time(args.keyttl) + args.keyttl = k + except ValueError: + pass + + try: + if args.resign: + r = parse_time(args.resign) + args.resign = r + except ValueError: + pass + + try: + if args.checklimit: + lim = args.checklimit + r = parse_time(args.checklimit) + if r == 0: + args.checklimit = None + else: + args.checklimit = time.time() + r + except ValueError: + pass + + # if we've got the values we need from the command line, stop now + if args.maxttl and args.keyttl: + return args + + # load keyttl and maxttl data from zonefile + if args.zone and args.filename: + try: + zone = keyzone(args.zone[0], args.filename, args.compilezone) + args.maxttl = args.maxttl or zone.maxttl + args.keyttl = args.maxttl or zone.keyttl + except Exception as e: + print("Unable to load zone data from %s: " % args.filename, e) + + if not args.maxttl: + output( + "WARNING: Maximum TTL value was not specified. Using 1 week\n" + "\t (604800 seconds); re-run with the -m option to get more\n" + "\t accurate results." + ) + args.maxttl = 604800 + + return args + + +############################################################################ +# Main +############################################################################ +def main(): + args = parse_args() + + print("PHASE 1--Loading keys to check for internal timing problems") + + try: + kd = keydict(path=args.path, zones=args.zone, keyttl=args.keyttl) + except Exception as e: + fatal("ERROR: Unable to build key dictionary: " + str(e)) + + for key in kd: + key.check_prepub(output) + if key.sep: + key.check_postpub(output) + else: + key.check_postpub(output, args.maxttl + args.resign) + + output("PHASE 2--Scanning future key events for coverage failures") + vreset() + + try: + elist = eventlist(kd) + except Exception as e: + fatal("ERROR: Unable to build event list: " + str(e)) + + errors = False + if not args.zone: + if not elist.coverage(None, args.keytype, args.checklimit, output): + errors = True + else: + for zone in args.zone: + try: + if not elist.coverage(zone, args.keytype, args.checklimit, output): + errors = True + except: + output("ERROR: Coverage check failed for zone " + zone) + + sys.exit(1 if errors else 0) diff --git a/bin/python/isc/dnskey.py.in b/bin/python/isc/dnskey.py.in new file mode 100644 index 0000000..c4cdc57 --- /dev/null +++ b/bin/python/isc/dnskey.py.in @@ -0,0 +1,570 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import os +import time +import calendar +from subprocess import Popen, PIPE + + +######################################################################## +# Class dnskey +######################################################################## +class TimePast(Exception): + def __init__(self, key, prop, value): + super(TimePast, self).__init__( + "%s time for key %s (%d) is already past" % (prop, key, value) + ) + + +class dnskey: + """An individual DNSSEC key. Identified by path, name, algorithm, keyid. + Contains a dictionary of metadata events.""" + + _PROPS = ( + "Created", + "Publish", + "Activate", + "Inactive", + "Delete", + "Revoke", + "DSPublish", + "SyncPublish", + "SyncDelete", + ) + _OPTS = (None, "-P", "-A", "-I", "-D", "-R", None, "-Psync", "-Dsync") + + _ALGNAMES = ( + None, + "RSAMD5", + "DH", + "DSA", + None, + "RSASHA1", + "NSEC3DSA", + "NSEC3RSASHA1", + "RSASHA256", + None, + "RSASHA512", + None, + "ECCGOST", + "ECDSAP256SHA256", + "ECDSAP384SHA384", + "ED25519", + "ED448", + ) + + def __init__(self, key, directory=None, keyttl=None): + # this makes it possible to use algname as a class or instance method + if isinstance(key, tuple) and len(key) == 3: + self._dir = directory or "." + (name, alg, keyid) = key + self.fromtuple(name, alg, keyid, keyttl) + + self._dir = directory or os.path.dirname(key) or "." + key = os.path.basename(key) + (name, alg, keyid) = key.split("+") + name = name[1:-1] + alg = int(alg) + keyid = int(keyid.split(".")[0]) + self.fromtuple(name, alg, keyid, keyttl) + + def fromtuple(self, name, alg, keyid, keyttl): + if name.endswith("."): + fullname = name + name = name.rstrip(".") + else: + fullname = name + "." + + keystr = "K%s+%03d+%05d" % (fullname, alg, keyid) + key_file = self._dir + (self._dir and os.sep or "") + keystr + ".key" + private_file = self._dir + (self._dir and os.sep or "") + keystr + ".private" + + self.keystr = keystr + + self.name = name + self.alg = int(alg) + self.keyid = int(keyid) + self.fullname = fullname + + kfp = open(key_file, "r") + for line in kfp: + if line[0] == ";": + continue + tokens = line.split() + if not tokens: + continue + + if tokens[1].lower() in ("in", "ch", "hs"): + septoken = 3 + self.ttl = keyttl + else: + septoken = 4 + self.ttl = int(tokens[1]) if not keyttl else keyttl + + if (int(tokens[septoken]) & 0x1) == 1: + self.sep = True + else: + self.sep = False + kfp.close() + + pfp = open(private_file, "r") + + self.metadata = dict() + self._changed = dict() + self._delete = dict() + self._times = dict() + self._fmttime = dict() + self._timestamps = dict() + self._original = dict() + self._origttl = None + + for line in pfp: + line = line.strip() + if not line or line[0] in ("!#"): + continue + punctuation = [line.find(c) for c in ":= "] + [len(line)] + found = min([pos for pos in punctuation if pos != -1]) + name = line[:found].rstrip() + value = line[found:].lstrip(":= ").rstrip() + self.metadata[name] = value + + for prop in dnskey._PROPS: + self._changed[prop] = False + if prop in self.metadata: + t = self.parsetime(self.metadata[prop]) + self._times[prop] = t + self._fmttime[prop] = self.formattime(t) + self._timestamps[prop] = self.epochfromtime(t) + self._original[prop] = self._timestamps[prop] + else: + self._times[prop] = None + self._fmttime[prop] = None + self._timestamps[prop] = None + self._original[prop] = None + + pfp.close() + + def commit(self, settime_bin, **kwargs): + quiet = kwargs.get("quiet", False) + cmd = [] + first = True + + if self._origttl is not None: + cmd += ["-L", str(self.ttl)] + + for prop, opt in zip(dnskey._PROPS, dnskey._OPTS): + if not opt or not self._changed[prop]: + continue + + delete = False + if prop in self._delete and self._delete[prop]: + delete = True + + when = "none" if delete else self._fmttime[prop] + cmd += [opt, when] + first = False + + if cmd: + fullcmd = ( + [settime_bin, "-K", self._dir] + + cmd + + [ + self.keystr, + ] + ) + if not quiet: + print("# " + " ".join(fullcmd)) + try: + p = Popen(fullcmd, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + if stderr: + raise Exception(str(stderr)) + except Exception as e: + raise Exception("unable to run %s: %s" % (settime_bin, str(e))) + self._origttl = None + for prop in dnskey._PROPS: + self._original[prop] = self._timestamps[prop] + self._changed[prop] = False + + @classmethod + def generate( + cls, + keygen_bin, + randomdev, + keys_dir, + name, + alg, + keysize, + sep, + ttl, + publish=None, + activate=None, + **kwargs + ): + quiet = kwargs.get("quiet", False) + + keygen_cmd = [keygen_bin, "-q", "-K", keys_dir, "-L", str(ttl)] + + if randomdev: + keygen_cmd += ["-r", randomdev] + + if sep: + keygen_cmd.append("-fk") + + if alg: + keygen_cmd += ["-a", alg] + + if keysize: + keygen_cmd += ["-b", str(keysize)] + + if publish: + t = dnskey.timefromepoch(publish) + keygen_cmd += ["-P", dnskey.formattime(t)] + + if activate: + t = dnskey.timefromepoch(activate) + keygen_cmd += ["-A", dnskey.formattime(activate)] + + keygen_cmd.append(name) + + if not quiet: + print("# " + " ".join(keygen_cmd)) + + p = Popen(keygen_cmd, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + if stderr: + raise Exception("unable to generate key: " + str(stderr)) + + try: + keystr = stdout.splitlines()[0].decode("ascii") + newkey = dnskey(keystr, keys_dir, ttl) + return newkey + except Exception as e: + raise Exception("unable to parse generated key: %s" % str(e)) + + def generate_successor(self, keygen_bin, randomdev, prepublish, **kwargs): + quiet = kwargs.get("quiet", False) + + if not self.inactive(): + raise Exception("predecessor key %s has no inactive date" % self) + + keygen_cmd = [keygen_bin, "-q", "-K", self._dir, "-S", self.keystr] + + if self.ttl: + keygen_cmd += ["-L", str(self.ttl)] + + if randomdev: + keygen_cmd += ["-r", randomdev] + + if prepublish: + keygen_cmd += ["-i", str(prepublish)] + + if not quiet: + print("# " + " ".join(keygen_cmd)) + + p = Popen(keygen_cmd, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + if stderr: + raise Exception("unable to generate key: " + stderr) + + try: + keystr = stdout.splitlines()[0].decode("ascii") + newkey = dnskey(keystr, self._dir, self.ttl) + return newkey + except: + raise Exception("unable to generate successor for key %s" % self) + + @staticmethod + def algstr(alg): + name = None + if alg in range(len(dnskey._ALGNAMES)): + name = dnskey._ALGNAMES[alg] + return name if name else ("%03d" % alg) + + @staticmethod + def algnum(alg): + if not alg: + return None + alg = alg.upper() + try: + return dnskey._ALGNAMES.index(alg) + except ValueError: + return None + + def algname(self, alg=None): + return self.algstr(alg or self.alg) + + @staticmethod + def timefromepoch(secs): + return time.gmtime(secs) + + @staticmethod + def parsetime(string): + return time.strptime(string, "%Y%m%d%H%M%S") + + @staticmethod + def epochfromtime(t): + return calendar.timegm(t) + + @staticmethod + def formattime(t): + return time.strftime("%Y%m%d%H%M%S", t) + + def setmeta(self, prop, secs, now, **kwargs): + force = kwargs.get("force", False) + + if self._timestamps[prop] == secs: + return + + if ( + self._original[prop] is not None + and self._original[prop] < now + and not force + ): + raise TimePast(self, prop, self._original[prop]) + + if secs is None: + self._changed[prop] = False if self._original[prop] is None else True + + self._delete[prop] = True + self._timestamps[prop] = None + self._times[prop] = None + self._fmttime[prop] = None + return + + t = self.timefromepoch(secs) + self._timestamps[prop] = secs + self._times[prop] = t + self._fmttime[prop] = self.formattime(t) + self._changed[prop] = ( + False if self._original[prop] == self._timestamps[prop] else True + ) + + def gettime(self, prop): + return self._times[prop] + + def getfmttime(self, prop): + return self._fmttime[prop] + + def gettimestamp(self, prop): + return self._timestamps[prop] + + def created(self): + return self._timestamps["Created"] + + def syncpublish(self): + return self._timestamps["SyncPublish"] + + def setsyncpublish(self, secs, now=time.time(), **kwargs): + self.setmeta("SyncPublish", secs, now, **kwargs) + + def publish(self): + return self._timestamps["Publish"] + + def setpublish(self, secs, now=time.time(), **kwargs): + self.setmeta("Publish", secs, now, **kwargs) + + def activate(self): + return self._timestamps["Activate"] + + def setactivate(self, secs, now=time.time(), **kwargs): + self.setmeta("Activate", secs, now, **kwargs) + + def revoke(self): + return self._timestamps["Revoke"] + + def setrevoke(self, secs, now=time.time(), **kwargs): + self.setmeta("Revoke", secs, now, **kwargs) + + def inactive(self): + return self._timestamps["Inactive"] + + def setinactive(self, secs, now=time.time(), **kwargs): + self.setmeta("Inactive", secs, now, **kwargs) + + def delete(self): + return self._timestamps["Delete"] + + def setdelete(self, secs, now=time.time(), **kwargs): + self.setmeta("Delete", secs, now, **kwargs) + + def syncdelete(self): + return self._timestamps["SyncDelete"] + + def setsyncdelete(self, secs, now=time.time(), **kwargs): + self.setmeta("SyncDelete", secs, now, **kwargs) + + def setttl(self, ttl): + if ttl is None or self.ttl == ttl: + return + elif self._origttl is None: + self._origttl = self.ttl + self.ttl = ttl + elif self._origttl == ttl: + self._origttl = None + self.ttl = ttl + else: + self.ttl = ttl + + def keytype(self): + return "KSK" if self.sep else "ZSK" + + def __str__(self): + return "%s/%s/%05d" % (self.name, self.algname(), self.keyid) + + def __repr__(self): + return "%s/%s/%05d (%s)" % ( + self.name, + self.algname(), + self.keyid, + ("KSK" if self.sep else "ZSK"), + ) + + def date(self): + return self.activate() or self.publish() or self.created() + + # keys are sorted first by zone name, then by algorithm. within + # the same name/algorithm, they are sorted according to their + # 'date' value: the activation date if set, OR the publication + # if set, OR the creation date. + def __lt__(self, other): + if self.name != other.name: + return self.name < other.name + if self.alg != other.alg: + return self.alg < other.alg + return self.date() < other.date() + + def check_prepub(self, output=None): + def noop(*args, **kwargs): + pass + + if not output: + output = noop + + now = int(time.time()) + a = self.activate() + p = self.publish() + + if not a: + return False + + if not p: + if a > now: + output( + "WARNING: Key %s is scheduled for\n" + "\t activation but not for publication." % repr(self) + ) + return False + + if p <= now and a <= now: + return True + + if p == a: + output( + "WARNING: %s is scheduled to be\n" + "\t published and activated at the same time. This\n" + "\t could result in a coverage gap if the zone was\n" + "\t previously signed. Activation should be at least\n" + "\t %s after publication." + % (repr(self), dnskey.duration(self.ttl) or "one DNSKEY TTL") + ) + return True + + if a < p: + output("WARNING: Key %s is active before it is published" % repr(self)) + return False + + if self.ttl is not None and a - p < self.ttl: + output( + "WARNING: Key %s is activated too soon\n" + "\t after publication; this could result in coverage \n" + "\t gaps due to resolver caches containing old data.\n" + "\t Activation should be at least %s after\n" + "\t publication." + % (repr(self), dnskey.duration(self.ttl) or "one DNSKEY TTL") + ) + return False + + return True + + def check_postpub(self, output=None, timespan=None): + def noop(*args, **kwargs): + pass + + if output is None: + output = noop + + if timespan is None: + timespan = self.ttl + + if timespan is None: + output("WARNING: Key %s using default TTL." % repr(self)) + timespan = 60 * 60 * 24 + + now = time.time() + d = self.delete() + i = self.inactive() + + if not d: + return False + + if not i: + if d > now: + output( + "WARNING: Key %s is scheduled for\n" + "\t deletion but not for inactivation." % repr(self) + ) + return False + + if d < now and i < now: + return True + + if d < i: + output( + "WARNING: Key %s is scheduled for\n" + "\t deletion before inactivation." % repr(self) + ) + return False + + if d - i < timespan: + output( + "WARNING: Key %s scheduled for\n" + "\t deletion too soon after deactivation; this may \n" + "\t result in coverage gaps due to resolver caches\n" + "\t containing old data. Deletion should be at least\n" + "\t %s after inactivation." % (repr(self), dnskey.duration(timespan)) + ) + return False + + return True + + @staticmethod + def duration(secs): + if not secs: + return None + + units = [ + ("year", 60 * 60 * 24 * 365), + ("month", 60 * 60 * 24 * 30), + ("day", 60 * 60 * 24), + ("hour", 60 * 60), + ("minute", 60), + ("second", 1), + ] + + output = [] + for unit in units: + v, secs = secs // unit[1], secs % unit[1] + if v > 0: + output.append("%d %s%s" % (v, unit[0], "s" if v > 1 else "")) + + return ", ".join(output) diff --git a/bin/python/isc/eventlist.py.in b/bin/python/isc/eventlist.py.in new file mode 100644 index 0000000..f2f26aa --- /dev/null +++ b/bin/python/isc/eventlist.py.in @@ -0,0 +1,178 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +from collections import defaultdict +from .dnskey import * +from .keydict import * +from .keyevent import * + + +class eventlist: + _K = defaultdict(lambda: defaultdict(list)) + _Z = defaultdict(lambda: defaultdict(list)) + _zones = set() + _kdict = None + + def __init__(self, kdict): + properties = [ + "SyncPublish", + "Publish", + "SyncDelete", + "Activate", + "Inactive", + "Delete", + ] + self._kdict = kdict + for zone in kdict.zones(): + self._zones.add(zone) + for alg, keys in kdict[zone].items(): + for k in keys.values(): + for prop in properties: + t = k.gettime(prop) + if not t: + continue + e = keyevent(prop, k, t) + if k.sep: + self._K[zone][alg].append(e) + else: + self._Z[zone][alg].append(e) + + self._K[zone][alg] = sorted( + self._K[zone][alg], key=lambda event: event.when + ) + self._Z[zone][alg] = sorted( + self._Z[zone][alg], key=lambda event: event.when + ) + + # scan events per zone, algorithm, and key type, in order of + # occurrence, noting inconsistent states when found + def coverage(self, zone, keytype, until, output=None): + def noop(*args, **kwargs): + pass + + if not output: + output = noop + + no_zsk = True if (keytype and keytype == "KSK") else False + no_ksk = True if (keytype and keytype == "ZSK") else False + kok = zok = True + found = False + + if zone and not zone in self._zones: + output("ERROR: No key events found for %s" % zone) + return False + + if zone: + found = True + if not no_ksk: + kok = self.checkzone(zone, "KSK", until, output) + if not no_zsk: + zok = self.checkzone(zone, "ZSK", until, output) + else: + for z in self._zones: + if not no_ksk and z in self._K.keys(): + found = True + kok = self.checkzone(z, "KSK", until, output) + if not no_zsk and z in self._Z.keys(): + found = True + zok = self.checkzone(z, "ZSK", until, output) + + if not found: + output("ERROR: No key events found") + return False + + return kok and zok + + def checkzone(self, zone, keytype, until, output): + allok = True + if keytype == "KSK": + kz = self._K[zone] + else: + kz = self._Z[zone] + + for alg in kz.keys(): + output( + "Checking scheduled %s events for zone %s, " + "algorithm %s..." % (keytype, zone, dnskey.algstr(alg)) + ) + ok = eventlist.checkset(kz[alg], keytype, until, output) + if ok: + output("No errors found") + allok = allok and ok + + return allok + + @staticmethod + def showset(eventset, output): + if not eventset: + return + output(" " + eventset[0].showtime() + ":", skip=False) + for event in eventset: + output(" %s: %s" % (event.what, repr(event.key)), skip=False) + + @staticmethod + def checkset(eventset, keytype, until, output): + groups = list() + group = list() + + # collect up all events that have the same time + eventsfound = False + for event in eventset: + # we found an event + eventsfound = True + + # add event to current group + if not group or group[0].when == event.when: + group.append(event) + + # if we're at the end of the list, we're done. if + # we've found an event with a later time, start a new group + if group[0].when != event.when: + groups.append(group) + group = list() + group.append(event) + + if group: + groups.append(group) + + if not eventsfound: + output("ERROR: No %s events found" % keytype) + return False + + active = published = None + for group in groups: + if until and calendar.timegm(group[0].when) > until: + output( + "Ignoring events after %s" + % time.strftime("%a %b %d %H:%M:%S UTC %Y", time.gmtime(until)) + ) + return True + + for event in group: + (active, published) = event.status(active, published) + + eventlist.showset(group, output) + + # and then check for inconsistencies: + if not active: + output("ERROR: No %s's are active after this event" % keytype) + return False + elif not published: + output("ERROR: No %s's are published after this event" % keytype) + return False + elif not published.intersection(active): + output( + "ERROR: No %s's are both active and published " + "after this event" % keytype + ) + return False + + return True diff --git a/bin/python/isc/keydict.py.in b/bin/python/isc/keydict.py.in new file mode 100644 index 0000000..723a32a --- /dev/null +++ b/bin/python/isc/keydict.py.in @@ -0,0 +1,87 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +from collections import defaultdict +from . import dnskey +import os +import glob + + +######################################################################## +# Class keydict +######################################################################## +class keydict: + """A dictionary of keys, indexed by name, algorithm, and key id""" + + _keydict = defaultdict(lambda: defaultdict(dict)) + _defttl = None + _missing = [] + + def __init__(self, dp=None, **kwargs): + self._defttl = kwargs.get("keyttl", None) + zones = kwargs.get("zones", None) + + if not zones: + path = kwargs.get("path", None) or "." + self.readall(path) + else: + for zone in zones: + if "path" in kwargs and kwargs["path"] is not None: + path = kwargs["path"] + else: + path = dp and dp.policy(zone).directory or "." + if not self.readone(path, zone): + self._missing.append(zone) + + def readall(self, path): + files = glob.glob(os.path.join(path, "*.private")) + + for infile in files: + key = dnskey(infile, path, self._defttl) + self._keydict[key.name][key.alg][key.keyid] = key + + def readone(self, path, zone): + if not zone.endswith("."): + zone += "." + match = "K" + zone + "+*.private" + files = glob.glob(os.path.join(path, match)) + + found = False + for infile in files: + key = dnskey(infile, path, self._defttl) + if key.fullname != zone: # shouldn't ever happen + continue + keyname = key.name if zone != "." else "." + self._keydict[keyname][key.alg][key.keyid] = key + found = True + + return found + + def __iter__(self): + for zone, algorithms in self._keydict.items(): + for alg, keys in algorithms.items(): + for key in keys.values(): + yield key + + def __getitem__(self, name): + return self._keydict[name] + + def zones(self): + return self._keydict.keys() + + def algorithms(self, zone): + return self._keydict[zone].keys() + + def keys(self, zone, alg): + return self._keydict[zone][alg].keys() + + def missing(self): + return self._missing diff --git a/bin/python/isc/keyevent.py.in b/bin/python/isc/keyevent.py.in new file mode 100644 index 0000000..d01c97a --- /dev/null +++ b/bin/python/isc/keyevent.py.in @@ -0,0 +1,80 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import time + + +######################################################################## +# Class keyevent +######################################################################## +class keyevent: + """A discrete key event, e.g., Publish, Activate, Inactive, Delete, + etc. Stores the date of the event, and identifying information + about the key to which the event will occur.""" + + def __init__(self, what, key, when=None): + self.what = what + self.when = when or key.gettime(what) + self.key = key + self.sep = key.sep + self.zone = key.name + self.alg = key.alg + self.keyid = key.keyid + + def __repr__(self): + return repr((self.when, self.what, self.keyid, self.sep, self.zone, self.alg)) + + def showtime(self): + return time.strftime("%a %b %d %H:%M:%S UTC %Y", self.when) + + # update sets of active and published keys, based on + # the contents of this keyevent + def status(self, active, published, output=None): + def noop(*args, **kwargs): + pass + + if not output: + output = noop + + if not active: + active = set() + if not published: + published = set() + + if self.what == "Activate": + active.add(self.keyid) + elif self.what == "Publish": + published.add(self.keyid) + elif self.what == "Inactive": + if self.keyid not in active: + output( + "\tWARNING: %s scheduled to become inactive " + "before it is active" % repr(self.key) + ) + else: + active.remove(self.keyid) + elif self.what == "Delete": + if self.keyid in published: + published.remove(self.keyid) + else: + output( + "WARNING: key %s is scheduled for deletion " + "before it is published" % repr(self.key) + ) + elif self.what == "Revoke": + # We don't need to worry about the logic of this one; + # just stop counting this key as either active or published + if self.keyid in published: + published.remove(self.keyid) + if self.keyid in active: + active.remove(self.keyid) + + return active, published diff --git a/bin/python/isc/keymgr.py.in b/bin/python/isc/keymgr.py.in new file mode 100644 index 0000000..67fe4c7 --- /dev/null +++ b/bin/python/isc/keymgr.py.in @@ -0,0 +1,207 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +from __future__ import print_function +import os, sys, argparse, glob, re, time, calendar, pprint +from collections import defaultdict + +prog = "dnssec-keymgr" + +from isc import dnskey, keydict, keyseries, policy, parsetab, utils + + +############################################################################ +# print a fatal error and exit +############################################################################ +def fatal(*args, **kwargs): + print(*args, **kwargs) + sys.exit(1) + + +############################################################################ +# find the location of an external command +############################################################################ +def set_path(command, default=None): + """find the location of a specified command. If a default is supplied, + exists and it's an executable, we use it; otherwise we search PATH + for an alternative. + :param command: command to look for + :param default: default value to use + :return: PATH with the location of a suitable binary + """ + fpath = default + if not fpath or not os.path.isfile(fpath) or not os.access(fpath, os.X_OK): + path = os.environ["PATH"] + if not path: + path = os.path.defpath + for directory in path.split(os.pathsep): + fpath = directory + os.sep + command + if os.path.isfile(fpath) and os.access(fpath, os.X_OK): + break + fpath = None + + return fpath + + +############################################################################ +# parse arguments +############################################################################ +def parse_args(): + """Read command line arguments, returns 'args' object + :return: args object properly prepared + """ + + keygen = set_path( + "dnssec-keygen", os.path.join(utils.prefix("sbin"), "dnssec-keygen") + ) + settime = set_path( + "dnssec-settime", os.path.join(utils.prefix("sbin"), "dnssec-settime") + ) + + parser = argparse.ArgumentParser( + description=prog + ": schedule " + "DNSSEC key rollovers according to a " + "pre-defined policy" + ) + + parser.add_argument( + "zone", + type=str, + nargs="*", + default=None, + help="Zone(s) to which the policy should be applied " + + "(default: all zones in the directory)", + ) + parser.add_argument( + "-K", dest="path", type=str, help="Directory containing keys", metavar="dir" + ) + parser.add_argument( + "-c", dest="policyfile", type=str, help="Policy definition file", metavar="file" + ) + parser.add_argument( + "-g", + dest="keygen", + default=keygen, + type=str, + help="Path to 'dnssec-keygen'", + metavar="path", + ) + parser.add_argument( + "-r", + dest="randomdev", + type=str, + default=None, + help="DEPRECATED", + metavar="path", + ) + parser.add_argument( + "-s", + dest="settime", + default=settime, + type=str, + help="Path to 'dnssec-settime'", + metavar="path", + ) + parser.add_argument( + "-k", + dest="no_zsk", + action="store_true", + default=False, + help="Only apply policy to key-signing keys (KSKs)", + ) + parser.add_argument( + "-z", + dest="no_ksk", + action="store_true", + default=False, + help="Only apply policy to zone-signing keys (ZSKs)", + ) + parser.add_argument( + "-f", + "--force", + dest="force", + action="store_true", + default=False, + help="Force updates to key events " + "even if they are in the past", + ) + parser.add_argument( + "-q", + "--quiet", + dest="quiet", + action="store_true", + default=False, + help="Update keys silently", + ) + parser.add_argument("-v", "--version", action="version", version=utils.version) + + args = parser.parse_args() + + if args.randomdev: + fatal("ERROR: -r option has been deprecated.") + + if args.no_zsk and args.no_ksk: + fatal("ERROR: -z and -k cannot be used together.") + + if args.keygen is None: + fatal("ERROR: dnssec-keygen not found") + + if args.settime is None: + fatal("ERROR: dnssec-settime not found") + + # if a policy file was specified, check that it exists. + # if not, use the default file, unless it doesn't exist + if args.policyfile is not None: + if not os.path.exists(args.policyfile): + fatal('ERROR: Policy file "%s" not found' % args.policyfile) + else: + args.policyfile = os.path.join(utils.sysconfdir, "dnssec-policy.conf") + if not os.path.exists(args.policyfile): + args.policyfile = None + + return args + + +############################################################################ +# main +############################################################################ +def main(): + args = parse_args() + + # As we may have specific locations for the binaries, we put that info + # into a context object that can be passed around + context = { + "keygen_path": args.keygen, + "settime_path": args.settime, + "keys_path": args.path, + "randomdev": args.randomdev, + } + + try: + dp = policy.dnssec_policy(args.policyfile) + except Exception as e: + fatal("Unable to load DNSSEC policy: " + str(e)) + + try: + kd = keydict(dp, path=args.path, zones=args.zone) + except Exception as e: + fatal("Unable to build key dictionary: " + str(e)) + + try: + ks = keyseries(kd, context=context) + except Exception as e: + fatal("Unable to build key series: " + str(e)) + + try: + ks.enforce_policy( + dp, ksk=args.no_zsk, zsk=args.no_ksk, force=args.force, quiet=args.quiet + ) + except Exception as e: + fatal("Unable to apply policy: " + str(e)) diff --git a/bin/python/isc/keyseries.py.in b/bin/python/isc/keyseries.py.in new file mode 100644 index 0000000..e75f82b --- /dev/null +++ b/bin/python/isc/keyseries.py.in @@ -0,0 +1,232 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +from collections import defaultdict +from .dnskey import * +from .keydict import * +from .keyevent import * +from .policy import * +import time + + +class keyseries: + _K = defaultdict(lambda: defaultdict(list)) + _Z = defaultdict(lambda: defaultdict(list)) + _zones = set() + _kdict = None + _context = None + + def __init__(self, kdict, now=time.time(), context=None): + self._kdict = kdict + self._context = context + self._zones = set(kdict.missing()) + + for zone in kdict.zones(): + self._zones.add(zone) + for alg, keys in kdict[zone].items(): + for k in keys.values(): + if k.sep: + if not (k.delete() and k.delete() < now): + self._K[zone][alg].append(k) + else: + if not (k.delete() and k.delete() < now): + self._Z[zone][alg].append(k) + + self._K[zone][alg].sort() + self._Z[zone][alg].sort() + + def __iter__(self): + for zone in self._zones: + for collection in [self._K, self._Z]: + if zone not in collection: + continue + for alg, keys in collection[zone].items(): + for key in keys: + yield key + + def dump(self): + for k in self: + print("%s" % repr(k)) + + def fixseries(self, keys, policy, now, **kwargs): + force = kwargs.get("force", False) + if not keys: + return + + # handle the first key + key = keys[0] + if key.sep: + rp = policy.ksk_rollperiod + prepub = policy.ksk_prepublish or (30 * 86400) + postpub = policy.ksk_postpublish or (30 * 86400) + else: + rp = policy.zsk_rollperiod + prepub = policy.zsk_prepublish or (30 * 86400) + postpub = policy.zsk_postpublish or (30 * 86400) + + # the first key should be published and active + p = key.publish() + a = key.activate() + if not p or p > now: + key.setpublish(now) + p = now + if not a or a > now: + key.setactivate(now) + a = now + + i = key.inactive() + fudge = 300 + if not rp: + key.setinactive(None, **kwargs) + key.setdelete(None, **kwargs) + elif not i or a + rp != i: + if not i and a + rp > now + prepub + fudge: + key.setinactive(a + rp, **kwargs) + key.setdelete(a + rp + postpub, **kwargs) + elif not i: + key.setinactive(now + prepub + fudge, **kwargs) + key.setdelete(now + prepub + postpub + fudge, **kwargs) + elif i < now: + pass + elif a + rp > i: + key.setinactive(a + rp, **kwargs) + key.setdelete(a + rp + postpub, **kwargs) + elif a + rp > now + prepub + fudge: + key.setinactive(a + rp, **kwargs) + key.setdelete(a + rp + postpub, **kwargs) + else: + key.setinactive(now + prepub + fudge, **kwargs) + key.setdelete(now + prepub + postpub + fudge, **kwargs) + else: + d = key.delete() + if not d or i + postpub > now + fudge: + key.setdelete(i + postpub, **kwargs) + elif not d: + key.setdelete(now + postpub + fudge, **kwargs) + elif d < now + fudge: + pass + elif d < i + postpub: + key.setdelete(i + postpub, **kwargs) + + if policy.keyttl != key.ttl: + key.setttl(policy.keyttl) + + # handle all the subsequent keys + prev = key + for key in keys[1:]: + # if no rollperiod, then all keys after the first in + # the series kept inactive. + # (XXX: we need to change this to allow standby keys) + if not rp: + key.setpublish(None, **kwargs) + key.setactivate(None, **kwargs) + key.setinactive(None, **kwargs) + key.setdelete(None, **kwargs) + if policy.keyttl != key.ttl: + key.setttl(policy.keyttl) + continue + + # otherwise, ensure all dates are set correctly based on + # the initial key + a = prev.inactive() + p = a - prepub + key.setactivate(a, **kwargs) + key.setpublish(p, **kwargs) + key.setinactive(a + rp, **kwargs) + key.setdelete(a + rp + postpub, **kwargs) + prev.setdelete(a + postpub, **kwargs) + if policy.keyttl != key.ttl: + key.setttl(policy.keyttl) + prev = key + + # if we haven't got sufficient coverage, create successor key(s) + while rp and prev.inactive() and prev.inactive() < now + policy.coverage: + # commit changes to predecessor: a successor can only be + # generated if Inactive has been set in the predecessor key + prev.commit(self._context["settime_path"], **kwargs) + key = prev.generate_successor( + self._context["keygen_path"], + self._context["randomdev"], + prepub, + **kwargs + ) + + key.setinactive(key.activate() + rp, **kwargs) + key.setdelete(key.inactive() + postpub, **kwargs) + keys.append(key) + prev = key + + # last key? we already know we have sufficient coverage now, so + # disable the inactivation of the final key (if it was set), + # ensuring that if dnssec-keymgr isn't run again, the last key + # in the series will at least remain usable. + prev.setinactive(None, **kwargs) + prev.setdelete(None, **kwargs) + + # commit changes + for key in keys: + key.commit(self._context["settime_path"], **kwargs) + + def enforce_policy(self, policies, now=time.time(), **kwargs): + # If zones is provided as a parameter, use that list. + # If not, use what we have in this object + zones = kwargs.get("zones", self._zones) + keys_dir = kwargs.get("dir", self._context.get("keys_path", None)) + force = kwargs.get("force", False) + + for zone in zones: + collections = [] + policy = policies.policy(zone) + keys_dir = keys_dir or policy.directory or "." + alg = policy.algorithm + algnum = dnskey.algnum(alg) + if "ksk" not in kwargs or not kwargs["ksk"]: + if len(self._Z[zone][algnum]) == 0: + k = dnskey.generate( + self._context["keygen_path"], + self._context["randomdev"], + keys_dir, + zone, + alg, + policy.zsk_keysize, + False, + policy.keyttl or 3600, + **kwargs + ) + self._Z[zone][algnum].append(k) + collections.append(self._Z[zone]) + + if "zsk" not in kwargs or not kwargs["zsk"]: + if len(self._K[zone][algnum]) == 0: + k = dnskey.generate( + self._context["keygen_path"], + self._context["randomdev"], + keys_dir, + zone, + alg, + policy.ksk_keysize, + True, + policy.keyttl or 3600, + **kwargs + ) + self._K[zone][algnum].append(k) + collections.append(self._K[zone]) + + for collection in collections: + for algorithm, keys in collection.items(): + if algorithm != algnum: + continue + try: + self.fixseries(keys, policy, now, **kwargs) + except Exception as e: + raise Exception( + "%s/%s: %s" % (zone, dnskey.algstr(algnum), str(e)) + ) diff --git a/bin/python/isc/keyzone.py.in b/bin/python/isc/keyzone.py.in new file mode 100644 index 0000000..c0c7043 --- /dev/null +++ b/bin/python/isc/keyzone.py.in @@ -0,0 +1,59 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import os +import sys +import re +from subprocess import Popen, PIPE + + +######################################################################## +# Exceptions +######################################################################## +class KeyZoneException(Exception): + pass + + +######################################################################## +# class keyzone +######################################################################## +class keyzone: + """reads a zone file to find data relevant to keys""" + + def __init__(self, name, filename, czpath): + self.maxttl = None + self.keyttl = None + + if not name: + return + + if not czpath or not os.path.isfile(czpath) or not os.access(czpath, os.X_OK): + raise KeyZoneException('"named-compilezone" not found') + return + + maxttl = keyttl = None + + fp, _ = Popen( + [czpath, "-o", "-", name, filename], stdout=PIPE, stderr=PIPE + ).communicate() + for line in fp.splitlines(): + if type(line) is not str: + line = line.decode("ascii") + if re.search("^[:space:]*;", line): + continue + fields = line.split() + if not maxttl or int(fields[1]) > maxttl: + maxttl = int(fields[1]) + if fields[3] == "DNSKEY": + keyttl = int(fields[1]) + + self.keyttl = keyttl + self.maxttl = maxttl diff --git a/bin/python/isc/policy.py.in b/bin/python/isc/policy.py.in new file mode 100644 index 0000000..0fa231c --- /dev/null +++ b/bin/python/isc/policy.py.in @@ -0,0 +1,761 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import re +import ply.lex as lex +import ply.yacc as yacc +from string import * +from copy import copy + + +############################################################################ +# PolicyLex: a lexer for the policy file syntax. +############################################################################ +class PolicyLex: + reserved = ( + "POLICY", + "ALGORITHM_POLICY", + "ZONE", + "ALGORITHM", + "DIRECTORY", + "KEYTTL", + "KEY_SIZE", + "ROLL_PERIOD", + "PRE_PUBLISH", + "POST_PUBLISH", + "COVERAGE", + "STANDBY", + "NONE", + ) + + tokens = reserved + ( + "DATESUFFIX", + "KEYTYPE", + "ALGNAME", + "STR", + "QSTRING", + "NUMBER", + "LBRACE", + "RBRACE", + "SEMI", + ) + reserved_map = {} + + t_ignore = " \t" + t_ignore_olcomment = r"(//|\#).*" + + t_LBRACE = r"\{" + t_RBRACE = r"\}" + t_SEMI = r";" + + def t_newline(self, t): + r"\n+" + t.lexer.lineno += t.value.count("\n") + + def t_comment(self, t): + r"/\*(.|\n)*?\*/" + t.lexer.lineno += t.value.count("\n") + + def t_DATESUFFIX(self, t): + r"(?<=[0-9 \t])(y(?:ears|ear|ea|e)?|mo(?:nths|nth|nt|n)?|w(?:eeks|eek|ee|e)?|d(?:ays|ay|a)?|h(?:ours|our|ou|o)?|mi(?:nutes|nute|nut|nu|n)?|s(?:econds|econd|econ|eco|ec|e)?)\b" + t.value = ( + re.match(r"(y|mo|w|d|h|mi|s)([a-z]*)", t.value, re.IGNORECASE) + .group(1) + .lower() + ) + return t + + def t_KEYTYPE(self, t): + r"\b(KSK|ZSK)\b" + t.value = t.value.upper() + return t + + def t_ALGNAME(self, t): + r"\b(DH|ECC|RSASHA1|NSEC3RSASHA1|RSASHA256|RSASHA512|ECDSAP256SHA256|ECDSAP384SHA384|ED25519|ED448)\b" + t.value = t.value.upper() + return t + + def t_STR(self, t): + r"[A-Za-z._-][\w._-]*" + t.type = self.reserved_map.get(t.value, "STR") + return t + + def t_QSTRING(self, t): + r'"([^"\n]|(\\"))*"' + t.type = self.reserved_map.get(t.value, "QSTRING") + t.value = t.value[1:-1] + return t + + def t_NUMBER(self, t): + r"\d+" + t.value = int(t.value) + return t + + def t_error(self, t): + print("Illegal character '%s'" % t.value[0]) + t.lexer.skip(1) + + def __init__(self, **kwargs): + if "maketrans" in dir(str): + trans = str.maketrans("_", "-") + else: + trans = maketrans("_", "-") + for r in self.reserved: + self.reserved_map[r.lower().translate(trans)] = r + self.lexer = lex.lex(object=self, reflags=re.VERBOSE | re.IGNORECASE, **kwargs) + + def test(self, text): + self.lexer.input(text) + while True: + t = self.lexer.token() + if not t: + break + print(t) + + +############################################################################ +# Policy: this object holds a set of DNSSEC policy settings. +############################################################################ +class Policy: + is_zone = False + is_alg = False + is_constructed = False + ksk_rollperiod = None + zsk_rollperiod = None + ksk_prepublish = None + zsk_prepublish = None + ksk_postpublish = None + zsk_postpublish = None + ksk_keysize = None + zsk_keysize = None + ksk_standby = None + zsk_standby = None + keyttl = None + coverage = None + directory = None + valid_key_sz_per_algo = { + "RSASHA1": [1024, 4096], + "NSEC3RSASHA1": [512, 4096], + "RSASHA256": [1024, 4096], + "RSASHA512": [1024, 4096], + "ECDSAP256SHA256": None, + "ECDSAP384SHA384": None, + "ED25519": None, + "ED448": None, + } + + def __init__(self, name=None, algorithm=None, parent=None): + self.name = name + self.algorithm = algorithm + self.parent = parent + pass + + def __repr__(self): + return ( + "%spolicy %s:\n" + "\tinherits %s\n" + "\tdirectory %s\n" + "\talgorithm %s\n" + "\tcoverage %s\n" + "\tksk_keysize %s\n" + "\tzsk_keysize %s\n" + "\tksk_rollperiod %s\n" + "\tzsk_rollperiod %s\n" + "\tksk_prepublish %s\n" + "\tksk_postpublish %s\n" + "\tzsk_prepublish %s\n" + "\tzsk_postpublish %s\n" + "\tksk_standby %s\n" + "\tzsk_standby %s\n" + "\tkeyttl %s\n" + % ( + ( + self.is_constructed + and "constructed " + or self.is_zone + and "zone " + or self.is_alg + and "algorithm " + or "" + ), + self.name or "UNKNOWN", + self.parent and self.parent.name or "None", + self.directory and ('"' + str(self.directory) + '"') or "None", + self.algorithm or "None", + self.coverage and str(self.coverage) or "None", + self.ksk_keysize and str(self.ksk_keysize) or "None", + self.zsk_keysize and str(self.zsk_keysize) or "None", + self.ksk_rollperiod and str(self.ksk_rollperiod) or "None", + self.zsk_rollperiod and str(self.zsk_rollperiod) or "None", + self.ksk_prepublish and str(self.ksk_prepublish) or "None", + self.ksk_postpublish and str(self.ksk_postpublish) or "None", + self.zsk_prepublish and str(self.zsk_prepublish) or "None", + self.zsk_postpublish and str(self.zsk_postpublish) or "None", + self.ksk_standby and str(self.ksk_standby) or "None", + self.zsk_standby and str(self.zsk_standby) or "None", + self.keyttl and str(self.keyttl) or "None", + ) + ) + + def __verify_size(self, key_size, size_range): + return size_range[0] <= key_size <= size_range[1] + + def get_name(self): + return self.name + + def constructed(self): + return self.is_constructed + + def validate(self): + """Check if the values in the policy make sense + :return: True/False if the policy passes validation + """ + if ( + self.ksk_rollperiod + and self.ksk_prepublish is not None + and self.ksk_prepublish > self.ksk_rollperiod + ): + print(self.ksk_rollperiod) + return ( + False, + ( + "KSK pre-publish period (%d) exceeds rollover period %d" + % (self.ksk_prepublish, self.ksk_rollperiod) + ), + ) + + if ( + self.ksk_rollperiod + and self.ksk_postpublish is not None + and self.ksk_postpublish > self.ksk_rollperiod + ): + return ( + False, + ( + "KSK post-publish period (%d) exceeds rollover period %d" + % (self.ksk_postpublish, self.ksk_rollperiod) + ), + ) + + if ( + self.zsk_rollperiod + and self.zsk_prepublish is not None + and self.zsk_prepublish >= self.zsk_rollperiod + ): + return ( + False, + ( + "ZSK pre-publish period (%d) exceeds rollover period %d" + % (self.zsk_prepublish, self.zsk_rollperiod) + ), + ) + + if ( + self.zsk_rollperiod + and self.zsk_postpublish is not None + and self.zsk_postpublish >= self.zsk_rollperiod + ): + return ( + False, + ( + "ZSK post-publish period (%d) exceeds rollover period %d" + % (self.zsk_postpublish, self.zsk_rollperiod) + ), + ) + + if ( + self.ksk_rollperiod + and self.ksk_prepublish + and self.ksk_postpublish + and self.ksk_prepublish + self.ksk_postpublish >= self.ksk_rollperiod + ): + return ( + False, + ( + ( + "KSK pre/post-publish periods (%d/%d) " + + "combined exceed rollover period %d" + ) + % (self.ksk_prepublish, self.ksk_postpublish, self.ksk_rollperiod) + ), + ) + + if ( + self.zsk_rollperiod + and self.zsk_prepublish + and self.zsk_postpublish + and self.zsk_prepublish + self.zsk_postpublish >= self.zsk_rollperiod + ): + return ( + False, + ( + ( + "ZSK pre/post-publish periods (%d/%d) " + + "combined exceed rollover period %d" + ) + % (self.zsk_prepublish, self.zsk_postpublish, self.zsk_rollperiod) + ), + ) + + if self.algorithm is not None: + # Validate the key size + key_sz_range = self.valid_key_sz_per_algo.get(self.algorithm) + if key_sz_range is not None: + # Verify KSK + if not self.__verify_size(self.ksk_keysize, key_sz_range): + return False, "KSK key size %d outside valid range %s" % ( + self.ksk_keysize, + key_sz_range, + ) + + # Verify ZSK + if not self.__verify_size(self.zsk_keysize, key_sz_range): + return False, "ZSK key size %d outside valid range %s" % ( + self.zsk_keysize, + key_sz_range, + ) + + if self.algorithm in [ + "ECDSAP256SHA256", + "ECDSAP384SHA384", + "ED25519", + "ED448", + ]: + self.ksk_keysize = None + self.zsk_keysize = None + + return True, "" + + +############################################################################ +# dnssec_policy: +# This class reads a dnssec.policy file and creates a dictionary of +# DNSSEC policy rules from which a policy for a specific zone can +# be generated. +############################################################################ +class PolicyException(Exception): + pass + + +class dnssec_policy: + alg_policy = {} + named_policy = {} + zone_policy = {} + current = None + filename = None + initial = True + + def __init__(self, filename=None, **kwargs): + self.plex = PolicyLex() + self.tokens = self.plex.tokens + if "debug" not in kwargs: + kwargs["debug"] = False + if "write_tables" not in kwargs: + kwargs["write_tables"] = False + self.parser = yacc.yacc(module=self, **kwargs) + + # set defaults + self.setup( + """policy global { algorithm rsasha256; + key-size ksk 2048; + key-size zsk 2048; + roll-period ksk 0; + roll-period zsk 1y; + pre-publish ksk 1mo; + pre-publish zsk 1mo; + post-publish ksk 1mo; + post-publish zsk 1mo; + standby ksk 0; + standby zsk 0; + keyttl 1h; + coverage 6mo; }; + policy default { policy global; };""" + ) + + p = Policy() + p.algorithm = None + p.is_alg = True + p.ksk_keysize = 2048 + p.zsk_keysize = 2048 + + # set default algorithm policies + + # these can use default settings + self.alg_policy["RSASHA1"] = copy(p) + self.alg_policy["RSASHA1"].algorithm = "RSASHA1" + self.alg_policy["RSASHA1"].name = "RSASHA1" + + self.alg_policy["NSEC3RSASHA1"] = copy(p) + self.alg_policy["NSEC3RSASHA1"].algorithm = "NSEC3RSASHA1" + self.alg_policy["NSEC3RSASHA1"].name = "NSEC3RSASHA1" + + self.alg_policy["RSASHA256"] = copy(p) + self.alg_policy["RSASHA256"].algorithm = "RSASHA256" + self.alg_policy["RSASHA256"].name = "RSASHA256" + + self.alg_policy["RSASHA512"] = copy(p) + self.alg_policy["RSASHA512"].algorithm = "RSASHA512" + self.alg_policy["RSASHA512"].name = "RSASHA512" + + self.alg_policy["ECDSAP256SHA256"] = copy(p) + self.alg_policy["ECDSAP256SHA256"].algorithm = "ECDSAP256SHA256" + self.alg_policy["ECDSAP256SHA256"].name = "ECDSAP256SHA256" + self.alg_policy["ECDSAP256SHA256"].ksk_keysize = None + self.alg_policy["ECDSAP256SHA256"].zsk_keysize = None + + self.alg_policy["ECDSAP384SHA384"] = copy(p) + self.alg_policy["ECDSAP384SHA384"].algorithm = "ECDSAP384SHA384" + self.alg_policy["ECDSAP384SHA384"].name = "ECDSAP384SHA384" + self.alg_policy["ECDSAP384SHA384"].ksk_keysize = None + self.alg_policy["ECDSAP384SHA384"].zsk_keysize = None + + self.alg_policy["ED25519"] = copy(p) + self.alg_policy["ED25519"].algorithm = "ED25519" + self.alg_policy["ED25519"].name = "ED25519" + self.alg_policy["ED25519"].ksk_keysize = None + self.alg_policy["ED25519"].zsk_keysize = None + + self.alg_policy["ED448"] = copy(p) + self.alg_policy["ED448"].algorithm = "ED448" + self.alg_policy["ED448"].name = "ED448" + self.alg_policy["ED448"].ksk_keysize = None + self.alg_policy["ED448"].zsk_keysize = None + + if filename: + self.load(filename) + + def load(self, filename): + self.filename = filename + self.initial = True + with open(filename) as f: + text = f.read() + self.plex.lexer.lineno = 0 + self.parser.parse(text) + + self.filename = None + + def setup(self, text): + self.initial = True + self.plex.lexer.lineno = 0 + self.parser.parse(text) + + def policy(self, zone, **kwargs): + z = zone.lower() + p = None + + if z in self.zone_policy: + p = self.zone_policy[z] + + if p is None: + p = copy(self.named_policy["default"]) + p.name = zone + p.is_constructed = True + + if p.algorithm is None: + parent = p.parent or self.named_policy["default"] + while parent and not parent.algorithm: + parent = parent.parent + p.algorithm = parent and parent.algorithm or None + + if p.algorithm in self.alg_policy: + ap = self.alg_policy[p.algorithm] + else: + raise PolicyException("algorithm not found") + + if p.directory is None: + parent = p.parent or self.named_policy["default"] + while parent is not None and not parent.directory: + parent = parent.parent + p.directory = parent and parent.directory + + if p.coverage is None: + parent = p.parent or self.named_policy["default"] + while parent and not parent.coverage: + parent = parent.parent + p.coverage = parent and parent.coverage or ap.coverage + + if p.ksk_keysize is None: + parent = p.parent or self.named_policy["default"] + while parent.parent and not parent.ksk_keysize: + parent = parent.parent + p.ksk_keysize = parent and parent.ksk_keysize or ap.ksk_keysize + + if p.zsk_keysize is None: + parent = p.parent or self.named_policy["default"] + while parent.parent and not parent.zsk_keysize: + parent = parent.parent + p.zsk_keysize = parent and parent.zsk_keysize or ap.zsk_keysize + + if p.ksk_rollperiod is None: + parent = p.parent or self.named_policy["default"] + while parent.parent and not parent.ksk_rollperiod: + parent = parent.parent + p.ksk_rollperiod = parent and parent.ksk_rollperiod or ap.ksk_rollperiod + + if p.zsk_rollperiod is None: + parent = p.parent or self.named_policy["default"] + while parent.parent and not parent.zsk_rollperiod: + parent = parent.parent + p.zsk_rollperiod = parent and parent.zsk_rollperiod or ap.zsk_rollperiod + + if p.ksk_prepublish is None: + parent = p.parent or self.named_policy["default"] + while parent.parent and not parent.ksk_prepublish: + parent = parent.parent + p.ksk_prepublish = parent and parent.ksk_prepublish or ap.ksk_prepublish + + if p.zsk_prepublish is None: + parent = p.parent or self.named_policy["default"] + while parent.parent and not parent.zsk_prepublish: + parent = parent.parent + p.zsk_prepublish = parent and parent.zsk_prepublish or ap.zsk_prepublish + + if p.ksk_postpublish is None: + parent = p.parent or self.named_policy["default"] + while parent.parent and not parent.ksk_postpublish: + parent = parent.parent + p.ksk_postpublish = parent and parent.ksk_postpublish or ap.ksk_postpublish + + if p.zsk_postpublish is None: + parent = p.parent or self.named_policy["default"] + while parent.parent and not parent.zsk_postpublish: + parent = parent.parent + p.zsk_postpublish = parent and parent.zsk_postpublish or ap.zsk_postpublish + + if p.keyttl is None: + parent = p.parent or self.named_policy["default"] + while parent is not None and not parent.keyttl: + parent = parent.parent + p.keyttl = parent and parent.keyttl + + if "novalidate" not in kwargs or not kwargs["novalidate"]: + (valid, msg) = p.validate() + if not valid: + raise PolicyException(msg) + return None + + return p + + def p_policylist(self, p): + """policylist : init policy + | policylist policy""" + pass + + def p_init(self, p): + "init :" + self.initial = False + + def p_policy(self, p): + """policy : alg_policy + | zone_policy + | named_policy""" + pass + + def p_name(self, p): + """name : STR + | KEYTYPE + | DATESUFFIX""" + p[0] = p[1] + pass + + def p_domain(self, p): + """domain : STR + | QSTRING + | KEYTYPE + | DATESUFFIX""" + p[0] = p[1].strip() + if not re.match(r"^[\w.-][\w.-]*$", p[0]): + raise PolicyException("invalid domain") + pass + + def p_new_policy(self, p): + "new_policy :" + self.current = Policy() + + def p_alg_policy(self, p): + "alg_policy : ALGORITHM_POLICY ALGNAME new_policy alg_option_group SEMI" + self.current.name = p[2] + self.current.is_alg = True + self.alg_policy[p[2]] = self.current + pass + + def p_zone_policy(self, p): + "zone_policy : ZONE domain new_policy policy_option_group SEMI" + self.current.name = p[2].rstrip(".") + self.current.is_zone = True + self.zone_policy[p[2].rstrip(".").lower()] = self.current + pass + + def p_named_policy(self, p): + "named_policy : POLICY name new_policy policy_option_group SEMI" + self.current.name = p[2] + self.named_policy[p[2].lower()] = self.current + pass + + def p_duration_1(self, p): + "duration : NUMBER" + p[0] = p[1] + pass + + def p_duration_2(self, p): + "duration : NONE" + p[0] = None + pass + + def p_duration_3(self, p): + "duration : NUMBER DATESUFFIX" + if p[2] == "y": + p[0] = p[1] * 31536000 # year + elif p[2] == "mo": + p[0] = p[1] * 2592000 # month + elif p[2] == "w": + p[0] = p[1] * 604800 # week + elif p[2] == "d": + p[0] = p[1] * 86400 # day + elif p[2] == "h": + p[0] = p[1] * 3600 # hour + elif p[2] == "mi": + p[0] = p[1] * 60 # minute + elif p[2] == "s": + p[0] = p[1] # second + else: + raise PolicyException("invalid duration") + + def p_policy_option_group(self, p): + "policy_option_group : LBRACE policy_option_list RBRACE" + pass + + def p_policy_option_list(self, p): + """policy_option_list : policy_option SEMI + | policy_option_list policy_option SEMI""" + pass + + def p_policy_option(self, p): + """policy_option : parent_option + | directory_option + | coverage_option + | rollperiod_option + | prepublish_option + | postpublish_option + | keysize_option + | algorithm_option + | keyttl_option + | standby_option""" + pass + + def p_alg_option_group(self, p): + "alg_option_group : LBRACE alg_option_list RBRACE" + pass + + def p_alg_option_list(self, p): + """alg_option_list : alg_option SEMI + | alg_option_list alg_option SEMI""" + pass + + def p_alg_option(self, p): + """alg_option : coverage_option + | rollperiod_option + | prepublish_option + | postpublish_option + | keyttl_option + | keysize_option + | standby_option""" + pass + + def p_parent_option(self, p): + "parent_option : POLICY name" + self.current.parent = self.named_policy[p[2].lower()] + + def p_directory_option(self, p): + "directory_option : DIRECTORY QSTRING" + self.current.directory = p[2] + + def p_coverage_option(self, p): + "coverage_option : COVERAGE duration" + self.current.coverage = p[2] + + def p_rollperiod_option(self, p): + "rollperiod_option : ROLL_PERIOD KEYTYPE duration" + if p[2] == "KSK": + self.current.ksk_rollperiod = p[3] + else: + self.current.zsk_rollperiod = p[3] + + def p_prepublish_option(self, p): + "prepublish_option : PRE_PUBLISH KEYTYPE duration" + if p[2] == "KSK": + self.current.ksk_prepublish = p[3] + else: + self.current.zsk_prepublish = p[3] + + def p_postpublish_option(self, p): + "postpublish_option : POST_PUBLISH KEYTYPE duration" + if p[2] == "KSK": + self.current.ksk_postpublish = p[3] + else: + self.current.zsk_postpublish = p[3] + + def p_keysize_option(self, p): + "keysize_option : KEY_SIZE KEYTYPE NUMBER" + if p[2] == "KSK": + self.current.ksk_keysize = p[3] + else: + self.current.zsk_keysize = p[3] + + def p_standby_option(self, p): + "standby_option : STANDBY KEYTYPE NUMBER" + if p[2] == "KSK": + self.current.ksk_standby = p[3] + else: + self.current.zsk_standby = p[3] + + def p_keyttl_option(self, p): + "keyttl_option : KEYTTL duration" + self.current.keyttl = p[2] + + def p_algorithm_option(self, p): + "algorithm_option : ALGORITHM ALGNAME" + self.current.algorithm = p[2] + + def p_error(self, p): + if p: + print( + "%s%s%d:syntax error near '%s'" + % (self.filename or "", ":" if self.filename else "", p.lineno, p.value) + ) + else: + if not self.initial: + raise PolicyException( + "%s%s%d:unexpected end of input" + % ( + self.filename or "", + ":" if self.filename else "", + p and p.lineno or 0, + ) + ) + + +if __name__ == "__main__": + import sys + + if sys.argv[1] == "lex": + file = open(sys.argv[2]) + text = file.read() + file.close() + plex = PolicyLex(debug=1) + plex.test(text) + elif sys.argv[1] == "parse": + try: + pp = dnssec_policy(sys.argv[2], write_tables=True, debug=True) + print(pp.named_policy["default"]) + print(pp.policy("nonexistent.zone")) + except Exception as e: + print(e.args[0]) diff --git a/bin/python/isc/rndc.py.in b/bin/python/isc/rndc.py.in new file mode 100644 index 0000000..a8af767 --- /dev/null +++ b/bin/python/isc/rndc.py.in @@ -0,0 +1,193 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +############################################################################ +# rndc.py +# This module implements the RNDC control protocol. +############################################################################ + +from collections import OrderedDict +import time +import struct +import hashlib +import hmac +import base64 +import random +import socket + + +class rndc(object): + """RNDC protocol client library""" + + __algos = { + "md5": 157, + "sha1": 161, + "sha224": 162, + "sha256": 163, + "sha384": 164, + "sha512": 165, + } + + def __init__(self, host, algo, secret): + """Creates a persistent connection to RNDC and logs in + host - (ip, port) tuple + algo - HMAC algorithm: one of md5, sha1, sha224, sha256, sha384, sha512 + (with optional prefix 'hmac-') + secret - HMAC secret, base64 encoded""" + self.host = host + algo = algo.lower() + if algo.startswith("hmac-"): + algo = algo[5:] + self.algo = algo + self.hlalgo = getattr(hashlib, algo) + self.secret = base64.b64decode(secret) + self.ser = random.randint(0, 1 << 24) + self.nonce = None + self.__connect_login() + + def call(self, cmd): + """Call a RNDC command, all parsing is done on the server side + cmd - a complete string with a command (eg 'reload zone example.com') + """ + return dict(self.__command(type=cmd)["_data"]) + + def __serialize_dict(self, data, ignore_auth=False): + rv = bytearray() + for k, v in data.items(): + if ignore_auth and k == "_auth": + continue + rv += struct.pack("B", len(k)) + k.encode("ascii") + if type(v) == str: + rv += struct.pack(">BI", 1, len(v)) + v.encode("ascii") + elif type(v) == bytes: + rv += struct.pack(">BI", 1, len(v)) + v + elif type(v) == bytearray: + rv += struct.pack(">BI", 1, len(v)) + v + elif type(v) == OrderedDict: + sd = self.__serialize_dict(v) + rv += struct.pack(">BI", 2, len(sd)) + sd + else: + raise NotImplementedError( + "Cannot serialize element of type %s" % type(v) + ) + return rv + + def __prep_message(self, *args, **kwargs): + self.ser += 1 + now = int(time.time()) + data = OrderedDict(*args, **kwargs) + + d = OrderedDict() + d["_auth"] = OrderedDict() + d["_ctrl"] = OrderedDict() + d["_ctrl"]["_ser"] = str(self.ser) + d["_ctrl"]["_tim"] = str(now) + d["_ctrl"]["_exp"] = str(now + 60) + if self.nonce is not None: + d["_ctrl"]["_nonce"] = self.nonce + d["_data"] = data + + msg = self.__serialize_dict(d, ignore_auth=True) + hash = hmac.new(self.secret, msg, self.hlalgo).digest() + bhash = base64.b64encode(hash) + if self.algo == "md5": + d["_auth"]["hmd5"] = struct.pack("22s", bhash) + else: + d["_auth"]["hsha"] = bytearray( + struct.pack("B88s", self.__algos[self.algo], bhash) + ) + msg = self.__serialize_dict(d) + msg = struct.pack(">II", len(msg) + 4, 1) + msg + return msg + + def __verify_msg(self, msg): + if self.nonce is not None and msg["_ctrl"]["_nonce"] != self.nonce: + return False + if self.algo == "md5": + bhash = msg["_auth"]["hmd5"] + else: + bhash = msg["_auth"]["hsha"][1:] + if type(bhash) == bytes: + bhash = bhash.decode("ascii") + bhash += "=" * (4 - (len(bhash) % 4)) + remote_hash = base64.b64decode(bhash) + my_msg = self.__serialize_dict(msg, ignore_auth=True) + my_hash = hmac.new(self.secret, my_msg, self.hlalgo).digest() + return my_hash == remote_hash + + def __command(self, *args, **kwargs): + msg = self.__prep_message(*args, **kwargs) + sent = self.socket.send(msg) + if sent != len(msg): + raise IOError("Cannot send the message") + + header = self.socket.recv(8) + if len(header) != 8: + # What should we throw here? Bad auth can cause this... + raise IOError("Can't read response header") + + length, version = struct.unpack(">II", header) + if version != 1: + raise NotImplementedError("Wrong message version %d" % version) + + # it includes the header + length -= 4 + data = self.socket.recv(length, socket.MSG_WAITALL) + if len(data) != length: + raise IOError("Can't read response data") + + if type(data) == str: + data = bytearray(data) + msg = self.__parse_message(data) + if not self.__verify_msg(msg): + raise IOError("Authentication failure") + + return msg + + def __connect_login(self): + self.socket = socket.create_connection(self.host) + self.nonce = None + msg = self.__command(type="null") + self.nonce = msg["_ctrl"]["_nonce"] + + def __parse_element(self, input): + pos = 0 + labellen = input[pos] + pos += 1 + label = input[pos : pos + labellen].decode("ascii") + pos += labellen + type = input[pos] + pos += 1 + datalen = struct.unpack(">I", input[pos : pos + 4])[0] + pos += 4 + data = input[pos : pos + datalen] + pos += datalen + rest = input[pos:] + + if type == 1: # raw binary value + return label, data, rest + elif type == 2: # dictionary + d = OrderedDict() + while len(data) > 0: + ilabel, value, data = self.__parse_element(data) + d[ilabel] = value + return label, d, rest + # TODO type 3 - list + else: + raise NotImplementedError("Unknown element type %d" % type) + + def __parse_message(self, input): + rv = OrderedDict() + hdata = None + while len(input) > 0: + label, value, input = self.__parse_element(input) + rv[label] = value + return rv diff --git a/bin/python/isc/tests/Makefile.in b/bin/python/isc/tests/Makefile.in new file mode 100644 index 0000000..233f7f9 --- /dev/null +++ b/bin/python/isc/tests/Makefile.in @@ -0,0 +1,33 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +PYTHON = @PYTHON@ + +PYTESTS = dnskey_test.py policy_test.py + +@BIND9_MAKE_RULES@ + +check test: + for test in $(PYTESTS); do \ + PYTHONPATH=${srcdir}/../.. $(PYTHON) ${srcdir}/$$test; \ + done + +clean distclean:: + rm -rf *.pyc __pycache__ + +distclean:: + rm -f ${PYTESTS} diff --git a/bin/python/isc/tests/dnskey_test.py.in b/bin/python/isc/tests/dnskey_test.py.in new file mode 100644 index 0000000..e3ce3f7 --- /dev/null +++ b/bin/python/isc/tests/dnskey_test.py.in @@ -0,0 +1,54 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import sys +import unittest + +sys.path.append("../..") +from isc import * + +kdict = None + + +def getkey(): + global kdict + if not kdict: + kd = keydict(path="testdata") + for key in kd: + return key + + +class DnskeyTest(unittest.TestCase): + def test_metdata(self): + key = getkey() + self.assertEqual(key.created(), 1448055647) + self.assertEqual(key.publish(), 1445463714) + self.assertEqual(key.activate(), 1448055714) + self.assertEqual(key.revoke(), 1479591714) + self.assertEqual(key.inactive(), 1511127714) + self.assertEqual(key.delete(), 1542663714) + self.assertEqual(key.syncpublish(), 1442871714) + self.assertEqual(key.syncdelete(), 1448919714) + + def test_fmttime(self): + key = getkey() + self.assertEqual(key.getfmttime("Created"), "20151120214047") + self.assertEqual(key.getfmttime("Publish"), "20151021214154") + self.assertEqual(key.getfmttime("Activate"), "20151120214154") + self.assertEqual(key.getfmttime("Revoke"), "20161119214154") + self.assertEqual(key.getfmttime("Inactive"), "20171119214154") + self.assertEqual(key.getfmttime("Delete"), "20181119214154") + self.assertEqual(key.getfmttime("SyncPublish"), "20150921214154") + self.assertEqual(key.getfmttime("SyncDelete"), "20151130214154") + + +if __name__ == "__main__": + unittest.main() diff --git a/bin/python/isc/tests/policy_test.py.in b/bin/python/isc/tests/policy_test.py.in new file mode 100644 index 0000000..c115a31 --- /dev/null +++ b/bin/python/isc/tests/policy_test.py.in @@ -0,0 +1,104 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import sys +import unittest + +sys.path.append("../..") +from isc import * + + +class PolicyTest(unittest.TestCase): + def test_keysize(self): + pol = policy.dnssec_policy() + pol.load("test-policies/01-keysize.pol") + + p = pol.policy("good_rsa.test", novalidate=True) + self.assertEqual(p.get_name(), "good_rsa.test") + self.assertEqual(p.constructed(), False) + self.assertEqual(p.validate(), (True, "")) + + def test_prepublish(self): + pol = policy.dnssec_policy() + pol.load("test-policies/02-prepublish.pol") + p = pol.policy("good_prepublish.test", novalidate=True) + self.assertEqual(p.validate(), (True, "")) + + p = pol.policy("bad_prepublish.test", novalidate=True) + self.assertEqual( + p.validate(), + ( + False, + "KSK pre/post-publish periods " + "(10368000/5184000) combined exceed " + "rollover period 10368000", + ), + ) + + def test_postpublish(self): + pol = policy.dnssec_policy() + pol.load("test-policies/03-postpublish.pol") + + p = pol.policy("good_postpublish.test", novalidate=True) + self.assertEqual(p.validate(), (True, "")) + + p = pol.policy("bad_postpublish.test", novalidate=True) + self.assertEqual( + p.validate(), + ( + False, + "KSK pre/post-publish periods " + "(10368000/5184000) combined exceed " + "rollover period 10368000", + ), + ) + + def test_combined_pre_post(self): + pol = policy.dnssec_policy() + pol.load("test-policies/04-combined-pre-post.pol") + + p = pol.policy("good_combined_pre_post_ksk.test", novalidate=True) + self.assertEqual(p.validate(), (True, "")) + + p = pol.policy("bad_combined_pre_post_ksk.test", novalidate=True) + self.assertEqual( + p.validate(), + ( + False, + "KSK pre/post-publish periods " + "(5184000/5184000) combined exceed " + "rollover period 10368000", + ), + ) + + p = pol.policy("good_combined_pre_post_zsk.test", novalidate=True) + self.assertEqual(p.validate(), (True, "")) + p = pol.policy("bad_combined_pre_post_zsk.test", novalidate=True) + self.assertEqual( + p.validate(), + ( + False, + "ZSK pre/post-publish periods " + "(5184000/5184000) combined exceed " + "rollover period 7776000", + ), + ) + + def test_numeric_zone(self): + pol = policy.dnssec_policy() + pol.load("test-policies/05-numeric-zone.pol") + + p = pol.policy("99example.test", novalidate=True) + self.assertEqual(p.validate(), (True, "")) + + +if __name__ == "__main__": + unittest.main() diff --git a/bin/python/isc/tests/test-policies/01-keysize.pol b/bin/python/isc/tests/test-policies/01-keysize.pol new file mode 100644 index 0000000..db22058 --- /dev/null +++ b/bin/python/isc/tests/test-policies/01-keysize.pol @@ -0,0 +1,54 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +policy keysize_rsa { + algorithm rsasha1; + coverage 1y; + roll-period zsk 3mo; + pre-publish zsk 2w; + post-publish zsk 2w; + roll-period ksk 1y; + pre-publish ksk 1mo; + post-publish ksk 2mo; + keyttl 1h; + key-size ksk 2048; + key-size zsk 1024; +}; + +policy keysize_dsa { + algorithm dsa; + coverage 1y; + key-size ksk 2048; + key-size zsk 1024; +}; + +zone good_rsa.test { + policy keysize_rsa; +}; + +zone bad_rsa.test { + policy keysize_rsa; + key-size ksk 511; +}; + +zone good_dsa.test { + policy keysize_dsa; + key-size ksk 1024; + key-size zsk 768; +}; + +zone bad_dsa.test { + policy keysize_dsa; + key-size ksk 1024; + key-size zsk 769; +}; diff --git a/bin/python/isc/tests/test-policies/02-prepublish.pol b/bin/python/isc/tests/test-policies/02-prepublish.pol new file mode 100644 index 0000000..7dd1b32 --- /dev/null +++ b/bin/python/isc/tests/test-policies/02-prepublish.pol @@ -0,0 +1,44 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +policy prepublish_rsa { + algorithm rsasha1; + coverage 1y; + roll-period zsk 3mo; + pre-publish zsk 2w; + post-publish zsk 2w; + roll-period ksk 1y; + pre-publish ksk 1mo; + post-publish ksk 2mo; + keyttl 1h; + key-size ksk 2048; + key-size zsk 1024; +}; + +// Policy that defines a pre-publish period lower than the rollover period +zone good_prepublish.test { + policy prepublish_rsa; + coverage 6mo; + roll-period ksk 4mo; + pre-publish ksk 1mo; +}; + +// Policy that defines a pre-publish period equal to the rollover period +zone bad_prepublish.test { + policy prepublish_rsa; + coverage 6mo; + roll-period ksk 4mo; + pre-publish ksk 4mo; +}; + + diff --git a/bin/python/isc/tests/test-policies/03-postpublish.pol b/bin/python/isc/tests/test-policies/03-postpublish.pol new file mode 100644 index 0000000..74bd822 --- /dev/null +++ b/bin/python/isc/tests/test-policies/03-postpublish.pol @@ -0,0 +1,44 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +policy postpublish_rsa { + algorithm rsasha1; + coverage 1y; + roll-period zsk 3mo; + pre-publish zsk 2w; + post-publish zsk 2w; + roll-period ksk 1y; + pre-publish ksk 1mo; + post-publish ksk 2mo; + keyttl 1h; + key-size ksk 2048; + key-size zsk 1024; +}; + +// Policy that defines a post-publish period lower than the rollover period +zone good_postpublish.test { + policy postpublish_rsa; + coverage 6mo; + roll-period ksk 4mo; + pre-publish ksk 1mo; +}; + +// Policy that defines a post-publish period equal to the rollover period +zone bad_postpublish.test { + policy postpublish_rsa; + coverage 6mo; + roll-period ksk 4mo; + pre-publish ksk 4mo; +}; + + diff --git a/bin/python/isc/tests/test-policies/04-combined-pre-post.pol b/bin/python/isc/tests/test-policies/04-combined-pre-post.pol new file mode 100644 index 0000000..82c001c --- /dev/null +++ b/bin/python/isc/tests/test-policies/04-combined-pre-post.pol @@ -0,0 +1,68 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +policy combined_pre_post_rsa { + algorithm rsasha1; + coverage 1y; + roll-period zsk 3mo; + pre-publish zsk 2w; + post-publish zsk 2w; + roll-period ksk 1y; + pre-publish ksk 1mo; + post-publish ksk 2mo; + keyttl 1h; + key-size ksk 2048; + key-size zsk 1024; +}; + +// Policy that defines a combined pre-publish and post-publish period lower +// than the rollover period +zone good_combined_pre_post_ksk.test { + policy combined_pre_post_rsa; + coverage 6mo; + roll-period ksk 4mo; + pre-publish ksk 1mo; + post-publish ksk 1mo; +}; + +// Policy that defines a combined pre-publish and post-publish period higher +// than the rollover period +zone bad_combined_pre_post_ksk.test { + policy combined_pre_post_rsa; + coverage 6mo; + roll-period ksk 4mo; + pre-publish ksk 2mo; + post-publish ksk 2mo; +}; + +// Policy that defines a combined pre-publish and post-publish period lower +// than the rollover period +zone good_combined_pre_post_zsk.test { + policy combined_pre_post_rsa; + coverage 1y; + roll-period zsk 3mo; + pre-publish zsk 1mo; + post-publish zsk 1mo; +}; + +// Policy that defines a combined pre-publish and post-publish period higher +// than the rollover period +zone bad_combined_pre_post_zsk.test { + policy combined_pre_post_rsa; + coverage 1y; + roll-period zsk 3mo; + pre-publish zsk 2mo; + post-publish zsk 2mo; +}; + + diff --git a/bin/python/isc/tests/test-policies/05-numeric-zone.pol b/bin/python/isc/tests/test-policies/05-numeric-zone.pol new file mode 100644 index 0000000..26e546b --- /dev/null +++ b/bin/python/isc/tests/test-policies/05-numeric-zone.pol @@ -0,0 +1,17 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +// Zone policy that uses a numeric name +zone "99example.test" { + coverage 6mo; +}; diff --git a/bin/python/isc/tests/testdata/Kexample.com.+007+35529.key b/bin/python/isc/tests/testdata/Kexample.com.+007+35529.key new file mode 100644 index 0000000..c5afbe2 --- /dev/null +++ b/bin/python/isc/tests/testdata/Kexample.com.+007+35529.key @@ -0,0 +1,8 @@ +; This is a key-signing key, keyid 35529, for example.com. +; Created: 20151120214047 (Fri Nov 20 13:40:47 2015) +; Publish: 20151021214154 (Wed Oct 21 14:41:54 2015) +; Activate: 20151120214154 (Fri Nov 20 13:41:54 2015) +; Revoke: 20161119214154 (Sat Nov 19 13:41:54 2016) +; Inactive: 20171119214154 (Sun Nov 19 13:41:54 2017) +; Delete: 20181119214154 (Mon Nov 19 13:41:54 2018) +example.com. IN DNSKEY 257 3 7 AwEAAbbJK96tY8d4sF6RLxh9SVIhho5s2ZhrcijT5j1SNLECen7QLutj VJPEiG8UgBLaJSGkxPDxOygYv4hwh4JXBSj89o9rNabAJtCa9XzIXSpt /cfiCfvqmcOZb9nepmDCXsC7gn/gbae/4Y5ym9XOiCp8lu+tlFWgRiJ+ kxDGN48rRPrGfpq+SfwM9NUtftVa7B0EFVzDkADKedRj0SSGYOqH+WYH CnWjhPFmgJoAw3/m4slTHW1l+mDwFvsCMjXopg4JV0CNnTybnOmyuIwO LWRhB3q8ze24sYBU1fpE9VAMxZ++4Kqh/2MZFeDAs7iPPKSmI3wkRCW5 pkwDLO5lJ9c= diff --git a/bin/python/isc/tests/testdata/Kexample.com.+007+35529.private b/bin/python/isc/tests/testdata/Kexample.com.+007+35529.private new file mode 100644 index 0000000..af22c6a --- /dev/null +++ b/bin/python/isc/tests/testdata/Kexample.com.+007+35529.private @@ -0,0 +1,18 @@ +Private-key-format: v1.3 +Algorithm: 7 (NSEC3RSASHA1) +Modulus: tskr3q1jx3iwXpEvGH1JUiGGjmzZmGtyKNPmPVI0sQJ6ftAu62NUk8SIbxSAEtolIaTE8PE7KBi/iHCHglcFKPz2j2s1psAm0Jr1fMhdKm39x+IJ++qZw5lv2d6mYMJewLuCf+Btp7/hjnKb1c6IKnyW762UVaBGIn6TEMY3jytE+sZ+mr5J/Az01S1+1VrsHQQVXMOQAMp51GPRJIZg6of5ZgcKdaOE8WaAmgDDf+biyVMdbWX6YPAW+wIyNeimDglXQI2dPJuc6bK4jA4tZGEHerzN7bixgFTV+kT1UAzFn77gqqH/YxkV4MCzuI88pKYjfCREJbmmTAMs7mUn1w== +PublicExponent: AQAB +PrivateExponent: jfiM6YU1Rd6Y5qrPsK7HP1Ko54DmNbvmzI1hfGmYYZAyQsNCXjQloix5aAW9QGdNhecrzJUhxJAMXFZC+lrKuD5a56R25JDE1Sw21nft3SHXhuQrqw5Z5hIMTWXhRrBR1lMOFnLj2PJxqCmenp+vJYjl1z20RBmbv/keE15SExFRJIJ3G0lI4V0KxprY5rgsT/vID0pS32f7rmXhgEzyWDyuxceTMidBooD5BSeEmSTYa4rvCVZ2vgnzIGSxjYDPJE2rGve2dpvdXQuujRFaf4+/FzjaOgg35rTtUmC9klfB4D6KJIfc1PNUwcH7V0VJ2fFlgZgMYi4W331QORl9sQ== +Prime1: 479rW3EeoBwHhUKDy5YeyfnMKjhaosrcYhW4resevLzatFrvS/n2KxJnsHoEzmGr2A13naI61RndgVBBOwNDWI3/tQ+aKvcr+V9m4omROV3xYa8s1FsDbEW0Z6G0UheaqRFir8WK98/Lj6Zht1uBXHSPPf91OW0qj+b5gbX7TK8= +Prime2: zXXlxgIq+Ih6kxsUw4Ith0nd/d2P3d42QYPjxYjsg4xYicPAjva9HltnbBQ2lr4JEG9Yyb8KalSnJUSuvXtn7bGfBzLu8W6omCeVWXQVH4NIu9AjpO16NpMKWGRfiHHbbSYJs1daTZKHC2FEmi18MKX/RauHGGOakFQ/3A/GMVk= +Exponent1: 0o9UQ1uHNAIWFedUEHJ/jr7LOrGVYnLpZCmu7+S0K0zzatGz8ets44+FnAyDywdUKFDzKSMm/4SFXRwE4vl2VzYZlp2RLG4PEuRYK9OCF6a6F1UsvjxTItQjIbjIDSnTjMINGnMps0lDa1EpgKsyI3eEQ46eI3TBZ//k6D6G0vM= +Exponent2: d+CYJgXRyJzo17fvT3s+0TbaHWsOq+chROyNEw4m4UIbzpW2XjO8eF/gYgERMLbEVyCAb4XVr+CgfXArfEbqhpciMHMZUyi7mbtOupiuUmqpH1v70Bj3O6xjVtuJmfTEkFSnSEppV+VsgclI26Q6V7Ai1yWTdzl2T0u4zs8tVlE= +Coefficient: E4EYw76gIChdQDn6+Uh44/xH9Uwmvq3OETR8w/kEZ0xQ8AkTdKFKUp84nlR6gN+ljb2mUxERKrVLwnBsU8EbUlo9UccMbBGkkZ/8MyfGCBb9nUyOFtOxdHY2M0MQadesRptXHt/m30XjdohwmT7qfSIENwtgUOHbwFnn7WPMc/k= +Created: 20151120214047 +Publish: 20151021214154 +Activate: 20151120214154 +Revoke: 20161119214154 +Inactive: 20171119214154 +Delete: 20181119214154 +SyncPublish: 20150921214154 +SyncDelete: 20151130214154 diff --git a/bin/python/isc/utils.py.in b/bin/python/isc/utils.py.in new file mode 100644 index 0000000..3ce4d4c --- /dev/null +++ b/bin/python/isc/utils.py.in @@ -0,0 +1,71 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import os + +# These routines permit platform-independent location of BIND 9 tools +if os.name == "nt": + import win32con + import win32api + + +def prefix(bindir=""): + if os.name != "nt": + return os.path.join("@prefix@", bindir) + + hklm = win32con.HKEY_LOCAL_MACHINE + bind_subkey = "Software\\ISC\\BIND" + sam = win32con.KEY_READ + h_key = None + key_found = True + # can fail if the registry redirected for 32/64 bits + try: + h_key = win32api.RegOpenKeyEx(hklm, bind_subkey, 0, sam) + except: + key_found = False + # retry for 32 bit python with 64 bit bind9 + if not key_found: + key_found = True + sam64 = sam | win32con.KEY_WOW64_64KEY + try: + h_key = win32api.RegOpenKeyEx(hklm, bind_subkey, 0, sam64) + except: + key_found = False + # retry 64 bit python with 32 bit bind9 + if not key_found: + key_found = True + sam32 = sam | win32con.KEY_WOW64_32KEY + try: + h_key = win32api.RegOpenKeyEx(hklm, bind_subkey, 0, sam32) + except: + key_found = False + if key_found: + try: + (named_base, _) = win32api.RegQueryValueEx(h_key, "InstallDir") + except: + key_found = False + win32api.RegCloseKey(h_key) + if key_found: + return os.path.join(named_base, bindir) + return os.path.join(win32api.GetSystemDirectory(), bindir) + + +def shellquote(s): + if os.name == "nt": + return '"' + s.replace('"', '"\\"') + '"' + return "'" + s.replace("'", "'\\''") + "'" + + +version = "@BIND9_VERSION@" +if os.name != "nt": + sysconfdir = "@expanded_sysconfdir@" +else: + sysconfdir = prefix("etc") diff --git a/bin/python/setup.py b/bin/python/setup.py new file mode 100644 index 0000000..4440b74 --- /dev/null +++ b/bin/python/setup.py @@ -0,0 +1,28 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +try: + from setuptools import setup +except ImportError: + # pylint: disable=deprecated-module + from distutils.core import setup + +setup( + name="isc", + version="2.0", + description="Python functions to support BIND utilities", + url="https://www.isc.org/bind", + author="Internet Systems Consortium, Inc", + author_email="info@isc.org", + license="MPL", + requires=["ply"], + packages=["isc"], +) diff --git a/bin/rndc/Makefile.in b/bin/rndc/Makefile.in new file mode 100644 index 0000000..d2a5366 --- /dev/null +++ b/bin/rndc/Makefile.in @@ -0,0 +1,74 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include ${ISC_INCLUDES} ${ISCCC_INCLUDES} \ + ${ISCCFG_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} + +CDEFINES = +CWARNINGS = + +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCLIBS = ../../lib/isccc/libisccc.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +BIND9LIBS = ../../lib/bind9/libbind9.@A@ + +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCDEPLIBS = ../../lib/isccc/libisccc.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ + +LIBS = ${ISCLIBS} @LIBS@ +NOSYMLIBS = ${ISCNOSYMLIBS} @LIBS@ + +RNDCDEPLIBS = ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${BIND9DEPLIBS} ${DNSDEPLIBS} ${ISCDEPLIBS} + +CONFDEPLIBS = ${DNSDEPLIBS} ${ISCDEPLIBS} + +SRCS= rndc.c + +TARGETS = rndc@EXEEXT@ + +@BIND9_MAKE_RULES@ + +rndc.@O@: rndc.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -DRNDC_CONFFILE=\"${sysconfdir}/rndc.conf\" \ + -DRNDC_KEYFILE=\"${sysconfdir}/rndc.key\" \ + -c ${srcdir}/rndc.c + +rndc@EXEEXT@: rndc.@O@ util.@O@ ${RNDCDEPLIBS} + export BASEOBJS="rndc.@O@ util.@O@"; \ + export LIBS0="${ISCCFGLIBS} ${ISCCCLIBS} ${BIND9LIBS} ${DNSLIBS} ${ISCLIBS}"; \ + ${FINALBUILDCMD} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} + +install:: rndc@EXEEXT@ installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} rndc@EXEEXT@ ${DESTDIR}${sbindir} + +uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${sbindir}/rndc@EXEEXT@ + +clean distclean maintainer-clean:: + rm -f ${TARGETS} diff --git a/bin/rndc/include/.clang-format b/bin/rndc/include/.clang-format new file mode 120000 index 0000000..0e62f72 --- /dev/null +++ b/bin/rndc/include/.clang-format @@ -0,0 +1 @@ +../../../.clang-format.headers \ No newline at end of file diff --git a/bin/rndc/include/rndc/os.h b/bin/rndc/include/rndc/os.h new file mode 100644 index 0000000..000dbde --- /dev/null +++ b/bin/rndc/include/rndc/os.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#ifndef RNDC_OS_H +#define RNDC_OS_H 1 + +#include + +#include + +ISC_LANG_BEGINDECLS + +int +set_user(FILE *fd, const char *user); +/*%< + * Set the owner of the file referenced by 'fd' to 'user'. + * Returns: + * 0 success + * -1 insufficient permissions, or 'user' does not exist. + */ + +ISC_LANG_ENDDECLS + +#endif /* ifndef RNDC_OS_H */ diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c new file mode 100644 index 0000000..2fa9ca6 --- /dev/null +++ b/bin/rndc/rndc.c @@ -0,0 +1,1105 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "util.h" + +#define SERVERADDRS 10 + +const char *progname; +bool verbose; + +static const char *admin_conffile; +static const char *admin_keyfile; +static const char *version = VERSION; +static const char *servername = NULL; +static isc_sockaddr_t serveraddrs[SERVERADDRS]; +static isc_sockaddr_t local4, local6; +static bool local4set = false, local6set = false; +static int nserveraddrs; +static int currentaddr = 0; +static unsigned int remoteport = 0; +static isc_socketmgr_t *socketmgr = NULL; +static isc_buffer_t *databuf; +static isccc_ccmsg_t ccmsg; +static uint32_t algorithm; +static isccc_region_t secret; +static bool failed = false; +static bool c_flag = false; +static isc_mem_t *rndc_mctx; +static atomic_uint_fast32_t sends = 0; +static atomic_uint_fast32_t recvs = 0; +static atomic_uint_fast32_t connects = 0; +static char *command; +static char *args; +static char program[256]; +static isc_socket_t *sock = NULL; +static uint32_t serial; +static bool quiet = false; +static bool showresult = false; + +static void +rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task); + +ISC_PLATFORM_NORETURN_PRE static void +usage(int status) ISC_PLATFORM_NORETURN_POST; + +static void +usage(int status) { + fprintf(stderr, "\ +Usage: %s [-b address] [-c config] [-s server] [-p port]\n\ + [-k key-file ] [-y key] [-r] [-V] [-4 | -6] command\n\ +\n\ +command is one of the following:\n\ +\n\ + addzone zone [class [view]] { zone-options }\n\ + Add zone to given view. Requires allow-new-zones option.\n\ + delzone [-clean] zone [class [view]]\n\ + Removes zone from given view.\n\ + dnssec -checkds [-key id [-alg algorithm]] [-when time] (published|withdrawn) zone [class [view]]\n\ + Mark the DS record for the KSK of the given zone as seen\n\ + in the parent. If the zone has multiple KSKs, select a\n\ + specific key by providing the keytag with -key id and\n\ + optionally the key's algorithm with -alg algorithm.\n\ + Requires the zone to have a dnssec-policy.\n\ + dnssec -rollover -key id [-alg algorithm] [-when time] zone [class [view]]\n\ + Rollover key with id of the given zone. Requires the zone\n\ + to have a dnssec-policy.\n\ + dnssec -status zone [class [view]]\n\ + Show the DNSSEC signing state for the specified zone.\n\ + Requires the zone to have a dnssec-policy.\n\ + dnstap -reopen\n\ + Close, truncate and re-open the DNSTAP output file.\n\ + dnstap -roll [count]\n\ + Close, rename and re-open the DNSTAP output file(s).\n\ + dumpdb [-all|-cache|-zones|-adb|-bad|-expired|-fail] [view ...]\n\ + Dump cache(s) to the dump file (named_dump.db).\n\ + flush Flushes all of the server's caches.\n\ + flush [view] Flushes the server's cache for a view.\n\ + flushname name [view]\n\ + Flush the given name from the server's cache(s)\n\ + flushtree name [view]\n\ + Flush all names under the given name from the server's cache(s)\n\ + freeze Suspend updates to all dynamic zones.\n\ + freeze zone [class [view]]\n\ + Suspend updates to a dynamic zone.\n\ + halt Stop the server without saving pending updates.\n\ + halt -p Stop the server without saving pending updates reporting\n\ + process id.\n\ + loadkeys zone [class [view]]\n\ + Update keys without signing immediately.\n\ + managed-keys refresh [class [view]]\n\ + Check trust anchor for RFC 5011 key changes\n\ + managed-keys status [class [view]]\n\ + Display RFC 5011 managed keys information\n\ + managed-keys sync [class [view]]\n\ + Write RFC 5011 managed keys to disk\n\ + modzone zone [class [view]] { zone-options }\n\ + Modify a zone's configuration.\n\ + Requires allow-new-zones option.\n\ + notify zone [class [view]]\n\ + Resend NOTIFY messages for the zone.\n\ + notrace Set debugging level to 0.\n\ + nta -dump\n\ + List all negative trust anchors.\n\ + nta [-lifetime duration] [-force] domain [view]\n\ + Set a negative trust anchor, disabling DNSSEC validation\n\ + for the given domain.\n\ + Using -lifetime specifies the duration of the NTA, up\n\ + to one week.\n\ + Using -force prevents the NTA from expiring before its\n\ + full lifetime, even if the domain can validate sooner.\n\ + nta -remove domain [view]\n\ + Remove a negative trust anchor, re-enabling validation\n\ + for the given domain.\n\ + querylog [ on | off ]\n\ + Enable / disable query logging.\n\ + reconfig Reload configuration file and new zones only.\n\ + recursing Dump the queries that are currently recursing (named.recursing)\n\ + refresh zone [class [view]]\n\ + Schedule immediate maintenance for a zone.\n\ + reload Reload configuration file and zones.\n\ + reload zone [class [view]]\n\ + Reload a single zone.\n\ + retransfer zone [class [view]]\n\ + Retransfer a single zone without checking serial number.\n\ + scan Scan available network interfaces for changes.\n\ + secroots [view ...]\n\ + Write security roots to the secroots file.\n\ + serve-stale [ on | off | reset | status ] [class [view]]\n\ + Control whether stale answers are returned\n\ + showzone zone [class [view]]\n\ + Print a zone's configuration.\n\ + sign zone [class [view]]\n\ + Update zone keys, and sign as needed.\n\ + signing -clear all zone [class [view]]\n\ + Remove the private records for all keys that have\n\ + finished signing the given zone.\n\ + signing -clear / zone [class [view]]\n\ + Remove the private record that indicating the given key\n\ + has finished signing the given zone.\n\ + signing -list zone [class [view]]\n\ + List the private records showing the state of DNSSEC\n\ + signing in the given zone.\n\ + signing -nsec3param hash flags iterations salt zone [class [view]]\n\ + Add NSEC3 chain to zone if already signed.\n\ + Prime zone with NSEC3 chain if not yet signed.\n\ + signing -nsec3param none zone [class [view]]\n\ + Remove NSEC3 chains from zone.\n\ + signing -serial zone [class [view]]\n\ + Set the zones's serial to .\n\ + stats Write server statistics to the statistics file.\n\ + status Display status of the server.\n\ + stop Save pending updates to master files and stop the server.\n\ + stop -p Save pending updates to master files and stop the server\n\ + reporting process id.\n\ + sync [-clean] Dump changes to all dynamic zones to disk, and optionally\n\ + remove their journal files.\n\ + sync [-clean] zone [class [view]]\n\ + Dump a single zone's changes to disk, and optionally\n\ + remove its journal file.\n\ + tcp-timeouts Display the tcp-*-timeout option values\n\ + tcp-timeouts initial idle keepalive advertised\n\ + Update the tcp-*-timeout option values\n\ + thaw Enable updates to all dynamic zones and reload them.\n\ + thaw zone [class [view]]\n\ + Enable updates to a frozen dynamic zone and reload it.\n\ + trace Increment debugging level by one.\n\ + trace level Change the debugging level.\n\ + tsig-delete keyname [view]\n\ + Delete a TKEY-negotiated TSIG key.\n\ + tsig-list List all currently active TSIG keys, including both statically\n\ + configured and TKEY-negotiated keys.\n\ + validation [ on | off | status ] [view]\n\ + Enable / disable DNSSEC validation.\n\ + zonestatus zone [class [view]]\n\ + Display the current status of a zone.\n\ +\n\ +Version: %s\n", + progname, version); + + exit(status); +} + +#define CMDLINE_FLAGS "46b:c:hk:Mmp:qrs:Vy:" + +static void +preparse_args(int argc, char **argv) { + bool ipv4only = false, ipv6only = false; + int ch; + + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case '4': + if (ipv6only) { + fatal("only one of -4 and -6 allowed"); + } + ipv4only = true; + break; + case '6': + if (ipv4only) { + fatal("only one of -4 and -6 allowed"); + } + ipv6only = true; + break; + default: + break; + } + } + + isc_commandline_reset = true; + isc_commandline_index = 1; +} + +static void +get_addresses(const char *host, in_port_t port) { + isc_result_t result; + int found = 0, count; + + REQUIRE(host != NULL); + + if (*host == '/') { + result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs], + host); + if (result == ISC_R_SUCCESS) { + nserveraddrs++; + } + } else { + count = SERVERADDRS - nserveraddrs; + result = bind9_getaddresses( + host, port, &serveraddrs[nserveraddrs], count, &found); + nserveraddrs += found; + } + if (result != ISC_R_SUCCESS) { + fatal("couldn't get address for '%s': %s", host, + isc_result_totext(result)); + } + INSIST(nserveraddrs > 0); +} + +static void +rndc_senddone(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + + if (sevent->result != ISC_R_SUCCESS) { + fatal("send failed: %s", isc_result_totext(sevent->result)); + } + isc_event_free(&event); + if (atomic_fetch_sub_release(&sends, 1) == 1 && + atomic_load_acquire(&recvs) == 0) + { + isc_socket_detach(&sock); + isc_task_detach(&task); + isc_app_shutdown(); + } +} + +static void +rndc_recvdone(isc_task_t *task, isc_event_t *event) { + isccc_sexpr_t *response = NULL; + isccc_sexpr_t *data; + isccc_region_t source; + char *errormsg = NULL; + char *textmsg = NULL; + isc_result_t result; + + atomic_fetch_sub_release(&recvs, 1); + + if (ccmsg.result == ISC_R_EOF) { + fatal("connection to remote host closed\n" + "This may indicate that\n" + "* the remote server is using an older version of" + " the command protocol,\n" + "* this host is not authorized to connect,\n" + "* the clocks are not synchronized, or\n" + "* the key is invalid."); + } + + if (ccmsg.result != ISC_R_SUCCESS) { + fatal("recv failed: %s", isc_result_totext(ccmsg.result)); + } + + source.rstart = isc_buffer_base(&ccmsg.buffer); + source.rend = isc_buffer_used(&ccmsg.buffer); + + DO("parse message", + isccc_cc_fromwire(&source, &response, algorithm, &secret)); + + data = isccc_alist_lookup(response, "_data"); + if (!isccc_alist_alistp(data)) { + fatal("bad or missing data section in response"); + } + result = isccc_cc_lookupstring(data, "err", &errormsg); + if (result == ISC_R_SUCCESS) { + failed = true; + fprintf(stderr, "%s: '%s' failed: %s\n", progname, command, + errormsg); + } else if (result != ISC_R_NOTFOUND) { + fprintf(stderr, "%s: parsing response failed: %s\n", progname, + isc_result_totext(result)); + } + + result = isccc_cc_lookupstring(data, "text", &textmsg); + if (result == ISC_R_SUCCESS) { + if ((!quiet || failed) && strlen(textmsg) != 0U) { + fprintf(failed ? stderr : stdout, "%s\n", textmsg); + } + } else if (result != ISC_R_NOTFOUND) { + fprintf(stderr, "%s: parsing response failed: %s\n", progname, + isc_result_totext(result)); + } + + if (showresult) { + isc_result_t eresult; + + result = isccc_cc_lookupuint32(data, "result", &eresult); + if (result == ISC_R_SUCCESS) { + printf("%s %u\n", isc_result_toid(eresult), eresult); + } else { + printf("NONE -1\n"); + } + } + + isc_event_free(&event); + isccc_sexpr_free(&response); + if (atomic_load_acquire(&sends) == 0 && + atomic_load_acquire(&recvs) == 0) + { + isc_socket_detach(&sock); + isc_task_detach(&task); + isc_app_shutdown(); + } +} + +static void +rndc_recvnonce(isc_task_t *task, isc_event_t *event) { + isccc_sexpr_t *response = NULL; + isccc_sexpr_t *_ctrl; + isccc_region_t source; + isc_result_t result; + uint32_t nonce; + isccc_sexpr_t *request = NULL; + isccc_time_t now; + isc_region_t r; + isccc_sexpr_t *data; + isc_buffer_t b; + + atomic_fetch_sub_release(&recvs, 1); + + if (ccmsg.result == ISC_R_EOF) { + fatal("connection to remote host closed\n" + "This may indicate that\n" + "* the remote server is using an older version of" + " the command protocol,\n" + "* this host is not authorized to connect,\n" + "* the clocks are not synchronized,\n" + "* the key signing algorithm is incorrect, or\n" + "* the key is invalid."); + } + + if (ccmsg.result != ISC_R_SUCCESS) { + fatal("recv failed: %s", isc_result_totext(ccmsg.result)); + } + + source.rstart = isc_buffer_base(&ccmsg.buffer); + source.rend = isc_buffer_used(&ccmsg.buffer); + + DO("parse message", + isccc_cc_fromwire(&source, &response, algorithm, &secret)); + + _ctrl = isccc_alist_lookup(response, "_ctrl"); + if (!isccc_alist_alistp(_ctrl)) { + fatal("bad or missing ctrl section in response"); + } + nonce = 0; + if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS) { + nonce = 0; + } + + isc_stdtime_get(&now); + + DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial, + now, now + 60, &request)); + data = isccc_alist_lookup(request, "_data"); + if (data == NULL) { + fatal("_data section missing"); + } + if (isccc_cc_definestring(data, "type", args) == NULL) { + fatal("out of memory"); + } + if (nonce != 0) { + _ctrl = isccc_alist_lookup(request, "_ctrl"); + if (_ctrl == NULL) { + fatal("_ctrl section missing"); + } + if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL) { + fatal("out of memory"); + } + } + + isc_buffer_clear(databuf); + /* Skip the length field (4 bytes) */ + isc_buffer_add(databuf, 4); + + DO("render message", + isccc_cc_towire(request, &databuf, algorithm, &secret)); + + isc_buffer_init(&b, databuf->base, 4); + isc_buffer_putuint32(&b, databuf->used - 4); + + r.base = databuf->base; + r.length = databuf->used; + + isccc_ccmsg_cancelread(&ccmsg); + DO("schedule recv", + isccc_ccmsg_readmessage(&ccmsg, task, rndc_recvdone, NULL)); + atomic_fetch_add_relaxed(&recvs, 1); + DO("send message", + isc_socket_send(sock, &r, task, rndc_senddone, NULL)); + atomic_fetch_add_relaxed(&sends, 1); + + isc_event_free(&event); + isccc_sexpr_free(&response); + isccc_sexpr_free(&request); + return; +} + +static void +rndc_connected(isc_task_t *task, isc_event_t *event) { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + isccc_sexpr_t *request = NULL; + isccc_sexpr_t *data; + isccc_time_t now; + isc_region_t r; + isc_buffer_t b; + isc_result_t result; + + atomic_fetch_sub_release(&connects, 1); + + if (sevent->result != ISC_R_SUCCESS) { + isc_sockaddr_format(&serveraddrs[currentaddr], socktext, + sizeof(socktext)); + if (sevent->result != ISC_R_CANCELED && + ++currentaddr < nserveraddrs) + { + notify("connection failed: %s: %s", socktext, + isc_result_totext(sevent->result)); + isc_socket_detach(&sock); + isc_event_free(&event); + rndc_startconnect(&serveraddrs[currentaddr], task); + return; + } else { + fatal("connect failed: %s: %s", socktext, + isc_result_totext(sevent->result)); + } + } + + isc_stdtime_get(&now); + DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial, + now, now + 60, &request)); + data = isccc_alist_lookup(request, "_data"); + if (data == NULL) { + fatal("_data section missing"); + } + if (isccc_cc_definestring(data, "type", "null") == NULL) { + fatal("out of memory"); + } + + isc_buffer_clear(databuf); + /* Skip the length field (4 bytes) */ + isc_buffer_add(databuf, 4); + + DO("render message", + isccc_cc_towire(request, &databuf, algorithm, &secret)); + + isc_buffer_init(&b, databuf->base, 4); + isc_buffer_putuint32(&b, databuf->used - 4); + + r.base = databuf->base; + r.length = databuf->used; + + isccc_ccmsg_init(rndc_mctx, sock, &ccmsg); + isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024); + + DO("schedule recv", + isccc_ccmsg_readmessage(&ccmsg, task, rndc_recvnonce, NULL)); + atomic_fetch_add_relaxed(&recvs, 1); + DO("send message", + isc_socket_send(sock, &r, task, rndc_senddone, NULL)); + atomic_fetch_add_relaxed(&sends, 1); + isc_event_free(&event); + isccc_sexpr_free(&request); +} + +static void +rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) { + isc_result_t result; + int pf; + isc_sockettype_t type; + + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(addr, socktext, sizeof(socktext)); + + notify("using server %s (%s)", servername, socktext); + + pf = isc_sockaddr_pf(addr); + if (pf == AF_INET || pf == AF_INET6) { + type = isc_sockettype_tcp; + } else { + type = isc_sockettype_unix; + } + DO("create socket", isc_socket_create(socketmgr, pf, type, &sock)); + switch (isc_sockaddr_pf(addr)) { + case AF_INET: + DO("bind socket", isc_socket_bind(sock, &local4, 0)); + break; + case AF_INET6: + DO("bind socket", isc_socket_bind(sock, &local6, 0)); + break; + default: + break; + } + DO("connect", + isc_socket_connect(sock, addr, task, rndc_connected, NULL)); + atomic_fetch_add_relaxed(&connects, 1); +} + +static void +rndc_start(isc_task_t *task, isc_event_t *event) { + isc_event_free(&event); + + currentaddr = 0; + rndc_startconnect(&serveraddrs[currentaddr], task); +} + +static void +parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname, + cfg_parser_t **pctxp, cfg_obj_t **configp) { + isc_result_t result; + const char *conffile = admin_conffile; + const cfg_obj_t *addresses = NULL; + const cfg_obj_t *defkey = NULL; + const cfg_obj_t *options = NULL; + const cfg_obj_t *servers = NULL; + const cfg_obj_t *server = NULL; + const cfg_obj_t *keys = NULL; + const cfg_obj_t *key = NULL; + const cfg_obj_t *defport = NULL; + const cfg_obj_t *secretobj = NULL; + const cfg_obj_t *algorithmobj = NULL; + cfg_obj_t *config = NULL; + const cfg_obj_t *address = NULL; + const cfg_listelt_t *elt; + const char *secretstr; + const char *algorithmstr; + static char secretarray[1024]; + const cfg_type_t *conftype = &cfg_type_rndcconf; + bool key_only = false; + const cfg_listelt_t *element; + + if (!isc_file_exists(conffile)) { + conffile = admin_keyfile; + conftype = &cfg_type_rndckey; + + if (c_flag) { + fatal("%s does not exist", admin_conffile); + } + + if (!isc_file_exists(conffile)) { + fatal("neither %s nor %s was found", admin_conffile, + admin_keyfile); + } + key_only = true; + } else if (!c_flag && isc_file_exists(admin_keyfile)) { + fprintf(stderr, + "WARNING: key file (%s) exists, but using " + "default configuration file (%s)\n", + admin_keyfile, admin_conffile); + } + + DO("create parser", cfg_parser_create(mctx, log, pctxp)); + + /* + * The parser will output its own errors, so DO() is not used. + */ + result = cfg_parse_file(*pctxp, conffile, conftype, &config); + if (result != ISC_R_SUCCESS) { + fatal("could not load rndc configuration"); + } + + if (!key_only) { + (void)cfg_map_get(config, "options", &options); + } + + if (key_only && servername == NULL) { + servername = "127.0.0.1"; + } else if (servername == NULL && options != NULL) { + const cfg_obj_t *defserverobj = NULL; + (void)cfg_map_get(options, "default-server", &defserverobj); + if (defserverobj != NULL) { + servername = cfg_obj_asstring(defserverobj); + } + } + + if (servername == NULL) { + fatal("no server specified and no default"); + } + + if (!key_only) { + (void)cfg_map_get(config, "server", &servers); + if (servers != NULL) { + for (elt = cfg_list_first(servers); elt != NULL; + elt = cfg_list_next(elt)) + { + const char *name; + server = cfg_listelt_value(elt); + name = cfg_obj_asstring( + cfg_map_getname(server)); + if (strcasecmp(name, servername) == 0) { + break; + } + server = NULL; + } + } + } + + /* + * Look for the name of the key to use. + */ + if (keyname != NULL) { + /* Was set on command line, do nothing. */ + } else if (server != NULL) { + DO("get key for server", cfg_map_get(server, "key", &defkey)); + keyname = cfg_obj_asstring(defkey); + } else if (options != NULL) { + DO("get default key", + cfg_map_get(options, "default-key", &defkey)); + keyname = cfg_obj_asstring(defkey); + } else if (!key_only) { + fatal("no key for server and no default"); + } + + /* + * Get the key's definition. + */ + if (key_only) { + DO("get key", cfg_map_get(config, "key", &key)); + } else { + DO("get config key list", cfg_map_get(config, "key", &keys)); + for (elt = cfg_list_first(keys); elt != NULL; + elt = cfg_list_next(elt)) + { + key = cfg_listelt_value(elt); + if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)), + keyname) == 0) + { + break; + } + } + if (elt == NULL) { + fatal("no key definition for name %s", keyname); + } + } + (void)cfg_map_get(key, "secret", &secretobj); + (void)cfg_map_get(key, "algorithm", &algorithmobj); + if (secretobj == NULL || algorithmobj == NULL) { + fatal("key must have algorithm and secret"); + } + + secretstr = cfg_obj_asstring(secretobj); + algorithmstr = cfg_obj_asstring(algorithmobj); + + if (strcasecmp(algorithmstr, "hmac-md5") == 0) { + algorithm = ISCCC_ALG_HMACMD5; + } else if (strcasecmp(algorithmstr, "hmac-sha1") == 0) { + algorithm = ISCCC_ALG_HMACSHA1; + } else if (strcasecmp(algorithmstr, "hmac-sha224") == 0) { + algorithm = ISCCC_ALG_HMACSHA224; + } else if (strcasecmp(algorithmstr, "hmac-sha256") == 0) { + algorithm = ISCCC_ALG_HMACSHA256; + } else if (strcasecmp(algorithmstr, "hmac-sha384") == 0) { + algorithm = ISCCC_ALG_HMACSHA384; + } else if (strcasecmp(algorithmstr, "hmac-sha512") == 0) { + algorithm = ISCCC_ALG_HMACSHA512; + } else { + fatal("unsupported algorithm: %s", algorithmstr); + } + + secret.rstart = (unsigned char *)secretarray; + secret.rend = (unsigned char *)secretarray + sizeof(secretarray); + DO("decode base64 secret", isccc_base64_decode(secretstr, &secret)); + secret.rend = secret.rstart; + secret.rstart = (unsigned char *)secretarray; + + /* + * Find the port to connect to. + */ + if (remoteport != 0) { + /* Was set on command line, do nothing. */ + } else { + if (server != NULL) { + (void)cfg_map_get(server, "port", &defport); + } + if (defport == NULL && options != NULL) { + (void)cfg_map_get(options, "default-port", &defport); + } + } + if (defport != NULL) { + remoteport = cfg_obj_asuint32(defport); + if (remoteport > 65535 || remoteport == 0) { + fatal("port %u out of range", remoteport); + } + } else if (remoteport == 0) { + remoteport = NS_CONTROL_PORT; + } + + if (server != NULL) { + result = cfg_map_get(server, "addresses", &addresses); + } else { + result = ISC_R_NOTFOUND; + } + if (result == ISC_R_SUCCESS) { + for (element = cfg_list_first(addresses); element != NULL; + element = cfg_list_next(element)) + { + isc_sockaddr_t sa; + + address = cfg_listelt_value(element); + if (!cfg_obj_issockaddr(address)) { + unsigned int myport; + const char *name; + const cfg_obj_t *obj; + + obj = cfg_tuple_get(address, "name"); + name = cfg_obj_asstring(obj); + obj = cfg_tuple_get(address, "port"); + if (cfg_obj_isuint32(obj)) { + myport = cfg_obj_asuint32(obj); + if (myport > UINT16_MAX || myport == 0) + { + fatal("port %u out of range", + myport); + } + } else { + myport = remoteport; + } + if (nserveraddrs < SERVERADDRS) { + get_addresses(name, (in_port_t)myport); + } else { + fprintf(stderr, + "too many address: " + "%s: dropped\n", + name); + } + continue; + } + sa = *cfg_obj_assockaddr(address); + if (isc_sockaddr_getport(&sa) == 0) { + isc_sockaddr_setport(&sa, remoteport); + } + if (nserveraddrs < SERVERADDRS) { + serveraddrs[nserveraddrs++] = sa; + } else { + char socktext[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(&sa, socktext, + sizeof(socktext)); + fprintf(stderr, + "too many address: %s: dropped\n", + socktext); + } + } + } + + if (!local4set && server != NULL) { + address = NULL; + cfg_map_get(server, "source-address", &address); + if (address != NULL) { + local4 = *cfg_obj_assockaddr(address); + local4set = true; + } + } + if (!local4set && options != NULL) { + address = NULL; + cfg_map_get(options, "default-source-address", &address); + if (address != NULL) { + local4 = *cfg_obj_assockaddr(address); + local4set = true; + } + } + + if (!local6set && server != NULL) { + address = NULL; + cfg_map_get(server, "source-address-v6", &address); + if (address != NULL) { + local6 = *cfg_obj_assockaddr(address); + local6set = true; + } + } + if (!local6set && options != NULL) { + address = NULL; + cfg_map_get(options, "default-source-address-v6", &address); + if (address != NULL) { + local6 = *cfg_obj_assockaddr(address); + local6set = true; + } + } + + *configp = config; +} + +int +main(int argc, char **argv) { + isc_result_t result = ISC_R_SUCCESS; + bool show_final_mem = false; + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_task_t *task = NULL; + isc_log_t *log = NULL; + isc_logconfig_t *logconfig = NULL; + isc_logdestination_t logdest; + cfg_parser_t *pctx = NULL; + cfg_obj_t *config = NULL; + const char *keyname = NULL; + struct in_addr in; + struct in6_addr in6; + char *p; + size_t argslen; + int ch; + int i; + + result = isc_file_progname(*argv, program, sizeof(program)); + if (result != ISC_R_SUCCESS) { + memmove(program, "rndc", 5); + } + progname = program; + + admin_conffile = RNDC_CONFFILE; + admin_keyfile = RNDC_KEYFILE; + + isc_sockaddr_any(&local4); + isc_sockaddr_any6(&local6); + + result = isc_app_start(); + if (result != ISC_R_SUCCESS) { + fatal("isc_app_start() failed: %s", isc_result_totext(result)); + } + + isc_commandline_errprint = false; + + preparse_args(argc, argv); + + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { + case '4': + if (isc_net_probeipv4() != ISC_R_SUCCESS) { + fatal("can't find IPv4 networking"); + } + isc_net_disableipv6(); + break; + case '6': + if (isc_net_probeipv6() != ISC_R_SUCCESS) { + fatal("can't find IPv6 networking"); + } + isc_net_disableipv4(); + break; + case 'b': + if (inet_pton(AF_INET, isc_commandline_argument, &in) == + 1) + { + isc_sockaddr_fromin(&local4, &in, 0); + local4set = true; + } else if (inet_pton(AF_INET6, isc_commandline_argument, + &in6) == 1) + { + isc_sockaddr_fromin6(&local6, &in6, 0); + local6set = true; + } + break; + + case 'c': + admin_conffile = isc_commandline_argument; + c_flag = true; + break; + + case 'k': + admin_keyfile = isc_commandline_argument; + break; + + case 'M': + isc_mem_debugging = ISC_MEM_DEBUGTRACE; + break; + + case 'm': + show_final_mem = true; + break; + + case 'p': + remoteport = atoi(isc_commandline_argument); + if (remoteport > 65535 || remoteport == 0) { + fatal("port '%s' out of range", + isc_commandline_argument); + } + break; + + case 'q': + quiet = true; + break; + + case 'r': + showresult = true; + break; + + case 's': + servername = isc_commandline_argument; + break; + + case 'V': + verbose = true; + break; + + case 'y': + keyname = isc_commandline_argument; + break; + + case '?': + if (isc_commandline_option != '?') { + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + usage(1); + } + FALLTHROUGH; + case 'h': + usage(0); + break; + default: + fprintf(stderr, "%s: unhandled option -%c\n", program, + isc_commandline_option); + exit(1); + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc < 1) { + usage(1); + } + + serial = isc_random32(); + + isc_mem_create(&rndc_mctx); + DO("create socket manager", + isc_socketmgr_create(rndc_mctx, &socketmgr)); + DO("create task manager", + isc_managers_create(rndc_mctx, 1, 0, &netmgr, &taskmgr)); + DO("create task", isc_task_create(taskmgr, 0, &task)); + + isc_log_create(rndc_mctx, &log, &logconfig); + isc_log_setcontext(log); + isc_log_settag(logconfig, progname); + logdest.file.stream = stderr; + logdest.file.name = NULL; + logdest.file.versions = ISC_LOG_ROLLNEVER; + logdest.file.maximum_size = 0; + isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, + ISC_LOG_INFO, &logdest, + ISC_LOG_PRINTTAG | ISC_LOG_PRINTLEVEL); + DO("enabling log channel", + isc_log_usechannel(logconfig, "stderr", NULL, NULL)); + + parse_config(rndc_mctx, log, keyname, &pctx, &config); + + isccc_result_register(); + + command = *argv; + + isc_buffer_allocate(rndc_mctx, &databuf, 2048); + + /* + * Convert argc/argv into a space-delimited command string + * similar to what the user might enter in interactive mode + * (if that were implemented). + */ + argslen = 0; + for (i = 0; i < argc; i++) { + argslen += strlen(argv[i]) + 1; + } + + args = isc_mem_get(rndc_mctx, argslen); + + p = args; + for (i = 0; i < argc; i++) { + size_t len = strlen(argv[i]); + memmove(p, argv[i], len); + p += len; + *p++ = ' '; + } + + p--; + *p++ = '\0'; + INSIST(p == args + argslen); + + notify("%s", command); + + if (strcmp(command, "restart") == 0) { + fatal("'%s' is not implemented", command); + } + + if (nserveraddrs == 0 && servername != NULL) { + get_addresses(servername, (in_port_t)remoteport); + } + + isc_task_attach(task, &(isc_task_t *){ NULL }); + DO("post event", isc_app_onrun(rndc_mctx, task, rndc_start, NULL)); + + result = isc_app_run(); + if (result != ISC_R_SUCCESS) { + fatal("isc_app_run() failed: %s", isc_result_totext(result)); + } + + if (atomic_load_acquire(&connects) > 0 || + atomic_load_acquire(&sends) > 0 || atomic_load_acquire(&recvs) > 0) + { + isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); + } + + isc_task_detach(&task); + isc_managers_destroy(&netmgr, &taskmgr); + isc_socketmgr_destroy(&socketmgr); + isc_log_destroy(&log); + isc_log_setcontext(NULL); + + cfg_obj_destroy(pctx, &config); + cfg_parser_destroy(&pctx); + + isc_mem_put(rndc_mctx, args, argslen); + isccc_ccmsg_invalidate(&ccmsg); + + isc_buffer_free(&databuf); + + if (show_final_mem) { + isc_mem_stats(rndc_mctx, stderr); + } + + isc_mem_destroy(&rndc_mctx); + + if (failed) { + return (1); + } + + return (0); +} diff --git a/bin/rndc/rndc.conf b/bin/rndc/rndc.conf new file mode 100644 index 0000000..78ee858 --- /dev/null +++ b/bin/rndc/rndc.conf @@ -0,0 +1,41 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Sample rndc configuration file. + */ + +options { + default-server localhost; + default-key "key"; +}; + +server localhost { + key "key"; +}; + +key "cc64b3d1db63fc88d7cb5d2f9f57d258" { + algorithm hmac-sha256; + secret "34f88008d07deabbe65bd01f1d233d47"; +}; + +server "test1" { + key "cc64b3d1db63fc88d7cb5d2f9f57d258"; + port 5353; + addresses { 10.53.0.1; }; +}; + +key "key" { + algorithm hmac-sha256; + secret "c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K"; +}; diff --git a/bin/rndc/rndc.conf.rst b/bin/rndc/rndc.conf.rst new file mode 100644 index 0000000..b02e780 --- /dev/null +++ b/bin/rndc/rndc.conf.rst @@ -0,0 +1,156 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_rndc.conf: + +rndc.conf - rndc configuration file +----------------------------------- + +Synopsis +~~~~~~~~ + +:program:`rndc.conf` + +Description +~~~~~~~~~~~ + +``rndc.conf`` is the configuration file for ``rndc``, the BIND 9 name +server control utility. This file has a similar structure and syntax to +``named.conf``. Statements are enclosed in braces and terminated with a +semi-colon. Clauses in the statements are also semi-colon terminated. +The usual comment styles are supported: + +C style: /\* \*/ + +C++ style: // to end of line + +Unix style: # to end of line + +``rndc.conf`` is much simpler than ``named.conf``. The file uses three +statements: an options statement, a server statement, and a key +statement. + +The ``options`` statement contains five clauses. The ``default-server`` +clause is followed by the name or address of a name server. This host +is used when no name server is given as an argument to ``rndc``. +The ``default-key`` clause is followed by the name of a key, which is +identified by a ``key`` statement. If no ``keyid`` is provided on the +rndc command line, and no ``key`` clause is found in a matching +``server`` statement, this default key is used to authenticate the +server's commands and responses. The ``default-port`` clause is followed +by the port to connect to on the remote name server. If no ``port`` +option is provided on the rndc command line, and no ``port`` clause is +found in a matching ``server`` statement, this default port is used +to connect. The ``default-source-address`` and +``default-source-address-v6`` clauses can be used to set the IPv4 +and IPv6 source addresses respectively. + +After the ``server`` keyword, the server statement includes a string +which is the hostname or address for a name server. The statement has +three possible clauses: ``key``, ``port``, and ``addresses``. The key +name must match the name of a key statement in the file. The port number +specifies the port to connect to. If an ``addresses`` clause is supplied, +these addresses are used instead of the server name. Each address +can take an optional port. If an ``source-address`` or +``source-address-v6`` is supplied, it is used to specify the +IPv4 and IPv6 source address, respectively. + +The ``key`` statement begins with an identifying string, the name of the +key. The statement has two clauses. ``algorithm`` identifies the +authentication algorithm for ``rndc`` to use; currently only HMAC-MD5 +(for compatibility), HMAC-SHA1, HMAC-SHA224, HMAC-SHA256 (default), +HMAC-SHA384, and HMAC-SHA512 are supported. This is followed by a secret +clause which contains the base-64 encoding of the algorithm's +authentication key. The base-64 string is enclosed in double quotes. + +There are two common ways to generate the base-64 string for the secret. +The BIND 9 program ``rndc-confgen`` can be used to generate a random +key, or the ``mmencode`` program, also known as ``mimencode``, can be +used to generate a base-64 string from known input. ``mmencode`` does +not ship with BIND 9 but is available on many systems. See the Example +section for sample command lines for each. + +Example +~~~~~~~ + +:: + + options { + default-server localhost; + default-key samplekey; + }; + +:: + + server localhost { + key samplekey; + }; + +:: + + server testserver { + key testkey; + addresses { localhost port 5353; }; + }; + +:: + + key samplekey { + algorithm hmac-sha256; + secret "6FMfj43Osz4lyb24OIe2iGEz9lf1llJO+lz"; + }; + +:: + + key testkey { + algorithm hmac-sha256; + secret "R3HI8P6BKw9ZwXwN3VZKuQ=="; + }; + + +In the above example, ``rndc`` by default uses the server at +localhost (127.0.0.1) and the key called "samplekey". Commands to the +localhost server use the "samplekey" key, which must also be defined +in the server's configuration file with the same name and secret. The +key statement indicates that "samplekey" uses the HMAC-SHA256 algorithm +and its secret clause contains the base-64 encoding of the HMAC-SHA256 +secret enclosed in double quotes. + +If ``rndc -s testserver`` is used, then ``rndc`` connects to the server +on localhost port 5353 using the key "testkey". + +To generate a random secret with ``rndc-confgen``: + +``rndc-confgen`` + +A complete ``rndc.conf`` file, including the randomly generated key, +is written to the standard output. Commented-out ``key`` and +``controls`` statements for ``named.conf`` are also printed. + +To generate a base-64 secret with ``mmencode``: + +``echo "known plaintext for a secret" | mmencode`` + +Name Server Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The name server must be configured to accept rndc connections and to +recognize the key specified in the ``rndc.conf`` file, using the +controls statement in ``named.conf``. See the sections on the +``controls`` statement in the BIND 9 Administrator Reference Manual for +details. + +See Also +~~~~~~~~ + +:manpage:`rndc(8)`, :manpage:`rndc-confgen(8)`, :manpage:`mmencode(1)`, BIND 9 Administrator Reference Manual. diff --git a/bin/rndc/rndc.rst b/bin/rndc/rndc.rst new file mode 100644 index 0000000..b2ec0e8 --- /dev/null +++ b/bin/rndc/rndc.rst @@ -0,0 +1,608 @@ +.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") +.. +.. SPDX-License-Identifier: MPL-2.0 +.. +.. This Source Code Form is subject to the terms of the Mozilla Public +.. License, v. 2.0. If a copy of the MPL was not distributed with this +.. file, you can obtain one at https://mozilla.org/MPL/2.0/. +.. +.. See the COPYRIGHT file distributed with this work for additional +.. information regarding copyright ownership. + +.. highlight: console + +.. _man_rndc: + +rndc - name server control utility +---------------------------------- + +Synopsis +~~~~~~~~ + +:program:`rndc` [**-b** source-address] [**-c** config-file] [**-k** key-file] [**-s** server] [**-p** port] [**-q**] [**-r**] [**-V**] [**-y** key_id] [[**-4**] | [**-6**]] {command} + +Description +~~~~~~~~~~~ + +``rndc`` controls the operation of a name server; it supersedes the +``ndc`` utility. If ``rndc`` is +invoked with no command line options or arguments, it prints a short +summary of the supported commands and the available options and their +arguments. + +``rndc`` communicates with the name server over a TCP connection, +sending commands authenticated with digital signatures. In the current +versions of ``rndc`` and ``named``, the only supported authentication +algorithms are HMAC-MD5 (for compatibility), HMAC-SHA1, HMAC-SHA224, +HMAC-SHA256 (default), HMAC-SHA384, and HMAC-SHA512. They use a shared +secret on each end of the connection, which provides TSIG-style +authentication for the command request and the name server's response. +All commands sent over the channel must be signed by a key_id known to +the server. + +``rndc`` reads a configuration file to determine how to contact the name +server and decide what algorithm and key it should use. + +Options +~~~~~~~ + +``-4`` + This option indicates use of IPv4 only. + +``-6`` + This option indicates use of IPv6 only. + +``-b source-address`` + This option indicates ``source-address`` as the source address for the connection to the + server. Multiple instances are permitted, to allow setting of both the + IPv4 and IPv6 source addresses. + +``-c config-file`` + This option indicates ``config-file`` as the configuration file instead of the default, + ``/etc/rndc.conf``. + +``-k key-file`` + This option indicates ``key-file`` as the key file instead of the default, + ``/etc/rndc.key``. The key in ``/etc/rndc.key`` is used to + authenticate commands sent to the server if the config-file does not + exist. + +``-s server`` + ``server`` is the name or address of the server which matches a server + statement in the configuration file for ``rndc``. If no server is + supplied on the command line, the host named by the default-server + clause in the options statement of the ``rndc`` configuration file + is used. + +``-p port`` + This option instructs BIND 9 to send commands to TCP port ``port`` instead of its default control + channel port, 953. + +``-q`` + This option sets quiet mode, where message text returned by the server is not printed + unless there is an error. + +``-r`` + This option instructs ``rndc`` to print the result code returned by ``named`` + after executing the requested command (e.g., ISC_R_SUCCESS, + ISC_R_FAILURE, etc.). + +``-V`` + This option enables verbose logging. + +``-y key_id`` + This option indicates use of the key ``key_id`` from the configuration file. For control message validation to succeed, ``key_id`` must be known + by ``named`` with the same algorithm and secret string. If no ``key_id`` is specified, + ``rndc`` first looks for a key clause in the server statement of + the server being used, or if no server statement is present for that + host, then in the default-key clause of the options statement. Note that + the configuration file contains shared secrets which are used to send + authenticated control commands to name servers, and should therefore + not have general read or write access. + +Commands +~~~~~~~~ + +A list of commands supported by ``rndc`` can be seen by running ``rndc`` +without arguments. + +Currently supported commands are: + +``addzone`` *zone* [*class* [*view*]] *configuration* + This command adds a zone while the server is running. This command requires the + ``allow-new-zones`` option to be set to ``yes``. The configuration + string specified on the command line is the zone configuration text + that would ordinarily be placed in ``named.conf``. + + The configuration is saved in a file called ``viewname.nzf`` (or, if + ``named`` is compiled with liblmdb, an LMDB database file called + ``viewname.nzd``). ``viewname`` is the name of the view, unless the view + name contains characters that are incompatible with use as a file + name, in which case a cryptographic hash of the view name is used + instead. When ``named`` is restarted, the file is loaded into + the view configuration so that zones that were added can persist + after a restart. + + This sample ``addzone`` command adds the zone ``example.com`` to + the default view: + + ``rndc addzone example.com '{ type master; file "example.com.db"; };'`` + + (Note the brackets around and semi-colon after the zone configuration + text.) + + See also ``rndc delzone`` and ``rndc modzone``. + +``delzone`` [**-clean**] *zone* [*class* [*view*]] + This command deletes a zone while the server is running. + + If the ``-clean`` argument is specified, the zone's master file (and + journal file, if any) are deleted along with the zone. Without + the ``-clean`` option, zone files must be deleted manually. (If the + zone is of type ``secondary`` or ``stub``, the files needing to be removed + are reported in the output of the ``rndc delzone`` command.) + + If the zone was originally added via ``rndc addzone``, then it is + removed permanently. However, if it was originally configured in + ``named.conf``, then that original configuration remains in place; + when the server is restarted or reconfigured, the zone is + recreated. To remove it permanently, it must also be removed from + ``named.conf``. + + See also ``rndc addzone`` and ``rndc modzone``. + +``dnssec`` ( **-status** | **-rollover** **-key** id [**-alg** *algorithm*] [**-when** *time*] | **-checkds** [**-key** *id* [**-alg** *algorithm*]] [**-when** *time*] ( *published* | *withdrawn* )) *zone* [*class* [*view*]] + This command allows you to interact with the "dnssec-policy" of a given + zone. + + ``rndc dnssec -status`` show the DNSSEC signing state for the specified + zone. + + ``rndc dnssec -rollover`` allows you to schedule key rollover for a + specific key (overriding the original key lifetime). + + ``rndc dnssec -checkds`` informs :iscman:`named` that the DS for + a specified zone's key-signing key has been confirmed to be published + in, or withdrawn from, the parent zone. This is required in order to + complete a KSK rollover. The ``-key id`` and ``-alg algorithm`` arguments + can be used to specify a particular KSK, if necessary; if there is only + one key acting as a KSK for the zone, these arguments can be omitted. + The time of publication or withdrawal for the DS is set to the current + time by default, but can be overridden to a specific time with the + argument ``-when time``, where ``time`` is expressed in YYYYMMDDHHMMSS + notation. + +``dnstap`` ( **-reopen** | **-roll** [*number*] ) + This command closes and re-opens DNSTAP output files. + + ``rndc dnstap -reopen`` allows + the output file to be renamed externally, so that ``named`` can + truncate and re-open it. + + ``rndc dnstap -roll`` causes the output file + to be rolled automatically, similar to log files. The most recent + output file has ".0" appended to its name; the previous most recent + output file is moved to ".1", and so on. If ``number`` is specified, then + the number of backup log files is limited to that number. + +``dumpdb`` [**-all** | **-cache** | **-zones** | **-adb** | **-bad** | **-expired** | **-fail**] [*view ...*] + This command dumps the server's caches (default) and/or zones to the dump file for + the specified views. If no view is specified, all views are dumped. + (See the ``dump-file`` option in the BIND 9 Administrator Reference + Manual.) + +``flush`` + This command flushes the server's cache. + +``flushname`` *name* [*view*] + This command flushes the given name from the view's DNS cache and, if applicable, + from the view's nameserver address database, bad server cache, and + SERVFAIL cache. + +``flushtree`` *name* [*view*] + This command flushes the given name, and all of its subdomains, from the view's + DNS cache, address database, bad server cache, and SERVFAIL cache. + +``freeze`` [*zone* [*class* [*view*]]] + This command suspends updates to a dynamic zone. If no zone is specified, then all + zones are suspended. This allows manual edits to be made to a zone + normally updated by dynamic update, and causes changes in the + journal file to be synced into the master file. All dynamic update + attempts are refused while the zone is frozen. + + See also ``rndc thaw``. + +``halt`` [**-p**] + This command stops the server immediately. Recent changes made through dynamic + update or IXFR are not saved to the master files, but are rolled + forward from the journal files when the server is restarted. If + ``-p`` is specified, ``named``'s process ID is returned. This allows + an external process to determine when ``named`` has completed + halting. + + See also ``rndc stop``. + +``loadkeys`` [*zone* [*class* [*view*]]] + This command fetches all DNSSEC keys for the given zone from the key directory. If + they are within their publication period, they are merged into the + zone's DNSKEY RRset. Unlike ``rndc sign``, however, the zone is not + immediately re-signed by the new keys, but is allowed to + incrementally re-sign over time. + + This command requires that the zone be configured with a ``dnssec-policy``, or + that the ``auto-dnssec`` zone option be set to ``maintain``, and also requires the + zone to be configured to allow dynamic DNS. (See "Dynamic Update Policies" in + the Administrator Reference Manual for more details.) + +``managed-keys`` (*status* | *refresh* | *sync* | *destroy*) [*class* [*view*]] + This command inspects and controls the "managed-keys" database which handles + :rfc:`5011` DNSSEC trust anchor maintenance. If a view is specified, these + commands are applied to that view; otherwise, they are applied to all + views. + + - When run with the ``status`` keyword, this prints the current status of + the managed-keys database. + + - When run with the ``refresh`` keyword, this forces an immediate refresh + query to be sent for all the managed keys, updating the + managed-keys database if any new keys are found, without waiting + the normal refresh interval. + + - When run with the ``sync`` keyword, this forces an immediate dump of + the managed-keys database to disk (in the file + ``managed-keys.bind`` or (``viewname.mkeys``). This synchronizes + the database with its journal file, so that the database's current + contents can be inspected visually. + + - When run with the ``destroy`` keyword, the managed-keys database + is shut down and deleted, and all key maintenance is terminated. + This command should be used only with extreme caution. + + Existing keys that are already trusted are not deleted from + memory; DNSSEC validation can continue after this command is used. + However, key maintenance operations cease until ``named`` is + restarted or reconfigured, and all existing key maintenance states + are deleted. + + Running ``rndc reconfig`` or restarting ``named`` immediately + after this command causes key maintenance to be reinitialized + from scratch, just as if the server were being started for the + first time. This is primarily intended for testing, but it may + also be used, for example, to jumpstart the acquisition of new + keys in the event of a trust anchor rollover, or as a brute-force + repair for key maintenance problems. + +``modzone`` *zone* [*class* [*view*]] *configuration* + This command modifies the configuration of a zone while the server is running. This + command requires the ``allow-new-zones`` option to be set to ``yes``. + As with ``addzone``, the configuration string specified on the + command line is the zone configuration text that would ordinarily be + placed in ``named.conf``. + + If the zone was originally added via ``rndc addzone``, the + configuration changes are recorded permanently and are still + in effect after the server is restarted or reconfigured. However, if + it was originally configured in ``named.conf``, then that original + configuration remains in place; when the server is restarted or + reconfigured, the zone reverts to its original configuration. To + make the changes permanent, it must also be modified in + ``named.conf``. + + See also ``rndc addzone`` and ``rndc delzone``. + +``notify`` *zone* [*class* [*view*]] + This command resends NOTIFY messages for the zone. + +``notrace`` + This command sets the server's debugging level to 0. + + See also ``rndc trace``. + +``nta`` [( **-class** *class* | **-dump** | **-force** | **-remove** | **-lifetime** *duration*)] *domain* [*view*] + This command sets a DNSSEC negative trust anchor (NTA) for ``domain``, with a + lifetime of ``duration``. The default lifetime is configured in + ``named.conf`` via the ``nta-lifetime`` option, and defaults to one + hour. The lifetime cannot exceed one week. + + A negative trust anchor selectively disables DNSSEC validation for + zones that are known to be failing because of misconfiguration rather + than an attack. When data to be validated is at or below an active + NTA (and above any other configured trust anchors), ``named`` + aborts the DNSSEC validation process and treats the data as insecure + rather than bogus. This continues until the NTA's lifetime has + elapsed. + + NTAs persist across restarts of the ``named`` server. The NTAs for a + view are saved in a file called ``name.nta``, where ``name`` is the name + of the view; if it contains characters that are incompatible with + use as a file name, a cryptographic hash is generated from the name of + the view. + + An existing NTA can be removed by using the ``-remove`` option. + + An NTA's lifetime can be specified with the ``-lifetime`` option. + TTL-style suffixes can be used to specify the lifetime in seconds, + minutes, or hours. If the specified NTA already exists, its lifetime + is updated to the new value. Setting ``lifetime`` to zero is + equivalent to ``-remove``. + + If ``-dump`` is used, any other arguments are ignored and a list + of existing NTAs is printed. Note that this may include NTAs that are + expired but have not yet been cleaned up. + + Normally, ``named`` periodically tests to see whether data below + an NTA can now be validated (see the ``nta-recheck`` option in the + Administrator Reference Manual for details). If data can be + validated, then the NTA is regarded as no longer necessary and is + allowed to expire early. The ``-force`` parameter overrides this behavior + and forces an NTA to persist for its entire lifetime, regardless of + whether data could be validated if the NTA were not present. + + The view class can be specified with ``-class``. The default is class + ``IN``, which is the only class for which DNSSEC is currently + supported. + + All of these options can be shortened, i.e., to ``-l``, ``-r``, + ``-d``, ``-f``, and ``-c``. + + Unrecognized options are treated as errors. To refer to a domain or + view name that begins with a hyphen, use a double-hyphen (--) on the + command line to indicate the end of options. + +``querylog`` [(*on* | *off*)] + This command enables or disables query logging. For backward compatibility, this + command can also be used without an argument to toggle query logging + on and off. + + Query logging can also be enabled by explicitly directing the + ``queries`` ``category`` to a ``channel`` in the ``logging`` section + of ``named.conf``, or by specifying ``querylog yes;`` in the + ``options`` section of ``named.conf``. + +``reconfig`` + This command reloads the configuration file and loads new zones, but does not reload + existing zone files even if they have changed. This is faster than a + full ``reload`` when there is a large number of zones, because it + avoids the need to examine the modification times of the zone files. + +``recursing`` + This command dumps the list of queries ``named`` is currently + recursing on, and the list of domains to which iterative queries + are currently being sent. + + The first list includes all unique clients that are waiting for + recursion to complete, including the query that is awaiting a + response and the timestamp (seconds since the Unix epoch) of + when named started processing this client query. + + The second list comprises of domains for which there are active + (or recently active) fetches in progress. It reports the number + of active fetches for each domain and the number of queries that + have been passed (allowed) or dropped (spilled) as a result of + the ``fetches-per-zone`` limit. (Note: these counters are not + cumulative over time; whenever the number of active fetches for + a domain drops to zero, the counter for that domain is deleted, + and the next time a fetch is sent to that domain, it is recreated + with the counters set to zero). + +``refresh`` *zone* [*class* [*view*]] + This command schedules zone maintenance for the given zone. + +``reload`` + This command reloads the configuration file and zones. + +``reload`` *zone* [*class* [*view*]] + This command reloads the given zone. + +``retransfer`` *zone* [*class* [*view*]] + This command retransfers the given secondary zone from the primary server. + + If the zone is configured to use ``inline-signing``, the signed + version of the zone is discarded; after the retransfer of the + unsigned version is complete, the signed version is regenerated + with new signatures. + +``scan`` + This command scans the list of available network interfaces for changes, without + performing a full ``reconfig`` or waiting for the + ``interface-interval`` timer. + +``secroots`` [**-**] [*view* ...] + This command dumps the security roots (i.e., trust anchors configured via + ``trust-anchors``, or the ``managed-keys`` or ``trusted-keys`` statements + [both deprecated], or ``dnssec-validation auto``) and negative trust anchors + for the specified views. If no view is specified, all views are + dumped. Security roots indicate whether they are configured as trusted + keys, managed keys, or initializing managed keys (managed keys that have not + yet been updated by a successful key refresh query). + + If the first argument is ``-``, then the output is returned via the + ``rndc`` response channel and printed to the standard output. + Otherwise, it is written to the secroots dump file, which defaults to + ``named.secroots``, but can be overridden via the ``secroots-file`` + option in ``named.conf``. + + See also ``rndc managed-keys``. + +``serve-stale`` (**on** | **off** | **reset** | **status**) [*class* [*view*]] + This command enables, disables, resets, or reports the current status of the serving + of stale answers as configured in ``named.conf``. + + If serving of stale answers is disabled by ``rndc-serve-stale off``, + then it remains disabled even if ``named`` is reloaded or + reconfigured. ``rndc serve-stale reset`` restores the setting as + configured in ``named.conf``. + + ``rndc serve-stale status`` reports whether serving of stale + answers is currently enabled, disabled by the configuration, or + disabled by ``rndc``. It also reports the values of + ``stale-answer-ttl`` and ``max-stale-ttl``. + +``showzone`` *zone* [*class* [*view*]] + This command prints the configuration of a running zone. + + See also ``rndc zonestatus``. + +``sign`` *zone* [*class* [*view*]] + This command fetches all DNSSEC keys for the given zone from the key directory (see + the ``key-directory`` option in the BIND 9 Administrator Reference + Manual). If they are within their publication period, they are merged into + the zone's DNSKEY RRset. If the DNSKEY RRset is changed, then the + zone is automatically re-signed with the new key set. + + This command requires that the zone be configured with a ``dnssec-policy``, or + that the ``auto-dnssec`` zone option be set to ``allow`` or ``maintain``, + and also requires the zone to be configured to allow dynamic DNS. (See + "Dynamic Update Policies" in the BIND 9 Administrator Reference Manual for more + details.) + + See also ``rndc loadkeys``. + +``signing`` [(**-list** | **-clear** *keyid/algorithm* | **-clear** *all* | **-nsec3param** ( *parameters* | none ) | **-serial** *value* ) *zone* [*class* [*view*]] + This command lists, edits, or removes the DNSSEC signing-state records for the + specified zone. The status of ongoing DNSSEC operations, such as + signing or generating NSEC3 chains, is stored in the zone in the form + of DNS resource records of type ``sig-signing-type``. + ``rndc signing -list`` converts these records into a human-readable + form, indicating which keys are currently signing or have finished + signing the zone, and which NSEC3 chains are being created or + removed. + + ``rndc signing -clear`` can remove a single key (specified in the + same format that ``rndc signing -list`` uses to display it), or all + keys. In either case, only completed keys are removed; any record + indicating that a key has not yet finished signing the zone is + retained. + + ``rndc signing -nsec3param`` sets the NSEC3 parameters for a zone. + This is the only supported mechanism for using NSEC3 with + ``inline-signing`` zones. Parameters are specified in the same format + as an NSEC3PARAM resource record: ``hash algorithm``, ``flags``, ``iterations``, + and ``salt``, in that order. + + Currently, the only defined value for ``hash algorithm`` is ``1``, + representing SHA-1. The ``flags`` may be set to ``0`` or ``1``, + depending on whether the opt-out bit in the NSEC3 + chain should be set. ``iterations`` defines the number of additional times to apply + the algorithm when generating an NSEC3 hash. The ``salt`` is a string + of data expressed in hexadecimal, a hyphen (``-``) if no salt is to be + used, or the keyword ``auto``, which causes ``named`` to generate a + random 64-bit salt. + + The only recommended configuration is ``rndc signing -nsec3param 1 0 0 - zone``, + i.e. no salt, no additional iterations, no opt-out. + + .. warning:: + Do not use extra iterations, salt, or opt-out unless all their implications + are fully understood. A higher number of iterations causes interoperability + problems and opens servers to CPU-exhausting DoS attacks. + + ``rndc signing -nsec3param none`` removes an existing NSEC3 chain and + replaces it with NSEC. + + ``rndc signing -serial value`` sets the serial number of the zone to + ``value``. If the value would cause the serial number to go backwards, it + is rejected. The primary use of this parameter is to set the serial number on inline + signed zones. + +``stats`` + This command writes server statistics to the statistics file. (See the + ``statistics-file`` option in the BIND 9 Administrator Reference + Manual.) + +``status`` + This command displays the status of the server. Note that the number of zones includes + the internal ``bind/CH`` zone and the default ``./IN`` hint zone, if + there is no explicit root zone configured. + +``stop`` **-p** + This command stops the server, making sure any recent changes made through dynamic + update or IXFR are first saved to the master files of the updated + zones. If ``-p`` is specified, ``named(8)`'s process ID is returned. + This allows an external process to determine when ``named`` has + completed stopping. + + See also ``rndc halt``. + +``sync`` **-clean** [*zone* [*class* [*view*]]] + This command syncs changes in the journal file for a dynamic zone to the master + file. If the "-clean" option is specified, the journal file is also + removed. If no zone is specified, then all zones are synced. + +``tcp-timeouts`` [*initial* *idle* *keepalive* *advertised*] + When called without arguments, this command displays the current values of the + ``tcp-initial-timeout``, ``tcp-idle-timeout``, + ``tcp-keepalive-timeout``, and ``tcp-advertised-timeout`` options. + When called with arguments, these values are updated. This allows an + administrator to make rapid adjustments when under a + denial-of-service (DoS) attack. See the descriptions of these options in the BIND 9 + Administrator Reference Manual for details of their use. + +``thaw`` [*zone* [*class* [*view*]]] + This command enables updates to a frozen dynamic zone. If no zone is specified, + then all frozen zones are enabled. This causes the server to reload + the zone from disk, and re-enables dynamic updates after the load has + completed. After a zone is thawed, dynamic updates are no longer + refused. If the zone has changed and the ``ixfr-from-differences`` + option is in use, the journal file is updated to reflect + changes in the zone. Otherwise, if the zone has changed, any existing + journal file is removed. + + See also ``rndc freeze``. + +``trace`` + This command increments the server's debugging level by one. + +``trace`` *level* + This command sets the server's debugging level to an explicit value. + + See also ``rndc notrace``. + +``tsig-delete`` *keyname* [*view*] + This command deletes a given TKEY-negotiated key from the server. This does not + apply to statically configured TSIG keys. + +``tsig-list`` + This command lists the names of all TSIG keys currently configured for use by + ``named`` in each view. The list includes both statically configured keys and + dynamic TKEY-negotiated keys. + +``validation`` (**on** | **off** | **status**) [*view* ...]`` + This command enables, disables, or checks the current status of DNSSEC validation. By + default, validation is enabled. + + The cache is flushed when validation is turned on or off to avoid using data + that might differ between states. + +``zonestatus`` *zone* [*class* [*view*]] + This command displays the current status of the given zone, including the master + file name and any include files from which it was loaded, when it was + most recently loaded, the current serial number, the number of nodes, + whether the zone supports dynamic updates, whether the zone is DNSSEC + signed, whether it uses automatic DNSSEC key management or inline + signing, and the scheduled refresh or expiry times for the zone. + + See also ``rndc showzone``. + +``rndc`` commands that specify zone names, such as ``reload``, +``retransfer``, or ``zonestatus``, can be ambiguous when applied to zones +of type ``redirect``. Redirect zones are always called ``.``, and can be +confused with zones of type ``hint`` or with secondary copies of the root +zone. To specify a redirect zone, use the special zone name +``-redirect``, without a trailing period. (With a trailing period, this +would specify a zone called "-redirect".) + +Limitations +~~~~~~~~~~~ + +There is currently no way to provide the shared secret for a ``key_id`` +without using the configuration file. + +Several error messages could be clearer. + +See Also +~~~~~~~~ + +:manpage:`rndc.conf(5)`, :manpage:`rndc-confgen(8)`, +:manpage:`named(8)`, :manpage:`named.conf(5)`, :manpage:`ndc(8)`, BIND 9 Administrator +Reference Manual. diff --git a/bin/rndc/util.c b/bin/rndc/util.c new file mode 100644 index 0000000..3b3587c --- /dev/null +++ b/bin/rndc/util.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include "util.h" +#include +#include +#include +#include + +#include + +extern bool verbose; +extern const char *progname; + +void +notify(const char *fmt, ...) { + va_list ap; + + if (verbose) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputs("\n", stderr); + } +} + +void +fatal(const char *format, ...) { + va_list args; + + fprintf(stderr, "%s: ", progname); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + exit(1); +} diff --git a/bin/rndc/util.h b/bin/rndc/util.h new file mode 100644 index 0000000..2d3c664 --- /dev/null +++ b/bin/rndc/util.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef RNDC_UTIL_H +#define RNDC_UTIL_H 1 + +/*! \file */ + +#include +#include +#include + +#define NS_CONTROL_PORT 953 + +#undef DO +#define DO(name, function) \ + do { \ + result = function; \ + if (result != ISC_R_SUCCESS) \ + fatal("%s: %s", name, isc_result_totext(result)); \ + else \ + notify("%s", name); \ + } while (0) + +ISC_LANG_BEGINDECLS + +void +notify(const char *fmt, ...) ISC_FORMAT_PRINTF(1, 2); + +ISC_PLATFORM_NORETURN_PRE void +fatal(const char *format, ...) + ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; + +ISC_LANG_ENDDECLS + +#endif /* RNDC_UTIL_H */ diff --git a/bin/rndc/win32/rndc.vcxproj.filters.in b/bin/rndc/win32/rndc.vcxproj.filters.in new file mode 100644 index 0000000..5187c16 --- /dev/null +++ b/bin/rndc/win32/rndc.vcxproj.filters.in @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/rndc/win32/rndc.vcxproj.in b/bin/rndc/win32/rndc.vcxproj.in new file mode 100644 index 0000000..2a72f5e --- /dev/null +++ b/bin/rndc/win32/rndc.vcxproj.in @@ -0,0 +1,122 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {39721F26-8B80-4AA9-9826-2AEF7322C3D5} + Win32Proj + rndc + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccc\include;..\..\..\lib\isccfg\include;..\..\..\lib\bind9\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@util.lib;libisc.lib;libdns.lib;libisccfg.lib;libisccc.lib;libbind9.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\isccc\include;..\..\..\lib\isccfg\include;..\..\..\lib\bind9\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + $(Configuration);..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\isccfg\win32\$(Configuration);..\..\..\lib\isccc\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@util.lib;libisc.lib;libdns.lib;libisccfg.lib;libisccc.lib;libbind9.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + + + + diff --git a/bin/rndc/win32/rndc.vcxproj.user b/bin/rndc/win32/rndc.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/rndc/win32/rndc.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/rndc/win32/rndcutil.vcxproj.filters.in b/bin/rndc/win32/rndcutil.vcxproj.filters.in new file mode 100644 index 0000000..766ea80 --- /dev/null +++ b/bin/rndc/win32/rndcutil.vcxproj.filters.in @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/rndc/win32/rndcutil.vcxproj.in b/bin/rndc/win32/rndcutil.vcxproj.in new file mode 100644 index 0000000..fad1472 --- /dev/null +++ b/bin/rndc/win32/rndcutil.vcxproj.in @@ -0,0 +1,113 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {7C8681A1-E3A8-470E-9EEF-16054D111A19} + Win32Proj + rndcutil + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + StaticLibrary + true + MultiByte + @PLATFORM_TOOLSET@ + + + StaticLibrary + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + .\$(Configuration)\ + .\$(Configuration)\ + None + util + + + false + .\$(Configuration)\ + .\$(Configuration)\ + None + util + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;..\include;..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + + + + + + + + diff --git a/bin/rndc/win32/rndcutil.vcxproj.user b/bin/rndc/win32/rndcutil.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/rndc/win32/rndcutil.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/tests/Makefile.in b/bin/tests/Makefile.in new file mode 100644 index 0000000..a1e7ea0 --- /dev/null +++ b/bin/tests/Makefile.in @@ -0,0 +1,87 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \ + ${OPENSSL_CFLAGS} + +CDEFINES = +CWARNINGS = +BACKTRACECFLAGS = @BACKTRACECFLAGS@ + +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ + +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +ISCDEPNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ + +LIBS = @LIBS@ + +SUBDIRS = system @PKCS11_TOOLS@ +TESTDIRS = system + +# Test programs that are built by default: +# cfg_test is needed for regenerating doc/misc/options +# makejournal is needed by system tests +# wire_test is needed for fuzz testing +# other opptional test programs have been moved to ./optional + +# Alphabetically +XTARGETS = all_tests +TARGETS = cfg_test@EXEEXT@ makejournal@EXEEXT@ \ + wire_test@EXEEXT@ @XTARGETS@ + +SRCS = cfg_test.c makejournal.c wire_test.c + +@BIND9_MAKE_RULES@ + +.NOTPARALLEL: + +.PHONY: +all_tests: + echo "making depend in `pwd`/optional"; \ + (cd optional; ${MAKE} ${MAKEDEFS} DESTDIR="${DESTDIR}" $@) + +wire_test@EXEEXT@: wire_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ wire_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +cfg_test@EXEEXT@: cfg_test.@O@ ${ISCCFGDEPLIBS} ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ cfg_test.@O@ \ + ${ISCCFGLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} + +makejournal@EXEEXT@: makejournal.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ makejournal.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +distclean:: + rm -f headerdep_test.sh + +clean distclean:: + rm -f ${TARGETS} + ( cd optional; $(MAKE) $@) + +check: test + +test: + @for dir in $(TESTDIRS) ;\ + do \ + ( cd $$dir; $(MAKE) test ) ;\ + done diff --git a/bin/tests/bigtest/README b/bin/tests/bigtest/README new file mode 100644 index 0000000..2d90f94 --- /dev/null +++ b/bin/tests/bigtest/README @@ -0,0 +1,18 @@ +Copyright (C) Internet Systems Consortium, Inc. ("ISC") + +See COPYRIGHT in the source root or https://isc.org/copyright.html for terms. + + bash buildzones.sh < zones # creates setup, run, servers/* master/* + # named.conf + sudo sh setup # configure interfaces + sh run # setup + + ../named/named [-g] -c named.conf + + sh tests.sh < zones + + sudo sh teardown # teardown interfaces + +The test server can controlled with + + rndc -k rndc.key -s 127.127.0.0 -p 5300 diff --git a/bin/tests/bigtest/buildzones.sh b/bin/tests/bigtest/buildzones.sh new file mode 100644 index 0000000..47b4cda --- /dev/null +++ b/bin/tests/bigtest/buildzones.sh @@ -0,0 +1,269 @@ +#!/bin/bash + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +SYSTEMTESTTOP=.. +. ../conf.sh + +addr=127.127.0.0 +ttl=300 +named=${NAMED} +keygen=${KEYGEN} +dsfromkey=${DSFROMKEY} + +nextaddr() { + OLDIF="$IFS" + IFS="${IFS}." + set $1 + IFS="$OLDIFS" + _a=$1 _b=$2 _c=$3 _d=$4 + _d=$(($_d + 1)) + case $_d in + 256) _c=$(($_c + 1)); _d=0;; + esac + case $_c in + 256) _b=$(($_b + 1)); _c=0;; + esac + echo $_a.$_b.$_c.$_d +} + +parent() { + OLDIF="$IFS" + IFS="${IFS}." + set $1 + IFS="$OLDIFS" + shift + while [ $# -ne 0 ] + do + printf %s ${1} + shift + printf %s ${1:+.} + + done +} + +blackhole() { + echo 'options {' + echo ' port 5300;' + echo " listen-on { $1; };" + echo " query-source $1;" + echo " notify-source $1;" + echo " transfer-source $1;" + echo ' key-directory "keys";' + echo " recursion ${2:-no};" + echo ' pid-file "pids/'"${addr}"'.pid";' + echo ' blackhole { 127.127.0.0; };' + echo '};' +} + +refuse() { + echo 'options {' + echo ' port 5300;' + echo " listen-on { $1; };" + echo " query-source $1;" + echo " notify-source $1;" + echo " transfer-source $1;" + echo ' key-directory "keys";' + echo " recursion ${2:-no};" + echo ' pid-file "pids/'"${addr}"'.pid";' + echo ' allow-query { !127.127.0.0; any; };' + echo '};' +} + +options() { + echo 'options {' + echo ' port 5300;' + echo " listen-on { $1; };" + echo " query-source $1;" + echo " notify-source $1;" + echo " transfer-source $1;" + echo ' key-directory "keys";' + echo " recursion ${2:-no};" + echo ' pid-file "pids/'"${addr}"'.pid";' + echo '};' +} + +controls() { + echo 'include "rndc.key";' + echo "controls { inet $addr port 9953 allow { any; } keys { "rndc-key"; }; };" +} + +delay() { + _s=$1 + OLDIF="$IFS" + IFS="${IFS}/" + set ${2:-.} + IFS="$OLDIFS" + + case $1 in + .) _d=;; + *) _d=$1;; + esac + case $_s in + 1) echo -T delay=${_d:-100};; + 2) echo -T delay=${2:-50};; + 3) echo -T delay=${3:-150};; + 4) echo -T delay=${4:-250};; + 5) echo -T delay=${5:-125};; + 6) echo -T delay=${6:-25};; + 7) echo -T delay=${7:-75};; + 8) echo -T delay=${8:-125};; + 9) echo -T delay=${9:-10};; + 10) echo -T delay=${10:-40};; + 11) echo -T delay=${11:-80};; + 12) echo -T delay=${12:-90};; + *) echo -T delay=50;; + esac +} + +trusted-keys () { + awk '$3 == "DNSKEY" { + b = ""; for (i=7; i <= NF; i++) { b = b $i; }; + print "trusted-keys { \""$1"\"",$4,$5,$6,"\""b"\"; };" };' +} + +signed-zone () { + echo "zone "'"'"${1:-.}"'"'" {" + echo " type master;" + echo " file "'"'"master/${2}.db"'"'";" + echo " auto-dnssec maintain;" + echo " allow-update { any; };" + echo "};" +} + +unsigned-zone () { + echo "zone "'"'"${1:-.}"'"'" {" + echo " type master;" + echo " file "'"'"master/${2}.db"'"'";" + echo "};" +} + +slave-zone () { + echo "zone "'"'"${zone:-.}"'"'" {" + echo " type slave;" + echo " masters { ${master}; };" + echo "};" +} + +rm -rf servers master keys setup teardown run +mkdir -p servers +mkdir -p master +mkdir -p keys + +echo "ifconfig lo0 $addr netmask 0xffffffff alias" >> setup +echo "ifconfig lo0 $addr -alias" >> teardown +controls $addr > named.conf +options $addr yes >> named.conf +echo 'zone "." { type hint; file "master/hint.db"; };' >> named.conf + +while read zone servers nsfmt signed delay blackhole refuse flags +do + i=1 + case "${zone}" in + .) file=root zone=;; + *) file="$zone";; + esac + if [ "${zone}" != "" ] ; then + p=$(parent $zone) + case "${p}" in + "") p=root;; + esac + else + p=hint + fi + #echo "zone='${zone}' parent='${p}'" + addr=$(nextaddr $addr) + ns=$(printf "$nsfmt" ${i} "${zone}") + d=$(delay $i ${delay:-.}) + + echo "${zone}. ${ttl} soa ${ns}. hostmaster.${zone}${zone:+.} 1 3600 1200 604800 1200" >> master/${file}.db + echo "${zone}. ${ttl} ns ${ns}." >> master/${file}.db + echo "${ns}. ${ttl} a ${addr}" >> master/${file}.db + echo "${zone}. ${ttl} ns ${ns}." >> master/${p}.db + echo "${ns}. ${ttl} a ${addr}" >> master/${p}.db + if [ $signed = "S" ]; then + kskkey=`${keygen} -K keys -f KSK ${zone:-.}` + zskkey=`${keygen} -K keys ${zone:-.}` + if [ "${zone}" != "" ] ; then + ${dsfromkey} -T ${ttl} keys/${kskkey}.key >> master/${p}.db + else + trusted-keys < keys/${kskkey}.key >> named.conf + fi + fi + echo "ifconfig lo0 $addr netmask 0xffffffff alias" >> setup + echo "ifconfig lo0 $addr -alias" >> teardown + echo "${named} -D bigtest -c servers/${addr}.conf $d $flags" >> run + options ${addr} > servers/${addr}.conf + case ${signed} in + S) signed-zone ${zone:-.} ${file} >> servers/${addr}.conf;; + P) unsigned-zone ${zone:-.} ${file} >> servers/${addr}.conf;; + *) echo ${signed}; exit 1;; + esac + + # slave servers + while [ $i -lt $servers ] + do + master=$addr + i=$(($i + 1)) + ns=$(printf "$nsfmt" ${i} "${zone}") + d=$(delay $i ${delay:-.}) + addr=$(nextaddr $addr) + echo "${zone}. ${ttl} ns ${ns}." >> master/${file}.db + echo "${ns}. ${ttl} a ${addr}" >> master/${file}.db + echo "${zone}. ${ttl} ns ${ns}." >> master/${p}.db + echo "${ns}. ${ttl} a ${addr}" >> master/${p}.db + echo "ifconfig lo0 $addr netmask 0xffffffff alias" >> setup + echo "ifconfig lo0 $addr -alias" >> teardown + echo "${named} -D bigtest -c servers/${addr}.conf $d $flags" >> run + if [ $i = ${refuse:-.} ] + then + refuse $addr > servers/${addr}.conf + elif [ $i = ${blackhole:-.} ] + then + blackhole $addr > servers/${addr}.conf + else + options $addr > servers/${addr}.conf + fi + slave-zone ${zone:-.} ${master} >> servers/${addr}.conf + done + if [ "${zone}" != "" ] ; then + echo "www.${zone}. ${ttl} a 127.0.0.1" >> master/${file}.db + echo "www.${zone}. ${ttl} aaaa ::1" >> master/${file}.db + echo "${zone}. ${ttl} mx 10 mail.${zone}." >> master/${file}.db + echo "mail.${zone}. ${ttl} a 127.0.0.1" >> master/${file}.db + echo "mail.${zone}. ${ttl} aaaa ::1" >> master/${file}.db + echo "*.big.${zone}. ${ttl} txt (" >> master/${file}.db + i=0 + while [ $i -lt 150 ] + do + echo "1234567890" >> master/${file}.db + i=$(($i + 1)) + done + echo ")" >> master/${file}.db + echo "*.medium.${zone}. ${ttl} txt (" >> master/${file}.db + i=0 + while [ $i -lt 120 ] + do + echo "1234567890" >> master/${file}.db + i=$(($i + 1)) + done + echo ")" >> master/${file}.db + echo "*.medium.${zone}. ${ttl} txt (" >> master/${file}.db + i=0 + while [ $i -lt 120 ] + do + echo "1234567890" >> master/${file}.db + i=$(($i + 1)) + done + echo ")" >> master/${file}.db + fi +done diff --git a/bin/tests/bigtest/rndc.key b/bin/tests/bigtest/rndc.key new file mode 100644 index 0000000..f279e14 --- /dev/null +++ b/bin/tests/bigtest/rndc.key @@ -0,0 +1,5 @@ +key "rndc-key" { + algorithm hmac-md5; + secret "xxxxxxxxxxxxxxxxxxxxHg=="; +}; + diff --git a/bin/tests/bigtest/tests.sh b/bin/tests/bigtest/tests.sh new file mode 100644 index 0000000..19fc238 --- /dev/null +++ b/bin/tests/bigtest/tests.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +TOP=$( (cd ../../.. && pwd) ) +dig=${TOP}/bin/dig/dig + +cmd="${dig} -p 5300 @127.127.0.0 txt" +inner() { + zone=$1 i=$2 to=$3 + x=$i + dout=dig$x.out + tout=time$x.out + while [ $i -lt $to ] + do + case $zone in + .) zone=;; + esac + + (time -p $cmd $i.${sub}$zone > $dout ) 2> $tout + s=`sed -n '/real/s/[^0-9]*\([0-9]*\)\..*/\1/p' $tout` + case $s in + 0);; + 1) t1=`expr ${t1:-0} + 1`;; + 2) t2=`expr ${t2:-0} + 1`;; + 3) t3=`expr ${t3:-0} + 1`;; + *) echo $i `grep real $tout`;; + esac + + grep "status: \(NXDOMAIN\|NOERROR\)" $dout > /dev/null || { + echo $cmd $i.${sub}$zone + cat $dout + } + i=`expr $i + 1` + done + if test ${t1:-0} -ne 0 -o ${t2:-0} -ne 0 -o ${t3:-0} -ne 0 + then + echo "$x timeouts: t1=${t1:-0} t2=${t2:-0} t3=${t3:-0}" + fi +} + +while read zone rest +do + for sub in "" medium. big. + do + case $zone in + .) echo doing ${sub:-.};; + *) echo doing $sub$zone;; + esac + ( inner $zone 1 100) & + ( inner $zone 101 200) & + ( inner $zone 201 300) & + ( inner $zone 301 400) & + ( inner $zone 401 500) & + ( inner $zone 501 600) & + ( inner $zone 601 700) & + ( inner $zone 701 800) & + ( inner $zone 801 900) & + ( inner $zone 901 1000) & + ( inner $zone 1001 1100) & + ( inner $zone 1101 1200) & + ( inner $zone 1201 1300) & + ( inner $zone 1301 1400) & + ( inner $zone 1401 1500) & + ( inner $zone 1501 1600) & + ( inner $zone 1601 1700) & + wait + done +done diff --git a/bin/tests/bigtest/zones b/bin/tests/bigtest/zones new file mode 100644 index 0000000..0bdcdfe --- /dev/null +++ b/bin/tests/bigtest/zones @@ -0,0 +1,18 @@ +noedns-1.tld 1 ns%u.%s P . x x -T noedns +dropedns-1.tld 1 ns%u.%s P . x x -T dropedns +maxudp512-1.tld 1 ns%u.%s S . x x -T maxudp=512 +maxudp1460-1.tld 1 ns%u.%s S . x x -T maxudp=1460 +plain-1.tld 1 ns%u.%s S . x x +noedns-3.tld 3 ns%u.%s P . 2 x -T noedns +dropedns-3.tld 3 ns%u.%s P . 2 x -T dropedns +maxudp512-3.tld 3 ns%u.%s S . x x -T maxudp=512 +maxudp1460-3.tld 3 ns%u.%s S . x x -T maxudp=1460 +plain-3.tld 3 ns%u.%s S . x 3 +noedns-5.tld 5 ns%u.%s P . 3 x -T noedns +dropedns-5.tld 5 ns%u.%s P . x x -T dropedns +maxudp512-5.tld 5 ns%u.%s S . x x -T maxudp=512 +maxudp1460-5.tld 5 ns%u.%s S . x x -T maxudp=1460 +400ms-1.tld 5 ns%u.%s S 400/400/400/400/400 2 x +plain-5.tld 5 ns%u.%s S . x x +tld 12 ns%u.%s S . 5 8 +. 12 ns%u.root-servers.nil%s S . x x diff --git a/bin/tests/cfg_test.c b/bin/tests/cfg_test.c new file mode 100644 index 0000000..a243a3e --- /dev/null +++ b/bin/tests/cfg_test.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +static void +check_result(isc_result_t result, const char *format, ...) { + va_list args; + + if (result == ISC_R_SUCCESS) { + return; + } + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, ": %s\n", isc_result_totext(result)); + exit(1); +} + +static void +output(void *closure, const char *text, int textlen) { + UNUSED(closure); + (void)fwrite(text, 1, textlen, stdout); +} + +static void +usage(void) { + fprintf(stderr, "usage: cfg_test --rndc|--named " + "[--grammar] [--zonegrammar] [--active] " + "[--memstats] conffile\n"); + exit(1); +} + +int +main(int argc, char **argv) { + isc_result_t result; + isc_mem_t *mctx = NULL; + isc_log_t *lctx = NULL; + isc_logconfig_t *lcfg = NULL; + isc_logdestination_t destination; + cfg_parser_t *pctx = NULL; + cfg_obj_t *cfg = NULL; + cfg_type_t *type = NULL; + bool grammar = false; + bool memstats = false; + char *filename = NULL; + unsigned int zonetype = 0; + unsigned int pflags = 0; + + isc_mem_create(&mctx); + + isc_log_create(mctx, &lctx, &lcfg); + isc_log_setcontext(lctx); + + /* + * Create and install the default channel. + */ + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, ISC_LOG_PRINTTIME); + + result = isc_log_usechannel(lcfg, "_default", NULL, NULL); + check_result(result, "isc_log_usechannel()"); + + /* + * Set the initial debug level. + */ + isc_log_setdebuglevel(lctx, 2); + + if (argc < 3) { + usage(); + } + + while (argc > 1) { + if (strcmp(argv[1], "--active") == 0) { + pflags |= CFG_PRINTER_ACTIVEONLY; + } else if (strcmp(argv[1], "--grammar") == 0) { + grammar = true; + } else if (strcmp(argv[1], "--zonegrammar") == 0) { + argv++, argc--; + if (argc <= 1) { + usage(); + } + if (strcmp(argv[1], "master") == 0 || + strcmp(argv[1], "primary") == 0) + { + zonetype = CFG_ZONE_PRIMARY; + } else if (strcmp(argv[1], "slave") == 0 || + strcmp(argv[1], "seconary") == 0) + { + zonetype = CFG_ZONE_SECONDARY; + } else if (strcmp(argv[1], "mirror") == 0) { + zonetype = CFG_ZONE_MIRROR; + } else if (strcmp(argv[1], "stub") == 0) { + zonetype = CFG_ZONE_STUB; + } else if (strcmp(argv[1], "static-stub") == 0) { + zonetype = CFG_ZONE_STATICSTUB; + } else if (strcmp(argv[1], "hint") == 0) { + zonetype = CFG_ZONE_HINT; + } else if (strcmp(argv[1], "forward") == 0) { + zonetype = CFG_ZONE_FORWARD; + } else if (strcmp(argv[1], "redirect") == 0) { + zonetype = CFG_ZONE_REDIRECT; + } else if (strcmp(argv[1], "delegation-only") == 0) { + zonetype = CFG_ZONE_DELEGATION; + } else if (strcmp(argv[1], "in-view") == 0) { + zonetype = CFG_ZONE_INVIEW; + } else { + usage(); + } + } else if (strcmp(argv[1], "--memstats") == 0) { + memstats = true; + } else if (strcmp(argv[1], "--named") == 0) { + type = &cfg_type_namedconf; + } else if (strcmp(argv[1], "--rndc") == 0) { + type = &cfg_type_rndcconf; + } else if (argv[1][0] == '-') { + usage(); + } else { + filename = argv[1]; + } + argv++, argc--; + } + + if (grammar) { + if (type == NULL) { + usage(); + } + cfg_print_grammar(type, pflags, output, NULL); + } else if (zonetype != 0) { + cfg_print_zonegrammar(zonetype, pflags, output, NULL); + } else { + if (type == NULL || filename == NULL) { + usage(); + } + RUNTIME_CHECK(cfg_parser_create(mctx, lctx, &pctx) == + ISC_R_SUCCESS); + + result = cfg_parse_file(pctx, filename, type, &cfg); + + fprintf(stderr, "read config: %s\n", isc_result_totext(result)); + + if (result != ISC_R_SUCCESS) { + exit(1); + } + + cfg_print(cfg, output, NULL); + + cfg_obj_destroy(pctx, &cfg); + + cfg_parser_destroy(&pctx); + } + + isc_log_destroy(&lctx); + if (memstats) { + isc_mem_stats(mctx, stderr); + } + isc_mem_destroy(&mctx); + + fflush(stdout); + if (ferror(stdout)) { + fprintf(stderr, "write error\n"); + return (1); + } else { + return (0); + } +} diff --git a/bin/tests/headerdep_test.sh.in b/bin/tests/headerdep_test.sh.in new file mode 100644 index 0000000..40503d2 --- /dev/null +++ b/bin/tests/headerdep_test.sh.in @@ -0,0 +1,51 @@ +#!/bin/sh + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +# +# Check the installed bind9 headers to make sure that no header +# depends on another header having been included first. +# + +prefix=@prefix@ +tmp=/tmp/thdr$$.tmp + +status=0 + +echo "Checking for header interdependencies..." + +# Make a list of header files. +(cd $prefix/include; find . -name '*.h' -print | sed 's!^./!!') > $tmp + +# Check each header. +while read h +do + echo " - <$h>" + + # Build a test program. + cat <test.c +#include <$h> +EOF + + # Compile the test program. + if + gcc @STD_CWARNINGS@ @STD_CINCLUDES@ -I$prefix/include -c test.c 2>&1 + then + : + else + status=1 + fi +done <$tmp + +rm -f test.c test.o $tmp + +exit $status diff --git a/bin/tests/makejournal.c b/bin/tests/makejournal.c new file mode 100644 index 0000000..2f602da --- /dev/null +++ b/bin/tests/makejournal.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define CHECK(r) \ + do { \ + result = (r); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +isc_mem_t *mctx = NULL; +isc_log_t *lctx = NULL; + +static bool dst_active = false; + +/* + * Logging categories: this needs to match the list in bin/named/log.c. + */ +static isc_logcategory_t categories[] = { { "", 0 }, + { "client", 0 }, + { "network", 0 }, + { "update", 0 }, + { "queries", 0 }, + { "unmatched", 0 }, + { "update-security", 0 }, + { "query-errors", 0 }, + { NULL, 0 } }; + +static isc_result_t +loadzone(dns_db_t **db, const char *origin, const char *filename) { + isc_result_t result; + dns_fixedname_t fixed; + dns_name_t *name; + + name = dns_fixedname_initname(&fixed); + + result = dns_name_fromstring(name, origin, 0, NULL); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, + dns_rdataclass_in, 0, NULL, db); + if (result != ISC_R_SUCCESS) { + return (result); + } + + result = dns_db_load(*db, filename, dns_masterformat_text, 0); + return (result); +} + +int +main(int argc, char **argv) { + isc_result_t result; + char *origin, *file1, *file2, *journal; + dns_db_t *olddb = NULL, *newdb = NULL; + isc_logdestination_t destination; + isc_logconfig_t *logconfig = NULL; + + if (argc != 5) { + printf("usage: %s origin file1 file2 journal\n", argv[0]); + return (1); + } + + origin = argv[1]; + file1 = argv[2]; + file2 = argv[3]; + journal = argv[4]; + + isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + isc_mem_create(&mctx); + + CHECK(dst_lib_init(mctx, NULL)); + dst_active = true; + + isc_log_create(mctx, &lctx, &logconfig); + isc_log_registercategories(lctx, categories); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, 0); + + CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL)); + + dns_result_register(); + + result = loadzone(&olddb, origin, file1); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "Couldn't load %s: ", file1); + goto cleanup; + } + + result = loadzone(&newdb, origin, file2); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "Couldn't load %s: ", file2); + goto cleanup; + } + + result = dns_db_diff(mctx, newdb, NULL, olddb, NULL, journal); + +cleanup: + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "%s\n", isc_result_totext(result)); + } + + if (newdb != NULL) { + dns_db_detach(&newdb); + } + if (olddb != NULL) { + dns_db_detach(&olddb); + } + + if (lctx != NULL) { + isc_log_destroy(&lctx); + } + if (dst_active) { + dst_lib_destroy(); + dst_active = false; + } + if (mctx != NULL) { + isc_mem_destroy(&mctx); + } + + return (result != ISC_R_SUCCESS ? 1 : 0); +} diff --git a/bin/tests/named.conf b/bin/tests/named.conf new file mode 100644 index 0000000..e251e71 --- /dev/null +++ b/bin/tests/named.conf @@ -0,0 +1,619 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * This is a worthless, nonrunnable example of a named.conf file that has + * every conceivable syntax element in use. We use it to test the parser. + * It could also be used as a conceptual template for users of new features. + */ + +/* + * C-style comments are OK + */ + +// So are C++-style comments + +# So are shell-style comments + +// watch out for ";" -- it's important! + +options { + additional-from-auth true; + additional-from-cache false; + + version "my version string"; + random-device "/dev/random"; + directory "/tmp"; + + port 666; + + sig-validity-interval 33; + +# Obsolete + named-xfer "/usr/libexec/named-xfer"; // _PATH_XFER + + dump-file "named_dump.db"; // _PATH_DUMPFILE + pid-file "/var/run/named.pid"; // _PATH_PIDFILE + statistics-file "named.stats"; // _PATH_STATS + memstatistics-file "named.memstats"; // _PATH_MEMSTATS + + max-cache-ttl 999; + min-cache-ttl 66; + auth-nxdomain yes; // always set AA on NXDOMAIN. + // don't set this to 'no' unless + // you know what you're doing -- older + // servers won't like it. + +# Obsolete + deallocate-on-exit no; + + dialup yes; + +# Obsolete + fake-iquery no; + + fetch-glue yes; + has-old-clients yes; + host-statistics no; + +# Obsolete + multiple-cnames no; // if yes, then a name my have more + // than one CNAME RR. This use + // is non-standard and is not + // recommended, but it is available + // because previous releases supported + // it and it was used by large sites + // for load balancing. + + notify yes; // send NOTIFY messages. You can set + // notify on a zone-by-zone + // basis in the "zone" statement + // see (below) + recursion yes; + rfc2308-type1 no; + +# Obsolete + use-id-pool yes; + +# Obsolete + treat-cr-as-space yes; + + also-notify { 10.0.2.3; }; + + // The "forward" option is only meaningful if you've defined + // forwarders. "first" gives the normal BIND + // forwarding behavior, i.e. ask the forwarders first, and if that + // doesn't work then do the full lookup. You can also say + // "forward only;" which is what used to be specified with + // "slave" or "options forward-only". "only" will never attempt + // a full lookup; only the forwarders will be used. + forward first; + forwarders { + 1.2.3.4; + 5.6.7.8; + }; + + check-names master fail; + check-names slave warn; + check-names response ignore; + + allow-query { any; }; + allow-transfer { any; }; + allow-recursion { !any; }; + blackhole { 45/24; }; + keep-response-order { 46/24; }; + + listen-on { + 10/24; + 10.0.0.3; + }; + + listen-on port 53 { any; }; + + listen-on { 5.6.7.8; }; + + listen-on port 1234 { + !1.2.3.4; + 1.2.3/24; + }; + + listen-on-v6 { + 1:1:1:1:1:1:1:1; + }; + + listen-on-v6 port 777 { + 2:2:2:2:2:2:2:2; + }; + + query-source-v6 address 8:7:6:5:4:3:2:1 port *; + query-source port * address 10.0.0.54 ; + + lame-ttl 444; + + max-transfer-time-in 300; + max-transfer-time-out 10; + max-transfer-idle-in 100; + max-transfer-idle-out 11; + + max-retry-time 1234; + min-retry-time 1111; + max-refresh-time 888; + min-refresh-time 777; + + max-ncache-ttl 333; + min-ncache-ttl 22; + min-roots 15; + serial-queries 34; + + transfer-format one-answer; + + transfers-in 10; + transfers-per-ns 2; + transfers-out 0; + + transfer-source 10.0.0.5; + transfer-source-v6 4:3:2:1:5:6:7:8; + + request-ixfr yes; + provide-ixfr yes; + +# Now called 'provide-ixfr' +# maintain-ixfr-base no; // If yes, keep transaction log file for IXFR + + max-ixfr-log-size 20m; + coresize 100; + datasize 101; + files 230; + max-cache-size 1m; + stacksize 231; + heartbeat-interval 1001; + interface-interval 1002; + statistics-interval 1003; + + topology { + 10/8; + + !1.2.3/24; + + { 1.2/16; 3/8; }; + + + }; + + sortlist { 10/8; 11/8; }; + + tkey-domain "foo.com"; + tkey-dhkey "xyz" 666 ; + + rrset-order { + class IN type A name "foo" order random; + order cyclic; + }; +}; + +/* + * Control listeners, for "ndc". Every nameserver needs at least one. + */ +controls { + // 'inet' lines without a 'port' defaults to 'port 953' + // 'keys' must be used and the list must have at least one entry + inet * port 52 allow { any; } keys { "key2"; }; + unix "/var/run/ndc" perm 0600 owner 0 group 0; // ignored by named. + inet 10.0.0.1 allow { any; key foo; } keys { "key4";}; + inet 10.0.0.2 allow { none; } keys { "key-1"; "key-2"; }; + inet 10.0.0.2 allow { none; }; +}; + +zone "master.demo.zone" { + type master; // what used to be called "primary" + database "somedb -option1 -option2 arg1 arg2 arg3"; + file "master.demo.zone"; + check-names fail; + allow-update { none; }; + allow-update-forwarding { 10.0.0.5; !any; }; + allow-transfer { any; }; + allow-query { any; }; + sig-validity-interval 990; + notify explicit; + also-notify { 1.0.0.1; }; // don't notify any nameservers other + // than those on the NS list for this + // zone + forward first; + forwarders { 10.0.0.3; 1:2:3:4:5:6:7:8; }; +}; + +zone "slave.demo.zone" { + type slave; // what used to be called "secondary" + file "slave.demo.zone"; + ixfr-base "slave.demo.zone.ixfr"; // File name for IXFR transaction log file + masters { + 1.2.3.4 port 10 key "foo"; // where to zone transfer from + 5.6.7.8; + 6.7.8.9 key "zippo"; + }; + transfer-source 10.0.0.53; // fixes multihoming problems + check-names warn; + allow-update { none; }; + allow-transfer { any; }; + allow-update-forwarding { any; }; + allow-query { any; }; + max-transfer-time-in 120; // if not set, global option is used. + max-transfer-time-out 1; // if not set, global option is used. + max-transfer-idle-in 2; // if not set, global option is used. + max-transfer-idle-out 3; // if not set, global option is used. + also-notify { 1.0.0.2; }; + forward only; + forwarders { 10.45.45.45; 10.0.0.3; 1:2:3:4:5:6:7:8; }; +}; + +key "non-viewkey" { secret "YWFh" ; algorithm "zzz" ; }; + +view "test-view" in { + key "viewkey" { algorithm "xxx" ; secret "eXl5" ; }; + also-notify { 10.2.2.3; }; + managed-keys { + foo.com. static 4 3 2 "abdefghijklmnopqrstuvwxyz"; + }; + sig-validity-interval 45; + max-cache-size 100000; + allow-query { 10.0.0.30;}; + additional-from-cache false; + additional-from-auth no; + match-clients { 10.0.0.1 ; }; + check-names master warn; + check-names slave ignore; + check-names response fail; + auth-nxdomain false; + recursion true; + provide-ixfr false; + request-ixfr true; + fetch-glue true; + notify false; + rfc2308-type1 false; + transfer-source 10.0.0.55; + transfer-source-v6 4:3:8:1:5:6:7:8; + query-source port * address 10.0.0.54 ; + query-source-v6 address 6:6:6:6:6:6:6:6 port *; + max-transfer-time-out 45; + max-transfer-idle-out 55; + min-roots 3; + lame-ttl 477; + max-ncache-ttl 333; + max-cache-ttl 777; + transfer-format many-answers; + max-retry-time 7; + min-retry-time 4; + max-refresh-time 999; + min-refresh-time 111; + + zone "view-zone.com" { + type master; + allow-update-forwarding { 10.0.0.34;}; + file "view-zone-master"; + }; + + server 5.6.7.8 { + keys "viewkey"; + }; + + server 10.9.8.7 { + keys "non-viewkey"; + }; + dialup yes; +}; + + +zone "stub.demo.zone" { + type stub; // stub zones are like slave zones, + // except that only the NS records + // are transferred. + dialup yes; + file "stub.demo.zone"; + masters { + 1.2.3.4 ; // where to zone transfer from + 5.6.7.8 port 999; + }; + check-names warn; + allow-update { none; }; + allow-transfer { any; }; + allow-query { any; }; + + max-retry-time 10; + min-retry-time 11; + max-refresh-time 12; + min-refresh-time 13; + + max-transfer-time-in 120; // if not set, global option is used. + pubkey 257 255 1 "a useless key"; + pubkey 257 255 1 "another useless key"; +}; + +zone "." { + type hint; // used to be specified w/ "cache" + file "cache.db"; +// pubkey 257 255 1 "AQP2fHpZ4VMpKo/jc9Fod821uyfY5p8j5h/Am0V/KpBTMZjdXmp9QJe6yFRoIIzkaNCgTIftASdpXGgCwFB2j2KXP/rick6gvEer5VcDEkLR5Q=="; +}; + +managed-keys { + "." static 257 255 1 "AQP2fHpZ4VMpKo/jc9Fod821uyfY5p8j5h/Am0V/KpBTMZjdXmp9QJe6yFRoIIzkaNCgTIftASdpXGgCwFB2j2KXP/rick6gvEer5VcDEkLR5Q=="; +}; + + +acl can_query { !1.2.3/24; any; }; // network 1.2.3.0 mask 255.255.255.0 + // is disallowed; rest are OK +acl can_axfr { 1.2.3.4; can_query; }; // host 1.2.3.4 and any host allowed + // by can_query are OK + +zone "disabled-zone.com" { + type master; + file "bar"; + + max-retry-time 100; + min-retry-time 110; + max-refresh-time 120; + min-refresh-time 130; +}; + +zone "non-default-acl.demo.zone" { + type master; + file "foo"; + allow-query { can_query; }; + allow-transfer { can_axfr; }; + allow-update { + 1.2.3.4; + 5.6.7.8; + }; + pubkey 666 665 664 "key of the beast"; + // Errors trapped by parser: + // identity or name not absolute + // 'wildcard' match type and no wildcard character in name + // + // issues: + // - certain rdatatype values (such as "key") are config file keywords and + // must be quoted or a syntax error will occur. + // + + update-policy { + grant root.domain. subdomain host.domain. A MX CNAME; + grant sub.root.domain. wildcard *.host.domain. A; + grant root.domain. name host.domain. a ns md mf cname soa mb mg + mr "null" wks ptr hinfo minfo mx txt rp afsdb x25 + isdn rt nsap sig "key" px gpos aaaa loc nxt srv naptr kx + cert a6 dname opt unspec uri tkey tsig ; + grant foo.bar.com. self foo.bar.com. a; + }; +}; + +key sample_key { // for TSIG; supported by parser + algorithm hmac-md5; // but not yet implemented in the + secret "eW91ciBzZWNyZXQgaGVyZQ=="; // rest of the server +}; + +key key2 { + algorithm hmac-md5; + secret "ZXJlaCB0ZXJjZXMgcm91eQ=="; +}; + +acl key_acl { key sample_key; }; // a request signed with sample_key + +server 1.2.3.4 { + request-ixfr no; + provide-ixfr no; + bogus no; // if yes, we won't query or listen + // to this server + transfer-format one-answer; // set transfer format for this + // server (see the description of + // 'transfer-format' above) + // if not specified, the global option + // will be used + transfers 0; // not implemented + keys { "sample_key" }; // for TSIG; supported by the parser + // but not yet implemented in the + // rest of the server +# Now called 'request-ixfr' +# support-ixfr yes; // for IXFR supported by server + // if yes, the listed server talks IXFR +}; + +logging { + /* + * All log output goes to one or more "channels"; you can make as + * many of them as you want. + */ + + channel syslog_errors { // this channel will send errors or + syslog user; // or worse to syslog (user facility) + severity error; + }; + + channel stderr_errors { + stderr; + }; + + /* + * Channels have a severity level. Messages at severity levels + * greater than or equal to the channel's level will be logged on + * the channel. In order of decreasing severity, the levels are: + * + * critical a fatal error + * error + * warning + * notice a normal, but significant event + * info an informational message + * debug 1 the least detailed debugging info + * ... + * debug 99 the most detailed debugging info + */ + + /* + * Here are the built-in channels: + * + * channel default_syslog { + * syslog daemon; + * severity info; + * }; + * + * channel default_debug { + * file "named.run"; // note: stderr is used instead + * // of "named.run" if the server + * // is started with the "-f" + * // option. + * severity dynamic; // this means log debugging + * // at whatever debugging level + * // the server is at, and don't + * // log anything if not + * // debugging. + * }; + * + * channel null { // this is the bit bucket; + * file "/dev/null"; // any logging to this channel + * // is discarded. + * }; + * + * channel default_stderr { // writes to stderr + * file ""; // this is illustrative only; + * // there's currently no way + * // of saying "stderr" in the + * // configuration language. + * // i.e. don't try this at home. + * severity info; + * }; + * + * default_stderr only works before the server daemonizes (i.e. + * during initial startup) or when it is running in foreground + * mode (-f command line option). + */ + + /* + * There are many categories, so you can send the logs + * you want to see wherever you want, without seeing logs you + * don't want. Right now the categories are + * + * default the catch-all. many things still + * aren't classified into categories, and + * they all end up here. also, if you + * don't specify any channels for a + * category, the default category is used + * instead. + * config high-level configuration file + * processing + * parser low-level configuration file processing + * queries what used to be called "query logging" + * lame-servers messages like "Lame server on ..." + * statistics + * panic if the server has to shut itself + * down due to an internal problem, it + * logs the problem here (as well as + * in the problem's native category) + * update dynamic update + * ncache negative caching + * xfer-in zone transfers we're receiving + * xfer-out zone transfers we're sending + * db all database operations + * eventlib debugging info from the event system + * (see below) + * packet dumps of packets received and sent + * (see below) + * notify the NOTIFY protocol + * cname messages like "XX points to a CNAME" + * security approved/unapproved requests + * os operating system problems + * insist consistency check failures + * maintenance periodic maintenance + * load zone loading + * response-checks messages like + * "Malformed response ..." + * "wrong ans. name ..." + * "unrelated additional info ..." + * "invalid RR type ..." + * "bad referral ..." + */ + + category parser { + syslog_errors; // you can log to as many channels + default_syslog; // as you want + }; + + category lame-servers { null; }; // don't log these at all + + channel moderate_debug { + file "foo"; // foo + severity debug 3; // level 3 debugging to file + print-time yes; // timestamp log entries + print-category yes; // print category name + print-severity yes; // print severity level + /* + * Note that debugging must have been turned on either + * on the command line or with a signal to get debugging + * output (non-debugging output will still be written to + * this channel). + */ + }; + + channel another { + file "bar" versions 99 size 10M; + severity info; + }; + + channel third { + file "bar" size 100000 versions unlimited; + severity debug; // use default debug level + }; + + /* + * If you don't want to see "zone XXXX loaded" messages but do + * want to see any problems, you could do the following. + */ + channel no_info_messages { + syslog; + severity notice; + }; + + category load { no_info_messages; }; + + /* + * You can also define category "default"; it gets used when no + * "category" statement has been given for a category. + */ + category default { + default_syslog; + moderate_debug; + }; + + /* + * If you don't define category default yourself, the default + * default category will be used. It is + * + * category default { default_syslog; default_debug; }; + */ + + /* + * If you don't define category panic yourself, the default + * panic category will be used. It is + * + * category panic { default_syslog; default_stderr; }; + */ + + /* + * Two categories, 'packet' and 'eventlib', are special. Only one + * channel may be assigned to each of them, and it must be a + * file channel. If you don't define them yourself, they default to + * + * category eventlib { default_debug; }; + * + * category packet { default_debug; }; + */ +}; + +#include "filename"; // can't do within a statement + diff --git a/bin/tests/optional/Kchild.example.+005+33180.key b/bin/tests/optional/Kchild.example.+005+33180.key new file mode 100644 index 0000000..ab92a6a --- /dev/null +++ b/bin/tests/optional/Kchild.example.+005+33180.key @@ -0,0 +1,5 @@ +; This is a zone-signing key, keyid 33180, for child.example. +; Created: 20181025104746 (Thu Oct 25 12:47:46 2018) +; Publish: 20181025104746 (Thu Oct 25 12:47:46 2018) +; Activate: 20181025104746 (Thu Oct 25 12:47:46 2018) +child.example. IN DNSKEY 256 3 5 AwEAAb9eatC8ASzDnRApcZuxyBrvJRANRQjCXQ1FWK+8vEyXV5NIE9Km hKIV2wbq2tLBPfjNQz4BTJ9RmDINf1RayDlt6L+IQV1JCaDaMjd1zU3n SQK18Y7fMu0ww4AMKOnoVRbkIxa3zlA0chImXcfPE0q2AvKBYLzPfkPO cfplAuRkLcGUxdADCipNzCOakpcd5gfm9Sa2HlaXcw3gyI1WcE8= diff --git a/bin/tests/optional/Kchild.example.+005+33180.private b/bin/tests/optional/Kchild.example.+005+33180.private new file mode 100644 index 0000000..83a50df --- /dev/null +++ b/bin/tests/optional/Kchild.example.+005+33180.private @@ -0,0 +1,13 @@ +Private-key-format: v1.3 +Algorithm: 5 (RSASHA1) +Modulus: v15q0LwBLMOdEClxm7HIGu8lEA1FCMJdDUVYr7y8TJdXk0gT0qaEohXbBura0sE9+M1DPgFMn1GYMg1/VFrIOW3ov4hBXUkJoNoyN3XNTedJArXxjt8y7TDDgAwo6ehVFuQjFrfOUDRyEiZdx88TSrYC8oFgvM9+Q85x+mUC5GQtwZTF0AMKKk3MI5qSlx3mB+b1JrYeVpdzDeDIjVZwTw== +PublicExponent: AQAB +PrivateExponent: WDsn9GU6BXGLENCK2MX3BLQN2oDDu24hiOTYJu5VwtpkPjuVKCIuNKzu9xmBGnqOIBBDWGsw8KOmEC247yOL/S53iRdBS8lI7yiqznc52RhlmrdPKXbNpVnPwil8wocw+oQYa7uvdPYxI2Yy3B/tRgUxlxSlc/LW/dr0BX2L7qr/aeOBeGSRUlCpc7tYU9a2RUaLpVxF6SlqicCpC91MAQ== +Prime1: 466f+JL66Bl4qYnkj0s9+1N3pYmdcM9Ja1AN66X4VLslA9Cm1JEaC5V9HOptfcXUk0XYEVnKeKM2lIQnvcLG0yuQHIa+pGi7P8vgQfdaRUE= +Prime2: 1yuUkTVRSbUWeUreEcHgeeBBJ61UshX7t07gnGgIr3artGdo2CVEb5//+2Mvj5bgjCQBvjBbmHNZrR0jKDRBTIGtqbBerOuhEN4AXdAEgY8= +Exponent1: KzUXbJ/P973ltR7S/hKEV66WVRbRhvf/cdsGWULs5n+BXcD59/r1W19qF9OxJZ4mYjBt+ZT1pIEsuXB+7jcJbkelGJTFlwO9DTVOgJZFTkE= +Exponent2: FTPsLertGbBIiKdB/sn2Dsx0Xy6LXAkihsu1AnSV9oRhIyPVhwcVGVLQ7Lq3YxThB648pbsqK3miapamcj3D+YAF1uTUT4Hgm0LlEll/OC0= +Coefficient: Vulw9kmmjKc+wmOukLdzheoA2hNPDVtgiynfzHybyXdqvapCoK+ZVmNFzjO0M41ATcpvya3iX0bekMQqYnBhLURNZUIyqz2nGskOjV8I5Jg= +Created: 20181025104746 +Publish: 20181025104746 +Activate: 20181025104746 diff --git a/bin/tests/optional/Makefile.in b/bin/tests/optional/Makefile.in new file mode 100644 index 0000000..29e026f --- /dev/null +++ b/bin/tests/optional/Makefile.in @@ -0,0 +1,254 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \ + ${OPENSSL_CFLAGS} @DST_GSSAPI_INC@ + +CDEFINES = @USE_GSSAPI@ + +CWARNINGS = +BACKTRACECFLAGS = @BACKTRACECFLAGS@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ + +DNSLIBS = ../../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +ISCLIBS = ../../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCCFGLIBS = ../../../lib/isccfg/libisccfg.@A@ + +DNSDEPLIBS = ../../../lib/dns/libdns.@A@ +ISCDEPLIBS = ../../../lib/isc/libisc.@A@ +ISCDEPNOSYMLIBS = ../../../lib/isc/libisc-nosymtbl.@A@ +ISCCFGDEPLIBS = ../../../lib/isccfg/libisccfg.@A@ + +LIBS = @LIBS@ + +SUBDIRS = + +# These programs are not built by default, but only when +# configured with --enable-developer or built explicitly with +# "make all_tests" + +TARGETS = @XTARGETS@ +XTARGETS = adb_test@EXEEXT@ \ + byaddr_test@EXEEXT@ \ + backtrace_test@EXEEXT@ \ + backtrace_test_nosymtbl@EXEEXT@ \ + byname_test@EXEEXT@ \ + db_test@EXEEXT@ \ + gsstest@EXEEXT@ \ + fsaccess_test@EXEEXT@ \ + inter_test@EXEEXT@ \ + lex_test@EXEEXT@ \ + lfsr_test@EXEEXT@ \ + log_test@EXEEXT@ \ + master_test@EXEEXT@ \ + mempool_test@EXEEXT@ \ + name_test@EXEEXT@ \ + nsecify@EXEEXT@ \ + ratelimiter_test@EXEEXT@ \ + rbt_test@EXEEXT@ \ + rwlock_test@EXEEXT@ \ + serial_test@EXEEXT@ \ + shutdown_test@EXEEXT@ \ + sig0_test@EXEEXT@ \ + sock_test@EXEEXT@ \ + sym_test@EXEEXT@ \ + task_test@EXEEXT@ \ + timer_test@EXEEXT@ \ + zone_test@EXEEXT@ + +SRCS = ${XSRCS} +XSRCS = adb_test.c \ + byaddr_test.c \ + backtrace_test.c \ + byname_test.c \ + db_test.c \ + fsaccess_test.c \ + gsstest.c \ + inter_test.c \ + lex_test.c \ + lfsr_test.c \ + log_test.c \ + master_test.c \ + mempool_test.c \ + name_test.c \ + nsecify.c \ + ratelimiter_test.c \ + rbt_test.c \ + rwlock_test.c \ + serial_test.c \ + shutdown_test.c \ + sig0_test.c \ + sock_test.c \ + sym_test.c \ + task_test.c \ + timer_test.c \ + zone_test.c + +@BIND9_MAKE_RULES@ + +# disable optimization for backtrace test to get the expected result +BTTEST_CFLAGS = ${BACKTRACECFLAGS} ${EXT_CFLAGS} ${ALL_CPPFLAGS} -g \ + ${ALWAYS_WARNINGS} ${STD_CWARNINGS} ${CWARNINGS} ${PTHREAD_CFLAGS} + +all_tests: ${XTARGETS} + +adb_test@EXEEXT@: adb_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ adb_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +backtrace_test_nosymtbl@EXEEXT@: ${srcdir}/backtrace_test.c ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} -o $@ \ + ${srcdir}/backtrace_test.c ${ISCLIBS} ${LIBS} + +backtrace_test@EXEEXT@: ${srcdir}/backtrace_test.c backtrace_test_nosymtbl@EXEEXT@ + #first step: create a first symbol table + rm -f symtbl.c + if test X${MKSYMTBL_PROGRAM} != X; then \ + ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \ + backtrace_test_nosymtbl@EXEEXT@; else \ + cp ${top_srcdir}/lib/isc/backtrace-emptytbl.c symtbl.c; fi + #second step: build a binary with the first symbol table + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} \ + -o $@0 ${srcdir}/backtrace_test.c symtbl.c \ + ${ISCNOSYMLIBS} ${LIBS} + rm -f symtbl.c + #third step: create a second symbol table + if test X${MKSYMTBL_PROGRAM} != X; then \ + ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl $@0; else \ + cp ${top_srcdir}/lib/isc/backtrace-emptytbl.c symtbl.c; fi + #fourth step: build the final binary + rm -f $@0 + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} \ + -o $@ ${srcdir}/backtrace_test.c symtbl.c ${ISCNOSYMLIBS} ${LIBS} + rm -f symtbl.c + +nsecify@EXEEXT@: nsecify.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ nsecify.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +byaddr_test@EXEEXT@: byaddr_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byaddr_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +byname_test@EXEEXT@: byname_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byname_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +lex_test@EXEEXT@: lex_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lex_test.@O@ \ + ${ISCLIBS} ${LIBS} + +lfsr_test@EXEEXT@: lfsr_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lfsr_test.@O@ \ + ${ISCLIBS} ${LIBS} + +log_test@EXEEXT@: log_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ log_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +name_test@EXEEXT@: name_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ name_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +entropy_test@EXEEXT@: entropy_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy_test.@O@ \ + ${ISCLIBS} ${LIBS} + +entropy2_test@EXEEXT@: entropy2_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy2_test.@O@ \ + ${ISCLIBS} ${LIBS} + +sock_test@EXEEXT@: sock_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sock_test.@O@ \ + ${ISCLIBS} ${LIBS} + +sym_test@EXEEXT@: sym_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sym_test.@O@ \ + ${ISCLIBS} ${LIBS} + +task_test@EXEEXT@: task_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ task_test.@O@ \ + ${ISCLIBS} ${LIBS} + +shutdown_test@EXEEXT@: shutdown_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ shutdown_test.@O@ \ + ${ISCLIBS} ${LIBS} + +timer_test@EXEEXT@: timer_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ timer_test.@O@ \ + ${ISCLIBS} ${LIBS} + +ratelimiter_test@EXEEXT@: ratelimiter_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ratelimiter_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +rbt_test@EXEEXT@: rbt_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rbt_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +rwlock_test@EXEEXT@: rwlock_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rwlock_test.@O@ \ + ${ISCLIBS} ${LIBS} + +master_test@EXEEXT@: master_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ master_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +db_test@EXEEXT@: db_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ db_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +mempool_test@EXEEXT@: mempool_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ mempool_test.@O@ \ + ${ISCLIBS} ${LIBS} + +serial_test@EXEEXT@: serial_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ serial_test.@O@ \ + ${ISCLIBS} ${LIBS} + +zone_test@EXEEXT@: zone_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zone_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +fsaccess_test@EXEEXT@: fsaccess_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ fsaccess_test.@O@ \ + ${ISCLIBS} ${LIBS} + +inter_test@EXEEXT@: inter_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ inter_test.@O@ \ + ${ISCLIBS} ${LIBS} + +sig0_test@EXEEXT@: sig0_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sig0_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +gsstest@EXEEXT@: gsstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} \ + -o $@ gsstest.@O@ ${DNSLIBS} ${ISCLIBS} ${LIBS} + +clean distclean:: + rm -f ${TARGETS} ${XTARGETS} + rm -f backtrace_test_symtbl.c + +check: test + +test: + @for dir in $(TESTDIRS) ;\ + do \ + ( cd $$dir; $(MAKE) test ) ;\ + done diff --git a/bin/tests/optional/adb_test.c b/bin/tests/optional/adb_test.c new file mode 100644 index 0000000..7e9e4ca --- /dev/null +++ b/bin/tests/optional/adb_test.c @@ -0,0 +1,410 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef struct client client_t; +struct client { + dns_name_t name; + const char *target; + ISC_LINK(client_t) link; + dns_adbfind_t *find; +}; + +static isc_mem_t *mctx = NULL; +static isc_mempool_t *cmp = NULL; +static isc_log_t *lctx = NULL; +static isc_logconfig_t *lcfg = NULL; +static isc_nm_t *netmgr = NULL; +static isc_taskmgr_t *taskmgr = NULL; +static isc_socketmgr_t *socketmgr = NULL; +static isc_timermgr_t *timermgr = NULL; +static dns_dispatchmgr_t *dispatchmgr = NULL; +static isc_task_t *t1 = NULL, *t2 = NULL; +static dns_view_t *view = NULL; +static dns_db_t *rootdb = NULL; +static ISC_LIST(client_t) clients; +static isc_mutex_t client_lock; +static isc_stdtime_t now; +static dns_adb_t *adb = NULL; + +static void +check_result(isc_result_t result, const char *format, ...) + ISC_FORMAT_PRINTF(2, 3); + +static void +check_result(isc_result_t result, const char *format, ...) { + va_list args; + + if (result == ISC_R_SUCCESS) { + return; + } + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, ": %s\n", isc_result_totext(result)); + exit(1); +} + +static client_t * +new_client(void) { + client_t *client; + + client = isc_mempool_get(cmp); + INSIST(client != NULL); + dns_name_init(&client->name, NULL); + ISC_LINK_INIT(client, link); + client->find = NULL; + + return (client); +} + +static void +free_client(client_t **c) { + client_t *client; + + INSIST(c != NULL); + client = *c; + *c = NULL; + INSIST(client != NULL); + dns_name_free(&client->name, mctx); + INSIST(!ISC_LINK_LINKED(client, link)); + INSIST(client->find == NULL); + + isc_mempool_put(cmp, client); +} + +static void +CLOCK(void) { + RUNTIME_CHECK(isc_mutex_lock(&client_lock) == ISC_R_SUCCESS); +} + +static void +CUNLOCK(void) { + RUNTIME_CHECK(isc_mutex_unlock(&client_lock) == ISC_R_SUCCESS); +} + +static void +lookup_callback(isc_task_t *task, isc_event_t *ev) { + client_t *client; + + client = ev->ev_arg; + INSIST(client->find == ev->ev_sender); + + printf("NAME %s:\n\tTask %p got event %p type %08x from %p, client " + "%p\n\terr4: %s err6: %s\n", + client->target, task, ev, ev->ev_type, client->find, client, + isc_result_totext(client->find->result_v4), + isc_result_totext(client->find->result_v6)); + + isc_event_free(&ev); + ev = NULL; + + CLOCK(); + + dns_adb_dumpfind(client->find, stderr); + dns_adb_destroyfind(&client->find); + + ISC_LIST_UNLINK(clients, client, link); + free_client(&client); + + CUNLOCK(); +} + +static void +create_managers(void) { + isc_result_t result; + + result = isc_managers_create(mctx, 5, 0, &netmgr, &taskmgr); + check_result(result, "isc_managers_create"); + + result = isc_timermgr_create(mctx, &timermgr); + check_result(result, "isc_timermgr_create"); + + result = isc_socketmgr_create(mctx, &socketmgr); + check_result(result, "isc_socketmgr_create"); + + result = dns_dispatchmgr_create(mctx, &dispatchmgr); + check_result(result, "dns_dispatchmgr_create"); +} + +static void +create_view(void) { + dns_cache_t *cache = NULL; + isc_result_t result; + + /* + * View. + */ + result = dns_view_create(mctx, dns_rdataclass_in, "_default", &view); + check_result(result, "dns_view_create"); + + /* + * Cache. + */ + result = dns_cache_create(mctx, mctx, taskmgr, timermgr, + dns_rdataclass_in, "", "rbt", 0, NULL, + &cache); + check_result(result, "dns_cache_create"); + dns_view_setcache(view, cache, false); + dns_cache_detach(&cache); + + { + unsigned int attrs; + isc_sockaddr_t any4, any6; + dns_dispatch_t *disp4 = NULL; + dns_dispatch_t *disp6 = NULL; + + isc_sockaddr_any(&any4); + isc_sockaddr_any6(&any6); + + attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any4, 512, 6, 1024, + 17, 19, attrs, attrs, + &disp4) == ISC_R_SUCCESS); + INSIST(disp4 != NULL); + + attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any6, 512, 6, 1024, + 17, 19, attrs, attrs, + &disp6) == ISC_R_SUCCESS); + INSIST(disp6 != NULL); + + RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1, + socketmgr, timermgr, 0, + dispatchmgr, disp4, + disp6) == ISC_R_SUCCESS); + } + + rootdb = NULL; + result = dns_rootns_create(mctx, dns_rdataclass_in, NULL, &rootdb); + check_result(result, "dns_rootns_create()"); + dns_view_sethints(view, rootdb); + dns_db_detach(&rootdb); + + dns_view_freeze(view); +} + +static void +lookup(const char *target) { + dns_name_t name; + unsigned char namedata[256]; + client_t *client; + isc_buffer_t t, namebuf; + isc_result_t result; + unsigned int options; + + INSIST(target != NULL); + + client = new_client(); + isc_buffer_constinit(&t, target, strlen(target)); + isc_buffer_add(&t, strlen(target)); + isc_buffer_init(&namebuf, namedata, sizeof(namedata)); + dns_name_init(&name, NULL); + result = dns_name_fromtext(&name, &t, dns_rootname, 0, &namebuf); + check_result(result, "dns_name_fromtext %s", target); + + dns_name_dup(&name, mctx, &client->name); + + options = 0; + options |= DNS_ADBFIND_INET; + options |= DNS_ADBFIND_INET6; + options |= DNS_ADBFIND_WANTEVENT; + options |= DNS_ADBFIND_HINTOK; + options |= DNS_ADBFIND_GLUEOK; + result = dns_adb_createfind( + adb, t2, lookup_callback, client, &client->name, dns_rootname, + 0, options, now, NULL, view->dstport, 0, NULL, &client->find); + if (result != ISC_R_SUCCESS) { + printf("DNS_ADB_CREATEFIND -> %s\n", dns_result_totext(result)); + } + dns_adb_dumpfind(client->find, stderr); + + if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) { + client->target = target; + ISC_LIST_APPEND(clients, client, link); + } else { + printf("NAME %s: err4 %s, err6 %s\n", target, + isc_result_totext(client->find->result_v4), + isc_result_totext(client->find->result_v6)); + + dns_adb_destroyfind(&client->find); + free_client(&client); + } +} + +int +main(int argc, char **argv) { + isc_result_t result; + isc_logdestination_t destination; + + UNUSED(argc); + UNUSED(argv); + + dns_result_register(); + result = isc_app_start(); + check_result(result, "isc_app_start()"); + + isc_stdtime_get(&now); + + isc_mutex_init(&client_lock); + + ISC_LIST_INIT(clients); + + /* + * EVERYTHING needs a memory context. + */ + isc_mem_create(&mctx); + + cmp = NULL; + isc_mempool_create(mctx, sizeof(client_t), &cmp); + isc_mempool_setname(cmp, "adb test clients"); + + isc_log_create(mctx, &lctx, &lcfg); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + /* + * Create and install the default channel. + */ + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, ISC_LOG_PRINTTIME); + + result = isc_log_usechannel(lcfg, "_default", NULL, NULL); + check_result(result, "isc_log_usechannel()"); + + /* + * Set the initial debug level. + */ + isc_log_setdebuglevel(lctx, 2); + + create_managers(); + + result = isc_task_create(taskmgr, 0, &t1); + check_result(result, "isc_task_create t1"); + result = isc_task_create(taskmgr, 0, &t2); + check_result(result, "isc_task_create t2"); + + printf("task 1 = %p\n", t1); + printf("task 2 = %p\n", t2); + + create_view(); + RUNTIME_CHECK(view != NULL); + + adb = view->adb; + + /* + * Lock the entire client list here. This will cause all events + * for found names to block as well. + */ + CLOCK(); + lookup("f.root-servers.net."); /* Should be in hints */ + lookup("www.iengines.com"); /* should fetch */ + lookup("www.isc.org"); /* should fetch */ + lookup("www.flame.org"); /* should fetch */ + lookup("kechara.flame.org."); /* should fetch */ + lookup("moghedien.flame.org."); /* should fetch */ + lookup("mailrelay.flame.org."); /* should fetch */ + lookup("ipv4v6.flame.org."); /* should fetch */ + lookup("nonexistent.flame.org."); /* should fail to be found */ + lookup("foobar.badns.flame.org."); /* should fail utterly (NS) */ + lookup("i.root-servers.net."); /* Should be in hints */ + lookup("www.firstcard.com."); + lookup("dns04.flame.org."); + CUNLOCK(); + + sleep(10); + + dns_adb_dump(adb, stderr); + + sleep(10); + + CLOCK(); + lookup("f.root-servers.net."); /* Should be in hints */ + lookup("www.iengines.com"); /* should fetch */ + lookup("www.isc.org"); /* should fetch */ + lookup("www.flame.org"); /* should fetch */ + lookup("kechara.flame.org."); /* should fetch */ + lookup("moghedien.flame.org."); /* should fetch */ + lookup("mailrelay.flame.org."); /* should fetch */ + lookup("ipv4v6.flame.org."); /* should fetch */ + lookup("nonexistent.flame.org."); /* should fail to be found */ + lookup("foobar.badns.flame.org."); /* should fail utterly (NS) */ + lookup("i.root-servers.net."); /* Should be in hints */ + CUNLOCK(); + + sleep(20); + + dns_adb_dump(adb, stderr); + + isc_task_detach(&t1); + isc_task_detach(&t2); + + isc_mem_stats(mctx, stdout); + dns_adb_dump(adb, stderr); + + isc_app_run(); + + dns_adb_dump(adb, stderr); + + dns_view_detach(&view); + adb = NULL; + + fprintf(stderr, "Destroying socket manager\n"); + isc_socketmgr_destroy(&socketmgr); + fprintf(stderr, "Destroying timer manager\n"); + isc_timermgr_destroy(&timermgr); + + fprintf(stderr, "Destroying task and network managers\n"); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_log_destroy(&lctx); + + isc_mempool_destroy(&cmp); + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/backtrace_test.c b/bin/tests/optional/backtrace_test.c new file mode 100644 index 0000000..2aa7979 --- /dev/null +++ b/bin/tests/optional/backtrace_test.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include + +const char *expected_symbols[] = { "func3", "func2", "func1", "main" }; + +static int +func3() { + void *tracebuf[16]; + int i, nframes; + int error = 0; + const char *fname; + isc_result_t result; + unsigned long offset; + + result = isc_backtrace_gettrace(tracebuf, 16, &nframes); + if (result != ISC_R_SUCCESS) { + printf("isc_backtrace_gettrace failed: %s\n", + isc_result_totext(result)); + return (1); + } + + if (nframes < 4) { + error++; + } + + for (i = 0; i < 4 && i < nframes; i++) { + fname = NULL; + result = isc_backtrace_getsymbol(tracebuf[i], &fname, &offset); + if (result != ISC_R_SUCCESS) { + error++; + continue; + } + if (strcmp(fname, expected_symbols[i]) != 0) { + error++; + } + } + + if (error) { + printf("Unexpected result:\n"); + printf(" # of frames: %d (expected: at least 4)\n", nframes); + printf(" symbols:\n"); + for (i = 0; i < nframes; i++) { + fname = NULL; + result = isc_backtrace_getsymbol(tracebuf[i], &fname, + &offset); + if (result == ISC_R_SUCCESS) { + printf(" [%d] %s\n", i, fname); + } else { + printf(" [%d] %p getsymbol failed: %s\n", i, + tracebuf[i], isc_result_totext(result)); + } + } + } + + return (error); +} + +static int +func2() { + return (func3()); +} + +static int +func1() { + return (func2()); +} + +int +main() { + return (func1()); +} diff --git a/bin/tests/optional/byaddr_test.c b/bin/tests/optional/byaddr_test.c new file mode 100644 index 0000000..7e24cfe --- /dev/null +++ b/bin/tests/optional/byaddr_test.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static void +done(isc_task_t *task, isc_event_t *event) { + dns_byaddrevent_t *bevent; + dns_byaddr_t *byaddr; + dns_name_t *name; + + REQUIRE(event->ev_type == DNS_EVENT_BYADDRDONE); + bevent = (dns_byaddrevent_t *)event; + + UNUSED(task); + + printf("byaddr event result = %s\n", isc_result_totext(bevent->result)); + + if (bevent->result == ISC_R_SUCCESS) { + for (name = ISC_LIST_HEAD(bevent->names); name != NULL; + name = ISC_LIST_NEXT(name, link)) + { + char text[DNS_NAME_FORMATSIZE]; + dns_name_format(name, text, sizeof(text)); + printf("%s\n", text); + } + } + + byaddr = event->ev_sender; + dns_byaddr_destroy(&byaddr); + isc_event_free(&event); + + isc_app_shutdown(); +} + +int +main(int argc, char *argv[]) { + isc_mem_t *mctx = NULL; + bool verbose = false; + unsigned int workers = 2; + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_task_t *task = NULL; + isc_timermgr_t *timermgr = NULL; + dns_view_t *view = NULL; + int ch; + isc_socketmgr_t *socketmgr = NULL; + dns_dispatchmgr_t *dispatchmgr = NULL; + isc_netaddr_t na; + dns_byaddr_t *byaddr = NULL; + isc_result_t result; + unsigned int options = 0; + dns_cache_t *cache; + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + + dns_result_register(); + + isc_mem_create(&mctx); + + while ((ch = isc_commandline_parse(argc, argv, "nvw:")) != -1) { + switch (ch) { + case 'n': + /* + * We only try nibbles, so do nothing for this option. + */ + break; + case 'v': + verbose = true; + break; + case 'w': + workers = (unsigned int)atoi(isc_commandline_argument); + break; + } + } + + if (verbose) { + printf("%u workers\n", workers); + printf("IPv4: %s\n", isc_result_totext(isc_net_probeipv4())); + printf("IPv6: %s\n", isc_result_totext(isc_net_probeipv6())); + } + + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS); + isc_task_setname(task, "byaddr", NULL); + + RUNTIME_CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr) == + ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(dns_cache_create(mctx, mctx, taskmgr, timermgr, + dns_rdataclass_in, "", "rbt", 0, NULL, + &cache) == ISC_R_SUCCESS); + + RUNTIME_CHECK(dns_view_create(mctx, dns_rdataclass_in, "default", + &view) == ISC_R_SUCCESS); + + { + unsigned int attrs; + dns_dispatch_t *disp4 = NULL; + dns_dispatch_t *disp6 = NULL; + + if (isc_net_probeipv4() == ISC_R_SUCCESS) { + isc_sockaddr_t any4; + + isc_sockaddr_any(&any4); + + attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK( + dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any4, 512, 6, + 1024, 17, 19, attrs, attrs, + &disp4) == ISC_R_SUCCESS); + INSIST(disp4 != NULL); + } + + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + isc_sockaddr_t any6; + + isc_sockaddr_any6(&any6); + + attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK( + dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any6, 512, 6, + 1024, 17, 19, attrs, attrs, + &disp6) == ISC_R_SUCCESS); + INSIST(disp6 != NULL); + } + + RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1, + socketmgr, timermgr, 0, + dispatchmgr, disp4, + disp6) == ISC_R_SUCCESS); + + if (disp4 != NULL) { + dns_dispatch_detach(&disp4); + } + if (disp6 != NULL) { + dns_dispatch_detach(&disp6); + } + } + + { + struct in_addr ina; + isc_sockaddr_t sa; + isc_sockaddrlist_t sal; + + ISC_LIST_INIT(sal); + ina.s_addr = inet_addr("127.0.0.1"); + isc_sockaddr_fromin(&sa, &ina, 53); + ISC_LIST_APPEND(sal, &sa, link); + + RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname, + &sal, dns_fwdpolicy_only) == + ISC_R_SUCCESS); + } + + dns_view_setcache(view, cache, false); + dns_view_freeze(view); + + dns_cache_detach(&cache); + + printf("address = %s\n", argv[isc_commandline_index]); + na.family = AF_INET; + if (inet_pton(AF_INET, argv[isc_commandline_index], + (char *)&na.type.in) != 1) + { + na.family = AF_INET6; + if (inet_pton(AF_INET6, argv[isc_commandline_index], + (char *)&na.type.in6) != 1) + { + printf("unknown address format\n"); + exit(1); + } + } + + result = dns_byaddr_create(mctx, &na, view, options, task, done, NULL, + &byaddr); + if (result != ISC_R_SUCCESS) { + printf("dns_byaddr_create() returned %s\n", + isc_result_totext(result)); + RUNTIME_CHECK(0); + } + + (void)isc_app_run(); + + /* + * XXXRTH if we get a control-C before we get to isc_app_run(), + * we're in trouble (because we might try to destroy things before + * they've been created. + */ + + dns_view_detach(&view); + + isc_task_shutdown(task); + isc_task_detach(&task); + + dns_dispatchmgr_destroy(&dispatchmgr); + + isc_managers_destroy(&netmgr, &taskmgr); + + isc_socketmgr_destroy(&socketmgr); + isc_timermgr_destroy(&timermgr); + + if (verbose) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/byname_test.c b/bin/tests/optional/byname_test.c new file mode 100644 index 0000000..fa76973 --- /dev/null +++ b/bin/tests/optional/byname_test.c @@ -0,0 +1,350 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static isc_mem_t *mctx = NULL; +static isc_nm_t *netmgr = NULL; +static isc_taskmgr_t *taskmgr = NULL; +static dns_view_t *view = NULL; +static dns_adbfind_t *find = NULL; +static isc_task_t *task = NULL; +static dns_fixedname_t fixed; +static dns_fixedname_t target; +static isc_log_t *lctx = NULL; +static isc_logconfig_t *lcfg = NULL; +static unsigned int level = 0; + +static void +adb_callback(isc_task_t *task, isc_event_t *event); + +static void +log_init(void) { + isc_logdestination_t destination; + unsigned int flags; + + /* + * Setup a logging context. + */ + isc_log_create(mctx, &lctx, &lcfg); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + /* + * Create and install the default channel. + */ + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + flags = ISC_LOG_PRINTTIME; + isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, flags); + + RUNTIME_CHECK(isc_log_usechannel(lcfg, "_default", NULL, NULL) == + ISC_R_SUCCESS); + isc_log_setdebuglevel(lctx, level); +} + +static void +print_addresses(dns_adbfind_t *adbfind) { + dns_adbaddrinfo_t *address; + + for (address = ISC_LIST_HEAD(adbfind->list); address != NULL; + address = ISC_LIST_NEXT(address, publink)) + { + isc_netaddr_t netaddr; + char text[ISC_NETADDR_FORMATSIZE]; + isc_netaddr_fromsockaddr(&netaddr, &address->sockaddr); + isc_netaddr_format(&netaddr, text, sizeof(text)); + printf("%s\n", text); + } +} + +static void +print_name(dns_name_t *name) { + char text[DNS_NAME_FORMATSIZE]; + + dns_name_format(name, text, sizeof(text)); + printf("%s\n", text); +} + +static void +do_find(bool want_event) { + isc_result_t result; + bool done = false; + unsigned int options; + + options = DNS_ADBFIND_INET | DNS_ADBFIND_INET6; + if (want_event) { + options |= DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT; + } + dns_fixedname_init(&target); + result = dns_adb_createfind(view->adb, task, adb_callback, NULL, + dns_fixedname_name(&fixed), dns_rootname, 0, + options, 0, dns_fixedname_name(&target), 0, + 0, NULL, &find); + if (result == ISC_R_SUCCESS) { + if (!ISC_LIST_EMPTY(find->list)) { + /* + * We have at least some of the addresses for the + * name. + */ + INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0); + print_addresses(find); + done = true; + } else { + /* + * We don't know any of the addresses for this + * name. + */ + if ((find->options & DNS_ADBFIND_WANTEVENT) == 0) { + /* + * And ADB isn't going to send us any events + * either. This query loses. + */ + done = true; + } + /* + * If the DNS_ADBFIND_WANTEVENT flag was set, we'll + * get an event when something happens. + */ + } + } else if (result == DNS_R_ALIAS) { + print_name(dns_fixedname_name(&target)); + done = true; + } else { + printf("dns_adb_createfind() returned %s\n", + isc_result_totext(result)); + done = true; + } + + if (done) { + if (find != NULL) { + dns_adb_destroyfind(&find); + } + isc_app_shutdown(); + } +} + +static void +adb_callback(isc_task_t *etask, isc_event_t *event) { + unsigned int type = event->ev_type; + + REQUIRE(etask == task); + + isc_event_free(&event); + dns_adb_destroyfind(&find); + + if (type == DNS_EVENT_ADBMOREADDRESSES) { + do_find(false); + } else if (type == DNS_EVENT_ADBNOMOREADDRESSES) { + printf("no more addresses\n"); + isc_app_shutdown(); + } else { + printf("unexpected ADB event type %u\n", type); + isc_app_shutdown(); + } +} + +static void +run(isc_task_t *xtask, isc_event_t *event) { + UNUSED(xtask); + do_find(true); + isc_event_free(&event); +} + +int +main(int argc, char *argv[]) { + bool verbose = false; + unsigned int workers = 2; + isc_timermgr_t *timermgr = NULL; + int ch; + isc_socketmgr_t *socketmgr = NULL; + dns_dispatchmgr_t *dispatchmgr = NULL; + dns_cache_t *cache = NULL; + isc_buffer_t b; + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + + dns_result_register(); + + isc_mem_create(&mctx); + + while ((ch = isc_commandline_parse(argc, argv, "d:vw:")) != -1) { + switch (ch) { + case 'd': + level = (unsigned int)atoi(isc_commandline_argument); + break; + case 'v': + verbose = true; + break; + case 'w': + workers = (unsigned int)atoi(isc_commandline_argument); + break; + } + } + + log_init(); + + if (verbose) { + printf("%u workers\n", workers); + printf("IPv4: %s\n", isc_result_totext(isc_net_probeipv4())); + printf("IPv6: %s\n", isc_result_totext(isc_net_probeipv6())); + } + + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS); + isc_task_setname(task, "byname", NULL); + + RUNTIME_CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr) == + ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(dns_cache_create(mctx, mctx, taskmgr, timermgr, + dns_rdataclass_in, "", "rbt", 0, NULL, + &cache) == ISC_R_SUCCESS); + + RUNTIME_CHECK(dns_view_create(mctx, dns_rdataclass_in, "default", + &view) == ISC_R_SUCCESS); + + { + unsigned int attrs; + dns_dispatch_t *disp4 = NULL; + dns_dispatch_t *disp6 = NULL; + + if (isc_net_probeipv4() == ISC_R_SUCCESS) { + isc_sockaddr_t any4; + isc_sockaddr_any(&any4); + + attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK( + dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any4, 512, 6, + 1024, 17, 19, attrs, attrs, + &disp4) == ISC_R_SUCCESS); + INSIST(disp4 != NULL); + } + + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + isc_sockaddr_t any6; + + isc_sockaddr_any6(&any6); + + attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK( + dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any6, 512, 6, + 1024, 17, 19, attrs, attrs, + &disp6) == ISC_R_SUCCESS); + INSIST(disp6 != NULL); + } + + RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1, + socketmgr, timermgr, 0, + dispatchmgr, disp4, + disp6) == ISC_R_SUCCESS); + + if (disp4 != NULL) { + dns_dispatch_detach(&disp4); + } + if (disp6 != NULL) { + dns_dispatch_detach(&disp6); + } + } + + { + struct in_addr ina; + isc_sockaddr_t sa; + isc_sockaddrlist_t sal; + + ISC_LIST_INIT(sal); + ina.s_addr = inet_addr("127.0.0.1"); + isc_sockaddr_fromin(&sa, &ina, 53); + ISC_LIST_APPEND(sal, &sa, link); + + REQUIRE(DNS_VIEW_VALID(view)); + RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname, + &sal, dns_fwdpolicy_only) == + ISC_R_SUCCESS); + } + + dns_view_setcache(view, cache, false); + dns_view_freeze(view); + + dns_cache_detach(&cache); + + printf("name = %s\n", argv[isc_commandline_index]); + isc_buffer_init(&b, argv[isc_commandline_index], + strlen(argv[isc_commandline_index])); + isc_buffer_add(&b, strlen(argv[isc_commandline_index])); + dns_fixedname_init(&fixed); + dns_fixedname_init(&target); + RUNTIME_CHECK(dns_name_fromtext(dns_fixedname_name(&fixed), &b, + dns_rootname, 0, + NULL) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_app_onrun(mctx, task, run, NULL) == ISC_R_SUCCESS); + + (void)isc_app_run(); + + dns_view_detach(&view); + isc_task_shutdown(task); + isc_task_detach(&task); + + dns_dispatchmgr_destroy(&dispatchmgr); + + isc_managers_destroy(&netmgr, &taskmgr); + + isc_socketmgr_destroy(&socketmgr); + isc_timermgr_destroy(&timermgr); + + isc_log_destroy(&lctx); + + if (verbose) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/db_test.c b/bin/tests/optional/db_test.c new file mode 100644 index 0000000..05bd748 --- /dev/null +++ b/bin/tests/optional/db_test.c @@ -0,0 +1,983 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXHOLD 100 +#define MAXVERSIONS 100 + +typedef struct dbinfo { + dns_db_t *db; + dns_dbversion_t *version; + dns_dbversion_t *wversion; + dns_dbversion_t *rversions[MAXVERSIONS]; + int rcount; + dns_dbnode_t *hold_nodes[MAXHOLD]; + int hold_count; + dns_dbiterator_t *dbiterator; + dns_dbversion_t *iversion; + int pause_every; + bool ascending; + ISC_LINK(struct dbinfo) link; +} dbinfo; + +static isc_mem_t *mctx = NULL; +static char dbtype[128]; +static dns_dbtable_t *dbtable; +static ISC_LIST(dbinfo) dbs; +static dbinfo *cache_dbi = NULL; +static int pause_every = 0; +static bool ascending = true; + +static void +print_result(const char *message, isc_result_t result) { + if (message == NULL) { + message = ""; + } + printf("%s%sresult %08x: %s\n", message, (*message == '\0') ? "" : " ", + result, isc_result_totext(result)); +} + +static void +print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) { + isc_buffer_t text; + char t[1000]; + isc_result_t result; + isc_region_t r; + + isc_buffer_init(&text, t, sizeof(t)); + result = dns_rdataset_totext(rdataset, name, false, false, &text); + isc_buffer_usedregion(&text, &r); + if (result == ISC_R_SUCCESS) { + printf("%.*s", (int)r.length, (char *)r.base); + } else { + print_result("", result); + } +} + +static void +print_rdatasets(dns_name_t *name, dns_rdatasetiter_t *rdsiter) { + isc_result_t result; + dns_rdataset_t rdataset; + + dns_rdataset_init(&rdataset); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &rdataset); + print_rdataset(name, &rdataset); + dns_rdataset_disassociate(&rdataset); + result = dns_rdatasetiter_next(rdsiter); + } + if (result != ISC_R_NOMORE) { + print_result("", result); + } +} + +static dbinfo * +select_db(char *origintext) { + dns_fixedname_t forigin; + dns_name_t *origin; + isc_buffer_t source; + size_t len; + dbinfo *dbi; + isc_result_t result; + + if (strcasecmp(origintext, "cache") == 0) { + if (cache_dbi == NULL) { + printf("the cache does not exist\n"); + } + return (cache_dbi); + } + len = strlen(origintext); + isc_buffer_init(&source, origintext, len); + isc_buffer_add(&source, len); + origin = dns_fixedname_initname(&forigin); + result = dns_name_fromtext(origin, &source, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + print_result("bad name", result); + return (NULL); + } + + for (dbi = ISC_LIST_HEAD(dbs); dbi != NULL; + dbi = ISC_LIST_NEXT(dbi, link)) + { + if (dns_name_compare(dns_db_origin(dbi->db), origin) == 0) { + break; + } + } + + return (dbi); +} + +static void +list(dbinfo *dbi, char *seektext) { + dns_fixedname_t fname; + dns_name_t *name; + dns_dbnode_t *node; + dns_rdatasetiter_t *rdsiter; + isc_result_t result; + int i; + size_t len; + dns_fixedname_t fseekname; + dns_name_t *seekname; + isc_buffer_t source; + + name = dns_fixedname_initname(&fname); + + if (dbi->dbiterator == NULL) { + INSIST(dbi->iversion == NULL); + if (dns_db_iszone(dbi->db)) { + if (dbi->version != NULL) { + dns_db_attachversion(dbi->db, dbi->version, + &dbi->iversion); + } else { + dns_db_currentversion(dbi->db, &dbi->iversion); + } + } + + result = dns_db_createiterator(dbi->db, 0, &dbi->dbiterator); + if (result == ISC_R_SUCCESS) { + if (seektext != NULL) { + len = strlen(seektext); + isc_buffer_init(&source, seektext, len); + isc_buffer_add(&source, len); + seekname = dns_fixedname_initname(&fseekname); + result = dns_name_fromtext( + seekname, &source, + dns_db_origin(dbi->db), 0, NULL); + if (result == ISC_R_SUCCESS) { + result = dns_dbiterator_seek( + dbi->dbiterator, seekname); + } + } else if (dbi->ascending) { + result = dns_dbiterator_first(dbi->dbiterator); + } else { + result = dns_dbiterator_last(dbi->dbiterator); + } + } + } else { + result = ISC_R_SUCCESS; + } + + node = NULL; + rdsiter = NULL; + i = 0; + while (result == ISC_R_SUCCESS) { + result = dns_dbiterator_current(dbi->dbiterator, &node, name); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + break; + } + result = dns_db_allrdatasets(dbi->db, node, dbi->iversion, 0, 0, + &rdsiter); + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(dbi->db, &node); + break; + } + print_rdatasets(name, rdsiter); + dns_rdatasetiter_destroy(&rdsiter); + dns_db_detachnode(dbi->db, &node); + if (dbi->ascending) { + result = dns_dbiterator_next(dbi->dbiterator); + } else { + result = dns_dbiterator_prev(dbi->dbiterator); + } + i++; + if (result == ISC_R_SUCCESS && i == dbi->pause_every) { + printf("[more...]\n"); + result = dns_dbiterator_pause(dbi->dbiterator); + if (result == ISC_R_SUCCESS) { + return; + } + } + } + if (result != ISC_R_NOMORE) { + print_result("", result); + } + + dns_dbiterator_destroy(&dbi->dbiterator); + if (dbi->iversion != NULL) { + dns_db_closeversion(dbi->db, &dbi->iversion, false); + } +} + +static isc_result_t +load(const char *filename, const char *origintext, bool cache) { + dns_fixedname_t forigin; + dns_name_t *origin; + isc_result_t result; + isc_buffer_t source; + size_t len; + dbinfo *dbi; + unsigned int i; + + dbi = isc_mem_get(mctx, sizeof(*dbi)); + + dbi->db = NULL; + dbi->version = NULL; + dbi->wversion = NULL; + for (i = 0; i < MAXVERSIONS; i++) { + dbi->rversions[i] = NULL; + } + dbi->hold_count = 0; + for (i = 0; i < MAXHOLD; i++) { + dbi->hold_nodes[i] = NULL; + } + dbi->dbiterator = NULL; + dbi->iversion = NULL; + dbi->pause_every = pause_every; + dbi->ascending = ascending; + ISC_LINK_INIT(dbi, link); + + len = strlen(origintext); + isc_buffer_constinit(&source, origintext, len); + isc_buffer_add(&source, len); + origin = dns_fixedname_initname(&forigin); + result = dns_name_fromtext(origin, &source, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, dbi, sizeof(*dbi)); + return (result); + } + + result = dns_db_create(mctx, dbtype, origin, + cache ? dns_dbtype_cache : dns_dbtype_zone, + dns_rdataclass_in, 0, NULL, &dbi->db); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, dbi, sizeof(*dbi)); + return (result); + } + + printf("loading %s (%s)\n", filename, origintext); + result = dns_db_load(dbi->db, filename, dns_masterformat_text, 0); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { + dns_db_detach(&dbi->db); + isc_mem_put(mctx, dbi, sizeof(*dbi)); + return (result); + } + printf("loaded\n"); + + if (cache) { + INSIST(cache_dbi == NULL); + dns_dbtable_adddefault(dbtable, dbi->db); + cache_dbi = dbi; + } else { + result = dns_dbtable_add(dbtable, dbi->db); + if (result != ISC_R_SUCCESS) { + dns_db_detach(&dbi->db); + isc_mem_put(mctx, dbi, sizeof(*dbi)); + return (result); + } + } + ISC_LIST_APPEND(dbs, dbi, link); + + return (ISC_R_SUCCESS); +} + +static void +unload_all(void) { + dbinfo *dbi, *dbi_next; + + for (dbi = ISC_LIST_HEAD(dbs); dbi != NULL; dbi = dbi_next) { + dbi_next = ISC_LIST_NEXT(dbi, link); + if (dns_db_iszone(dbi->db)) { + dns_dbtable_remove(dbtable, dbi->db); + } else { + INSIST(dbi == cache_dbi); + dns_dbtable_removedefault(dbtable); + cache_dbi = NULL; + } + dns_db_detach(&dbi->db); + ISC_LIST_UNLINK(dbs, dbi, link); + isc_mem_put(mctx, dbi, sizeof(*dbi)); + } +} + +#define DBI_CHECK(dbi) \ + if ((dbi) == NULL) { \ + printf("You must first select a database with !DB\n"); \ + continue; \ + } + +int +main(int argc, char *argv[]) { + dns_db_t *db; + dns_dbnode_t *node; + isc_result_t result; + dns_name_t name; + dns_offsets_t offsets; + size_t len; + isc_buffer_t source, target; + char s[1000]; + char b[255]; + dns_rdataset_t rdataset, sigrdataset; + int ch; + dns_rdatatype_t type = 1; + bool printnode = false; + bool addmode = false; + bool delmode = false; + bool holdmode = false; + bool verbose = false; + bool done = false; + bool quiet = false; + bool time_lookups = false; + bool found_as; + bool find_zonecut = false; + bool noexact_zonecut = false; + int i, v; + dns_rdatasetiter_t *rdsiter; + char t1[256]; + char t2[256]; + isc_buffer_t tb1, tb2; + isc_region_t r1, r2; + dns_fixedname_t foundname; + dns_name_t *fname; + unsigned int options = 0, zcoptions; + isc_time_t start, finish; + const char *origintext; + dbinfo *dbi; + dns_dbversion_t *version; + const dns_name_t *origin; + dns_trust_t trust = 0; + unsigned int addopts; + isc_log_t *lctx = NULL; + size_t n; + + dns_result_register(); + + isc_mem_create(&mctx); + RUNTIME_CHECK(dns_dbtable_create(mctx, dns_rdataclass_in, &dbtable) == + ISC_R_SUCCESS); + + snprintf(dbtype, sizeof(dbtype), "rbt"); + while ((ch = isc_commandline_parse(argc, argv, "c:d:t:z:P:Q:glpqvT")) != + -1) + { + switch (ch) { + case 'c': + result = load(isc_commandline_argument, ".", true); + if (result != ISC_R_SUCCESS) { + printf("cache load(%s) %08x: %s\n", + isc_commandline_argument, result, + isc_result_totext(result)); + } + break; + case 'd': + n = strlcpy(dbtype, isc_commandline_argument, + sizeof(dbtype)); + if (n >= sizeof(dbtype)) { + fprintf(stderr, "bad db type '%s'\n", + isc_commandline_argument); + exit(1); + } + break; + case 'g': + options |= (DNS_DBFIND_GLUEOK | + DNS_DBFIND_VALIDATEGLUE); + break; + case 'l': + isc_log_create(mctx, &lctx, NULL); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + break; + case 'q': + quiet = true; + verbose = false; + break; + case 'p': + printnode = true; + break; + case 'P': + pause_every = atoi(isc_commandline_argument); + break; + case 't': + type = atoi(isc_commandline_argument); + break; + case 'T': + time_lookups = true; + break; + case 'v': + verbose = true; + break; + case 'z': + origintext = strrchr(isc_commandline_argument, '/'); + if (origintext == NULL) { + origintext = isc_commandline_argument; + } else { + origintext++; /* Skip '/'. */ + } + result = load(isc_commandline_argument, origintext, + false); + if (result != ISC_R_SUCCESS) { + printf("zone load(%s) %08x: %s\n", + isc_commandline_argument, result, + isc_result_totext(result)); + } + break; + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + POST(argv); + + if (argc != 0) { + printf("ignoring trailing arguments\n"); + } + + /* + * Some final initialization... + */ + fname = dns_fixedname_initname(&foundname); + dbi = NULL; + origin = dns_rootname; + version = NULL; + + if (time_lookups) { + TIME_NOW(&start); + } + + while (!done) { + if (!quiet) { + printf("\n"); + } + if (fgets(s, sizeof(s), stdin) == NULL) { + done = true; + continue; + } + len = strlen(s); + if (len > 0U && s[len - 1] == '\n') { + s[len - 1] = '\0'; + len--; + } + if (verbose && dbi != NULL) { + if (dbi->wversion != NULL) { + printf("future version (%p)\n", dbi->wversion); + } + for (i = 0; i < dbi->rcount; i++) { + if (dbi->rversions[i] != NULL) { + printf("open version %d (%p)\n", i, + dbi->rversions[i]); + } + } + } + dns_name_init(&name, offsets); + if (strcmp(s, "!R") == 0) { + DBI_CHECK(dbi); + if (dbi->rcount == MAXVERSIONS) { + printf("too many open versions\n"); + continue; + } + dns_db_currentversion(dbi->db, + &dbi->rversions[dbi->rcount]); + printf("opened version %d\n", dbi->rcount); + dbi->version = dbi->rversions[dbi->rcount]; + version = dbi->version; + dbi->rcount++; + continue; + } else if (strcmp(s, "!W") == 0) { + DBI_CHECK(dbi); + if (dbi->wversion != NULL) { + printf("using existing future version\n"); + dbi->version = dbi->wversion; + version = dbi->version; + continue; + } + result = dns_db_newversion(dbi->db, &dbi->wversion); + if (result != ISC_R_SUCCESS) { + print_result("", result); + } else { + printf("newversion\n"); + } + dbi->version = dbi->wversion; + version = dbi->version; + continue; + } else if (strcmp(s, "!C") == 0) { + DBI_CHECK(dbi); + addmode = false; + delmode = false; + if (dbi->version == NULL) { + continue; + } + if (dbi->version == dbi->wversion) { + printf("closing future version\n"); + dbi->wversion = NULL; + } else { + for (i = 0; i < dbi->rcount; i++) { + if (dbi->version == dbi->rversions[i]) { + dbi->rversions[i] = NULL; + printf("closing open version " + "%d\n", + i); + break; + } + } + } + dns_db_closeversion(dbi->db, &dbi->version, true); + version = NULL; + continue; + } else if (strcmp(s, "!X") == 0) { + DBI_CHECK(dbi); + addmode = false; + delmode = false; + if (dbi->version == NULL) { + continue; + } + if (dbi->version == dbi->wversion) { + printf("aborting future version\n"); + dbi->wversion = NULL; + } else { + for (i = 0; i < dbi->rcount; i++) { + if (dbi->version == dbi->rversions[i]) { + dbi->rversions[i] = NULL; + printf("closing open version " + "%d\n", + i); + break; + } + } + } + dns_db_closeversion(dbi->db, &dbi->version, false); + version = NULL; + continue; + } else if (strcmp(s, "!A") == 0) { + DBI_CHECK(dbi); + delmode = false; + if (addmode) { + addmode = false; + } else { + addmode = true; + } + printf("addmode = %s\n", addmode ? "TRUE" : "FALSE"); + continue; + } else if (strcmp(s, "!D") == 0) { + DBI_CHECK(dbi); + addmode = false; + if (delmode) { + delmode = false; + } else { + delmode = true; + } + printf("delmode = %s\n", delmode ? "TRUE" : "FALSE"); + continue; + } else if (strcmp(s, "!H") == 0) { + DBI_CHECK(dbi); + if (holdmode) { + holdmode = false; + } else { + holdmode = true; + } + printf("holdmode = %s\n", holdmode ? "TRUE" : "FALSE"); + continue; + } else if (strcmp(s, "!HR") == 0) { + DBI_CHECK(dbi); + for (i = 0; i < dbi->hold_count; i++) { + dns_db_detachnode(dbi->db, &dbi->hold_nodes[i]); + } + dbi->hold_count = 0; + holdmode = false; + printf("held nodes have been detached\n"); + continue; + } else if (strcmp(s, "!VC") == 0) { + DBI_CHECK(dbi); + printf("switching to current version\n"); + dbi->version = NULL; + version = NULL; + continue; + } else if (strstr(s, "!V") == s) { + DBI_CHECK(dbi); + v = atoi(&s[2]); + if (v >= dbi->rcount || v < 0) { + printf("unknown open version %d\n", v); + continue; + } + if (dbi->rversions[v] == NULL) { + printf("version %d is not open\n", v); + continue; + } + printf("switching to open version %d\n", v); + dbi->version = dbi->rversions[v]; + version = dbi->version; + continue; + } else if (strstr(s, "!TR") == s) { + trust = (unsigned int)atoi(&s[3]); + printf("trust level is now %u\n", (unsigned int)trust); + continue; + } else if (strstr(s, "!T") == s) { + type = (unsigned int)atoi(&s[2]); + printf("now searching for type %u\n", type); + continue; + } else if (strcmp(s, "!G") == 0) { + if ((options & DNS_DBFIND_GLUEOK) != 0) { + options &= ~DNS_DBFIND_GLUEOK; + } else { + options |= DNS_DBFIND_GLUEOK; + } + printf("glue ok = %s\n", + ((options & DNS_DBFIND_GLUEOK) != 0) ? "TRUE" + : "FALSE"); + continue; + } else if (strcmp(s, "!GV") == 0) { + if ((options & DNS_DBFIND_VALIDATEGLUE) != 0) { + options &= ~DNS_DBFIND_VALIDATEGLUE; + } else { + options |= DNS_DBFIND_VALIDATEGLUE; + } + printf("validate glue = %s\n", + ((options & DNS_DBFIND_VALIDATEGLUE) != 0) + ? "TRUE" + : "FALSE"); + continue; + } else if (strcmp(s, "!WC") == 0) { + if ((options & DNS_DBFIND_NOWILD) != 0) { + options &= ~DNS_DBFIND_NOWILD; + } else { + options |= DNS_DBFIND_NOWILD; + } + printf("wildcard matching = %s\n", + ((options & DNS_DBFIND_NOWILD) == 0) ? "TRUE" + : "FALSE"); + continue; + } else if (strstr(s, "!LS ") == s) { + DBI_CHECK(dbi); + list(dbi, &s[4]); + continue; + } else if (strcmp(s, "!LS") == 0) { + DBI_CHECK(dbi); + list(dbi, NULL); + continue; + } else if (strstr(s, "!DU ") == s) { + DBI_CHECK(dbi); + result = dns_db_dump(dbi->db, dbi->version, s + 4); + if (result != ISC_R_SUCCESS) { + printf("\n"); + print_result("", result); + } + continue; + } else if (strcmp(s, "!PN") == 0) { + if (printnode) { + printnode = false; + } else { + printnode = true; + } + printf("printnode = %s\n", + printnode ? "TRUE" : "FALSE"); + continue; + } else if (strstr(s, "!P") == s) { + DBI_CHECK(dbi); + v = atoi(&s[2]); + dbi->pause_every = v; + continue; + } else if (strcmp(s, "!+") == 0) { + DBI_CHECK(dbi); + dbi->ascending = true; + continue; + } else if (strcmp(s, "!-") == 0) { + DBI_CHECK(dbi); + dbi->ascending = false; + continue; + } else if (strcmp(s, "!DB") == 0) { + dbi = NULL; + origin = dns_rootname; + version = NULL; + printf("now searching all databases\n"); + continue; + } else if (strncmp(s, "!DB ", 4) == 0) { + dbi = select_db(s + 4); + if (dbi != NULL) { + db = dbi->db; + origin = dns_db_origin(dbi->db); + version = dbi->version; + addmode = false; + delmode = false; + holdmode = false; + } else { + db = NULL; + version = NULL; + origin = dns_rootname; + printf("database not found; " + "now searching all databases\n"); + } + continue; + } else if (strcmp(s, "!ZC") == 0) { + if (find_zonecut) { + find_zonecut = false; + } else { + find_zonecut = true; + } + printf("find_zonecut = %s\n", + find_zonecut ? "TRUE" : "FALSE"); + continue; + } else if (strcmp(s, "!NZ") == 0) { + if (noexact_zonecut) { + noexact_zonecut = false; + } else { + noexact_zonecut = true; + } + printf("noexact_zonecut = %s\n", + noexact_zonecut ? "TRUE" : "FALSE"); + continue; + } + + isc_buffer_init(&source, s, len); + isc_buffer_add(&source, len); + isc_buffer_init(&target, b, sizeof(b)); + result = dns_name_fromtext(&name, &source, origin, 0, &target); + if (result != ISC_R_SUCCESS) { + print_result("bad name: ", result); + continue; + } + + if (dbi == NULL) { + zcoptions = 0; + if (noexact_zonecut) { + zcoptions |= DNS_DBTABLEFIND_NOEXACT; + } + db = NULL; + result = dns_dbtable_find(dbtable, &name, zcoptions, + &db); + if (result != ISC_R_SUCCESS && + result != DNS_R_PARTIALMATCH) + { + if (!quiet) { + printf("\n"); + print_result("", result); + } + continue; + } + isc_buffer_init(&tb1, t1, sizeof(t1)); + result = dns_name_totext(dns_db_origin(db), false, + &tb1); + if (result != ISC_R_SUCCESS) { + printf("\n"); + print_result("", result); + dns_db_detach(&db); + continue; + } + isc_buffer_usedregion(&tb1, &r1); + printf("\ndatabase = %.*s (%s)\n", (int)r1.length, + r1.base, (dns_db_iszone(db)) ? "zone" : "cache"); + } + node = NULL; + dns_rdataset_init(&rdataset); + dns_rdataset_init(&sigrdataset); + + if (find_zonecut && dns_db_iscache(db)) { + zcoptions = options; + if (noexact_zonecut) { + zcoptions |= DNS_DBFIND_NOEXACT; + } + result = dns_db_findzonecut(db, &name, zcoptions, 0, + &node, fname, NULL, + &rdataset, &sigrdataset); + } else { + result = dns_db_find(db, &name, version, type, options, + 0, &node, fname, &rdataset, + &sigrdataset); + } + + if (!quiet) { + if (dbi != NULL) { + printf("\n"); + } + print_result("", result); + } + + found_as = false; + switch (result) { + case ISC_R_SUCCESS: + case DNS_R_GLUE: + case DNS_R_CNAME: + case DNS_R_ZONECUT: + break; + case DNS_R_DNAME: + case DNS_R_DELEGATION: + found_as = true; + break; + case DNS_R_NXRRSET: + if (dns_rdataset_isassociated(&rdataset)) { + break; + } + if (dbi != NULL) { + if (holdmode) { + RUNTIME_CHECK(dbi->hold_count < + MAXHOLD); + dbi->hold_nodes[dbi->hold_count++] = + node; + node = NULL; + } else { + dns_db_detachnode(db, &node); + } + } else { + dns_db_detachnode(db, &node); + dns_db_detach(&db); + } + continue; + case DNS_R_NXDOMAIN: + if (dns_rdataset_isassociated(&rdataset)) { + break; + } + FALLTHROUGH; + default: + if (dbi == NULL) { + dns_db_detach(&db); + } + if (quiet) { + print_result("", result); + } + continue; + } + if (found_as && !quiet) { + isc_buffer_init(&tb1, t1, sizeof(t1)); + isc_buffer_init(&tb2, t2, sizeof(t2)); + result = dns_name_totext(&name, false, &tb1); + if (result != ISC_R_SUCCESS) { + print_result("", result); + dns_db_detachnode(db, &node); + if (dbi == NULL) { + dns_db_detach(&db); + } + continue; + } + result = dns_name_totext(fname, false, &tb2); + if (result != ISC_R_SUCCESS) { + print_result("", result); + dns_db_detachnode(db, &node); + if (dbi == NULL) { + dns_db_detach(&db); + } + continue; + } + isc_buffer_usedregion(&tb1, &r1); + isc_buffer_usedregion(&tb2, &r2); + printf("found %.*s as %.*s\n", (int)r1.length, r1.base, + (int)r2.length, r2.base); + } + + if (printnode) { + dns_db_printnode(db, node, stdout); + } + + if (!found_as && type == dns_rdatatype_any) { + rdsiter = NULL; + result = dns_db_allrdatasets(db, node, version, 0, 0, + &rdsiter); + if (result == ISC_R_SUCCESS) { + if (!quiet) { + print_rdatasets(fname, rdsiter); + } + dns_rdatasetiter_destroy(&rdsiter); + } else { + print_result("", result); + } + } else { + if (!quiet) { + print_rdataset(fname, &rdataset); + } + if (dns_rdataset_isassociated(&sigrdataset)) { + if (!quiet) { + print_rdataset(fname, &sigrdataset); + } + dns_rdataset_disassociate(&sigrdataset); + } + if (dbi != NULL && addmode && !found_as) { + rdataset.ttl++; + rdataset.trust = trust; + if (dns_db_iszone(db)) { + addopts = DNS_DBADD_MERGE; + } else { + addopts = 0; + } + result = dns_db_addrdataset(db, node, version, + 0, &rdataset, + addopts, NULL); + if (result != ISC_R_SUCCESS) { + print_result("", result); + } + if (printnode) { + dns_db_printnode(db, node, stdout); + } + } else if (dbi != NULL && delmode && !found_as) { + result = dns_db_deleterdataset( + db, node, version, type, 0); + if (result != ISC_R_SUCCESS) { + print_result("", result); + } + if (printnode) { + dns_db_printnode(db, node, stdout); + } + } + dns_rdataset_disassociate(&rdataset); + } + + if (dbi != NULL) { + if (holdmode) { + RUNTIME_CHECK(dbi->hold_count < MAXHOLD); + dbi->hold_nodes[dbi->hold_count++] = node; + node = NULL; + } else { + dns_db_detachnode(db, &node); + } + } else { + dns_db_detachnode(db, &node); + dns_db_detach(&db); + } + } + + if (time_lookups) { + uint64_t usec; + + TIME_NOW(&finish); + + usec = isc_time_microdiff(&finish, &start); + + printf("elapsed time: %lu.%06lu seconds\n", + (unsigned long)(usec / 1000000), + (unsigned long)(usec % 1000000)); + } + + unload_all(); + + dns_dbtable_detach(&dbtable); + + if (lctx != NULL) { + isc_log_destroy(&lctx); + } + + if (!quiet) { + isc_mem_stats(mctx, stdout); + } + + return (0); +} diff --git a/bin/tests/optional/fsaccess_test.c b/bin/tests/optional/fsaccess_test.c new file mode 100644 index 0000000..db5d21e --- /dev/null +++ b/bin/tests/optional/fsaccess_test.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include /* Non-portable. */ +#include /* Non-portable. */ + +#include +#include +#include + +#define PATH "/tmp/fsaccess" + +int +main(void) { + isc_fsaccess_t access; + isc_result_t result; + FILE *fp; + int n; + + n = remove(PATH); + if (n != 0 && errno != ENOENT) { + fprintf(stderr, "unable to remove(%s)\n", PATH); + exit(1); + } + fp = fopen(PATH, "w"); + if (fp == NULL) { + fprintf(stderr, "unable to fopen(%s)\n", PATH); + exit(1); + } + n = chmod(PATH, 0); + if (n != 0) { + fprintf(stderr, "unable chmod(%s, 0)\n", PATH); + exit(1); + } + + access = 0; + + isc_fsaccess_add(ISC_FSACCESS_OWNER | ISC_FSACCESS_GROUP, + ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, &access); + + printf("fsaccess=%u\n", access); + + isc_fsaccess_add(ISC_FSACCESS_OTHER, ISC_FSACCESS_READ, &access); + + printf("fsaccess=%u\n", access); + + result = isc_fsaccess_set(PATH, access); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "result = %s\n", isc_result_totext(result)); + } + (void)fclose(fp); + + return (0); +} diff --git a/bin/tests/optional/gsstest.c b/bin/tests/optional/gsstest.c new file mode 100644 index 0000000..1cc18eb --- /dev/null +++ b/bin/tests/optional/gsstest.c @@ -0,0 +1,550 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef GSSAPI +#include ISC_PLATFORM_GSSAPIHEADER + +#define CHECK(str, x) \ + { \ + if ((x) != ISC_R_SUCCESS) { \ + fprintf(stderr, "I:%d:%s: %s\n", __LINE__, (str), \ + isc_result_totext(x)); \ + goto end; \ + } \ + } + +static dns_fixedname_t servername, gssname; + +static isc_mem_t *mctx = NULL; +static dns_requestmgr_t *requestmgr = NULL; +static isc_sockaddr_t address; + +static dns_tsig_keyring_t *ring = NULL; +static dns_tsigkey_t *tsigkey = NULL; +static dns_gss_ctx_id_t gssctx; +static dns_gss_ctx_id_t *gssctxp = &gssctx; + +#define RUNCHECK(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS) + +#define PORT 53 +#define TIMEOUT 30 + +static void +initctx1(isc_task_t *task, isc_event_t *event); +static void +sendquery(isc_task_t *task, isc_event_t *event); +static void +setup(); + +static void +console(isc_task_t *task, isc_event_t *event) { + char buf[32]; + int c; + + isc_event_t *ev = NULL; + + isc_event_free(&event); + + for (;;) { + printf("\nCommand => "); + c = scanf("%31s", buf); + + if (c == EOF || strcmp(buf, "quit") == 0) { + isc_app_shutdown(); + return; + } + + if (strcmp(buf, "initctx") == 0) { + ev = isc_event_allocate(mctx, (void *)1, 1, initctx1, + NULL, sizeof(*event)); + isc_task_send(task, &ev); + return; + } + + if (strcmp(buf, "query") == 0) { + ev = isc_event_allocate(mctx, (void *)1, 1, sendquery, + NULL, sizeof(*event)); + isc_task_send(task, &ev); + return; + } + + printf("Unknown command\n"); + } +} + +static void +recvresponse(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = (dns_requestevent_t *)event; + isc_result_t result, result2; + dns_message_t *query = NULL, *response = NULL; + isc_buffer_t outtoken; + isc_buffer_t outbuf; + char output[10 * 1024]; + + unsigned char array[DNS_NAME_MAXTEXT + 1]; + isc_buffer_init(&outtoken, array, sizeof(array)); + + UNUSED(task); + + REQUIRE(reqev != NULL); + + query = reqev->ev_arg; + + if (reqev->result != ISC_R_SUCCESS) { + fprintf(stderr, "I:request event result: %s\n", + isc_result_totext(reqev->result)); + goto end; + } + + response = NULL; + dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); + + printf("\nReceived Response:\n"); + + result2 = dns_request_getresponse(reqev->request, response, + DNS_MESSAGEPARSE_PRESERVEORDER); + isc_buffer_init(&outbuf, output, sizeof(output)); + result = dns_message_totext(response, &dns_master_style_debug, 0, + &outbuf); + CHECK("dns_message_totext", result); + printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf), + (char *)isc_buffer_base(&outbuf)); + + CHECK("dns_request_getresponse", result2); + + if (response != NULL) { + dns_message_detach(&response); + } + +end: + if (query != NULL) { + dns_message_detach(&query); + } + + if (reqev->request != NULL) { + dns_request_destroy(&reqev->request); + } + + isc_event_free(&event); + + event = isc_event_allocate(mctx, (void *)1, 1, console, NULL, + sizeof(*event)); + isc_task_send(task, &event); + return; +} + +static void +sendquery(isc_task_t *task, isc_event_t *event) { + dns_request_t *request = NULL; + dns_message_t *message = NULL; + dns_name_t *qname = NULL; + dns_rdataset_t *qrdataset = NULL; + isc_result_t result; + dns_fixedname_t queryname; + isc_buffer_t buf; + isc_buffer_t outbuf; + char output[10 * 1024]; + static char host[256]; + int c; + + isc_event_free(&event); + + printf("Query => "); + c = scanf("%255s", host); + if (c == EOF) { + return; + } + + dns_fixedname_init(&queryname); + isc_buffer_init(&buf, host, strlen(host)); + isc_buffer_add(&buf, strlen(host)); + result = dns_name_fromtext(dns_fixedname_name(&queryname), &buf, + dns_rootname, 0, NULL); + CHECK("dns_name_fromtext", result); + + dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message); + + message->opcode = dns_opcode_query; + message->rdclass = dns_rdataclass_in; + message->id = (unsigned short)(random() & 0xFFFF); + + result = dns_message_gettempname(message, &qname); + if (result != ISC_R_SUCCESS) { + goto end; + } + + result = dns_message_gettemprdataset(message, &qrdataset); + if (result != ISC_R_SUCCESS) { + goto end; + } + + dns_name_init(qname, NULL); + dns_name_clone(dns_fixedname_name(&queryname), qname); + dns_rdataset_makequestion(qrdataset, dns_rdataclass_in, + dns_rdatatype_a); + ISC_LIST_APPEND(qname->list, qrdataset, link); + dns_message_addname(message, qname, DNS_SECTION_QUESTION); + + result = dns_request_create(requestmgr, message, &address, 0, tsigkey, + TIMEOUT, task, recvresponse, message, + &request); + CHECK("dns_request_create", result); + + printf("Submitting query:\n"); + isc_buffer_init(&outbuf, output, sizeof(output)); + result = dns_message_totext(message, &dns_master_style_debug, 0, + &outbuf); + CHECK("dns_message_totext", result); + printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf), + (char *)isc_buffer_base(&outbuf)); + + return; + +end: + if (qname != NULL) { + dns_message_puttempname(message, &qname); + } + if (qrdataset != NULL) { + dns_message_puttemprdataset(message, &qrdataset); + } + if (message != NULL) { + dns_message_detach(&message); + } +} + +static void +initctx2(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = (dns_requestevent_t *)event; + isc_result_t result; + dns_message_t *query = NULL, *response = NULL; + isc_buffer_t outtoken; + unsigned char array[DNS_NAME_MAXTEXT + 1]; + dns_rdataset_t *rdataset; + dns_rdatatype_t qtype; + dns_name_t *question_name; + + UNUSED(task); + + REQUIRE(reqev != NULL); + + query = reqev->ev_arg; + + if (reqev->result != ISC_R_SUCCESS) { + fprintf(stderr, "I:request event result: %s\n", + isc_result_totext(reqev->result)); + goto end; + } + + response = NULL; + dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); + + result = dns_request_getresponse(reqev->request, response, + DNS_MESSAGEPARSE_PRESERVEORDER); + CHECK("dns_request_getresponse", result); + + if (response->rcode != dns_rcode_noerror) { + result = ISC_RESULTCLASS_DNSRCODE + response->rcode; + fprintf(stderr, "I:response rcode: %s\n", + isc_result_totext(result)); + goto end; + } + + printf("Received token from server, calling gss_init_sec_context()\n"); + isc_buffer_init(&outtoken, array, DNS_NAME_MAXTEXT + 1); + result = dns_tkey_processgssresponse( + query, response, dns_fixedname_name(&gssname), &gssctx, + &outtoken, &tsigkey, ring, NULL); + gssctx = *gssctxp; + CHECK("dns_tkey_processgssresponse", result); + printf("Context accepted\n"); + + question_name = NULL; + dns_message_currentname(response, DNS_SECTION_ANSWER, &question_name); + rdataset = ISC_LIST_HEAD(question_name->list); + INSIST(rdataset != NULL); + qtype = rdataset->type; + if (qtype == dns_rdatatype_tkey) { + printf("Received TKEY response from server\n"); + printf("Context completed\n"); + } else { + printf("Did not receive TKEY response from server\n"); + printf("Context not completed\n"); + dns_tsigkey_detach(&tsigkey); + tsigkey = NULL; + } + + dns_message_detach(&response); + +end: + if (query != NULL) { + dns_message_detach(&query); + } + + if (reqev->request != NULL) { + dns_request_destroy(&reqev->request); + } + + isc_event_free(&event); + + event = isc_event_allocate(mctx, (void *)1, 1, console, NULL, + sizeof(*event)); + isc_task_send(task, &event); + return; +} + +static void +initctx1(isc_task_t *task, isc_event_t *event) { + char gssid[512]; + char contextname[512]; + isc_result_t result; + isc_buffer_t buf; + dns_message_t *query; + dns_request_t *request; + int c; + + isc_event_free(&event); + + printf("Initctx - GSS name => "); + c = scanf("%511s", gssid); + if (c == EOF) { + return; + } + + snprintf(contextname, sizeof(contextname), "gsstest.context.%d.", + (int)time(NULL)); + + printf("Initctx - context name we're using: %s\n", contextname); + + printf("Negotiating GSSAPI context: "); + printf("%s", gssid); + printf("\n"); + + /* + * Setup a GSSAPI context with the server + */ + dns_fixedname_init(&servername); + isc_buffer_init(&buf, contextname, strlen(contextname)); + isc_buffer_add(&buf, strlen(contextname)); + result = dns_name_fromtext(dns_fixedname_name(&servername), &buf, + dns_rootname, 0, NULL); + CHECK("dns_name_fromtext", result); + + /* Make name happen */ + dns_fixedname_init(&gssname); + isc_buffer_init(&buf, gssid, strlen(gssid)); + isc_buffer_add(&buf, strlen(gssid)); + result = dns_name_fromtext(dns_fixedname_name(&gssname), &buf, + dns_rootname, 0, NULL); + CHECK("dns_name_fromtext", result); + + query = NULL; + dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query); + + printf("Calling gss_init_sec_context()\n"); + gssctx = GSS_C_NO_CONTEXT; + result = dns_tkey_buildgssquery(query, dns_fixedname_name(&servername), + dns_fixedname_name(&gssname), NULL, + 36000, &gssctx, true, mctx, NULL); + CHECK("dns_tkey_buildgssquery", result); + + printf("Sending context token to server\n"); + request = NULL; + result = dns_request_create(requestmgr, query, &address, 0, NULL, + TIMEOUT, task, initctx2, query, &request); + CHECK("dns_request_create", result); + + return; +end: + event = isc_event_allocate(mctx, (void *)1, 1, console, NULL, + sizeof(*event)); + isc_task_send(task, &event); + return; +} + +static void +setup(void) { + for (;;) { + char serveraddress[512]; + struct in_addr inaddr; + int c; + + printf("Server IP => "); + c = scanf("%511s", serveraddress); + + if (c == EOF || strcmp(serveraddress, "quit") == 0) { + isc_app_shutdown(); + return; + } + + if (inet_pton(AF_INET, serveraddress, &inaddr) == 1) { + isc_sockaddr_fromin(&address, &inaddr, PORT); + return; + } + } +} + +int +main(int argc, char *argv[]) { + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_timermgr_t *timermgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_socket_t *sock = NULL; + unsigned int attrs, attrmask; + isc_sockaddr_t bind_any; + dns_dispatchmgr_t *dispatchmgr = NULL; + dns_dispatch_t *dispatchv4 = NULL; + dns_view_t *view = NULL; + isc_task_t *task = NULL; + isc_log_t *lctx = NULL; + isc_logconfig_t *lcfg = NULL; + isc_logdestination_t destination; + + UNUSED(argv); + UNUSED(argc); + + RUNCHECK(isc_app_start()); + + dns_result_register(); + + mctx = NULL; + isc_mem_create(&mctx); + + isc_log_create(mctx, &lctx, &lcfg); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + /* + * Create and install the default channel. + */ + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, ISC_LOG_PRINTTIME); + + RUNCHECK(isc_log_usechannel(lcfg, "_default", NULL, NULL)); + + isc_log_setdebuglevel(lctx, 9); + + RUNCHECK(dst_lib_init(mctx, NULL)); + + RUNCHECK(isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr)); + RUNCHECK(isc_task_create(taskmgr, 0, &task)); + RUNCHECK(isc_timermgr_create(mctx, &timermgr)); + RUNCHECK(isc_socketmgr_create(mctx, &socketmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + isc_sockaddr_any(&bind_any); + attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | + DNS_DISPATCHATTR_IPV4; + attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP | + DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; + RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any, + 4096, 4, 2, 3, 5, attrs, attrmask, + &dispatchv4)); + RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, + dispatchmgr, dispatchv4, NULL, + &requestmgr)); + + RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); + + RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); + dns_view_setkeyring(view, ring); + + RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, + &sock)); + + setup(); + + RUNCHECK(isc_app_onrun(mctx, task, console, NULL)); + + (void)isc_app_run(); + + if (tsigkey) { + dns_tsigkey_detach(&tsigkey); + } + + dns_requestmgr_shutdown(requestmgr); + dns_requestmgr_detach(&requestmgr); + + dns_dispatch_detach(&dispatchv4); + dns_dispatchmgr_destroy(&dispatchmgr); + + isc_timermgr_destroy(&timermgr); + + isc_task_detach(&task); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_socket_detach(&sock); + isc_socketmgr_destroy(&socketmgr); + + isc_mem_stats(mctx, stdout); + + dns_view_detach(&view); + + dst_lib_destroy(); + + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + isc_app_finish(); + + return (0); +} +#else /* ifdef GSSAPI */ +int +main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + fprintf(stderr, "R:GSSAPIONLY\n"); + return (0); +} +#endif /* ifdef GSSAPI */ diff --git a/bin/tests/optional/inter_test.c b/bin/tests/optional/inter_test.c new file mode 100644 index 0000000..32fbb2e --- /dev/null +++ b/bin/tests/optional/inter_test.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include + +#include +#include +#include +#include + +int +main(int argc, char **argv) { + isc_mem_t *mctx = NULL; + isc_interfaceiter_t *iter = NULL; + isc_interface_t ifdata; + isc_result_t result; + const char *res; + char buf[128]; + + UNUSED(argc); + UNUSED(argv); + + isc_mem_create(&mctx); + result = isc_interfaceiter_create(mctx, &iter); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + result = isc_interfaceiter_first(iter); + while (result == ISC_R_SUCCESS) { + result = isc_interfaceiter_current(iter, &ifdata); + if (result != ISC_R_SUCCESS) { + fprintf(stdout, "isc_interfaceiter_current: %s", + isc_result_totext(result)); + continue; + } + fprintf(stdout, "%s %u %x\n", ifdata.name, ifdata.af, + ifdata.flags); + INSIST(ifdata.af == AF_INET || ifdata.af == AF_INET6); + res = inet_ntop(ifdata.af, &ifdata.address.type, buf, + sizeof(buf)); + if (ifdata.address.zone != 0) { + fprintf(stdout, "address = %s (zone %u)\n", + res == NULL ? "BAD" : res, ifdata.address.zone); + } else { + fprintf(stdout, "address = %s\n", + res == NULL ? "BAD" : res); + } + INSIST(ifdata.address.family == ifdata.af); + res = inet_ntop(ifdata.af, &ifdata.netmask.type, buf, + sizeof(buf)); + fprintf(stdout, "netmask = %s\n", res == NULL ? "BAD" : res); + INSIST(ifdata.netmask.family == ifdata.af); + if ((ifdata.flags & INTERFACE_F_POINTTOPOINT) != 0) { + res = inet_ntop(ifdata.af, &ifdata.dstaddress.type, buf, + sizeof(buf)); + fprintf(stdout, "dstaddress = %s\n", + res == NULL ? "BAD" : res); + + INSIST(ifdata.dstaddress.family == ifdata.af); + } + result = isc_interfaceiter_next(iter); + if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) { + fprintf(stdout, "isc_interfaceiter_next: %s", + isc_result_totext(result)); + continue; + } + } + isc_interfaceiter_destroy(&iter); + + fprintf(stdout, "\nPass 2\n\n"); + + result = isc_interfaceiter_create(mctx, &iter); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + result = isc_interfaceiter_first(iter); + while (result == ISC_R_SUCCESS) { + result = isc_interfaceiter_current(iter, &ifdata); + if (result != ISC_R_SUCCESS) { + fprintf(stdout, "isc_interfaceiter_current: %s", + isc_result_totext(result)); + continue; + } + fprintf(stdout, "%s %u %x\n", ifdata.name, ifdata.af, + ifdata.flags); + INSIST(ifdata.af == AF_INET || ifdata.af == AF_INET6); + res = inet_ntop(ifdata.af, &ifdata.address.type, buf, + sizeof(buf)); + if (ifdata.address.zone != 0) { + fprintf(stdout, "address = %s (zone %u)\n", + res == NULL ? "BAD" : res, ifdata.address.zone); + } else { + fprintf(stdout, "address = %s\n", + res == NULL ? "BAD" : res); + } + INSIST(ifdata.address.family == ifdata.af); + res = inet_ntop(ifdata.af, &ifdata.netmask.type, buf, + sizeof(buf)); + fprintf(stdout, "netmask = %s\n", res == NULL ? "BAD" : res); + INSIST(ifdata.netmask.family == ifdata.af); + if ((ifdata.flags & INTERFACE_F_POINTTOPOINT) != 0) { + res = inet_ntop(ifdata.af, &ifdata.dstaddress.type, buf, + sizeof(buf)); + fprintf(stdout, "dstaddress = %s\n", + res == NULL ? "BAD" : res); + + INSIST(ifdata.dstaddress.family == ifdata.af); + } + result = isc_interfaceiter_next(iter); + if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) { + fprintf(stdout, "isc_interfaceiter_next: %s", + isc_result_totext(result)); + continue; + } + } + isc_interfaceiter_destroy(&iter); +cleanup: + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/lex_test.c b/bin/tests/optional/lex_test.c new file mode 100644 index 0000000..e0e88f7 --- /dev/null +++ b/bin/tests/optional/lex_test.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include +#include + +isc_mem_t *mctx; +isc_lex_t *lex; + +isc_lexspecials_t specials; + +static void +print_token(isc_token_t *tokenp, FILE *stream) { + switch (tokenp->type) { + case isc_tokentype_unknown: + fprintf(stream, "UNKNOWN"); + break; + case isc_tokentype_string: + fprintf(stream, "STRING %.*s", + (int)tokenp->value.as_region.length, + tokenp->value.as_region.base); + break; + case isc_tokentype_number: + fprintf(stream, "NUMBER %lu", tokenp->value.as_ulong); + break; + case isc_tokentype_qstring: + fprintf(stream, "QSTRING \"%.*s\"", + (int)tokenp->value.as_region.length, + tokenp->value.as_region.base); + break; + case isc_tokentype_eol: + fprintf(stream, "EOL"); + break; + case isc_tokentype_eof: + fprintf(stream, "EOF"); + break; + case isc_tokentype_initialws: + fprintf(stream, "INITIALWS"); + break; + case isc_tokentype_special: + fprintf(stream, "SPECIAL %c", tokenp->value.as_char); + break; + case isc_tokentype_nomore: + fprintf(stream, "NOMORE"); + break; + default: + FATAL_ERROR(__FILE__, __LINE__, "Unexpected type %d", + tokenp->type); + } +} + +int +main(int argc, char *argv[]) { + isc_token_t token; + isc_result_t result; + int quiet = 0; + int c; + int masterfile = 1; + int stats = 0; + unsigned int options = 0; + int done = 0; + + while ((c = isc_commandline_parse(argc, argv, "qmcs")) != -1) { + switch (c) { + case 'q': + quiet = 1; + break; + case 'm': + masterfile = 1; + break; + case 'c': + masterfile = 0; + break; + case 's': + stats = 1; + break; + } + } + + isc_mem_create(&mctx); + RUNTIME_CHECK(isc_lex_create(mctx, 256, &lex) == ISC_R_SUCCESS); + + if (masterfile) { + /* Set up to lex DNS master file. */ + + specials['('] = 1; + specials[')'] = 1; + specials['"'] = 1; + isc_lex_setspecials(lex, specials); + options = ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE | + ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING | + ISC_LEXOPT_NOMORE; + isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); + } else { + /* Set up to lex DNS config file. */ + + specials['{'] = 1; + specials['}'] = 1; + specials[';'] = 1; + specials['/'] = 1; + specials['"'] = 1; + specials['!'] = 1; + specials['*'] = 1; + isc_lex_setspecials(lex, specials); + options = ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING | + ISC_LEXOPT_NUMBER | ISC_LEXOPT_NOMORE; + isc_lex_setcomments(lex, (ISC_LEXCOMMENT_C | + ISC_LEXCOMMENT_CPLUSPLUS | + ISC_LEXCOMMENT_SHELL)); + } + + RUNTIME_CHECK(isc_lex_openstream(lex, stdin) == ISC_R_SUCCESS); + + while ((result = isc_lex_gettoken(lex, options, &token)) == + ISC_R_SUCCESS && + !done) + { + if (!quiet) { + char *name = isc_lex_getsourcename(lex); + print_token(&token, stdout); + printf(" line = %lu file = %s\n", + isc_lex_getsourceline(lex), + (name == NULL) ? "" : name); + } + if (token.type == isc_tokentype_eof) { + isc_lex_close(lex); + } + if (token.type == isc_tokentype_nomore) { + done = 1; + } + } + if (result != ISC_R_SUCCESS) { + printf("Result: %s\n", isc_result_totext(result)); + } + + isc_lex_close(lex); + isc_lex_destroy(&lex); + if (!quiet && stats) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/lfsr_test.c b/bin/tests/optional/lfsr_test.c new file mode 100644 index 0000000..c1c99f0 --- /dev/null +++ b/bin/tests/optional/lfsr_test.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include + +#include +#include +#include + +uint32_t state[1024 * 64]; + +int +main(int argc, char **argv) { + isc_lfsr_t lfsr1, lfsr2; + int i; + uint32_t temp; + + UNUSED(argc); + UNUSED(argv); + + /* + * Verify that returned values are reproducible. + */ + isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr1, &state[i], 4); + printf("lfsr1: state[%2d] = %08x\n", i, state[i]); + } + isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr1, &temp, 4); + if (state[i] != temp) { + printf("lfsr1: state[%2d] = %08x, " + "but new state is %08x\n", + i, state[i], temp); + } + } + + /* + * Now do the same with skipping. + */ + isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr1, &state[i], 4); + isc_lfsr_skip(&lfsr1, 32); + printf("lfsr1: state[%2d] = %08x\n", i, state[i]); + } + isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr1, &temp, 4); + isc_lfsr_skip(&lfsr1, 32); + if (state[i] != temp) { + printf("lfsr1: state[%2d] = %08x, " + "but new state is %08x\n", + i, state[i], temp); + } + } + + /* + * Try to find the period of the LFSR. + * + * x^16 + x^5 + x^3 + x^2 + 1 + */ + isc_lfsr_init(&lfsr2, 0, 16, 0x00008016U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr2, &state[i], 4); + printf("lfsr2: state[%2d] = %08x\n", i, state[i]); + } + isc_lfsr_init(&lfsr2, 0, 16, 0x00008016U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr2, &temp, 4); + if (state[i] != temp) { + printf("lfsr2: state[%2d] = %08x, " + "but new state is %08x\n", + i, state[i], temp); + } + } + + return (0); +} diff --git a/bin/tests/optional/log_test.c b/bin/tests/optional/log_test.c new file mode 100644 index 0000000..006b1e2 --- /dev/null +++ b/bin/tests/optional/log_test.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define TEST_FILE "/tmp/test_log" +#define SYSLOG_FILE "/var/log/daemon.log" +#define FILE_VERSIONS 10 + +char usage[] = "Usage: %s [-m] [-s syslog_logfile] [-r file_versions]\n"; + +#define CHECK(expr) \ + result = expr; \ + if (result != ISC_R_SUCCESS) { \ + fprintf(stderr, "%s: " #expr "%s: exiting\n", progname, \ + isc_result_totext(result)); \ + } + +int +main(int argc, char **argv) { + const char *progname, *syslog_file, *message; + int ch, i, file_versions, stderr_line; + bool show_final_mem = false; + isc_log_t *lctx; + isc_logconfig_t *lcfg; + isc_mem_t *mctx; + isc_result_t result; + isc_logdestination_t destination; + const isc_logcategory_t *category; + const isc_logmodule_t *module; + + progname = strrchr(*argv, '/'); + if (progname != NULL) { + progname++; + } else { + progname = *argv; + } + + syslog_file = SYSLOG_FILE; + file_versions = FILE_VERSIONS; + + while ((ch = isc_commandline_parse(argc, argv, "ms:r:")) != -1) { + switch (ch) { + case 'm': + show_final_mem = true; + break; + case 's': + syslog_file = isc_commandline_argument; + break; + case 'r': + file_versions = atoi(isc_commandline_argument); + if (file_versions < 0 && + file_versions != ISC_LOG_ROLLNEVER && + file_versions != ISC_LOG_ROLLINFINITE) + { + fprintf(stderr, + "%s: file rotations must be " + "%d (ISC_LOG_ROLLNEVER),\n\t" + "%d (ISC_LOG_ROLLINFINITE) " + "or > 0\n", + progname, ISC_LOG_ROLLNEVER, + ISC_LOG_ROLLINFINITE); + exit(1); + } + break; + case '?': + fprintf(stderr, usage, progname); + exit(1); + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + POST(argv); + + if (argc > 0) { + fprintf(stderr, usage, progname); + exit(1); + } + + fprintf(stderr, "EXPECT:\n%s%d%s%s%s", + "8 lines to stderr (first 4 numbered, #3 repeated)\n", + file_versions == 0 || file_versions == ISC_LOG_ROLLNEVER ? 1 + : file_versions > 0 ? file_versions + 1 + : FILE_VERSIONS + 1, + " " TEST_FILE " files, and\n", "2 lines to syslog\n", + "lines ending with exclamation marks are errors\n\n"); + + isc_log_opensyslog(progname, LOG_PID, LOG_DAEMON); + + mctx = NULL; + lctx = NULL; + lcfg = NULL; + + isc_mem_create(&mctx); + isc_log_create(mctx, &lctx, &lcfg); + + isc_log_settag(lcfg, progname); + + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + /* + * Test isc_log_categorybyname and isc_log_modulebyname. + */ + category = isc_log_categorybyname(lctx, "notify"); + if (category != NULL) { + fprintf(stderr, "%s category found. (expected)\n", + category->name); + } else { + fprintf(stderr, "notify category not found!\n"); + } + + module = isc_log_modulebyname(lctx, "xyzzy"); + if (module != NULL) { + fprintf(stderr, "%s module found!\n", module->name); + } else { + fprintf(stderr, "xyzzy module not found. (expected)\n"); + } + + /* + * Create a file channel to test file opening, size limiting and + * version rolling. + */ + + destination.file.name = TEST_FILE; + destination.file.maximum_size = 1; + destination.file.versions = file_versions; + + isc_log_createchannel( + lcfg, "file_test", ISC_LOG_TOFILE, ISC_LOG_INFO, &destination, + ISC_LOG_PRINTTIME | ISC_LOG_PRINTTAG | ISC_LOG_PRINTLEVEL | + ISC_LOG_PRINTCATEGORY | ISC_LOG_PRINTMODULE); + + /* + * Create a dynamic debugging channel to a file descriptor. + */ + destination.file.stream = stderr; + + isc_log_createchannel(lcfg, "debug_test", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, + ISC_LOG_PRINTTIME | ISC_LOG_PRINTLEVEL | + ISC_LOG_DEBUGONLY); + + /* + * Test the usability of the four predefined logging channels. + */ + CHECK(isc_log_usechannel(lcfg, "default_syslog", + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE)); + CHECK(isc_log_usechannel(lcfg, "default_stderr", + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE)); + CHECK(isc_log_usechannel(lcfg, "default_debug", + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE)); + CHECK(isc_log_usechannel(lcfg, "null", DNS_LOGCATEGORY_DATABASE, NULL)); + + /* + * Use the custom channels. + */ + CHECK(isc_log_usechannel(lcfg, "file_test", DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DB)); + + CHECK(isc_log_usechannel(lcfg, "debug_test", DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_RBTDB)); + + fprintf(stderr, "\n==> stderr begin\n"); + + /* + * Write to the internal default by testing both a category for which + * no channel has been specified and a category which was specified + * but not with the named module. + */ + stderr_line = 1; + + isc_log_write(lctx, DNS_LOGCATEGORY_SECURITY, DNS_LOGMODULE_RBT, + ISC_LOG_CRITICAL, "%s (%d)", + "Unspecified category and unspecified module to stderr", + stderr_line++); + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBT, + ISC_LOG_CRITICAL, "%s (%d)", + "Specified category and unspecified module to stderr", + stderr_line++); + + /* + * Write to default_syslog, default_stderr and default_debug. + */ + isc_log_write(lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE, + ISC_LOG_WARNING, "%s (%d twice)", + "Using the predefined channels to syslog+stderr", + stderr_line++); + + /* + * Write to predefined null channel. + */ + isc_log_write(lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_RBTDB, + ISC_LOG_INFO, "This is to null and should not appear!"); + + /* + * Reset the internal default to use syslog instead of stderr, + * and test it. + */ + CHECK(isc_log_usechannel(lcfg, "default_syslog", + ISC_LOGCATEGORY_DEFAULT, NULL)); + isc_log_write(lctx, DNS_LOGCATEGORY_SECURITY, DNS_LOGMODULE_RBT, + ISC_LOG_ERROR, "%s%s", + "This message to the redefined default category should ", + "be second in syslog"); + /* + * Write to the file channel. + */ + if (file_versions >= 0 || file_versions == ISC_LOG_ROLLINFINITE) { + /* + * If file_versions is 0 or ISC_LOG_ROLLINFINITE, write + * the "should not appear" and "should be in file" messages + * to ensure they get rolled. + */ + if (file_versions <= 0) { + file_versions = FILE_VERSIONS; + } else { + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DB, ISC_LOG_NOTICE, + "This should be rolled over " + "and not appear!"); + } + + for (i = file_versions - 1; i >= 0; i--) { + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DB, ISC_LOG_NOTICE, + "should be in file %d/%d", i, + file_versions - 1); + } + + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DB, + ISC_LOG_NOTICE, "should be in base file"); + } else { + file_versions = FILE_VERSIONS; + for (i = 1; i <= file_versions; i++) { + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DB, ISC_LOG_NOTICE, + "This is message %d in the log file", i); + } + } + + /* + * Write a debugging message to a category that has no + * debugging channels for the named module. + */ + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DB, + ISC_LOG_DEBUG(1), + "This debug message should not appear!"); + + /* + * Write debugging messages to a dynamic debugging channel. + */ + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, + "This critical message should " + "not appear because the debug level is 0!"); + + isc_log_setdebuglevel(lctx, 3); + + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_DEBUG(1), "%s (%d)", + "Dynamic debugging to stderr", stderr_line++); + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_DEBUG(5), + "This debug level is too high and should not appear!"); + + /* + * Test out the duplicate filtering using the debug_test channel. + */ + isc_log_setduplicateinterval(lcfg, 10); + message = "This message should appear only once on stderr"; + + isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, "%s", message); + isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, "%s", message); + + isc_log_setduplicateinterval(lcfg, 1); + message = "This message should appear twice on stderr"; + + isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, "%s", message); + sleep(2); + isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, "%s", message); + + /* + * Review where everything went. + * XXXDCL NT + */ + fputc('\n', stderr); + if (system("head " TEST_FILE "*; rm -f " TEST_FILE "*") != 0) { + fprintf(stderr, "system(\"head " TEST_FILE "*; rm -f " TEST_FILE + "*\") failed\n"); + goto cleanup; + } + + /* This is highly system specific. */ + if (freopen(syslog_file, "r", stdin) == NULL) { + fprintf(stderr, "freopen(%s, \"r\", stdin) failed\n", + syslog_file); + goto cleanup; + } + fprintf(stderr, "\n==> %s <==\n", syslog_file); + if (system("tail -2") != 0) { + fprintf(stderr, "system(\"tail -2\") failed\n"); + goto cleanup; + } + fputc('\n', stderr); + +cleanup: + isc_log_destroy(&lctx); + + if (show_final_mem) { + isc_mem_stats(mctx, stderr); + } + + return (0); +} diff --git a/bin/tests/optional/master_test.c b/bin/tests/optional/master_test.c new file mode 100644 index 0000000..1cd6ec7 --- /dev/null +++ b/bin/tests/optional/master_test.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +isc_mem_t *mctx; + +static isc_result_t +print_dataset(void *arg, const dns_name_t *owner, dns_rdataset_t *dataset) { + char buf[64 * 1024]; + isc_buffer_t target; + isc_result_t result; + + UNUSED(arg); + + isc_buffer_init(&target, buf, 64 * 1024); + result = dns_rdataset_totext(dataset, owner, false, false, &target); + if (result == ISC_R_SUCCESS) { + fprintf(stdout, "%.*s\n", (int)target.used, + (char *)target.base); + } else { + fprintf(stdout, "dns_rdataset_totext: %s\n", + dns_result_totext(result)); + } + + return (ISC_R_SUCCESS); +} + +int +main(int argc, char *argv[]) { + isc_result_t result; + dns_name_t origin; + isc_buffer_t source; + isc_buffer_t target; + unsigned char name_buf[255]; + dns_rdatacallbacks_t callbacks; + + UNUSED(argc); + + isc_mem_create(&mctx); + + if (argv[1]) { + isc_buffer_init(&source, argv[1], strlen(argv[1])); + isc_buffer_add(&source, strlen(argv[1])); + isc_buffer_setactive(&source, strlen(argv[1])); + isc_buffer_init(&target, name_buf, 255); + dns_name_init(&origin, NULL); + result = dns_name_fromtext(&origin, &source, dns_rootname, 0, + &target); + if (result != ISC_R_SUCCESS) { + fprintf(stdout, "dns_name_fromtext: %s\n", + dns_result_totext(result)); + exit(1); + } + + dns_rdatacallbacks_init_stdio(&callbacks); + callbacks.add = print_dataset; + + result = dns_master_loadfile( + argv[1], &origin, &origin, dns_rdataclass_in, 0, 0, + &callbacks, NULL, NULL, mctx, dns_masterformat_text, 0); + fprintf(stdout, "dns_master_loadfile: %s\n", + dns_result_totext(result)); + } + return (0); +} diff --git a/bin/tests/optional/mempool_test.c b/bin/tests/optional/mempool_test.c new file mode 100644 index 0000000..b3d04ee --- /dev/null +++ b/bin/tests/optional/mempool_test.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +isc_mem_t *mctx; + +int +main(int argc, char *argv[]) { + void *items1[50]; + void *items2[50]; + void *tmp; + isc_mempool_t *mp1, *mp2; + unsigned int i, j; + + UNUSED(argc); + UNUSED(argv); + + isc_mem_debugging = ISC_MEM_DEBUGRECORD; + + mctx = NULL; + isc_mem_create(&mctx); + + mp1 = NULL; + isc_mempool_create(mctx, 24, &mp1); + + mp2 = NULL; + isc_mempool_create(mctx, 31, &mp2); + + isc_mem_stats(mctx, stderr); + + isc_mempool_setfreemax(mp1, 10); + isc_mempool_setfillcount(mp1, 10); + isc_mempool_setmaxalloc(mp1, 30); + + /* + * Allocate 30 items from the pool. This is our max. + */ + for (i = 0; i < 30; i++) { + items1[i] = isc_mempool_get(mp1); + RUNTIME_CHECK(items1[i] != NULL); + } + + /* + * Try to allocate one more. This should fail. + */ + tmp = isc_mempool_get(mp1); + RUNTIME_CHECK(tmp == NULL); + + /* + * Free the first 11 items. Verify that there are 10 free items on + * the free list (which is our max). + */ + + for (i = 0; i < 11; i++) { + isc_mempool_put(mp1, items1[i]); + items1[i] = NULL; + } + + RUNTIME_CHECK(isc_mempool_getfreecount(mp1) == 10); + RUNTIME_CHECK(isc_mempool_getallocated(mp1) == 19); + + isc_mem_stats(mctx, stderr); + + /* + * Now, beat up on mp2 for a while. Allocate 50 items, then free + * them, then allocate 50 more, etc. + */ + isc_mempool_setfreemax(mp2, 25); + isc_mempool_setfillcount(mp2, 25); + for (j = 0; j < 5000; j++) { + for (i = 0; i < 50; i++) { + items2[i] = isc_mempool_get(mp2); + RUNTIME_CHECK(items2[i] != NULL); + } + for (i = 0; i < 50; i++) { + isc_mempool_put(mp2, items2[i]); + items2[i] = NULL; + } + } + + /* + * Free all the other items and blow away this pool. + */ + for (i = 11; i < 30; i++) { + isc_mempool_put(mp1, items1[i]); + items1[i] = NULL; + } + + isc_mempool_destroy(&mp1); + + isc_mem_stats(mctx, stderr); + + isc_mempool_destroy(&mp2); + + isc_mem_stats(mctx, stderr); + + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/name_test.c b/bin/tests/optional/name_test.c new file mode 100644 index 0000000..4c37441 --- /dev/null +++ b/bin/tests/optional/name_test.c @@ -0,0 +1,365 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +static void +print_wirename(isc_region_t *name) { + unsigned char *ccurr, *cend; + + if (name->length == 0) { + printf("\n"); + return; + } + ccurr = name->base; + cend = ccurr + name->length; + while (ccurr != cend) { + printf("%02x ", *ccurr++); + } + printf("\n"); +} + +static void +print_name(dns_name_t *name) { + isc_result_t result; + isc_buffer_t source; + isc_region_t r; + char s[1000]; + + isc_buffer_init(&source, s, sizeof(s)); + if (dns_name_countlabels(name) > 0) { + result = dns_name_totext(name, false, &source); + } else { + result = ISC_R_SUCCESS; + } + if (result == ISC_R_SUCCESS) { + isc_buffer_usedregion(&source, &r); + if (r.length > 0) { + printf("%.*s\n", (int)r.length, r.base); + } else { + printf("\n"); + } + } else { + printf("error: %s\n", dns_result_totext(result)); + } +} + +int +main(int argc, char *argv[]) { + char s[1000]; + isc_result_t result; + dns_fixedname_t wname, wname2, oname, compname, downname; + isc_buffer_t source; + isc_region_t r; + dns_name_t *name, *comp, *down; + const dns_name_t *origin; + unsigned int downcase = 0; + size_t len; + bool quiet = false; + bool concatenate = false; + bool got_name = false; + bool check_absolute = false; + bool check_wildcard = false; + bool test_downcase = false; + bool inplace = false; + bool want_split = false; + unsigned int labels, split_label = 0; + dns_fixedname_t fprefix, fsuffix; + dns_name_t *prefix, *suffix; + int ch; + + while ((ch = isc_commandline_parse(argc, argv, "acdiqs:w")) != -1) { + switch (ch) { + case 'a': + check_absolute = true; + break; + case 'c': + concatenate = true; + break; + case 'd': + test_downcase = true; + break; + case 'i': + inplace = true; + break; + case 'q': + quiet = true; + break; + case 's': + want_split = true; + split_label = atoi(isc_commandline_argument); + break; + case 'w': + check_wildcard = true; + break; + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc > 0) { + if (strcasecmp("none", argv[0]) == 0) { + origin = NULL; + } else { + len = strlen(argv[0]); + isc_buffer_init(&source, argv[0], len); + isc_buffer_add(&source, len); + dns_fixedname_init(&oname); + result = dns_name_fromtext(dns_fixedname_name(&oname), + &source, dns_rootname, 0, + NULL); + if (result != 0) { + fprintf(stderr, + "dns_name_fromtext() failed: %s\n", + dns_result_totext(result)); + exit(1); + } + origin = dns_fixedname_name(&oname); + } + } else if (concatenate) { + origin = NULL; + } else { + origin = dns_rootname; + } + + if (argc >= 1) { + if (strcasecmp("none", argv[1]) == 0) { + comp = NULL; + } else { + len = strlen(argv[1]); + isc_buffer_init(&source, argv[1], len); + isc_buffer_add(&source, len); + comp = dns_fixedname_initname(&compname); + result = dns_name_fromtext(comp, &source, origin, 0, + NULL); + if (result != 0) { + fprintf(stderr, + "dns_name_fromtext() failed: %s\n", + dns_result_totext(result)); + exit(1); + } + } + } else { + comp = NULL; + } + + name = dns_fixedname_initname(&wname); + dns_fixedname_init(&wname2); + while (fgets(s, sizeof(s), stdin) != NULL) { + len = strlen(s); + if (len > 0U && s[len - 1] == '\n') { + s[len - 1] = '\0'; + len--; + } + isc_buffer_init(&source, s, len); + isc_buffer_add(&source, len); + + if (len > 0U) { + result = dns_name_fromtext(name, &source, origin, + downcase, NULL); + } else { + if (name == dns_fixedname_name(&wname)) { + dns_fixedname_init(&wname); + } else { + dns_fixedname_init(&wname2); + } + result = ISC_R_SUCCESS; + } + + if (result != ISC_R_SUCCESS) { + printf("%s\n", dns_result_totext(result)); + if (name == dns_fixedname_name(&wname)) { + dns_fixedname_init(&wname); + } else { + dns_fixedname_init(&wname2); + } + continue; + } + + if (check_absolute && dns_name_countlabels(name) > 0) { + if (dns_name_isabsolute(name)) { + printf("absolute\n"); + } else { + printf("relative\n"); + } + } + if (check_wildcard && dns_name_countlabels(name) > 0) { + if (dns_name_iswildcard(name)) { + printf("wildcard\n"); + } else { + printf("not wildcard\n"); + } + } + dns_name_toregion(name, &r); + if (!quiet) { + print_wirename(&r); + printf("%u labels, %u bytes.\n", + dns_name_countlabels(name), r.length); + } + + if (concatenate) { + if (got_name) { + printf("Concatenating.\n"); + result = dns_name_concatenate( + dns_fixedname_name(&wname), + dns_fixedname_name(&wname2), + dns_fixedname_name(&wname2), NULL); + name = dns_fixedname_name(&wname2); + if (result == ISC_R_SUCCESS) { + if (check_absolute && + dns_name_countlabels(name) > 0) + { + if (dns_name_isabsolute(name)) { + printf("absolute\n"); + } else { + printf("relative\n"); + } + } + if (check_wildcard && + dns_name_countlabels(name) > 0) + { + if (dns_name_iswildcard(name)) { + printf("wildcard\n"); + } else { + printf("not " + "wildcard\n"); + } + } + dns_name_toregion(name, &r); + if (!quiet) { + print_wirename(&r); + printf("%u labels, " + "%u bytes.\n", + dns_name_countlabels( + name), + r.length); + } + } else { + printf("%s\n", + dns_result_totext(result)); + } + got_name = false; + } else { + got_name = true; + } + } + isc_buffer_init(&source, s, sizeof(s)); + if (dns_name_countlabels(name) > 0) { + result = dns_name_totext(name, false, &source); + } else { + result = ISC_R_SUCCESS; + } + if (result == ISC_R_SUCCESS) { + isc_buffer_usedregion(&source, &r); + if (r.length > 0) { + printf("%.*s\n", (int)r.length, r.base); + } else { + printf("\n"); + } + if (!quiet) { + printf("%u bytes.\n", source.used); + } + } else { + printf("%s\n", dns_result_totext(result)); + } + + if (test_downcase) { + if (inplace) { + down = name; + } else { + down = dns_fixedname_initname(&downname); + } + result = dns_name_downcase(name, down, NULL); + INSIST(result == ISC_R_SUCCESS); + if (!quiet) { + dns_name_toregion(down, &r); + print_wirename(&r); + printf("%u labels, %u bytes.\n", + dns_name_countlabels(down), r.length); + } + isc_buffer_init(&source, s, sizeof(s)); + print_name(down); + } + + if (comp != NULL && dns_name_countlabels(name) > 0) { + int order; + unsigned int nlabels; + dns_namereln_t namereln; + + namereln = dns_name_fullcompare(name, comp, &order, + &nlabels); + if (!quiet) { + if (order < 0) { + printf("<"); + } else if (order > 0) { + printf(">"); + } else { + printf("="); + } + switch (namereln) { + case dns_namereln_contains: + printf(", contains"); + break; + case dns_namereln_subdomain: + printf(", subdomain"); + break; + case dns_namereln_commonancestor: + printf(", common ancestor"); + break; + default: + break; + } + if (namereln != dns_namereln_none && + namereln != dns_namereln_equal) + { + printf(", nlabels = %u", nlabels); + } + printf("\n"); + } + printf("dns_name_equal() returns %s\n", + dns_name_equal(name, comp) ? "TRUE" : "FALSE"); + } + + labels = dns_name_countlabels(name); + if (want_split && split_label < labels) { + prefix = dns_fixedname_initname(&fprefix); + suffix = dns_fixedname_initname(&fsuffix); + printf("splitting at label %u: ", split_label); + dns_name_split(name, split_label, prefix, suffix); + printf("\n prefix = "); + print_name(prefix); + printf(" suffix = "); + print_name(suffix); + } + + if (concatenate) { + if (got_name) { + name = dns_fixedname_name(&wname2); + } else { + name = dns_fixedname_name(&wname); + } + } + } + + return (0); +} diff --git a/bin/tests/optional/nsecify.c b/bin/tests/optional/nsecify.c new file mode 100644 index 0000000..357b47f --- /dev/null +++ b/bin/tests/optional/nsecify.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static isc_mem_t *mctx = NULL; + +ISC_PLATFORM_NORETURN_PRE static void +fatal(const char *message) ISC_PLATFORM_NORETURN_POST; + +static void +fatal(const char *message) { + fprintf(stderr, "%s\n", message); + exit(1); +} + +static void +check_result(isc_result_t result, const char *message) { + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "%s: %s\n", message, isc_result_totext(result)); + exit(1); + } +} + +static bool +active_node(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) { + dns_rdatasetiter_t *rdsiter; + bool active = false; + isc_result_t result; + dns_rdataset_t rdataset; + + dns_rdataset_init(&rdataset); + rdsiter = NULL; + result = dns_db_allrdatasets(db, node, version, 0, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &rdataset); + if (rdataset.type != dns_rdatatype_nsec) { + active = true; + } + dns_rdataset_disassociate(&rdataset); + if (!active) { + result = dns_rdatasetiter_next(rdsiter); + } else { + result = ISC_R_NOMORE; + } + } + if (result != ISC_R_NOMORE) { + fatal("rdataset iteration failed"); + } + dns_rdatasetiter_destroy(&rdsiter); + + if (!active) { + /* + * Make sure there is no NSEC record for this node. + */ + result = dns_db_deleterdataset(db, node, version, + dns_rdatatype_nsec, 0); + if (result == DNS_R_UNCHANGED) { + result = ISC_R_SUCCESS; + } + check_result(result, "dns_db_deleterdataset"); + } + + return (active); +} + +static isc_result_t +next_active(dns_db_t *db, dns_dbversion_t *version, dns_dbiterator_t *dbiter, + dns_name_t *name, dns_dbnode_t **nodep) { + isc_result_t result; + bool active; + + do { + active = false; + result = dns_dbiterator_current(dbiter, nodep, name); + if (result == ISC_R_SUCCESS) { + active = active_node(db, version, *nodep); + if (!active) { + dns_db_detachnode(db, nodep); + result = dns_dbiterator_next(dbiter); + } + } + } while (result == ISC_R_SUCCESS && !active); + + return (result); +} + +static void +nsecify(char *filename) { + isc_result_t result; + dns_db_t *db; + dns_dbversion_t *wversion; + dns_dbnode_t *node, *nextnode; + const char *origintext; + dns_fixedname_t fname, fnextname; + dns_name_t *name, *nextname, *target; + isc_buffer_t b; + size_t len; + dns_dbiterator_t *dbiter; + char newfilename[1024]; + + name = dns_fixedname_initname(&fname); + nextname = dns_fixedname_initname(&fnextname); + + origintext = strrchr(filename, '/'); + if (origintext == NULL) { + origintext = filename; + } else { + origintext++; /* Skip '/'. */ + } + len = strlen(origintext); + isc_buffer_constinit(&b, origintext, len); + isc_buffer_add(&b, len); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + check_result(result, "dns_name_fromtext()"); + + db = NULL; + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, + dns_rdataclass_in, 0, NULL, &db); + check_result(result, "dns_db_create()"); + result = dns_db_load(db, filename, dns_masterformat_text, 0); + if (result == DNS_R_SEENINCLUDE) { + result = ISC_R_SUCCESS; + } + check_result(result, "dns_db_load()"); + wversion = NULL; + result = dns_db_newversion(db, &wversion); + check_result(result, "dns_db_newversion()"); + dbiter = NULL; + result = dns_db_createiterator(db, 0, &dbiter); + check_result(result, "dns_db_createiterator()"); + result = dns_dbiterator_first(dbiter); + check_result(result, "dns_dbiterator_first()"); + node = NULL; + result = next_active(db, wversion, dbiter, name, &node); + while (result == ISC_R_SUCCESS) { + nextnode = NULL; + result = dns_dbiterator_next(dbiter); + if (result == ISC_R_SUCCESS) { + result = next_active(db, wversion, dbiter, nextname, + &nextnode); + } + if (result == ISC_R_SUCCESS) { + target = nextname; + } else if (result == ISC_R_NOMORE) { + target = dns_db_origin(db); + } else { + target = NULL; /* Make compiler happy. */ + fatal("db iteration failed"); + } + dns_nsec_build(db, wversion, node, target, 3600); /* XXX BEW */ + dns_db_detachnode(db, &node); + node = nextnode; + } + if (result != ISC_R_NOMORE) { + fatal("db iteration failed"); + } + dns_dbiterator_destroy(&dbiter); + /* + * XXXRTH For now, we don't increment the SOA serial. + */ + dns_db_closeversion(db, &wversion, true); + len = strlen(filename); + if (len + 4 + 1 > sizeof(newfilename)) { + fatal("filename too long"); + } + snprintf(newfilename, sizeof(newfilename), "%s.new", filename); + result = dns_db_dump(db, NULL, newfilename); + check_result(result, "dns_db_dump"); + dns_db_detach(&db); +} + +int +main(int argc, char *argv[]) { + int i; + + dns_result_register(); + + isc_mem_create(&mctx); + + argc--; + argv++; + + for (i = 0; i < argc; i++) { + nsecify(argv[i]); + } + + /* isc_mem_stats(mctx, stdout); */ + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/ratelimiter_test.c b/bin/tests/optional/ratelimiter_test.c new file mode 100644 index 0000000..c8972f8 --- /dev/null +++ b/bin/tests/optional/ratelimiter_test.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +isc_ratelimiter_t *rlim = NULL; +isc_nm_t *netmgr = NULL; +isc_taskmgr_t *taskmgr = NULL; +isc_timermgr_t *timermgr = NULL; +isc_task_t *g_task = NULL; +isc_mem_t *mctx = NULL; + +static void +utick(isc_task_t *task, isc_event_t *event); +static void +shutdown_rl(isc_task_t *task, isc_event_t *event); +static void +shutdown_all(isc_task_t *task, isc_event_t *event); + +typedef struct { + int milliseconds; + void (*fun)(isc_task_t *, isc_event_t *); +} schedule_t; + +schedule_t schedule[] = { { 100, utick }, { 200, utick }, + { 300, utick }, { 3000, utick }, + { 3100, utick }, { 3200, utick }, + { 3300, shutdown_rl }, { 5000, utick }, + { 6000, shutdown_all } }; + +#define NEVENTS (int)(sizeof(schedule) / sizeof(schedule[0])) + +isc_timer_t *timers[NEVENTS]; + +static void +ltick(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + printf("** ltick%s **\n", + (event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 ? " (" + "canceled" + ")" + : ""); + isc_event_free(&event); +} + +static void +utick(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + UNUSED(task); + event->ev_action = ltick; + event->ev_sender = NULL; + result = isc_ratelimiter_enqueue(rlim, g_task, &event); + printf("enqueue: %s\n", result == ISC_R_SUCCESS ? "ok" : "failed"); +} + +static void +shutdown_rl(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + UNUSED(event); + printf("shutdown ratelimiter\n"); + isc_ratelimiter_shutdown(rlim); +} + +static void +shutdown_all(isc_task_t *task, isc_event_t *event) { + int i; + UNUSED(task); + UNUSED(event); + printf("shutdown all\n"); + for (i = 0; i < NEVENTS; i++) { + isc_timer_destroy(&timers[i]); + } + + isc_app_shutdown(); +} + +int +main(int argc, char *argv[]) { + isc_interval_t linterval; + int i; + + UNUSED(argc); + UNUSED(argv); + + isc_app_start(); + isc_interval_set(&linterval, 1, 0); + + isc_mem_create(&mctx); + RUNTIME_CHECK(isc_managers_create(mctx, 3, 0, &netmgr, &taskmgr) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &g_task) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_ratelimiter_create(mctx, timermgr, g_task, &rlim) == + ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_ratelimiter_setinterval(rlim, &linterval) == + ISC_R_SUCCESS); + + for (i = 0; i < NEVENTS; i++) { + isc_interval_t uinterval; + int ms = schedule[i].milliseconds; + isc_interval_set(&uinterval, ms / 1000, (ms % 1000) * 1000000); + timers[i] = NULL; + RUNTIME_CHECK(isc_timer_create(timermgr, isc_timertype_once, + NULL, &uinterval, g_task, + schedule[i].fun, NULL, + &timers[i]) == ISC_R_SUCCESS); + } + + isc_app_run(); + + isc_task_destroy(&g_task); + + isc_ratelimiter_detach(&rlim); + + isc_timermgr_destroy(&timermgr); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_mem_stats(mctx, stdout); + + isc_app_finish(); + return (0); +} diff --git a/bin/tests/optional/rbt_test.c b/bin/tests/optional/rbt_test.c new file mode 100644 index 0000000..735c229 --- /dev/null +++ b/bin/tests/optional/rbt_test.c @@ -0,0 +1,432 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +const char *progname; +isc_mem_t *mctx; + +#define DNSNAMELEN 255 + +static dns_name_t * +create_name(char *s) { + int length; + isc_result_t result; + isc_buffer_t source, target; + static dns_name_t *name; + + if (s == NULL || *s == '\0') { + printf("missing name argument\n"); + return (NULL); + } + + length = strlen(s); + + isc_buffer_init(&source, s, length); + isc_buffer_add(&source, length); + + /* + * It isn't really necessary in this program to create individual + * memory spaces for each name structure and its associated character + * string. It is done here to provide a relatively easy way to test + * the callback from dns_rbt_deletename that is supposed to free the + * data associated with a node. + * + * The buffer for the actual name will immediately follow the + * name structure. + */ + name = isc_mem_get(mctx, sizeof(*name) + DNSNAMELEN); + + dns_name_init(name, NULL); + isc_buffer_init(&target, name + 1, DNSNAMELEN); + + result = dns_name_fromtext(name, &source, dns_rootname, 0, &target); + + if (result != ISC_R_SUCCESS) { + printf("dns_name_fromtext(%s) failed: %s\n", s, + dns_result_totext(result)); + return (NULL); + } + + return (name); +} + +static void +delete_name(void *data, void *arg) { + dns_name_t *name; + + UNUSED(arg); + name = data; + isc_mem_put(mctx, name, sizeof(*name) + DNSNAMELEN); +} + +static void +print_name(dns_name_t *name) { + isc_buffer_t target; + char buffer[1024]; + + isc_buffer_init(&target, buffer, sizeof(buffer)); + + /* + * false means absolute names have the final dot added. + */ + dns_name_totext(name, false, &target); + + printf("%.*s", (int)target.used, (char *)target.base); +} + +static void +detail(dns_rbt_t *rbt, dns_name_t *name) { + dns_name_t *foundname, *origin, *fullname; + dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname; + dns_rbtnode_t *node1, *node2; + dns_rbtnodechain_t chain; + isc_result_t result; + bool nodes_should_match = false; + + dns_rbtnodechain_init(&chain); + + origin = dns_fixedname_initname(&fixedorigin); + fullname = dns_fixedname_initname(&fixedfullname); + foundname = dns_fixedname_initname(&fixedfoundname); + + node1 = node2 = NULL; + + printf("checking chain information for "); + print_name(name); + printf("\n"); + + result = dns_rbt_findnode(rbt, name, foundname, &node1, &chain, + DNS_RBTFIND_EMPTYDATA, NULL, NULL); + + switch (result) { + case ISC_R_SUCCESS: + printf(" found exact."); + nodes_should_match = true; + break; + case DNS_R_PARTIALMATCH: + printf(" found parent."); + break; + case ISC_R_NOTFOUND: + printf(" name not found."); + break; + default: + printf(" unexpected result: %s\n", dns_result_totext(result)); + return; + } + + if (node1 != NULL && node1->data != NULL) { + printf(" data at node: "); + print_name(node1->data); + } else { + printf(" no data at node."); + } + + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { + printf("\n name from dns_rbt_findnode: "); + print_name(foundname); + } + + result = dns_rbtnodechain_current(&chain, foundname, origin, &node2); + + if (result == ISC_R_SUCCESS) { + printf("\n name from dns_rbtnodechain_current: "); + + result = dns_name_concatenate(foundname, origin, fullname, + NULL); + if (result == ISC_R_SUCCESS) { + print_name(fullname); + } else { + printf("%s\n", dns_result_totext(result)); + } + printf("\n (foundname = "); + print_name(foundname); + printf(", origin = "); + print_name(origin); + printf(")\n"); + if (nodes_should_match && node1 != node2) { + printf(" nodes returned from each function " + "DO NOT match!\n"); + } + } else { + printf("\n result from dns_rbtnodechain_current: %s\n", + dns_result_totext(result)); + } + + printf(" level_matches = %u, level_count = %u\n", chain.level_matches, + chain.level_count); +} + +static void +iterate(dns_rbt_t *rbt, bool forward) { + dns_name_t foundname, *origin; + dns_rbtnodechain_t chain; + dns_fixedname_t fixedorigin; + isc_result_t result; + isc_result_t (*move)(dns_rbtnodechain_t *chain, dns_name_t *name, + dns_name_t *origin); + + dns_rbtnodechain_init(&chain); + + dns_name_init(&foundname, NULL); + origin = dns_fixedname_initname(&fixedorigin); + + if (forward) { + printf("iterating forward\n"); + move = dns_rbtnodechain_next; + + result = dns_rbtnodechain_first(&chain, rbt, &foundname, + origin); + } else { + printf("iterating backward\n"); + move = dns_rbtnodechain_prev; + + result = dns_rbtnodechain_last(&chain, rbt, &foundname, origin); + } + + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + printf("start not found!\n"); + } else { + for (;;) { + if (result == DNS_R_NEWORIGIN) { + printf(" new origin: "); + print_name(origin); + printf("\n"); + } + + if (result == ISC_R_SUCCESS || + result == DNS_R_NEWORIGIN) + { + print_name(&foundname); + printf("\n"); + } else { + if (result != ISC_R_NOMORE) { + printf("UNEXPECTED ITERATION ERROR: %s", + dns_result_totext(result)); + } + break; + } + + result = move(&chain, &foundname, origin); + } + } +} + +#define CMDCHECK(s) (strncasecmp(command, (s), length) == 0) +#define PRINTERR(r) \ + if (r != ISC_R_SUCCESS) \ + printf("... %s\n", dns_result_totext(r)); + +int +main(int argc, char **argv) { + char *command, *arg, buffer[1024]; + const char *whitespace; + dns_name_t *name, *foundname; + dns_fixedname_t fixedname; + dns_rbt_t *rbt = NULL; + int length, ch; + bool show_final_mem = false; + isc_result_t result; + void *data; + + progname = strrchr(*argv, '/'); + if (progname != NULL) { + progname++; + } else { + progname = *argv; + } + + while ((ch = isc_commandline_parse(argc, argv, "m")) != -1) { + switch (ch) { + case 'm': + show_final_mem = true; + break; + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + POST(argv); + + if (argc > 1) { + printf("Usage: %s [-m]\n", progname); + exit(1); + } + + setbuf(stdout, NULL); + + /* + * So isc_mem_stats() can report any allocation leaks. + */ + isc_mem_debugging = ISC_MEM_DEBUGRECORD; + + isc_mem_create(&mctx); + + result = dns_rbt_create(mctx, delete_name, NULL, &rbt); + if (result != ISC_R_SUCCESS) { + printf("dns_rbt_create: %s: exiting\n", + dns_result_totext(result)); + exit(1); + } + + whitespace = " \t"; + + while (fgets(buffer, sizeof(buffer), stdin) != NULL) { + length = strlen(buffer); + + if (buffer[length - 1] != '\n') { + printf("line to long (%lu max), ignored\n", + (unsigned long)sizeof(buffer) - 2); + continue; + } + + buffer[length - 1] = '\0'; + + command = buffer + strspn(buffer, whitespace); + + if (*command == '#') { + continue; + } + + arg = strpbrk(command, whitespace); + if (arg != NULL) { + *arg++ = '\0'; + arg += strspn(arg, whitespace); + } + + length = strlen(command); + if (*command != '\0') { + if (CMDCHECK("add")) { + name = create_name(arg); + if (name != NULL) { + printf("adding name %s\n", arg); + result = dns_rbt_addname(rbt, name, + name); + PRINTERR(result); + } + } else if (CMDCHECK("delete")) { + name = create_name(arg); + if (name != NULL) { + printf("deleting name %s\n", arg); + result = dns_rbt_deletename(rbt, name, + false); + PRINTERR(result); + delete_name(name, NULL); + } + } else if (CMDCHECK("nuke")) { + name = create_name(arg); + if (name != NULL) { + printf("nuking name %s " + "and its descendants\n", + arg); + result = dns_rbt_deletename(rbt, name, + true); + PRINTERR(result); + delete_name(name, NULL); + } + } else if (CMDCHECK("search")) { + name = create_name(arg); + if (name != NULL) { + printf("searching for name %s ... ", + arg); + + foundname = dns_fixedname_initname( + &fixedname); + data = NULL; + + result = dns_rbt_findname( + rbt, name, 0, foundname, &data); + switch (result) { + case ISC_R_SUCCESS: + printf("found exact: "); + print_name(data); + putchar('\n'); + break; + case DNS_R_PARTIALMATCH: + printf("found parent: "); + print_name(data); + printf("\n\t(foundname: "); + print_name(foundname); + printf(")\n"); + break; + case ISC_R_NOTFOUND: + printf("NOT FOUND!\n"); + break; + case ISC_R_NOMEMORY: + printf("OUT OF MEMORY!\n"); + break; + default: + printf("UNEXPECTED RESULT\n"); + } + + delete_name(name, NULL); + } + } else if (CMDCHECK("check")) { + /* + * Or "chain". I know, I know. Lame name. + * I was having a hard time thinking of a + * name (especially one that did not have + * a conflicting first letter with another + * command) that would differentiate this + * from the search command. + * + * But it is just a test program, eh? + */ + name = create_name(arg); + if (name != NULL) { + detail(rbt, name); + + delete_name(name, NULL); + } + } else if (CMDCHECK("forward")) { + iterate(rbt, true); + } else if (CMDCHECK("backward")) { + iterate(rbt, false); + } else if (CMDCHECK("print")) { + if (arg == NULL || *arg == '\0') { + dns_rbt_printtext(rbt, NULL, stdout); + } else { + printf("usage: print\n"); + } + } else if (CMDCHECK("quit")) { + if (arg == NULL || *arg == '\0') { + break; + } else { + printf("usage: quit\n"); + } + } else { + printf("a(dd) NAME, d(elete) NAME, " + "s(earch) NAME, p(rint), or q(uit)\n"); + } + } + } + + dns_rbt_destroy(&rbt); + + if (show_final_mem) { + isc_mem_stats(mctx, stderr); + } + + return (0); +} diff --git a/bin/tests/optional/rbt_test.out b/bin/tests/optional/rbt_test.out new file mode 100644 index 0000000..95bf4f9 --- /dev/null +++ b/bin/tests/optional/rbt_test.out @@ -0,0 +1,395 @@ +adding name a.vix.com +adding name b.vix.com +adding name c.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (RED from b) + NULL + NULL + c (RED from b) + NULL + NULL + -- END down from vix.com. + NULL + NULL +adding name a.b.c.d.e.f.vix.com +adding name b.b.c.d.e.f.vix.com +adding name c.b.c.d.e.f.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + NULL + NULL + c (black from b) + NULL + b.c.d.e.f (RED from c) + ++ BEG down from b.c.d.e.f + b (black) + a (RED from b) + NULL + NULL + c (RED from b) + NULL + NULL + -- END down from b.c.d.e.f + NULL + NULL + -- END down from vix.com. + NULL + NULL +adding name a.d.e.f.vix.com +adding name q.d.e.f.vix.com +adding name d.e.f.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + NULL + NULL + c (black from b) + NULL + d.e.f (RED from c) + ++ BEG down from d.e.f + b.c (black) + ++ BEG down from b.c + b (black) + a (RED from b) + NULL + NULL + c (RED from b) + NULL + NULL + -- END down from b.c + a (RED from b.c) + NULL + NULL + q (RED from b.c) + NULL + NULL + -- END down from d.e.f + NULL + NULL + -- END down from vix.com. + NULL + NULL +adding name g.h.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + NULL + NULL + d.e.f (black from b) + ++ BEG down from d.e.f + b.c (black) + ++ BEG down from b.c + b (black) + a (RED from b) + NULL + NULL + c (RED from b) + NULL + NULL + -- END down from b.c + a (RED from b.c) + NULL + NULL + q (RED from b.c) + NULL + NULL + -- END down from d.e.f + c (RED from d.e.f) + NULL + NULL + g.h (RED from d.e.f) + NULL + NULL + -- END down from vix.com. + NULL + NULL +searching for name q.d.e.f.vix.com ... found exact: q.d.e.f.vix.com. +searching for name just-parent.a.vix.com ... found parent: a.vix.com. + (foundname: a.vix.com.) +searching for name no-real-parent.vix.com ... NOT FOUND! +searching for name does.not.exist.at.all ... NOT FOUND! +iterating forward + new origin: . +vix.com + new origin: vix.com. +a +b +c +d.e.f + new origin: d.e.f.vix.com. +a +b.c + new origin: b.c.d.e.f.vix.com. +a +b +c + new origin: d.e.f.vix.com. +q + new origin: vix.com. +g.h +iterating backward + new origin: vix.com. +g.h + new origin: d.e.f.vix.com. +q + new origin: b.c.d.e.f.vix.com. +c +b +a + new origin: d.e.f.vix.com. +b.c +a + new origin: vix.com. +d.e.f +c +b +a + new origin: . +vix.com +checking chain information for vix.com. + found exact. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: vix.com. + (foundname = vix.com, origin = .) + level_matches = 0, level_count = 0 +checking chain information for zzz.com. + name not found. no data at node. + name from dns_rbtnodechain_current: g.h.vix.com. + (foundname = g.h, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for 0.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: vix.com. + (foundname = vix.com, origin = .) + level_matches = 0, level_count = 0 +checking chain information for d.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: c.vix.com. + (foundname = c, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for f.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: c.vix.com. + (foundname = c, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for a.e.f.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: c.vix.com. + (foundname = c, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for z.e.f.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: q.d.e.f.vix.com. + (foundname = q, origin = d.e.f.vix.com.) + level_matches = 0, level_count = 2 +checking chain information for g.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: q.d.e.f.vix.com. + (foundname = q, origin = d.e.f.vix.com.) + level_matches = 0, level_count = 2 +checking chain information for i.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: g.h.vix.com. + (foundname = g.h, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for b.c.vix.com. + found parent. data at node: c.vix.com. + name from dns_rbt_findnode: c.vix.com. + name from dns_rbtnodechain_current: c.vix.com. + (foundname = c, origin = vix.com.) + level_matches = 1, level_count = 1 +nuking name d.e.f.vix.com and its descendants +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + NULL + NULL + g.h (black from b) + c (RED from g.h) + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +adding name x.a.vix.com +adding name y.x.a.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + ++ BEG down from a + x (black) + ++ BEG down from x + y (black) + NULL + NULL + -- END down from x + NULL + NULL + -- END down from a + NULL + NULL + g.h (black from b) + c (RED from g.h) + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +deleting name a.vix.com +deleting name x.a.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + ++ BEG down from a + x (black) + ++ BEG down from x + y (black) + NULL + NULL + -- END down from x + NULL + NULL + -- END down from a + NULL + NULL + g.h (black from b) + c (RED from g.h) + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +deleting name b.vix.com +deleting name c.vix.com +vix.com. (black) + ++ BEG down from vix.com. + g.h (black) + a (RED from g.h) + ++ BEG down from a + x (black) + ++ BEG down from x + y (black) + NULL + NULL + -- END down from x + NULL + NULL + -- END down from a + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +deleting name y.x.a.vix.com +vix.com. (black) + ++ BEG down from vix.com. + g.h (black) + a (RED from g.h) + ++ BEG down from a + x (black) + NULL + NULL + -- END down from a + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +deleting name g.h.vix.com. +adding name \[b100000].vix.com. +adding name \[b010000].vix.com. +adding name \[b001000].vix.com. +adding name \[b000100].vix.com. +adding name \[b000010].vix.com. +adding name \[b000001].vix.com. +vix.com. (black) + ++ BEG down from vix.com. + \[x80/6] (black) + \[x0/1] (RED from \[x80/6]) + ++ BEG down from \[x0/1] + \[x80/5] (black) + \[x0/1] (RED from \[x80/5]) + ++ BEG down from \[x0/1] + \[x8/4] (black) + \[x0/1] (RED from \[x8/4]) + ++ BEG down from \[x0/1] + \[x8/3] (black) + \[x0/1] (RED from \[x8/3]) + ++ BEG down from \[x0/1] + \[x8/2] (black) + \[x4/2] (RED from \[x8/2]) + NULL + NULL + NULL + -- END down from \[x0/1] + NULL + NULL + NULL + -- END down from \[x0/1] + NULL + NULL + NULL + -- END down from \[x0/1] + NULL + NULL + NULL + -- END down from \[x0/1] + NULL + NULL + a (RED from \[x80/6]) + ++ BEG down from a + x (black) + NULL + NULL + -- END down from a + NULL + NULL + -- END down from vix.com. + NULL + NULL +searching for name \[b000100].vix.com. ... found exact: \[x10/6].vix.com. +adding name vix.com. +nuking name vix.com. and its descendants +adding name a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. +adding name b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. +b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. (black) + ++ BEG down from b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. + a (black) + NULL + NULL + -- END down from b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. + NULL + NULL +adding name . +nuking name . and its descendants +adding name \[xFFFF/16].\[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/256].com +adding name \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com +\[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com. (black) + ++ BEG down from \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com. + \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/144] (black) + NULL + NULL + -- END down from \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com. + NULL + NULL diff --git a/bin/tests/optional/rbt_test.txt b/bin/tests/optional/rbt_test.txt new file mode 100644 index 0000000..e44d72e --- /dev/null +++ b/bin/tests/optional/rbt_test.txt @@ -0,0 +1,87 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +add a.vix.com +add b.vix.com +add c.vix.com +print +add a.b.c.d.e.f.vix.com +add b.b.c.d.e.f.vix.com +add c.b.c.d.e.f.vix.com +print +add a.d.e.f.vix.com +add q.d.e.f.vix.com +add d.e.f.vix.com +print +add g.h.vix.com +print +search q.d.e.f.vix.com +search just-parent.a.vix.com +search no-real-parent.vix.com +search does.not.exist.at.all +forward +backward +# existing name +check vix.com. +# greater than stop node, which has down pointer +check zzz.com. +# less than lowest in level (would be left link from stop node) +check 0.vix.com +# greater than stop node, no down pointer +check d.vix.com +# superdomain stored in existing node +check f.vix.com +# common ancestor stored in existing node; existing is successor +check a.e.f.vix.com +# common ancestor stored in existing node; existing is less but not predecessor +check z.e.f.vix.com +# +check g.vix.com +# +check i.vix.com +# +check b.c.vix.com +nuke d.e.f.vix.com +print +add x.a.vix.com +add y.x.a.vix.com +print +delete a.vix.com +delete x.a.vix.com +print +delete b.vix.com +delete c.vix.com +print +delete y.x.a.vix.com +print +delete g.h.vix.com. +add \[b100000].vix.com. +add \[b010000].vix.com. +add \[b001000].vix.com. +add \[b000100].vix.com. +add \[b000010].vix.com. +add \[b000001].vix.com. +p +search \[b000100].vix.com. +# zap the entire tree +add vix.com. +nuke vix.com. +add a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. +add b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. +print +add . +# zap it again +nuke . +# test splitting of maximal bitstring +add \[xFFFF/16].\[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/256].com +add \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com +print +quit diff --git a/bin/tests/optional/rwlock_test.c b/bin/tests/optional/rwlock_test.c new file mode 100644 index 0000000..fc94eaf --- /dev/null +++ b/bin/tests/optional/rwlock_test.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#define sleep(x) Sleep(1000 * x) +#endif /* ifdef WIN32 */ + +isc_rwlock_t lock; + +static isc_threadresult_t +#ifdef WIN32 + WINAPI +#endif /* ifdef WIN32 */ + run1(void *arg) { + char *message = arg; + + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + printf("%s got READ lock\n", message); + sleep(1); + printf("%s giving up READ lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + printf("%s got READ lock\n", message); + sleep(1); + printf("%s giving up READ lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + printf("%s got WRITE lock\n", message); + sleep(1); + printf("%s giving up WRITE lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + return ((isc_threadresult_t)0); +} + +static isc_threadresult_t +#ifdef WIN32 + WINAPI +#endif /* ifdef WIN32 */ + run2(void *arg) { + char *message = arg; + + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + printf("%s got WRITE lock\n", message); + sleep(1); + printf("%s giving up WRITE lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + printf("%s got WRITE lock\n", message); + sleep(1); + printf("%s giving up WRITE lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + printf("%s got READ lock\n", message); + sleep(1); + printf("%s giving up READ lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + return ((isc_threadresult_t)0); +} + +int +main(int argc, char *argv[]) { + unsigned int nworkers; + unsigned int i; + isc_thread_t workers[100]; + char name[100]; + void *dupname; + + if (argc > 1) { + nworkers = atoi(argv[1]); + } else { + nworkers = 2; + } + if (nworkers > 100) { + nworkers = 100; + } + printf("%u workers\n", nworkers); + + isc_rwlock_init(&lock, 5, 10); + + for (i = 0; i < nworkers; i++) { + snprintf(name, sizeof(name), "%02u", i); + dupname = strdup(name); + RUNTIME_CHECK(dupname != NULL); + if (i != 0 && i % 3 == 0) { + isc_thread_create(run1, dupname, &workers[i]); + } else { + isc_thread_create(run2, dupname, &workers[i]); + } + } + + for (i = 0; i < nworkers; i++) { + isc_thread_join(workers[i], NULL); + } + + isc_rwlock_destroy(&lock); + + return (0); +} diff --git a/bin/tests/optional/serial_test.c b/bin/tests/optional/serial_test.c new file mode 100644 index 0000000..c16acc0 --- /dev/null +++ b/bin/tests/optional/serial_test.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +#include +#include + +int +main() { + uint32_t a, b; + char buf[1024]; + char *s, *e; + + while (fgets(buf, sizeof(buf), stdin) != NULL) { + buf[sizeof(buf) - 1] = '\0'; + s = buf; + a = strtoul(s, &e, 0); + if (s == e) { + continue; + } + s = e; + b = strtoul(s, &e, 0); + if (s == e) { + continue; + } + fprintf(stdout, "%u %u gt:%d lt:%d ge:%d le:%d eq:%d ne:%d\n", + a, b, isc_serial_gt(a, b), isc_serial_lt(a, b), + isc_serial_ge(a, b), isc_serial_le(a, b), + isc_serial_eq(a, b), isc_serial_ne(a, b)); + } + return (0); +} diff --git a/bin/tests/optional/shutdown_test.c b/bin/tests/optional/shutdown_test.c new file mode 100644 index 0000000..c8cf03c --- /dev/null +++ b/bin/tests/optional/shutdown_test.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + isc_mem_t *mctx; + isc_task_t *task; + isc_timer_t *timer; + unsigned int ticks; + char name[16]; + bool exiting; + isc_task_t *peer; +} t_info; + +#define MAX_TASKS 3 +#define T2_SHUTDOWNOK (ISC_EVENTCLASS(1024) + 0) +#define T2_SHUTDOWNDONE (ISC_EVENTCLASS(1024) + 1) +#define FOO_EVENT (ISC_EVENTCLASS(1024) + 2) + +static t_info tasks[MAX_TASKS]; +static unsigned int task_count; +static isc_nm_t *netmgr = NULL; +static isc_taskmgr_t *taskmgr = NULL; +static isc_timermgr_t *timer_manager; + +static void +t1_shutdown(isc_task_t *task, isc_event_t *event) { + t_info *info = event->ev_arg; + + printf("task %s (%p) t1_shutdown\n", info->name, task); + isc_task_detach(&info->task); + isc_event_free(&event); +} + +static void +t2_shutdown(isc_task_t *task, isc_event_t *event) { + t_info *info = event->ev_arg; + + printf("task %s (%p) t2_shutdown\n", info->name, task); + info->exiting = true; + isc_event_free(&event); +} + +static void +shutdown_action(isc_task_t *task, isc_event_t *event) { + t_info *info = event->ev_arg; + isc_event_t *nevent; + + INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN); + + printf("task %s (%p) shutdown\n", info->name, task); + if (strcmp(info->name, "0") == 0) { + isc_timer_destroy(&info->timer); + nevent = isc_event_allocate(info->mctx, info, T2_SHUTDOWNOK, + t2_shutdown, &tasks[1], + sizeof(*event)); + RUNTIME_CHECK(nevent != NULL); + info->exiting = true; + isc_task_sendanddetach(&info->peer, &nevent); + } + isc_event_free(&event); +} + +static void +foo_event(isc_task_t *task, isc_event_t *event) { + printf("task(%p) foo\n", task); + isc_event_free(&event); +} + +static void +tick(isc_task_t *task, isc_event_t *event) { + t_info *info = event->ev_arg; + isc_event_t *nevent; + + INSIST(event->ev_type == ISC_TIMEREVENT_TICK); + + printf("task %s (%p) tick\n", info->name, task); + + info->ticks++; + if (strcmp(info->name, "1") == 0) { + if (info->ticks == 10) { + isc_app_shutdown(); + } else if (info->ticks >= 15 && info->exiting) { + isc_timer_destroy(&info->timer); + isc_task_detach(&info->task); + nevent = isc_event_allocate( + info->mctx, info, T2_SHUTDOWNDONE, t1_shutdown, + &tasks[0], sizeof(*event)); + RUNTIME_CHECK(nevent != NULL); + isc_task_send(info->peer, &nevent); + isc_task_detach(&info->peer); + } + } else if (strcmp(info->name, "foo") == 0) { + isc_timer_destroy(&info->timer); + nevent = isc_event_allocate(info->mctx, info, FOO_EVENT, + foo_event, task, sizeof(*event)); + RUNTIME_CHECK(nevent != NULL); + isc_task_sendanddetach(&task, &nevent); + } + + isc_event_free(&event); +} + +static t_info * +new_task(isc_mem_t *mctx, const char *name) { + t_info *ti; + isc_time_t expires; + isc_interval_t interval; + + RUNTIME_CHECK(task_count < MAX_TASKS); + ti = &tasks[task_count]; + ti->mctx = mctx; + ti->task = NULL; + ti->timer = NULL; + ti->ticks = 0; + if (name != NULL) { + INSIST(strlen(name) < sizeof(ti->name)); + strlcpy(ti->name, name, sizeof(ti->name)); + } else { + snprintf(ti->name, sizeof(ti->name), "%u", task_count); + } + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &ti->task) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(ti->task, shutdown_action, ti) == + ISC_R_SUCCESS); + + isc_time_settoepoch(&expires); + isc_interval_set(&interval, 1, 0); + RUNTIME_CHECK(isc_timer_create(timer_manager, isc_timertype_ticker, + &expires, &interval, ti->task, tick, ti, + &ti->timer) == ISC_R_SUCCESS); + + task_count++; + + return (ti); +} + +int +main(int argc, char *argv[]) { + unsigned int workers; + t_info *t1, *t2 = NULL; + isc_task_t *task = NULL; + isc_mem_t *mctx = NULL, *mctx2 = NULL; + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + + if (argc > 1) { + workers = atoi(argv[1]); + if (workers < 1) { + workers = 1; + } + if (workers > 8192) { + workers = 8192; + } + } else { + workers = 2; + } + printf("%u workers\n", workers); + + isc_mem_create(&mctx); + isc_mem_create(&mctx2); + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_timermgr_create(mctx, &timer_manager) == + ISC_R_SUCCESS); + + t1 = new_task(mctx, NULL); + t2 = new_task(mctx2, NULL); + isc_task_attach(t2->task, &t1->peer); + isc_task_attach(t1->task, &t2->peer); + + /* + * Test run-triggered shutdown. + */ + (void)new_task(mctx2, "foo"); + + /* + * Test implicit shutdown. + */ + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS); + isc_task_detach(&task); + + /* + * Test anti-zombie code. + */ + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS); + isc_task_detach(&task); + + RUNTIME_CHECK(isc_app_run() == ISC_R_SUCCESS); + + isc_managers_destroy(&netmgr, &taskmgr); + isc_timermgr_destroy(&timer_manager); + + printf("Statistics for mctx:\n"); + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + printf("Statistics for mctx2:\n"); + isc_mem_stats(mctx2, stdout); + isc_mem_destroy(&mctx2); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/sig0_test.c b/bin/tests/optional/sig0_test.c new file mode 100644 index 0000000..e419700 --- /dev/null +++ b/bin/tests/optional/sig0_test.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define CHECK(str, x) \ + { \ + if ((x) != ISC_R_SUCCESS) { \ + printf("%s: %s\n", (str), isc_result_totext(x)); \ + exit(-1); \ + } \ + } + +isc_mutex_t lock; +dst_key_t *key = NULL; +isc_mem_t *mctx = NULL; +unsigned char qdata[1024], rdata[1024]; +isc_buffer_t qbuffer, rbuffer; +isc_nm_t *netmgr = NULL; +isc_taskmgr_t *taskmgr = NULL; +isc_task_t *task1 = NULL; +isc_log_t *lctx = NULL; +isc_logconfig_t *logconfig = NULL; +isc_socket_t *s = NULL; +isc_sockaddr_t address; +char output[10 * 1024]; +isc_buffer_t outbuf; +static const dns_master_style_t *style = &dns_master_style_debug; + +static void +senddone(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + + REQUIRE(sevent != NULL); + REQUIRE(sevent->ev_type == ISC_SOCKEVENT_SENDDONE); + REQUIRE(task == task1); + + printf("senddone\n"); + + isc_event_free(&event); +} + +static void +recvdone(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + isc_buffer_t source; + isc_result_t result; + dns_message_t *response = NULL; + + REQUIRE(sevent != NULL); + REQUIRE(sevent->ev_type == ISC_SOCKEVENT_RECVDONE); + REQUIRE(task == task1); + + printf("recvdone\n"); + if (sevent->result != ISC_R_SUCCESS) { + printf("failed\n"); + exit(-1); + } + + isc_buffer_init(&source, sevent->region.base, sevent->region.length); + isc_buffer_add(&source, sevent->n); + + dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); + result = dns_message_parse(response, &source, 0); + CHECK("dns_message_parse", result); + + isc_buffer_init(&outbuf, output, sizeof(output)); + result = dns_message_totext(response, style, 0, &outbuf); + CHECK("dns_message_totext", result); + printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf), + (char *)isc_buffer_base(&outbuf)); + + dns_message_detach(&response); + isc_event_free(&event); + + isc_app_shutdown(); +} + +static void +buildquery(void) { + isc_result_t result; + dns_rdataset_t *question = NULL; + dns_name_t *qname = NULL; + isc_region_t r, inr; + dns_message_t *query = NULL; + char nametext[] = "host.example"; + isc_buffer_t namesrc, namedst; + unsigned char namedata[256]; + isc_sockaddr_t sa; + dns_compress_t cctx; + + dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query); + result = dns_message_setsig0key(query, key); + CHECK("dns_message_setsig0key", result); + + result = dns_message_gettemprdataset(query, &question); + CHECK("dns_message_gettemprdataset", result); + dns_rdataset_makequestion(question, dns_rdataclass_in, dns_rdatatype_a); + result = dns_message_gettempname(query, &qname); + CHECK("dns_message_gettempname", result); + isc_buffer_init(&namesrc, nametext, strlen(nametext)); + isc_buffer_add(&namesrc, strlen(nametext)); + isc_buffer_init(&namedst, namedata, sizeof(namedata)); + dns_name_init(qname, NULL); + result = dns_name_fromtext(qname, &namesrc, dns_rootname, 0, &namedst); + CHECK("dns_name_fromtext", result); + ISC_LIST_APPEND(qname->list, question, link); + dns_message_addname(query, qname, DNS_SECTION_QUESTION); + + isc_buffer_init(&qbuffer, qdata, sizeof(qdata)); + + result = dns_compress_init(&cctx, -1, mctx); + CHECK("dns_compress_init", result); + result = dns_message_renderbegin(query, &cctx, &qbuffer); + CHECK("dns_message_renderbegin", result); + result = dns_message_rendersection(query, DNS_SECTION_QUESTION, 0); + CHECK("dns_message_rendersection(question)", result); + result = dns_message_rendersection(query, DNS_SECTION_ANSWER, 0); + CHECK("dns_message_rendersection(answer)", result); + result = dns_message_rendersection(query, DNS_SECTION_AUTHORITY, 0); + CHECK("dns_message_rendersection(auth)", result); + result = dns_message_rendersection(query, DNS_SECTION_ADDITIONAL, 0); + CHECK("dns_message_rendersection(add)", result); + result = dns_message_renderend(query); + CHECK("dns_message_renderend", result); + dns_compress_invalidate(&cctx); + + isc_buffer_init(&outbuf, output, sizeof(output)); + result = dns_message_totext(query, style, 0, &outbuf); + CHECK("dns_message_totext", result); + printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf), + (char *)isc_buffer_base(&outbuf)); + + isc_buffer_usedregion(&qbuffer, &r); + isc_sockaddr_any(&sa); + result = isc_socket_bind(s, &sa, 0); + CHECK("isc_socket_bind", result); + result = isc_socket_sendto(s, &r, task1, senddone, NULL, &address, + NULL); + CHECK("isc_socket_sendto", result); + + inr.base = rdata; + inr.length = sizeof(rdata); + result = isc_socket_recv(s, &inr, 1, task1, recvdone, NULL); + CHECK("isc_socket_recv", result); + dns_message_detach(&query); +} + +int +main(int argc, char *argv[]) { + bool verbose = false; + isc_socketmgr_t *socketmgr = NULL; + isc_timermgr_t *timermgr = NULL; + struct in_addr inaddr; + dns_fixedname_t fname; + dns_name_t *name = NULL; + isc_buffer_t b; + int ch; + isc_result_t result; + in_port_t port = 53; + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + + isc_mutex_init(&lock); + + mctx = NULL; + isc_mem_create(&mctx); + + while ((ch = isc_commandline_parse(argc, argv, "vp:")) != -1) { + switch (ch) { + case 'v': + verbose = true; + break; + case 'p': + port = (unsigned int)atoi(isc_commandline_argument); + break; + } + } + + RUNTIME_CHECK(dst_lib_init(mctx, NULL) == ISC_R_SUCCESS); + + dns_result_register(); + dst_result_register(); + + RUNTIME_CHECK(isc_managers_create(mctx, 2, 0, &netmgr, &taskmgr) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task1) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + + isc_log_create(mctx, &lctx, &logconfig); + + RUNTIME_CHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, + &s) == ISC_R_SUCCESS); + + inaddr.s_addr = htonl(INADDR_LOOPBACK); + isc_sockaddr_fromin(&address, &inaddr, port); + + name = dns_fixedname_initname(&fname); + isc_buffer_constinit(&b, "child.example.", strlen("child.example.")); + isc_buffer_add(&b, strlen("child.example.")); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + CHECK("dns_name_fromtext", result); + + result = dst_key_fromfile(name, 33180, DNS_KEYALG_RSASHA1, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, NULL, + mctx, &key); + CHECK("dst_key_fromfile", result); + + buildquery(); + + (void)isc_app_run(); + + isc_task_shutdown(task1); + isc_task_detach(&task1); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_socket_detach(&s); + isc_socketmgr_destroy(&socketmgr); + isc_timermgr_destroy(&timermgr); + + dst_key_free(&key); + + dst_lib_destroy(); + + isc_log_destroy(&lctx); + + if (verbose) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + isc_mutex_destroy(&lock); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/sock_test.c b/bin/tests/optional/sock_test.c new file mode 100644 index 0000000..f88f76d --- /dev/null +++ b/bin/tests/optional/sock_test.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +isc_mem_t *mctx = NULL; +isc_nm_t *netmgr = NULL; +isc_taskmgr_t *taskmgr = NULL; + +static void +my_shutdown(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + printf("shutdown %s (%p)\n", name, task); + fflush(stdout); + isc_event_free(&event); +} + +static void +my_send(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock; + isc_socketevent_t *dev; + + sock = event->ev_sender; + dev = (isc_socketevent_t *)event; + + printf("my_send: %s task %p\n\t(sock %p, base %p, length %u, n %u, " + "result %u)\n", + (char *)(event->ev_arg), task, sock, dev->region.base, + dev->region.length, dev->n, dev->result); + + if (dev->result != ISC_R_SUCCESS) { + isc_socket_detach(&sock); + isc_task_shutdown(task); + } + + if (dev->region.base != NULL) { + isc_mem_put(mctx, dev->region.base, dev->region.length); + } + + isc_event_free(&event); +} + +static void +my_recv(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock; + isc_socketevent_t *dev; + isc_region_t region; + char buf[1024]; + char host[256]; + + sock = event->ev_sender; + dev = (isc_socketevent_t *)event; + + printf("Socket %s (sock %p, base %p, length %u, n %u, result %u)\n", + (char *)(event->ev_arg), sock, dev->region.base, + dev->region.length, dev->n, dev->result); + if (dev->address.type.sa.sa_family == AF_INET6) { + inet_ntop(AF_INET6, &dev->address.type.sin6.sin6_addr, host, + sizeof(host)); + printf("\tFrom: %s port %d\n", host, + ntohs(dev->address.type.sin6.sin6_port)); + } else { + inet_ntop(AF_INET, &dev->address.type.sin.sin_addr, host, + sizeof(host)); + printf("\tFrom: %s port %d\n", host, + ntohs(dev->address.type.sin.sin_port)); + } + + if (dev->result != ISC_R_SUCCESS) { + isc_socket_detach(&sock); + + if (dev->region.base != NULL) { + isc_mem_put(mctx, dev->region.base, dev->region.length); + } + isc_event_free(&event); + + isc_task_shutdown(task); + return; + } + + /* + * Echo the data back. + */ + if (strcmp(event->ev_arg, "so2") != 0) { + region = dev->region; + snprintf(buf, sizeof(buf), "\r\nReceived: %.*s\r\n\r\n", + (int)dev->n, (char *)region.base); + region.base = isc_mem_get(mctx, strlen(buf) + 1); + { + region.length = strlen(buf) + 1; + strlcpy((char *)region.base, buf, region.length); + } + isc_socket_send(sock, ®ion, task, my_send, event->ev_arg); + } else { + region = dev->region; + printf("\r\nReceived: %.*s\r\n\r\n", (int)dev->n, + (char *)region.base); + } + + isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->ev_arg); + + isc_event_free(&event); +} + +static void +my_http_get(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock; + isc_socketevent_t *dev; + + sock = event->ev_sender; + dev = (isc_socketevent_t *)event; + + printf("my_http_get: %s task %p\n\t(sock %p, base %p, length %u, " + "n %u, result %u)\n", + (char *)(event->ev_arg), task, sock, dev->region.base, + dev->region.length, dev->n, dev->result); + + if (dev->result != ISC_R_SUCCESS) { + isc_socket_detach(&sock); + isc_task_shutdown(task); + if (dev->region.base != NULL) { + isc_mem_put(mctx, dev->region.base, dev->region.length); + } + isc_event_free(&event); + return; + } + + isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->ev_arg); + + isc_event_free(&event); +} + +static void +my_connect(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock; + isc_socket_connev_t *dev; + isc_region_t region; + char buf[1024]; + + sock = event->ev_sender; + dev = (isc_socket_connev_t *)event; + + printf("%s: Connection result: %u\n", (char *)(event->ev_arg), + dev->result); + + if (dev->result != ISC_R_SUCCESS) { + isc_socket_detach(&sock); + isc_event_free(&event); + isc_task_shutdown(task); + return; + } + + /* + * Send a GET string, and set up to receive (and just display) + * the result. + */ + snprintf(buf, sizeof(buf), + "GET / HTTP/1.1\r\nHost: www.flame.org\r\n" + "Connection: Close\r\n\r\n"); + region.base = isc_mem_get(mctx, strlen(buf) + 1); + { + region.length = strlen(buf) + 1; + strlcpy((char *)region.base, buf, region.length); + } + + isc_socket_send(sock, ®ion, task, my_http_get, event->ev_arg); + + isc_event_free(&event); +} + +static void +my_listen(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + isc_socket_newconnev_t *dev = NULL; + isc_region_t region; + isc_socket_t *oldsock = NULL; + isc_task_t *newtask = NULL; + + dev = (isc_socket_newconnev_t *)event; + + printf("newcon %s (task %p, oldsock %p, newsock %p, result %u)\n", name, + task, event->ev_sender, dev->newsocket, dev->result); + fflush(stdout); + + if (dev->result == ISC_R_SUCCESS) { + /* + * Queue another listen on this socket. + */ + RUNTIME_CHECK(isc_socket_accept(event->ev_sender, task, + my_listen, event->ev_arg) == + ISC_R_SUCCESS); + + region.base = isc_mem_get(mctx, 20); + region.length = 20; + + /* + * Create a new task for this socket, and queue up a + * recv on it. + */ + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &newtask) == + ISC_R_SUCCESS); + isc_socket_recv(dev->newsocket, ®ion, 1, newtask, my_recv, + event->ev_arg); + isc_task_detach(&newtask); + } else { + printf("detaching from socket %p\n", event->ev_sender); + oldsock = event->ev_sender; + + isc_socket_detach(&oldsock); + + isc_event_free(&event); + isc_task_shutdown(task); + return; + } + + isc_event_free(&event); +} + +static void +timeout(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock = event->ev_arg; + + printf("Timeout, canceling IO on socket %p (task %p)\n", sock, task); + + isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_ALL); + isc_timer_destroy((isc_timer_t **)&event->ev_sender); + isc_event_free(&event); +} + +static char one[] = "1"; +static char two[] = "2"; +static char xso1[] = "so1"; +static char xso2[] = "so2"; + +int +main(int argc, char *argv[]) { + isc_task_t *t1 = NULL, *t2 = NULL; + isc_timermgr_t *timgr = NULL; + isc_time_t expires; + isc_interval_t interval; + isc_timer_t *ti1 = NULL; + unsigned int workers; + isc_socketmgr_t *socketmgr = NULL; + isc_socket_t *so1 = NULL, *so2 = NULL; + isc_sockaddr_t sockaddr; + struct in_addr ina; + struct in6_addr in6a; + isc_result_t result; + int pf; + + if (argc > 1) { + workers = atoi(argv[1]); + if (workers < 1) { + workers = 1; + } + if (workers > 8192) { + workers = 8192; + } + } else { + workers = 2; + } + printf("%u workers\n", workers); + + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + pf = PF_INET6; + } else { + pf = PF_INET; + } + + /* + * EVERYTHING needs a memory context. + */ + isc_mem_create(&mctx); + + /* + * The task manager is independent (other than memory context) + */ + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + + /* + * Timer manager depends only on the memory context as well. + */ + RUNTIME_CHECK(isc_timermgr_create(mctx, &timgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t1) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t2) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t1, my_shutdown, one) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t2, my_shutdown, two) == + ISC_R_SUCCESS); + + printf("task 1 = %p\n", t1); + printf("task 2 = %p\n", t2); + + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + + /* + * Open up a listener socket. + */ + + if (pf == PF_INET6) { + in6a = in6addr_any; + isc_sockaddr_fromin6(&sockaddr, &in6a, 5544); + } else { + ina.s_addr = INADDR_ANY; + isc_sockaddr_fromin(&sockaddr, &ina, 5544); + } + RUNTIME_CHECK(isc_socket_create(socketmgr, pf, isc_sockettype_tcp, + &so1) == ISC_R_SUCCESS); + result = isc_socket_bind(so1, &sockaddr, ISC_SOCKET_REUSEADDRESS); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socket_listen(so1, 0) == ISC_R_SUCCESS); + + /* + * Queue up the first accept event. + */ + RUNTIME_CHECK(isc_socket_accept(so1, t1, my_listen, xso1) == + ISC_R_SUCCESS); + isc_time_settoepoch(&expires); + isc_interval_set(&interval, 10, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, &expires, + &interval, t1, timeout, so1, + &ti1) == ISC_R_SUCCESS); + + /* + * Open up a socket that will connect to www.flame.org, port 80. + * Why not. :) + */ + ina.s_addr = inet_addr("204.152.184.97"); + if (0 && pf == PF_INET6) { + isc_sockaddr_v6fromin(&sockaddr, &ina, 80); + } else { + isc_sockaddr_fromin(&sockaddr, &ina, 80); + } + RUNTIME_CHECK(isc_socket_create(socketmgr, isc_sockaddr_pf(&sockaddr), + isc_sockettype_tcp, + &so2) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_socket_connect(so2, &sockaddr, t2, my_connect, + xso2) == ISC_R_SUCCESS); + + /* + * Detaching these is safe, since the socket will attach to the + * task for any outstanding requests. + */ + isc_task_detach(&t1); + isc_task_detach(&t2); + + /* + * Wait a short while. + */ +#ifndef WIN32 + sleep(10); +#else /* ifndef WIN32 */ + Sleep(10000); +#endif /* ifndef WIN32 */ + + fprintf(stderr, "Destroying socket manager\n"); + isc_socketmgr_destroy(&socketmgr); + + fprintf(stderr, "Destroying timer manager\n"); + isc_timermgr_destroy(&timgr); + + fprintf(stderr, "Destroying task manager\n"); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/sym_test.c b/bin/tests/optional/sym_test.c new file mode 100644 index 0000000..81e2916 --- /dev/null +++ b/bin/tests/optional/sym_test.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include +#include +#include + +isc_mem_t *mctx; +isc_symtab_t *st; + +static void +undefine_action(char *key, unsigned int type, isc_symvalue_t value, void *arg) { + UNUSED(arg); + + INSIST(type == 1); + isc_mem_free(mctx, key); + isc_mem_free(mctx, value.as_pointer); +} + +int +main(int argc, char *argv[]) { + char s[1000], *cp, *key; + size_t len; + isc_result_t result; + isc_symvalue_t value; + int trace = 0; + int c; + isc_symexists_t exists_policy = isc_symexists_reject; + bool case_sensitive = false; + + while ((c = isc_commandline_parse(argc, argv, "tarc")) != -1) { + switch (c) { + case 't': + trace = 1; + break; + case 'a': + exists_policy = isc_symexists_add; + break; + case 'r': + exists_policy = isc_symexists_replace; + break; + case 'c': + case_sensitive = true; + break; + } + } + + isc_mem_create(&mctx); + RUNTIME_CHECK(isc_symtab_create(mctx, 691, undefine_action, NULL, + case_sensitive, &st) == ISC_R_SUCCESS); + + while (fgets(s, sizeof(s), stdin) != NULL) { + len = strlen(s); + if (len > 0U && s[len - 1] == '\n') { + s[len - 1] = '\0'; + len--; + } + + cp = s; + + if (cp[0] == '!') { + cp++; + result = isc_symtab_undefine(st, cp, 1); + if (trace || result != ISC_R_SUCCESS) { + printf("undefine('%s'): %s\n", cp, + isc_result_totext(result)); + } + } else { + key = cp; + while (*cp != '\0' && *cp != ' ' && *cp != '\t') { + cp++; + } + if (*cp == '\0') { + result = isc_symtab_lookup(st, key, 0, &value); + if (trace || result != ISC_R_SUCCESS) { + printf("lookup('%s'): %s", key, + isc_result_totext(result)); + if (result == ISC_R_SUCCESS) { + cp = value.as_pointer; + printf(", value == '%s'", cp); + } + printf("\n"); + } + } else { + *cp++ = '\0'; + key = isc_mem_strdup(mctx, key); + value.as_pointer = isc_mem_strdup(mctx, cp); + result = isc_symtab_define(st, key, 1, value, + exists_policy); + if (trace || result != ISC_R_SUCCESS) { + printf("define('%s', '%s'): %s\n", key, + cp, isc_result_totext(result)); + if (result != ISC_R_SUCCESS) { + undefine_action(key, 1, value, + NULL); + } + } + } + } + } + + isc_symtab_destroy(&st); + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/task_test.c b/bin/tests/optional/task_test.c new file mode 100644 index 0000000..48e6bfd --- /dev/null +++ b/bin/tests/optional/task_test.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +isc_mem_t *mctx = NULL; + +static void +my_callback(isc_task_t *task, isc_event_t *event) { + int i, j; + char *name = event->ev_arg; + + j = 0; + for (i = 0; i < 1000000; i++) { + j += 100; + } + printf("task %s (%p): %d\n", name, task, j); + isc_event_free(&event); +} + +static void +my_shutdown(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + printf("shutdown %s (%p)\n", name, task); + isc_event_free(&event); +} + +static void +my_tick(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + printf("task %p tick %s\n", task, name); + isc_event_free(&event); +} + +static char one[] = "1"; +static char two[] = "2"; +static char three[] = "3"; +static char four[] = "4"; +static char foo[] = "foo"; +static char bar[] = "bar"; + +int +main(int argc, char *argv[]) { + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_task_t *t1 = NULL, *t2 = NULL; + isc_task_t *t3 = NULL, *t4 = NULL; + isc_event_t *event; + unsigned int workers; + isc_timermgr_t *timgr; + isc_timer_t *ti1, *ti2; + struct isc_interval interval; + + if (argc > 1) { + workers = atoi(argv[1]); + if (workers < 1) { + workers = 1; + } + if (workers > 8192) { + workers = 8192; + } + } else { + workers = 2; + } + printf("%u workers\n", workers); + + isc_mem_create(&mctx); + + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t1) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t2) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t3) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t4) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_task_onshutdown(t1, my_shutdown, one) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t2, my_shutdown, two) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t3, my_shutdown, three) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t4, my_shutdown, four) == + ISC_R_SUCCESS); + + timgr = NULL; + RUNTIME_CHECK(isc_timermgr_create(mctx, &timgr) == ISC_R_SUCCESS); + ti1 = NULL; + + isc_interval_set(&interval, 1, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_ticker, NULL, + &interval, t1, my_tick, foo, + &ti1) == ISC_R_SUCCESS); + + ti2 = NULL; + isc_interval_set(&interval, 1, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_ticker, NULL, + &interval, t2, my_tick, bar, + &ti2) == ISC_R_SUCCESS); + + printf("task 1 = %p\n", t1); + printf("task 2 = %p\n", t2); +#ifndef WIN32 + sleep(2); +#else /* ifndef WIN32 */ + Sleep(2000); +#endif /* ifndef WIN32 */ + + /* + * Note: (void *)1 is used as a sender here, since some compilers + * don't like casting a function pointer to a (void *). + * + * In a real use, it is more likely the sender would be a + * structure (socket, timer, task, etc) but this is just a test + * program. + */ + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, two, + sizeof(*event)); + isc_task_send(t2, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, three, + sizeof(*event)); + isc_task_send(t3, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, four, + sizeof(*event)); + isc_task_send(t4, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, two, + sizeof(*event)); + isc_task_send(t2, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, three, + sizeof(*event)); + isc_task_send(t3, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, four, + sizeof(*event)); + isc_task_send(t4, &event); + isc_task_purgerange(t3, NULL, ISC_EVENTTYPE_FIRSTEVENT, + ISC_EVENTTYPE_LASTEVENT, NULL); + + isc_task_detach(&t1); + isc_task_detach(&t2); + isc_task_detach(&t3); + isc_task_detach(&t4); + +#ifndef WIN32 + sleep(10); +#else /* ifndef WIN32 */ + Sleep(10000); +#endif /* ifndef WIN32 */ + printf("destroy\n"); + isc_timer_destroy(&ti1); + isc_timer_destroy(&ti2); + isc_timermgr_destroy(&timgr); + isc_managers_destroy(&netmgr, &taskmgr); + printf("destroyed\n"); + + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/timer_test.c b/bin/tests/optional/timer_test.c new file mode 100644 index 0000000..0eb6e9f --- /dev/null +++ b/bin/tests/optional/timer_test.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +isc_mem_t *mctx1, *mctx2, *mctx3; +isc_task_t *t1, *t2, *t3; +isc_timer_t *ti1, *ti2, *ti3; +int tick_count = 0; + +static void +shutdown_task(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + printf("task %p shutdown %s\n", task, name); + isc_event_free(&event); +} + +static void +tick(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + INSIST(event->ev_type == ISC_TIMEREVENT_TICK); + + printf("task %s (%p) tick\n", name, task); + + tick_count++; + if (ti3 != NULL && tick_count % 3 == 0) { + isc_timer_touch(ti3); + } + + if (ti3 != NULL && tick_count == 7) { + isc_time_t expires; + isc_interval_t interval; + + isc_interval_set(&interval, 5, 0); + (void)isc_time_nowplusinterval(&expires, &interval); + isc_interval_set(&interval, 4, 0); + printf("*** resetting ti3 ***\n"); + RUNTIME_CHECK(isc_timer_reset(ti3, isc_timertype_once, &expires, + &interval, + true) == ISC_R_SUCCESS); + } + + isc_event_free(&event); +} + +static void +timeout(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + const char *type; + + INSIST(event->ev_type == ISC_TIMEREVENT_IDLE || + event->ev_type == ISC_TIMEREVENT_LIFE); + + if (event->ev_type == ISC_TIMEREVENT_IDLE) { + type = "idle"; + } else { + type = "life"; + } + printf("task %s (%p) %s timeout\n", name, task, type); + + if (strcmp(name, "3") == 0) { + printf("*** saving task 3 ***\n"); + isc_event_free(&event); + return; + } + + isc_event_free(&event); + isc_task_shutdown(task); +} + +static char one[] = "1"; +static char two[] = "2"; +static char three[] = "3"; + +int +main(int argc, char *argv[]) { + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_timermgr_t *timgr = NULL; + unsigned int workers; + isc_time_t expires, now; + isc_interval_t interval; + + if (argc > 1) { + workers = atoi(argv[1]); + if (workers < 1) { + workers = 1; + } + if (workers > 8192) { + workers = 8192; + } + } else { + workers = 2; + } + printf("%u workers\n", workers); + + isc_mem_create(&mctx1); + RUNTIME_CHECK(isc_managers_create(mctx1, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_timermgr_create(mctx1, &timgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t1) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t2) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t3) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t1, shutdown_task, one) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t2, shutdown_task, two) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t3, shutdown_task, three) == + ISC_R_SUCCESS); + + printf("task 1: %p\n", t1); + printf("task 2: %p\n", t2); + printf("task 3: %p\n", t3); + + TIME_NOW(&now); + + isc_interval_set(&interval, 2, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, NULL, + &interval, t2, timeout, two, + &ti2) == ISC_R_SUCCESS); + + isc_interval_set(&interval, 1, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_ticker, NULL, + &interval, t1, tick, one, + &ti1) == ISC_R_SUCCESS); + + isc_interval_set(&interval, 10, 0); + RUNTIME_CHECK(isc_time_add(&now, &interval, &expires) == ISC_R_SUCCESS); + isc_interval_set(&interval, 2, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, &expires, + &interval, t3, timeout, three, + &ti3) == ISC_R_SUCCESS); + + isc_task_detach(&t1); + isc_task_detach(&t2); + isc_task_detach(&t3); + +#ifndef WIN32 + sleep(15); +#else /* ifndef WIN32 */ + Sleep(15000); +#endif /* ifndef WIN32 */ + printf("destroy\n"); + isc_timer_destroy(&ti1); + isc_timer_destroy(&ti2); + isc_timer_destroy(&ti3); +#ifndef WIN32 + sleep(2); +#else /* ifndef WIN32 */ + Sleep(2000); +#endif /* ifndef WIN32 */ + isc_timermgr_destroy(&timgr); + isc_managers_destroy(&netmgr, &taskmgr); + printf("destroyed\n"); + + printf("Statistics for mctx1:\n"); + isc_mem_stats(mctx1, stdout); + isc_mem_destroy(&mctx1); + + return (0); +} diff --git a/bin/tests/optional/zone_test.c b/bin/tests/optional/zone_test.c new file mode 100644 index 0000000..05193f8 --- /dev/null +++ b/bin/tests/optional/zone_test.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int debug = 0; +static int quiet = 0; +static int stats = 0; +static isc_mem_t *mctx = NULL; +dns_zone_t *zone = NULL; +isc_nm_t *netmgr = NULL; +isc_taskmgr_t *taskmgr = NULL; +isc_timermgr_t *timermgr = NULL; +isc_socketmgr_t *socketmgr = NULL; +dns_zonemgr_t *zonemgr = NULL; +dns_zonetype_t zonetype = dns_zone_primary; +isc_sockaddr_t addr; + +#define ERRRET(result, function) \ + do { \ + if (result != ISC_R_SUCCESS) { \ + fprintf(stderr, "%s() returned %s\n", function, \ + dns_result_totext(result)); \ + return; \ + } \ + } while (0) + +#define ERRCONT(result, function) \ + if (result != ISC_R_SUCCESS) { \ + fprintf(stderr, "%s() returned %s\n", function, \ + dns_result_totext(result)); \ + continue; \ + } else \ + (void)NULL + +static void +usage(void) { + fprintf(stderr, "usage: zone_test [-dqsSM] [-c class] [-f file] " + "zone\n"); + exit(1); +} + +static void +setup(const char *zonename, const char *filename, const char *classname) { + isc_result_t result; + dns_rdataclass_t rdclass; + isc_consttextregion_t region; + isc_buffer_t buffer; + dns_fixedname_t fixorigin; + dns_name_t *origin; + const char *rbt = "rbt"; + + if (debug) { + fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n", + zonename, filename, classname); + } + result = dns_zone_create(&zone, mctx); + ERRRET(result, "dns_zone_new"); + + dns_zone_settype(zone, zonetype); + + isc_buffer_constinit(&buffer, zonename, strlen(zonename)); + isc_buffer_add(&buffer, strlen(zonename)); + dns_fixedname_init(&fixorigin); + result = dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer, + dns_rootname, 0, NULL); + ERRRET(result, "dns_name_fromtext"); + origin = dns_fixedname_name(&fixorigin); + + result = dns_zone_setorigin(zone, origin); + ERRRET(result, "dns_zone_setorigin"); + + dns_zone_setdbtype(zone, 1, &rbt); + + result = dns_zone_setfile(zone, filename, dns_masterformat_text, + &dns_master_style_default); + ERRRET(result, "dns_zone_setfile"); + + region.base = classname; + region.length = strlen(classname); + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)(void *)®ion); + ERRRET(result, "dns_rdataclass_fromtext"); + + dns_zone_setclass(zone, rdclass); + + if (zonetype == dns_zone_secondary) { + dns_zone_setprimaries(zone, &addr, 1); + } + + result = dns_zone_load(zone, false); + ERRRET(result, "dns_zone_load"); + + result = dns_zonemgr_managezone(zonemgr, zone); + ERRRET(result, "dns_zonemgr_managezone"); +} + +static void +print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) { + isc_buffer_t text; + char t[1000]; + isc_result_t result; + isc_region_t r; + + isc_buffer_init(&text, t, sizeof(t)); + result = dns_rdataset_totext(rdataset, name, false, false, &text); + isc_buffer_usedregion(&text, &r); + if (result == ISC_R_SUCCESS) { + printf("%.*s", (int)r.length, (char *)r.base); + } else { + printf("%s\n", dns_result_totext(result)); + } +} + +static void +query(void) { + char buf[1024]; + dns_fixedname_t name; + dns_fixedname_t found; + dns_db_t *db; + isc_buffer_t buffer; + isc_result_t result; + dns_rdataset_t rdataset; + dns_rdataset_t sigset; + fd_set rfdset = { { 0 } }; + + db = NULL; + result = dns_zone_getdb(zone, &db); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "%s() returned %s\n", "dns_zone_getdb", + dns_result_totext(result)); + return; + } + + dns_fixedname_init(&found); + dns_rdataset_init(&rdataset); + dns_rdataset_init(&sigset); + + do { + char *s; + fprintf(stdout, "zone_test "); + fflush(stdout); + FD_ZERO(&rfdset); + FD_SET(0, &rfdset); + select(1, &rfdset, NULL, NULL, NULL); + if (fgets(buf, sizeof(buf), stdin) == NULL) { + fprintf(stdout, "\n"); + break; + } + buf[sizeof(buf) - 1] = '\0'; + + s = strchr(buf, '\n'); + if (s != NULL) { + *s = '\0'; + } + s = strchr(buf, '\r'); + if (s != NULL) { + *s = '\0'; + } + if (strcmp(buf, "dump") == 0) { + dns_zone_dumptostream(zone, stdout, + dns_masterformat_text, + &dns_master_style_default, 0); + continue; + } + if (strlen(buf) == 0U) { + continue; + } + dns_fixedname_init(&name); + isc_buffer_init(&buffer, buf, strlen(buf)); + isc_buffer_add(&buffer, strlen(buf)); + result = dns_name_fromtext(dns_fixedname_name(&name), &buffer, + dns_rootname, 0, NULL); + ERRCONT(result, "dns_name_fromtext"); + + result = dns_db_find(db, dns_fixedname_name(&name), + NULL /*version*/, dns_rdatatype_a, + 0 /*options*/, 0 /*time*/, NULL /*nodep*/, + dns_fixedname_name(&found), &rdataset, + &sigset); + fprintf(stderr, "%s() returned %s\n", "dns_db_find", + dns_result_totext(result)); + switch (result) { + case DNS_R_DELEGATION: + print_rdataset(dns_fixedname_name(&found), &rdataset); + break; + case ISC_R_SUCCESS: + print_rdataset(dns_fixedname_name(&name), &rdataset); + break; + default: + break; + } + + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + if (dns_rdataset_isassociated(&sigset)) { + dns_rdataset_disassociate(&sigset); + } + } while (1); + dns_rdataset_invalidate(&rdataset); + dns_db_detach(&db); +} + +int +main(int argc, char **argv) { + int c; + char *filename = NULL; + const char *classname = "IN"; + + while ((c = isc_commandline_parse(argc, argv, "cdf:m:qsMS")) != EOF) { + switch (c) { + case 'c': + classname = isc_commandline_argument; + break; + case 'd': + debug++; + break; + case 'f': + if (filename != NULL) { + usage(); + } + filename = isc_commandline_argument; + break; + case 'm': + memset(&addr, 0, sizeof(addr)); + addr.type.sin.sin_family = AF_INET; + if (inet_pton(AF_INET, isc_commandline_argument, + &addr.type.sin.sin_addr) != 1) + { + fprintf(stderr, "bad master address '%s'\n", + isc_commandline_argument); + exit(1); + } + addr.type.sin.sin_port = htons(53); + break; + case 'q': + quiet++; + break; + case 's': + stats++; + break; + case 'S': + zonetype = dns_zone_secondary; + break; + case 'M': + zonetype = dns_zone_primary; + break; + default: + usage(); + } + } + + if (argv[isc_commandline_index] == NULL) { + usage(); + } + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + isc_mem_create(&mctx); + RUNTIME_CHECK(isc_managers_create(mctx, 2, 0, NULL, &taskmgr) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr, + &zonemgr) == ISC_R_SUCCESS); + if (filename == NULL) { + filename = argv[isc_commandline_index]; + } + setup(argv[isc_commandline_index], filename, classname); + query(); + if (zone != NULL) { + dns_zone_detach(&zone); + } + dns_zonemgr_shutdown(zonemgr); + dns_zonemgr_detach(&zonemgr); + isc_socketmgr_destroy(&socketmgr); + isc_managers_destroy(&netmgr, &taskmgr); + isc_timermgr_destroy(&timermgr); + if (!quiet && stats) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/pkcs11/Makefile.in b/bin/tests/pkcs11/Makefile.in new file mode 100644 index 0000000..56024c4 --- /dev/null +++ b/bin/tests/pkcs11/Makefile.in @@ -0,0 +1,32 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = ${ISC_INCLUDES} +CDEFINES = + +ISCLIBS = ../../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ + +LIBS = ${ISCLIBS} @LIBS@ + +SUBDIRS = benchmarks + +@BIND9_MAKE_RULES@ + +test: + +clean distclean:: + rm -f ${TARGETS} diff --git a/bin/tests/pkcs11/README b/bin/tests/pkcs11/README new file mode 100644 index 0000000..2b594d9 --- /dev/null +++ b/bin/tests/pkcs11/README @@ -0,0 +1,15 @@ +"pkcs11-hmacmd5" is here to check for the presence of a known bug in +the Thales nCipher PKCS#11 provider library. To test for the bug, use +pkcs11-hmacmd5 to hash a test vector from RFC 2104, and determine +whether the resulting digest is is correct. For instance: + + echo -n "Hi There" | \ + ./pkcs11-hmacmd5 -p -k '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b' + +...must return "9294727a3638bb1c13f48ef8158bfc9d". + +If any other value is returned, then the provider library is buggy, +and theflag PK11_MD5_HMAC_REPLACE must be defined in +lib/isc/include/pk11/site.h +However, if the correct value is returned, then it is safe to turn +off PK11_MD5_HMAC_REPLACE. (It is on by default.) diff --git a/bin/tests/pkcs11/benchmarks/Makefile.in b/bin/tests/pkcs11/benchmarks/Makefile.in new file mode 100644 index 0000000..8101efc --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/Makefile.in @@ -0,0 +1,74 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = ${ISC_INCLUDES} +CDEFINES = + +ISCLIBS = ../../../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ + +LIBS = ${ISCLIBS} @LIBS@ + +SUBDIRS = + +TARGETS = session@EXEEXT@ login@EXEEXT@ \ + create@EXEEXT@ find@EXEEXT@ \ + pubrsa@EXEEXT@ privrsa@EXEEXT@ genrsa@EXEEXT@ \ + sign@EXEEXT@ verify@EXEEXT@ + +SRCS = session.c login.c create.c find.c \ + pubrsa.c privrsa.c genrsa.c sign.c verify.c + +@BIND9_MAKE_RULES@ + +session@EXEEXT@: @srcdir@/session.c + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ @srcdir@/session.c ${LIBS} + +login@EXEEXT@: @srcdir@/login.c + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ @srcdir@/login.c ${LIBS} + +create@EXEEXT@: @srcdir@/create.c + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ @srcdir@/create.c ${LIBS} + +find@EXEEXT@: @srcdir@/find.c + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ @srcdir@/find.c ${LIBS} + +pubrsa@EXEEXT@: @srcdir@/pubrsa.c + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ @srcdir@/pubrsa.c ${LIBS} + +privrsa@EXEEXT@: @srcdir@/privrsa.c + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ @srcdir@/privrsa.c ${LIBS} + +genrsa@EXEEXT@: @srcdir@/genrsa.c + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ @srcdir@/genrsa.c ${LIBS} + +sign@EXEEXT@: @srcdir@/sign.c + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ @srcdir@/sign.c ${LIBS} + +verify@EXEEXT@: @srcdir@/verify.c + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ + -o $@ @srcdir@/verify.c ${LIBS} + +clean distclean:: + rm -f ${TARGETS} diff --git a/bin/tests/pkcs11/benchmarks/create.c b/bin/tests/pkcs11/benchmarks/create.c new file mode 100644 index 0000000..2f1c365 --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/create.c @@ -0,0 +1,264 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* create [-m module] [-s $slot] [-p pin] [-t] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +CK_BYTE buf[1024]; +char label[16]; + +static CK_BBOOL truevalue = TRUE; +static CK_BBOOL falsevalue = FALSE; + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE *hKey; + CK_OBJECT_CLASS kClass = CKO_DATA; + CK_ULONG len = sizeof(buf); + CK_ATTRIBUTE kTemplate[] = { + { CKA_CLASS, &kClass, (CK_ULONG)sizeof(kClass) }, + { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_LABEL, (CK_BYTE_PTR)label, (CK_ULONG)sizeof(label) }, + { CKA_VALUE, buf, (CK_ULONG)sizeof(buf) } + }; + pk11_context_t pctx; + char *lib_name = NULL; + char *pin = NULL; + int error = 0; + int c, errflg = 0; + int ontoken = 0; + unsigned int count = 1000; + unsigned int i; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + break; + case 't': + ontoken = 1; + break; + case 'p': + pin = isc_commandline_argument; + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tcreate [-m module] [-s slot] [-t] [-n " + "count]\n"); + exit(1); + } + + pk11_result_register(); + + /* Allocate handles */ + hKey = (CK_SESSION_HANDLE *)malloc(count * sizeof(CK_SESSION_HANDLE)); + if (hKey == NULL) { + perror("malloc"); + exit(1); + } + for (i = 0; i < count; i++) { + hKey[i] = CK_INVALID_HANDLE; + } + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, OP_ANY, true, true, true, + (const char *)pin, slot); + if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) && + (result != PK11_R_NODIGESTSERVICE) && + (result != PK11_R_NOAESSERVICE)) + { + fprintf(stderr, "Error initializing PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + if (pin != NULL) { + memset(pin, 0, strlen((char *)pin)); + } + + hSession = pctx.session; + + /* Randomize the buffer */ + rv = pkcs_C_GenerateRandom(hSession, buf, len); + if (rv != CKR_OK) { + fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv); + goto exit_objects; + } + + if (ontoken) { + kTemplate[1].pValue = &truevalue; + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_objects; + } + + for (i = 0; i < count; i++) { + (void)snprintf(label, sizeof(label), "obj%u", i); + kTemplate[3].ulValueLen = strlen(label); + rv = pkcs_C_CreateObject(hSession, kTemplate, 5, &hKey[i]); + if (rv != CKR_OK) { + fprintf(stderr, "C_CreateObject[%u]: Error = 0x%.8lX\n", + i, rv); + error = 1; + if (i == 0) { + goto exit_objects; + } + break; + } + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_objects; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%u created objects in %ld.%09lds\n", i, endtime.tv_sec, + endtime.tv_nsec); + if (i > 0) { + printf("%g created objects/s\n", + 1024 * i / + ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + +exit_objects: + for (i = 0; i < count; i++) { + /* Destroy objects */ + if (hKey[i] == CK_INVALID_HANDLE) { + continue; + } + rv = pkcs_C_DestroyObject(hSession, hKey[i]); + if ((rv != CKR_OK) && !errflg) { + fprintf(stderr, + "C_DestroyObject[%u]: Error = 0x%.8lX\n", i, + rv); + errflg = 1; + } + } + + free(hKey); + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/tests/pkcs11/benchmarks/find.c b/bin/tests/pkcs11/benchmarks/find.c new file mode 100644 index 0000000..e43fb68 --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/find.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* find [-m module] [-s $slot] [-p pin] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +CK_BYTE label[] = "foo??bar!!"; + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; + CK_ATTRIBUTE sTemplate[] = { + { CKA_LABEL, label, (CK_ULONG)sizeof(label) }, + }; + CK_OBJECT_HANDLE sKey = CK_INVALID_HANDLE; + CK_ULONG found = 0; + pk11_context_t pctx; + pk11_optype_t op_type = OP_RSA; + char *lib_name = NULL; + char *pin = NULL; + int error = 0; + int c, errflg = 0; + unsigned int count = 1000; + unsigned int i; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:p:n:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + op_type = OP_ANY; + break; + case 'p': + pin = isc_commandline_argument; + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tfind [-m module] [-s slot] [-p pin] [-n " + "count]\n"); + exit(1); + } + + pk11_result_register(); + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, op_type, false, false, true, + (const char *)pin, slot); + if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) && + (result != PK11_R_NODIGESTSERVICE) && + (result != PK11_R_NOAESSERVICE)) + { + fprintf(stderr, "Error initializing PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + if (pin != NULL) { + memset(pin, 0, strlen((char *)pin)); + } + + hSession = pctx.session; + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_objects; + } + + for (i = 0; !error && (i < count); i++) { + rv = pkcs_C_FindObjectsInit(hSession, sTemplate, 1); + if (rv != CKR_OK) { + fprintf(stderr, + "C_FindObjectsInit[%u]: Error = 0x%.8lX\n", i, + rv); + error = 1; + break; + } + + rv = pkcs_C_FindObjects(hSession, &sKey, 1, &found); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjects[%u]: Error = 0x%.8lX\n", + i, rv); + error = 1; + /* no break here! */ + } + + rv = pkcs_C_FindObjectsFinal(hSession); + if (rv != CKR_OK) { + fprintf(stderr, + "C_FindObjectsFinal[%u]: Error = 0x%.8lX\n", i, + rv); + error = 1; + break; + } + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_objects; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%u object searches in %ld.%09lds\n", i, endtime.tv_sec, + endtime.tv_nsec); + if (i > 0) { + printf("%g object searches/s\n", + 1024 * i / + ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + +exit_objects: + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/tests/pkcs11/benchmarks/genrsa.c b/bin/tests/pkcs11/benchmarks/genrsa.c new file mode 100644 index 0000000..062fa69 --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/genrsa.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* genrsa [-m module] [-s $slot] [-p pin] [-t] [-b bits] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +static CK_BBOOL truevalue = TRUE; +static CK_BBOOL falsevalue = FALSE; + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; + CK_MECHANISM mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 }; + CK_OBJECT_HANDLE *pubKey; + CK_OBJECT_HANDLE *privKey; + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; + CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE kType = CKK_RSA; + CK_ULONG bits = 1024; + CK_BYTE exponent[] = { 0x01, 0x00, 0x01 }; + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, (CK_ULONG)sizeof(pubClass) }, + { CKA_KEY_TYPE, &kType, (CK_ULONG)sizeof(kType) }, + { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_VERIFY, &truevalue, (CK_ULONG)sizeof(truevalue) }, + { CKA_MODULUS_BITS, &bits, (CK_ULONG)sizeof(bits) }, + { CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG)sizeof(exponent) } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, (CK_ULONG)sizeof(privClass) }, + { CKA_KEY_TYPE, &kType, (CK_ULONG)sizeof(kType) }, + { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_PRIVATE, &truevalue, (CK_ULONG)sizeof(truevalue) }, + { CKA_SIGN, &truevalue, (CK_ULONG)sizeof(truevalue) }, + }; + pk11_context_t pctx; + pk11_optype_t op_type = OP_RSA; + char *lib_name = NULL; + char *pin = NULL; + int error = 0; + int c, errflg = 0; + int ontoken = 0; + unsigned int count = 1000; + unsigned int i; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tb:n:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + op_type = OP_ANY; + break; + case 'p': + pin = isc_commandline_argument; + break; + case 't': + ontoken = 1; + break; + case 'b': + bits = (CK_ULONG)atoi(isc_commandline_argument); + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tgenrsa [-m module] [-s slot] [-p pin] " + "[-t] [-b bits] [-n count]\n"); + exit(1); + } + + pk11_result_register(); + + /* Allocate handles */ + pubKey = (CK_SESSION_HANDLE *)malloc(count * sizeof(CK_SESSION_HANDLE)); + if (pubKey == NULL) { + perror("malloc"); + exit(1); + } + privKey = + (CK_SESSION_HANDLE *)malloc(count * sizeof(CK_SESSION_HANDLE)); + if (privKey == NULL) { + free(pubKey); + perror("malloc"); + exit(1); + } + for (i = 0; i < count; i++) { + pubKey[i] = CK_INVALID_HANDLE; + privKey[i] = CK_INVALID_HANDLE; + } + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, op_type, false, true, true, + (const char *)pin, slot); + if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) && + (result != PK11_R_NODIGESTSERVICE) && + (result != PK11_R_NOAESSERVICE)) + { + fprintf(stderr, "Error initializing PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + if (pin != NULL) { + memset(pin, 0, strlen((char *)pin)); + } + + hSession = pctx.session; + + if (ontoken) { + pubTemplate[2].pValue = &truevalue; + privTemplate[2].pValue = &truevalue; + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_keys; + } + + for (i = 0; i < count; i++) { + rv = pkcs_C_GenerateKeyPair(hSession, &mech, pubTemplate, 7, + privTemplate, 5, &pubKey[i], + &privKey[i]); + if (rv != CKR_OK) { + fprintf(stderr, + "C_GenerateKeyPair[%u]: Error = 0x%.8lX\n", i, + rv); + error = 1; + if (i == 0) { + goto exit_keys; + } + break; + } + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_keys; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%u generated RSA in %ld.%09lds\n", i, endtime.tv_sec, + endtime.tv_nsec); + if (i > 0) { + printf("%g generated RSA/s\n", + 1024 * i / + ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + +exit_keys: + for (i = 0; i < count; i++) { + /* Destroy keys */ + if (pubKey[i] == CK_INVALID_HANDLE) { + goto destroy_priv; + } + rv = pkcs_C_DestroyObject(hSession, pubKey[i]); + if ((rv != CKR_OK) && !errflg) { + fprintf(stderr, + "C_DestroyObject[pub%u]: Error = 0x%.8lX\n", i, + rv); + errflg = 1; + } + destroy_priv: + if (privKey[i] == CK_INVALID_HANDLE) { + continue; + } + rv = pkcs_C_DestroyObject(hSession, privKey[i]); + if ((rv != CKR_OK) && !errflg) { + fprintf(stderr, + "C_DestroyObject[priv%u]: Error = 0x%.8lX\n", i, + rv); + errflg = 1; + } + } + + free(pubKey); + free(privKey); + + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/tests/pkcs11/benchmarks/login.c b/bin/tests/pkcs11/benchmarks/login.c new file mode 100644 index 0000000..70dd0a1 --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/login.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* login [-m module] [-s $slot] [-p pin] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +int +main(int argc, char *argv[]) { + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE *hSession; + CK_UTF8CHAR *pin = NULL; + char *lib_name = NULL; + int error = 0; + int c, errflg = 0; + unsigned int count = 1000; + unsigned int i, j; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:p:n:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + break; + case 'p': + pin = (CK_UTF8CHAR *)isc_commandline_argument; + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tlogin [-m module] [-s slot] [-p pin] [-n " + "count]\n"); + exit(1); + } + + /* allocate sessions */ + hSession = + (CK_SESSION_HANDLE *)malloc(count * sizeof(CK_SESSION_HANDLE)); + if (hSession == NULL) { + perror("malloc"); + exit(1); + } + for (i = 0; i < count; i++) { + hSession[i] = CK_INVALID_HANDLE; + } + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = (CK_UTF8CHAR *)getpass("Enter Pin: "); + } + + rv = pkcs_C_Initialize(NULL_PTR); + if (rv != CKR_OK) { + if (rv == 0xfe) { + fprintf(stderr, "Can't load or link module \"%s\"\n", + pk11_get_lib_name()); + } else { + fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv); + } + free(hSession); + exit(1); + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_program; + } + + /* loop */ + for (i = 0; i < count; i++) { + /* Open sessions */ + rv = pkcs_C_OpenSession(slot, CKF_SERIAL_SESSION, NULL_PTR, + NULL_PTR, &hSession[i]); + if (rv != CKR_OK) { + fprintf(stderr, "C_OpenSession[%u]: Error = 0x%.8lX\n", + i, rv); + error = 1; + if (i == 0) { + goto exit_program; + } + break; + } + + /* Logon */ + rv = pkcs_C_Login(hSession[i], CKU_USER, pin, + strlen((char *)pin)); + if (rv != CKR_OK) { + fprintf(stderr, "C_Login[%u]: Error = 0x%.8lX\n", i, + rv); + error = 1; + if (i == 0) { + goto exit_program; + } + break; + } + + /* Logoff */ + rv = pkcs_C_Logout(hSession[i]); + if (rv != CKR_OK) { + fprintf(stderr, "C_Logout[%u]: Error = 0x%.8lX\n", i, + rv); + error = 1; + if (i == 0) { + goto exit_program; + } + break; + } + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_program; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%u logins in %ld.%09lds\n", i, endtime.tv_sec, endtime.tv_nsec); + if (i > 0) { + printf("%g logins/s\n", + i / ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + + for (j = 0; j < i; j++) { + if (hSession[j] == CK_INVALID_HANDLE) { + continue; + } + /* Close sessions */ + rv = pkcs_C_CloseSession(hSession[j]); + if ((rv != CKR_OK) && !errflg) { + fprintf(stderr, "C_CloseSession[%u]: Error = 0x%.8lX\n", + j, rv); + errflg = 1; + } + } + +exit_program: + free(hSession); + + rv = pkcs_C_Finalize(NULL_PTR); + if (rv != CKR_OK) { + fprintf(stderr, "C_Finalize: Error = 0x%.8lX\n", rv); + } + + exit(error); +} diff --git a/bin/tests/pkcs11/benchmarks/privrsa.c b/bin/tests/pkcs11/benchmarks/privrsa.c new file mode 100644 index 0000000..bd6911e --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/privrsa.c @@ -0,0 +1,332 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* privrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +CK_BYTE modulus[] = { + 0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99, 0x44, 0x82, 0x20, 0x78, + 0x43, 0x7f, 0x5f, 0x3b, 0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90, + 0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f, 0x16, 0x1c, 0x56, 0xf8, + 0xc1, 0x06, 0x2f, 0x96, 0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5, + 0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b, 0x9f, 0xdc, 0x36, 0xcb, + 0xad, 0x56, 0xf4, 0xbd, 0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08, + 0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79, 0xca, 0x4e, 0x72, 0xeb, + 0xfb, 0x2c, 0xf1, 0x45, 0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7, + 0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd, 0x49, 0xdd, 0x8a, 0x3c, + 0x3c, 0xf7, 0xa1, 0x5d, 0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f, + 0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34, 0xbf +}; +CK_BYTE pubexp[] = { 0x01, 0x00, 0x01 }; +CK_BYTE privexp[] = { + 0x00, 0xae, 0x02, 0xf1, 0x47, 0xa8, 0x07, 0x02, 0xb8, 0xf1, 0xd6, 0x92, + 0x03, 0xee, 0x50, 0x33, 0xab, 0x67, 0x9e, 0x3b, 0xb1, 0x57, 0xc7, 0x3e, + 0xc4, 0x86, 0x46, 0x61, 0xf1, 0xf8, 0xb6, 0x63, 0x9f, 0x91, 0xe6, 0x3f, + 0x44, 0xb8, 0x77, 0x1b, 0xbe, 0x4c, 0x3c, 0xb8, 0x9f, 0xf7, 0x45, 0x7d, + 0xbf, 0x4f, 0xef, 0x3b, 0xcc, 0xda, 0x1a, 0x4e, 0x34, 0xa8, 0x40, 0xea, + 0x51, 0x72, 0x8a, 0xea, 0x47, 0x06, 0x04, 0xd0, 0x62, 0x31, 0xa0, 0x6c, + 0x09, 0x60, 0xf9, 0xc7, 0x95, 0x88, 0x4a, 0xd7, 0x19, 0xce, 0x89, 0x08, + 0x87, 0x14, 0xef, 0xcc, 0x0a, 0xef, 0x72, 0xb9, 0x21, 0xf5, 0xf0, 0xcd, + 0x6d, 0xe5, 0xfa, 0x15, 0x7f, 0xae, 0x33, 0x9f, 0x26, 0xac, 0x2e, 0x52, + 0x02, 0x07, 0xfb, 0x1d, 0x4b, 0xec, 0x9a, 0x6b, 0x3b, 0x26, 0x1f, 0x52, + 0xfc, 0x47, 0xf8, 0x66, 0x33, 0xfa, 0x50, 0x6c, 0x41 +}; +CK_BYTE prime1[] = { 0x00, 0xe8, 0x98, 0xeb, 0xa1, 0xf0, 0xce, 0xde, 0xc2, 0x74, + 0x01, 0x18, 0x2b, 0xd3, 0x8f, 0x58, 0xcd, 0xe9, 0x8e, 0x97, + 0xbe, 0xfe, 0xe8, 0x6f, 0xd6, 0x0c, 0x0a, 0x47, 0xf8, 0x56, + 0x84, 0x36, 0x15, 0xe6, 0x75, 0x1c, 0x69, 0x48, 0x8b, 0xf5, + 0x0f, 0x84, 0xd2, 0x60, 0x8b, 0xa2, 0x2a, 0xa1, 0xeb, 0xed, + 0xbe, 0x2d, 0xe9, 0x41, 0x0b, 0xed, 0x17, 0x7c, 0xd3, 0xa6, + 0x35, 0x6e, 0xa6, 0xd8, 0x21 }; +CK_BYTE prime2[] = { 0x00, 0xca, 0x15, 0x6a, 0x43, 0x5e, 0x83, 0xc9, 0x09, 0xeb, + 0x14, 0x1e, 0x46, 0x46, 0x97, 0xfa, 0xfa, 0x3c, 0x61, 0x7e, + 0xc1, 0xf8, 0x8c, 0x5e, 0xcb, 0xbf, 0xe4, 0xb9, 0x78, 0x7f, + 0x4f, 0xab, 0x82, 0x15, 0x53, 0xaa, 0x04, 0xee, 0x11, 0x21, + 0x2e, 0x23, 0x08, 0xa0, 0x14, 0x6d, 0x3a, 0x88, 0xe6, 0xf8, + 0xbe, 0x61, 0x38, 0x99, 0xca, 0x36, 0x0d, 0x3e, 0x42, 0x0f, + 0x63, 0x4d, 0x73, 0xf0, 0xdf }; +CK_BYTE exp_1[] = { 0x66, 0x2d, 0xb7, 0x65, 0xbe, 0x99, 0xc2, 0x35, 0xfe, 0x2b, + 0xf4, 0xe8, 0x5b, 0xd9, 0xdf, 0x13, 0x26, 0x04, 0xe4, 0x18, + 0x9d, 0x76, 0x92, 0x9a, 0x9f, 0x53, 0x6c, 0xe6, 0x65, 0x6b, + 0x53, 0x2f, 0x2f, 0xbc, 0x46, 0xac, 0xe1, 0x97, 0xca, 0x21, + 0xf5, 0x21, 0x4e, 0x14, 0x49, 0x3b, 0x1d, 0x42, 0xbd, 0x80, + 0x0c, 0x3f, 0x29, 0xba, 0x09, 0x7f, 0x85, 0xf0, 0x9c, 0x55, + 0x60, 0xb4, 0x9e, 0xc1 }; +CK_BYTE exp_2[] = { 0x00, 0x87, 0x22, 0x74, 0xf1, 0xe2, 0x15, 0x3c, 0x6d, 0xde, + 0x7e, 0x90, 0x94, 0x2c, 0x06, 0xdb, 0xb5, 0x54, 0x85, 0x59, + 0xcf, 0x7a, 0x56, 0xdb, 0xd9, 0x62, 0x54, 0x20, 0x56, 0xdc, + 0xc3, 0xb9, 0x0b, 0xff, 0x18, 0xf8, 0x7b, 0xdd, 0x7b, 0x24, + 0xf6, 0x06, 0x45, 0x71, 0x4e, 0xd7, 0x90, 0x2a, 0x16, 0x52, + 0x46, 0x75, 0x1a, 0xf5, 0x74, 0x8c, 0x5a, 0xa4, 0xc4, 0x66, + 0x27, 0xe0, 0x96, 0x64, 0x7f }; +CK_BYTE coeff[] = { 0x00, 0xd0, 0x1f, 0xb3, 0x47, 0x40, 0x93, 0x8b, 0x99, 0xd7, + 0xb5, 0xc6, 0x09, 0x82, 0x65, 0x94, 0x9d, 0x56, 0x0a, 0x05, + 0x55, 0x7d, 0x93, 0x04, 0xa4, 0x26, 0xee, 0x42, 0x86, 0xa3, + 0xf1, 0xd5, 0x7a, 0x42, 0x84, 0x3c, 0x21, 0x96, 0x9a, 0xd9, + 0x36, 0xd4, 0x62, 0x01, 0xb0, 0x8b, 0x77, 0xe5, 0xcc, 0x1b, + 0xd2, 0x12, 0xd2, 0x9c, 0x89, 0x67, 0x0c, 0x00, 0x09, 0x56, + 0x8c, 0x33, 0x57, 0xf9, 0x8c }; + +char label[16]; + +static CK_BBOOL truevalue = TRUE; +static CK_BBOOL falsevalue = FALSE; + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE *hKey; + CK_OBJECT_CLASS kClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE kType = CKK_RSA; + CK_ATTRIBUTE kTemplate[] = { + { CKA_CLASS, &kClass, (CK_ULONG)sizeof(kClass) }, + { CKA_KEY_TYPE, &kType, (CK_ULONG)sizeof(kType) }, + { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_PRIVATE, &truevalue, (CK_ULONG)sizeof(truevalue) }, + { CKA_LABEL, (CK_BYTE_PTR)label, (CK_ULONG)sizeof(label) }, + { CKA_SIGN, &truevalue, (CK_ULONG)sizeof(truevalue) }, + { CKA_MODULUS, modulus, (CK_ULONG)sizeof(modulus) }, + { CKA_PUBLIC_EXPONENT, pubexp, (CK_ULONG)sizeof(pubexp) }, + { CKA_PRIVATE_EXPONENT, privexp, (CK_ULONG)sizeof(privexp) }, + { CKA_PRIME_1, prime1, (CK_ULONG)sizeof(prime1) }, + { CKA_PRIME_2, prime2, (CK_ULONG)sizeof(prime2) }, + { CKA_EXPONENT_1, exp_1, (CK_ULONG)sizeof(exp_1) }, + { CKA_EXPONENT_2, exp_2, (CK_ULONG)sizeof(exp_2) }, + { CKA_COEFFICIENT, coeff, (CK_ULONG)sizeof(coeff) } + }; + pk11_context_t pctx; + pk11_optype_t op_type = OP_RSA; + char *lib_name = NULL; + char *pin = NULL; + int error = 0; + int c, errflg = 0; + int ontoken = 0; + unsigned int count = 1000; + unsigned int i; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + op_type = OP_ANY; + break; + case 'p': + pin = isc_commandline_argument; + break; + case 't': + ontoken = 1; + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tprivrsa [-m module] [-s slot] [-p pin] " + "[-t] [-n count]\n"); + exit(1); + } + + pk11_result_register(); + + /* Allocate handles */ + hKey = (CK_SESSION_HANDLE *)malloc(count * sizeof(CK_SESSION_HANDLE)); + if (hKey == NULL) { + perror("malloc"); + exit(1); + } + for (i = 0; i < count; i++) { + hKey[i] = CK_INVALID_HANDLE; + } + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, op_type, false, true, true, + (const char *)pin, slot); + if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) && + (result != PK11_R_NODIGESTSERVICE) && + (result != PK11_R_NOAESSERVICE)) + { + fprintf(stderr, "Error initializing PKCS#11: %s\n", + isc_result_totext(result)); + free(hKey); + exit(1); + } + + if (pin != NULL) { + memset(pin, 0, strlen((char *)pin)); + } + + hSession = pctx.session; + + if (ontoken) { + kTemplate[2].pValue = &truevalue; + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_objects; + } + + for (i = 0; i < count; i++) { + (void)snprintf(label, sizeof(label), "obj%u", i); + kTemplate[4].ulValueLen = strlen(label); + rv = pkcs_C_CreateObject(hSession, kTemplate, 14, &hKey[i]); + if (rv != CKR_OK) { + fprintf(stderr, "C_CreateObject[%u]: Error = 0x%.8lX\n", + i, rv); + error = 1; + if (i == 0) { + goto exit_objects; + } + break; + } + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_objects; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%u private RSA keys in %ld.%09lds\n", i, endtime.tv_sec, + endtime.tv_nsec); + if (i > 0) { + printf("%g private RSA keys/s\n", + 1024 * i / + ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + +exit_objects: + for (i = 0; i < count; i++) { + /* Destroy objects */ + if (hKey[i] == CK_INVALID_HANDLE) { + continue; + } + rv = pkcs_C_DestroyObject(hSession, hKey[i]); + if ((rv != CKR_OK) && !errflg) { + fprintf(stderr, + "C_DestroyObject[%u]: Error = 0x%.8lX\n", i, + rv); + errflg = 1; + } + } + + free(hKey); + + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/tests/pkcs11/benchmarks/pubrsa.c b/bin/tests/pkcs11/benchmarks/pubrsa.c new file mode 100644 index 0000000..1036df7 --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/pubrsa.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* pubrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +CK_BYTE modulus[] = { + 0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99, 0x44, 0x82, 0x20, 0x78, + 0x43, 0x7f, 0x5f, 0x3b, 0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90, + 0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f, 0x16, 0x1c, 0x56, 0xf8, + 0xc1, 0x06, 0x2f, 0x96, 0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5, + 0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b, 0x9f, 0xdc, 0x36, 0xcb, + 0xad, 0x56, 0xf4, 0xbd, 0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08, + 0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79, 0xca, 0x4e, 0x72, 0xeb, + 0xfb, 0x2c, 0xf1, 0x45, 0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7, + 0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd, 0x49, 0xdd, 0x8a, 0x3c, + 0x3c, 0xf7, 0xa1, 0x5d, 0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f, + 0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34, 0xbf +}; +CK_BYTE exponent[] = { 0x01, 0x00, 0x01 }; + +char label[16]; + +static CK_BBOOL truevalue = TRUE; +static CK_BBOOL falsevalue = FALSE; + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE *hKey; + CK_OBJECT_CLASS kClass = CKO_PUBLIC_KEY; + CK_KEY_TYPE kType = CKK_RSA; + CK_ATTRIBUTE kTemplate[] = { + { CKA_CLASS, &kClass, (CK_ULONG)sizeof(kClass) }, + { CKA_KEY_TYPE, &kType, (CK_ULONG)sizeof(kType) }, + { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_LABEL, (CK_BYTE_PTR)label, (CK_ULONG)sizeof(label) }, + { CKA_VERIFY, &truevalue, (CK_ULONG)sizeof(truevalue) }, + { CKA_MODULUS, modulus, (CK_ULONG)sizeof(modulus) }, + { CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG)sizeof(exponent) } + }; + pk11_context_t pctx; + pk11_optype_t op_type = OP_RSA; + char *lib_name = NULL; + char *pin = NULL; + int error = 0; + int c, errflg = 0; + int ontoken = 0; + unsigned int count = 1000; + unsigned int i; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + op_type = OP_ANY; + break; + case 'p': + pin = isc_commandline_argument; + break; + case 't': + ontoken = 1; + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tpubrsa [-m module] [-s slot] [-p pin] " + "[-t] [-n count]\n"); + exit(1); + } + + pk11_result_register(); + + /* Allocate handles */ + hKey = (CK_SESSION_HANDLE *)malloc(count * sizeof(CK_SESSION_HANDLE)); + if (hKey == NULL) { + perror("malloc"); + exit(1); + } + for (i = 0; i < count; i++) { + hKey[i] = CK_INVALID_HANDLE; + } + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, op_type, false, true, true, + (const char *)pin, slot); + if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) && + (result != PK11_R_NODIGESTSERVICE) && + (result != PK11_R_NOAESSERVICE)) + { + fprintf(stderr, "Error initializing PKCS#11: %s\n", + isc_result_totext(result)); + free(hKey); + exit(1); + } + + if (pin != NULL) { + memset(pin, 0, strlen((char *)pin)); + } + + hSession = pctx.session; + + if (ontoken) { + kTemplate[2].pValue = &truevalue; + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_objects; + } + + for (i = 0; i < count; i++) { + (void)snprintf(label, sizeof(label), "obj%u", i); + kTemplate[4].ulValueLen = strlen(label); + rv = pkcs_C_CreateObject(hSession, kTemplate, 8, &hKey[i]); + if (rv != CKR_OK) { + fprintf(stderr, "C_CreateObject[%u]: Error = 0x%.8lX\n", + i, rv); + error = 1; + if (i == 0) { + goto exit_objects; + } + break; + } + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_objects; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%u public RSA keys in %ld.%09lds\n", i, endtime.tv_sec, + endtime.tv_nsec); + if (i > 0) { + printf("%g public RSA keys/s\n", + 1024 * i / + ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + +exit_objects: + for (i = 0; i < count; i++) { + /* Destroy objects */ + if (hKey[i] == CK_INVALID_HANDLE) { + continue; + } + rv = pkcs_C_DestroyObject(hSession, hKey[i]); + if ((rv != CKR_OK) && !errflg) { + fprintf(stderr, + "C_DestroyObject[%u]: Error = 0x%.8lX\n", i, + rv); + errflg = 1; + } + } + + free(hKey); + + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/tests/pkcs11/benchmarks/session.c b/bin/tests/pkcs11/benchmarks/session.c new file mode 100644 index 0000000..69f823f --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/session.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* session [-m module] [-s $slot] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +int +main(int argc, char *argv[]) { + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE *hSession; + char *lib_name = NULL; + int error = 0; + int c, errflg = 0; + unsigned int count = 1000; + unsigned int i; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:n:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tsession [-m module] [-s slot] [-n count]\n"); + exit(1); + } + + /* Allocate sessions */ + hSession = + (CK_SESSION_HANDLE *)malloc(count * sizeof(CK_SESSION_HANDLE)); + if (hSession == NULL) { + perror("malloc"); + exit(1); + } + for (i = 0; i < count; i++) { + hSession[i] = CK_INVALID_HANDLE; + } + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + rv = pkcs_C_Initialize(NULL_PTR); + if (rv != CKR_OK) { + if (rv == 0xfe) { + fprintf(stderr, "Can't load or link module \"%s\"\n", + pk11_get_lib_name()); + } else { + fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv); + } + free(hSession); + exit(1); + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_program; + } + + /* loop */ + for (i = 0; i < count; i++) { + /* Open sessions */ + rv = pkcs_C_OpenSession(slot, CKF_SERIAL_SESSION, NULL_PTR, + NULL_PTR, &hSession[i]); + if (rv != CKR_OK) { + fprintf(stderr, "C_OpenSession[%u]: Error = 0x%.8lX\n", + i, rv); + error = 1; + if (i == 0) { + goto exit_program; + } + break; + } + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_program; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%u sessions in %ld.%09lds\n", i, endtime.tv_sec, + endtime.tv_nsec); + if (i > 0) { + printf("%g sessions/s\n", + i / ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + + for (i = 0; i < count; i++) { + /* Close sessions */ + if (hSession[i] == CK_INVALID_HANDLE) { + continue; + } + rv = pkcs_C_CloseSession(hSession[i]); + if ((rv != CKR_OK) && !errflg) { + fprintf(stderr, "C_CloseSession[%u]: Error = 0x%.8lX\n", + i, rv); + errflg = 1; + } + } + +exit_program: + free(hSession); + + rv = pkcs_C_Finalize(NULL_PTR); + if (rv != CKR_OK) { + fprintf(stderr, "C_Finalize: Error = 0x%.8lX\n", rv); + } + + exit(error); +} diff --git a/bin/tests/pkcs11/benchmarks/sha1.c b/bin/tests/pkcs11/benchmarks/sha1.c new file mode 100644 index 0000000..17a5662 --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/sha1.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* sha1 [-m module] [-s $slot] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +CK_BYTE buf[1024]; + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; + CK_MECHANISM mech = { CKM_SHA_1, NULL, 0 }; + CK_ULONG len = sizeof(buf); + pk11_context_t pctx; + pk11_optype_t op_type = OP_DIGEST; + char *lib_name = NULL; + int error = 0; + int c, errflg = 0; + unsigned int count = 1000; + unsigned int i; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:n:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + op_type = OP_ANY; + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tssha1 [-m module] [-s slot] [-n count]\n"); + exit(1); + } + + pk11_result_register(); + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + result = pk11_get_session(&pctx, op_type, false, false, false, NULL, + slot); + if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) && + (result != PK11_R_NOAESSERVICE)) + { + fprintf(stderr, "Error initializing PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + hSession = pctx.session; + + /* Randomize the buffer */ + rv = pkcs_C_GenerateRandom(hSession, buf, len); + if (rv != CKR_OK) { + fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv); + goto exit_session; + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_session; + } + + /* Initialize Digest */ + rv = pkcs_C_DigestInit(hSession, &mech); + if (rv != CKR_OK) { + fprintf(stderr, "C_DigestInit: Error = 0x%.8lX\n", rv); + goto exit_session; + } + + for (i = 0; i < count; i++) { + /* Digest buffer */ + rv = pkcs_C_DigestUpdate(hSession, buf, len); + if (rv != CKR_OK) { + fprintf(stderr, "C_DigestUpdate[%u]: Error = 0x%.8lX\n", + i, rv); + error = 1; + break; + } + } + + /* Finalize Digest (unconditionally) */ + len = 20U; + rv = pkcs_C_DigestFinal(hSession, buf, &len); + if ((rv != CKR_OK) && !error) { + fprintf(stderr, "C_DigestFinal: Error = 0x%.8lX\n", rv); + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_session; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%uK digested bytes in %ld.%09lds\n", i, endtime.tv_sec, + endtime.tv_nsec); + if (i > 0) { + printf("%g digested bytes/s\n", + 1024 * i / + ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + +exit_session: + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/tests/pkcs11/benchmarks/sign.c b/bin/tests/pkcs11/benchmarks/sign.c new file mode 100644 index 0000000..0a2bed7 --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/sign.c @@ -0,0 +1,336 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* signrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +CK_BYTE modulus[] = { + 0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99, 0x44, 0x82, 0x20, 0x78, + 0x43, 0x7f, 0x5f, 0x3b, 0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90, + 0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f, 0x16, 0x1c, 0x56, 0xf8, + 0xc1, 0x06, 0x2f, 0x96, 0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5, + 0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b, 0x9f, 0xdc, 0x36, 0xcb, + 0xad, 0x56, 0xf4, 0xbd, 0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08, + 0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79, 0xca, 0x4e, 0x72, 0xeb, + 0xfb, 0x2c, 0xf1, 0x45, 0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7, + 0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd, 0x49, 0xdd, 0x8a, 0x3c, + 0x3c, 0xf7, 0xa1, 0x5d, 0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f, + 0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34, 0xbf +}; +CK_BYTE pubexp[] = { 0x01, 0x00, 0x01 }; +CK_BYTE privexp[] = { + 0x00, 0xae, 0x02, 0xf1, 0x47, 0xa8, 0x07, 0x02, 0xb8, 0xf1, 0xd6, 0x92, + 0x03, 0xee, 0x50, 0x33, 0xab, 0x67, 0x9e, 0x3b, 0xb1, 0x57, 0xc7, 0x3e, + 0xc4, 0x86, 0x46, 0x61, 0xf1, 0xf8, 0xb6, 0x63, 0x9f, 0x91, 0xe6, 0x3f, + 0x44, 0xb8, 0x77, 0x1b, 0xbe, 0x4c, 0x3c, 0xb8, 0x9f, 0xf7, 0x45, 0x7d, + 0xbf, 0x4f, 0xef, 0x3b, 0xcc, 0xda, 0x1a, 0x4e, 0x34, 0xa8, 0x40, 0xea, + 0x51, 0x72, 0x8a, 0xea, 0x47, 0x06, 0x04, 0xd0, 0x62, 0x31, 0xa0, 0x6c, + 0x09, 0x60, 0xf9, 0xc7, 0x95, 0x88, 0x4a, 0xd7, 0x19, 0xce, 0x89, 0x08, + 0x87, 0x14, 0xef, 0xcc, 0x0a, 0xef, 0x72, 0xb9, 0x21, 0xf5, 0xf0, 0xcd, + 0x6d, 0xe5, 0xfa, 0x15, 0x7f, 0xae, 0x33, 0x9f, 0x26, 0xac, 0x2e, 0x52, + 0x02, 0x07, 0xfb, 0x1d, 0x4b, 0xec, 0x9a, 0x6b, 0x3b, 0x26, 0x1f, 0x52, + 0xfc, 0x47, 0xf8, 0x66, 0x33, 0xfa, 0x50, 0x6c, 0x41 +}; +CK_BYTE prime1[] = { 0x00, 0xe8, 0x98, 0xeb, 0xa1, 0xf0, 0xce, 0xde, 0xc2, 0x74, + 0x01, 0x18, 0x2b, 0xd3, 0x8f, 0x58, 0xcd, 0xe9, 0x8e, 0x97, + 0xbe, 0xfe, 0xe8, 0x6f, 0xd6, 0x0c, 0x0a, 0x47, 0xf8, 0x56, + 0x84, 0x36, 0x15, 0xe6, 0x75, 0x1c, 0x69, 0x48, 0x8b, 0xf5, + 0x0f, 0x84, 0xd2, 0x60, 0x8b, 0xa2, 0x2a, 0xa1, 0xeb, 0xed, + 0xbe, 0x2d, 0xe9, 0x41, 0x0b, 0xed, 0x17, 0x7c, 0xd3, 0xa6, + 0x35, 0x6e, 0xa6, 0xd8, 0x21 }; +CK_BYTE prime2[] = { 0x00, 0xca, 0x15, 0x6a, 0x43, 0x5e, 0x83, 0xc9, 0x09, 0xeb, + 0x14, 0x1e, 0x46, 0x46, 0x97, 0xfa, 0xfa, 0x3c, 0x61, 0x7e, + 0xc1, 0xf8, 0x8c, 0x5e, 0xcb, 0xbf, 0xe4, 0xb9, 0x78, 0x7f, + 0x4f, 0xab, 0x82, 0x15, 0x53, 0xaa, 0x04, 0xee, 0x11, 0x21, + 0x2e, 0x23, 0x08, 0xa0, 0x14, 0x6d, 0x3a, 0x88, 0xe6, 0xf8, + 0xbe, 0x61, 0x38, 0x99, 0xca, 0x36, 0x0d, 0x3e, 0x42, 0x0f, + 0x63, 0x4d, 0x73, 0xf0, 0xdf }; +CK_BYTE exp_1[] = { 0x66, 0x2d, 0xb7, 0x65, 0xbe, 0x99, 0xc2, 0x35, 0xfe, 0x2b, + 0xf4, 0xe8, 0x5b, 0xd9, 0xdf, 0x13, 0x26, 0x04, 0xe4, 0x18, + 0x9d, 0x76, 0x92, 0x9a, 0x9f, 0x53, 0x6c, 0xe6, 0x65, 0x6b, + 0x53, 0x2f, 0x2f, 0xbc, 0x46, 0xac, 0xe1, 0x97, 0xca, 0x21, + 0xf5, 0x21, 0x4e, 0x14, 0x49, 0x3b, 0x1d, 0x42, 0xbd, 0x80, + 0x0c, 0x3f, 0x29, 0xba, 0x09, 0x7f, 0x85, 0xf0, 0x9c, 0x55, + 0x60, 0xb4, 0x9e, 0xc1 }; +CK_BYTE exp_2[] = { 0x00, 0x87, 0x22, 0x74, 0xf1, 0xe2, 0x15, 0x3c, 0x6d, 0xde, + 0x7e, 0x90, 0x94, 0x2c, 0x06, 0xdb, 0xb5, 0x54, 0x85, 0x59, + 0xcf, 0x7a, 0x56, 0xdb, 0xd9, 0x62, 0x54, 0x20, 0x56, 0xdc, + 0xc3, 0xb9, 0x0b, 0xff, 0x18, 0xf8, 0x7b, 0xdd, 0x7b, 0x24, + 0xf6, 0x06, 0x45, 0x71, 0x4e, 0xd7, 0x90, 0x2a, 0x16, 0x52, + 0x46, 0x75, 0x1a, 0xf5, 0x74, 0x8c, 0x5a, 0xa4, 0xc4, 0x66, + 0x27, 0xe0, 0x96, 0x64, 0x7f }; +CK_BYTE coeff[] = { 0x00, 0xd0, 0x1f, 0xb3, 0x47, 0x40, 0x93, 0x8b, 0x99, 0xd7, + 0xb5, 0xc6, 0x09, 0x82, 0x65, 0x94, 0x9d, 0x56, 0x0a, 0x05, + 0x55, 0x7d, 0x93, 0x04, 0xa4, 0x26, 0xee, 0x42, 0x86, 0xa3, + 0xf1, 0xd5, 0x7a, 0x42, 0x84, 0x3c, 0x21, 0x96, 0x9a, 0xd9, + 0x36, 0xd4, 0x62, 0x01, 0xb0, 0x8b, 0x77, 0xe5, 0xcc, 0x1b, + 0xd2, 0x12, 0xd2, 0x9c, 0x89, 0x67, 0x0c, 0x00, 0x09, 0x56, + 0x8c, 0x33, 0x57, 0xf9, 0x8c }; + +CK_BYTE buf[1024]; +CK_BYTE sig[128]; + +static CK_BBOOL truevalue = TRUE; +static CK_BBOOL falsevalue = FALSE; + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; + CK_ULONG len; + CK_ULONG slen; + CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; + CK_OBJECT_CLASS kClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE kType = CKK_RSA; + CK_ATTRIBUTE kTemplate[] = { + { CKA_CLASS, &kClass, (CK_ULONG)sizeof(kClass) }, + { CKA_KEY_TYPE, &kType, (CK_ULONG)sizeof(kType) }, + { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_PRIVATE, &truevalue, (CK_ULONG)sizeof(truevalue) }, + { CKA_SIGN, &truevalue, (CK_ULONG)sizeof(truevalue) }, + { CKA_MODULUS, modulus, (CK_ULONG)sizeof(modulus) }, + { CKA_PUBLIC_EXPONENT, pubexp, (CK_ULONG)sizeof(pubexp) }, + { CKA_PRIVATE_EXPONENT, privexp, (CK_ULONG)sizeof(privexp) }, + { CKA_PRIME_1, prime1, (CK_ULONG)sizeof(prime1) }, + { CKA_PRIME_2, prime2, (CK_ULONG)sizeof(prime2) }, + { CKA_EXPONENT_1, exp_1, (CK_ULONG)sizeof(exp_1) }, + { CKA_EXPONENT_2, exp_2, (CK_ULONG)sizeof(exp_2) }, + { CKA_COEFFICIENT, coeff, (CK_ULONG)sizeof(coeff) } + }; + CK_MECHANISM mech = { CKM_SHA1_RSA_PKCS, NULL, 0 }; + pk11_context_t pctx; + pk11_optype_t op_type = OP_RSA; + char *lib_name = NULL; + char *pin = NULL; + int error = 0; + int c, errflg = 0; + int ontoken = 0; + unsigned int count = 1000; + unsigned int i; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + op_type = OP_ANY; + break; + case 'p': + pin = isc_commandline_argument; + break; + case 't': + ontoken = 1; + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tsign [-m module] [-s slot] [-p pin] " + "[-t] [-n count]\n"); + exit(1); + } + + pk11_result_register(); + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, op_type, false, true, true, + (const char *)pin, slot); + if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) && + (result != PK11_R_NODIGESTSERVICE) && + (result != PK11_R_NOAESSERVICE)) + { + fprintf(stderr, "Error initializing PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + if (pin != NULL) { + memset(pin, 0, strlen((char *)pin)); + } + + hSession = pctx.session; + + /* Create the private RSA key */ + if (ontoken) { + kTemplate[2].pValue = &truevalue; + } + + rv = pkcs_C_CreateObject(hSession, kTemplate, 13, &hKey); + if (rv != CKR_OK) { + fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv); + goto exit_key; + } + + /* Randomize the buffer */ + len = (CK_ULONG)sizeof(buf); + rv = pkcs_C_GenerateRandom(hSession, buf, len); + if (rv != CKR_OK) { + fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv); + goto exit_key; + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_key; + } + + for (i = 0; i < count; i++) { + /* Initialize Sign */ + rv = pkcs_C_SignInit(hSession, &mech, hKey); + if (rv != CKR_OK) { + fprintf(stderr, "C_SignInit[%u]: Error = 0x%.8lX\n", i, + rv); + error = 1; + break; + } + + /* Perform Sign */ + slen = (CK_ULONG)sizeof(sig); + rv = pkcs_C_Sign(hSession, buf, len, sig, &slen); + if (rv != CKR_OK) { + fprintf(stderr, "C_Sign[%u]: Error = 0x%.8lX\n", i, rv); + error = 1; + break; + } + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_key; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%u RSA signs in %ld.%09lds\n", i, endtime.tv_sec, + endtime.tv_nsec); + if (i > 0) { + printf("%g RSA signs/s\n", + 1024 * i / + ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + +exit_key: + if (hKey != CK_INVALID_HANDLE) { + rv = pkcs_C_DestroyObject(hSession, hKey); + if (rv != CKR_OK) { + fprintf(stderr, "C_DestroyObject: Error = 0x%.8lX\n", + rv); + } + } + + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/tests/pkcs11/benchmarks/verify.c b/bin/tests/pkcs11/benchmarks/verify.c new file mode 100644 index 0000000..a2f1c29 --- /dev/null +++ b/bin/tests/pkcs11/benchmarks/verify.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Portions copyright (c) 2008 Nominet UK. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* verify [-m module] [-s $slot] [-p pin] [-t] [-n count] */ + +/*! \file */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef HAVE_CLOCK_GETTIME + +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif /* ifndef CLOCK_REALTIME */ + +static int +clock_gettime(int32_t id, struct timespec *tp); + +static int +clock_gettime(int32_t id, struct timespec *tp) { + struct timeval tv; + int result; + + UNUSED(id); + + result = gettimeofday(&tv, NULL); + if (result == 0) { + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = (long)tv.tv_usec * 1000; + } + return (result); +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +CK_BYTE modulus[] = { + 0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99, 0x44, 0x82, 0x20, 0x78, + 0x43, 0x7f, 0x5f, 0x3b, 0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90, + 0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f, 0x16, 0x1c, 0x56, 0xf8, + 0xc1, 0x06, 0x2f, 0x96, 0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5, + 0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b, 0x9f, 0xdc, 0x36, 0xcb, + 0xad, 0x56, 0xf4, 0xbd, 0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08, + 0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79, 0xca, 0x4e, 0x72, 0xeb, + 0xfb, 0x2c, 0xf1, 0x45, 0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7, + 0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd, 0x49, 0xdd, 0x8a, 0x3c, + 0x3c, 0xf7, 0xa1, 0x5d, 0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f, + 0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34, 0xbf +}; +CK_BYTE exponent[] = { 0x01, 0x00, 0x01 }; + +CK_BYTE buf[1024]; +CK_BYTE sig[128]; + +static CK_BBOOL truevalue = TRUE; +static CK_BBOOL falsevalue = FALSE; + +int +main(int argc, char *argv[]) { + isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; + CK_ULONG len; + CK_ULONG slen; + CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; + CK_OBJECT_CLASS kClass = CKO_PUBLIC_KEY; + CK_KEY_TYPE kType = CKK_RSA; + CK_ATTRIBUTE kTemplate[] = { + { CKA_CLASS, &kClass, (CK_ULONG)sizeof(kClass) }, + { CKA_KEY_TYPE, &kType, (CK_ULONG)sizeof(kType) }, + { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, + { CKA_VERIFY, &truevalue, (CK_ULONG)sizeof(truevalue) }, + { CKA_MODULUS, modulus, (CK_ULONG)sizeof(modulus) }, + { CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG)sizeof(exponent) } + }; + CK_MECHANISM mech = { CKM_SHA1_RSA_PKCS, NULL, 0 }; + pk11_context_t pctx; + pk11_optype_t op_type = OP_RSA; + char *lib_name = NULL; + char *pin = NULL; + int error = 0; + int c, errflg = 0; + int ontoken = 0; + unsigned int count = 1000; + unsigned int i; + struct timespec starttime; + struct timespec endtime; + + while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { + switch (c) { + case 'm': + lib_name = isc_commandline_argument; + break; + case 's': + slot = atoi(isc_commandline_argument); + op_type = OP_ANY; + break; + case 'p': + pin = isc_commandline_argument; + break; + case 't': + ontoken = 1; + break; + case 'n': + count = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", + isc_commandline_option); + errflg++; + break; + case '?': + default: + fprintf(stderr, "Unrecognised option: -%c\n", + isc_commandline_option); + errflg++; + } + } + + if (errflg) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tverify [-m module] [-s slot] [-p pin] " + "[-t] [-n count]\n"); + exit(1); + } + + pk11_result_register(); + + /* Initialize the CRYPTOKI library */ + if (lib_name != NULL) { + pk11_set_lib_name(lib_name); + } + + if (pin == NULL) { + pin = getpass("Enter Pin: "); + } + + result = pk11_get_session(&pctx, op_type, false, true, true, + (const char *)pin, slot); + if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) && + (result != PK11_R_NODIGESTSERVICE) && + (result != PK11_R_NOAESSERVICE)) + { + fprintf(stderr, "Error initializing PKCS#11: %s\n", + isc_result_totext(result)); + exit(1); + } + + if (pin != NULL) { + memset(pin, 0, strlen((char *)pin)); + } + + hSession = pctx.session; + + /* Create the private RSA key */ + if (ontoken) { + kTemplate[2].pValue = &truevalue; + } + + rv = pkcs_C_CreateObject(hSession, kTemplate, 7, &hKey); + if (rv != CKR_OK) { + fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv); + error = 1; + goto exit_key; + } + + /* Randomize the buffer */ + len = (CK_ULONG)sizeof(buf); + rv = pkcs_C_GenerateRandom(hSession, buf, len); + if (rv != CKR_OK) { + fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv); + goto exit_key; + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { + perror("clock_gettime(start)"); + goto exit_key; + } + + for (i = 0; i < count; i++) { + /* Initialize Verify */ + rv = pkcs_C_VerifyInit(hSession, &mech, hKey); + if (rv != CKR_OK) { + fprintf(stderr, "C_VerifyInit[%u]: Error = 0x%.8lX\n", + i, rv); + error = 1; + break; + } + + /* Perform Verify */ + slen = (CK_ULONG)sizeof(sig); + rv = pkcs_C_Verify(hSession, buf, len, sig, slen); + if ((rv != CKR_OK) && (rv != CKR_SIGNATURE_INVALID)) { + fprintf(stderr, "C_Verify[%u]: Error = 0x%.8lX\n", i, + rv); + error = 1; + break; + } + } + + if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { + perror("clock_gettime(end)"); + goto exit_key; + } + + endtime.tv_sec -= starttime.tv_sec; + endtime.tv_nsec -= starttime.tv_nsec; + while (endtime.tv_nsec < 0) { + endtime.tv_sec -= 1; + endtime.tv_nsec += 1000000000; + } + printf("%u RSA verify in %ld.%09lds\n", i, endtime.tv_sec, + endtime.tv_nsec); + if (i > 0) { + printf("%g RSA verify/s\n", + 1024 * i / + ((double)endtime.tv_sec + + (double)endtime.tv_nsec / 1000000000.)); + } + +exit_key: + if (hKey != CK_INVALID_HANDLE) { + rv = pkcs_C_DestroyObject(hSession, hKey); + if (rv != CKR_OK) { + fprintf(stderr, "C_DestroyObject: Error = 0x%.8lX\n", + rv); + error = 1; + } + } + + pk11_return_session(&pctx); + (void)pk11_finalize(); + + exit(error); +} diff --git a/bin/tests/prepare-softhsm2.sh b/bin/tests/prepare-softhsm2.sh new file mode 100755 index 0000000..f1fa194 --- /dev/null +++ b/bin/tests/prepare-softhsm2.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +if [ -n "${SOFTHSM2_CONF}" ] && command -v softhsm2-util >/dev/null; then + SOFTHSM2_DIR=$(dirname "$SOFTHSM2_CONF") + mkdir -p "${SOFTHSM2_DIR}/tokens" + echo "directories.tokendir = ${SOFTHSM2_DIR}/tokens" > "${SOFTHSM2_CONF}" + echo "objectstore.backend = file" >> "${SOFTHSM2_CONF}" + echo "log.level = DEBUG" >> "${SOFTHSM2_CONF}" + softhsm2-util --init-token --free --pin 1234 --so-pin 1234 --label "softhsm2" | awk '/^The token has been initialized and is reassigned to slot/ { print $NF }' +fi +exit 0 diff --git a/bin/tests/startperf/README b/bin/tests/startperf/README new file mode 100644 index 0000000..2f0afa7 --- /dev/null +++ b/bin/tests/startperf/README @@ -0,0 +1,30 @@ + + +These scripts generate a named.conf file with an arbitrary number of +small zones, for testing startup performance. + +To generate a test server with 1000 zones each of which contains 5 A +records, run: + + $ sh setup.sh 1000 5 > named.conf + +Zones are generated with random names, and the zone files are created +in the subdirectory "zones". + +Or, to generate a test server with 100 zones which all load from the same +generic file (smallzone.db): + + $ sh setup.sh -s 100 > named.conf + +The "number of records" argument is ignored if -s is used. diff --git a/bin/tests/startperf/clean.sh b/bin/tests/startperf/clean.sh new file mode 100644 index 0000000..5f7e51a --- /dev/null +++ b/bin/tests/startperf/clean.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +rm -rf zones +rm -f named.conf diff --git a/bin/tests/startperf/makenames.pl b/bin/tests/startperf/makenames.pl new file mode 100644 index 0000000..cb4a734 --- /dev/null +++ b/bin/tests/startperf/makenames.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +use strict; + +die "Usage: makenames.pl []" if (@ARGV == 0 || @ARGV > 2); +my $len = 10; +$len = @ARGV[1] if (@ARGV == 2); + +my @chars = split("", "abcdefghijklmnopqrstuvwxyz123456789"); + +srand; +for (my $i = 0; $i < @ARGV[0]; $i++) { + my $name = ""; + for (my $j = 0; $j < $len; $j++) { + my $r = rand 35; + $name .= $chars[$r]; + } + print "$name" . ".example\n"; +} diff --git a/bin/tests/startperf/mkzonefile.pl b/bin/tests/startperf/mkzonefile.pl new file mode 100644 index 0000000..3fdc802 --- /dev/null +++ b/bin/tests/startperf/mkzonefile.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +use strict; + +die "Usage: makenames.pl zonename num_records" if (@ARGV != 2); +my $zname = @ARGV[0]; +my $nrecords = @ARGV[1]; + +my @chars = split("", "abcdefghijklmnopqrstuvwxyz"); + +print"\$TTL 300 ; 5 minutes +\$ORIGIN $zname. +@ IN SOA mname1. . ( + 2011080201 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 600 ; minimum (1 hour) + ) + NS ns +ns A 10.53.0.3\n"; + +srand; +for (my $i = 0; $i < $nrecords; $i++) { + my $name = ""; + for (my $j = 0; $j < 8; $j++) { + my $r = rand 25; + $name .= $chars[$r]; + } + print "$name" . "\tIN\tA\t"; + my $x = int rand 254; + my $y = int rand 254; + my $z = int rand 254; + print "10.$x.$y.$z\n"; +} + diff --git a/bin/tests/startperf/setup.sh b/bin/tests/startperf/setup.sh new file mode 100644 index 0000000..e664bbc --- /dev/null +++ b/bin/tests/startperf/setup.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +usage () { + echo "Usage: $0 [-s] []" + echo " -s: use the same zone file all zones" + exit 1 +} + +if [ "$#" -lt 1 -o "$#" -gt 3 ]; then + usage +fi + +single_file="" +if [ $1 = "-s" ]; then + single_file=yes + shift +fi + +nzones=$1 +shift + +nrecords=5 +[ "$#" -eq 1 ] && nrecords=$1 + +. ../system/conf.sh + +cat << EOF +options { + directory "`pwd`"; + listen-on { localhost; }; + listen-on-v6 { localhost; }; + port 5300; + allow-query { any; }; + allow-transfer { localhost; }; + allow-recursion { none; }; + recursion no; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-md5; +}; + +controls { + inet 127.0.0.1 port 9953 allow { any; } keys { rndc_key; }; +}; + +logging { + channel basic { + file "`pwd`/named.log" versions 3 size 100m; + severity info; + print-time yes; + print-severity no; + print-category no; + }; + category default { + basic; + }; +}; + +EOF + +$PERL makenames.pl $nzones | while read zonename; do + if [ $single_file ]; then + echo "zone $zonename { type master; file \"smallzone.db\"; };" + else + [ -d zones ] || mkdir zones + $PERL mkzonefile.pl $zonename $nrecords > zones/$zonename.db + echo "zone $zonename { type master; file \"zones/$zonename.db\"; };" + fi +done diff --git a/bin/tests/startperf/smallzone.db b/bin/tests/startperf/smallzone.db new file mode 100644 index 0000000..3a26acd --- /dev/null +++ b/bin/tests/startperf/smallzone.db @@ -0,0 +1,28 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, you can obtain one at https://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 ; 5 minutes +@ IN SOA mname1. . ( + 2000042407 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + NS ns +ns A 10.53.0.3 + +a A 10.0.0.1 +b A 10.0.0.2 +d A 10.0.0.4 +z A 10.0.0.26 +a.a.a.a A 10.0.0.3 +*.e A 10.0.0.6 diff --git a/bin/tests/system/Makefile.in b/bin/tests/system/Makefile.in new file mode 100644 index 0000000..7b8b42c --- /dev/null +++ b/bin/tests/system/Makefile.in @@ -0,0 +1,108 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +SUBDIRS = dlzexternal dyndb pipelined rndc rpz rsabigexponent tkey + +CINCLUDES = ${ISC_INCLUDES} \ + ${DNS_INCLUDES} \ + ${ISCCFG_INCLUDES} \ + ${IRS_INCLUDES} + +CDEFINES = @USE_GSSAPI@ @CONTRIB_DLZ@ +CWARNINGS = + +ISCLIBS = ../../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +DNSLIBS = ../../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +ISCCFGLIBS = ../../../lib/isccfg/libisccfg.@A@ +IRSLIBS = ../../../lib/irs/libirs.@A@ + +ISCDEPLIBS = ../../../lib/isc/libisc.@A@ +DNSDEPLIBS = ../../../lib/dns/libdns.@A@ +ISCCFGDEPLIBS = ../../../lib/isccfg/libisccfg.@A@ +IRSDEPLIBS = ../../../lib/irs/libirs.@A@ + +DEPLIBS = ${IRSDEPLIBS} ${ISCCFGDEPLIBS} ${DNSDEPLIBS} ${ISCDEPLIBS} + +LIBS = ${IRSLIBS} ${ISCCFGLIBS} ${DNSLIBS} ${ISCLIBS} @LIBS@ + +OBJS = feature-test.@O@ resolve.@O@ +SRCS = feature-test.c resolve.c + +TARGETS = feature-test@EXEEXT@ resolve@EXEEXT@ + +@BIND9_MAKE_RULES@ + +subdirs: ${TARGETS} + +feature-test@EXEEXT@: feature-test.@O@ + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ feature-test.@O@ ${ISCLIBS} ${LIBS} + +resolve@EXEEXT@: resolve.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + resolve.@O@ ${LIBS} + +# Running the scripts below is bypassed when a separate build directory is +# used. + +# Produce intermediate makefile that assigns unique port numbers to each +# parallel test. The start port number of 5,000 is arbitrary - it must just +# be greater than the highest privileged port, 1024. +# +# Test names need to be sanitized because Solaris make does not like +# underscores in target names and requires explicit differentiation +# between a target name and a directory name (.PHONY is not supported). + +.PHONY: parallel.mk + +parallel.mk: + $(SHELL) parallel.sh > parallel.mk + +# Targets to run the tests. + +test: parallel.mk subdirs + @$(MAKE) -f parallel.mk check + @$(SHELL) ./runsequential.sh + @$(SHELL) ./testsummary.sh + +check: test + +# Other targets: +# +# testclean - delete files generated by running tests. +# clean - testclean + also delete files built for the tests by "make". +# distclean - clean + also delete test-related files generated by "configure". + +testclean clean distclean:: + if test -f ./cleanall.sh; then $(SHELL) ./cleanall.sh; fi + rm -f systests.output + rm -f random.data + rm -f parallel.mk + +clean distclean:: + rm -f ${TARGETS} + rm -f ${OBJS} + +distclean:: + rm -f conf.sh + +installdirs: + +install:: + +uninstall:: diff --git a/bin/tests/system/README b/bin/tests/system/README new file mode 100644 index 0000000..fc9294d --- /dev/null +++ b/bin/tests/system/README @@ -0,0 +1,724 @@ +Copyright (C) Internet Systems Consortium, Inc. ("ISC") + +SPDX-License-Identifier: MPL-2.0 + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, you can obtain one at https://mozilla.org/MPL/2.0/. + +See the COPYRIGHT file distributed with this work for additional +information regarding copyright ownership. + +Introduction +=== +This directory holds a simple test environment for running bind9 system tests +involving multiple name servers. + +With the exception of "common" (which holds configuration information common to +multiple tests) and "win32" (which holds files needed to run the tests in a +Windows environment), each directory holds a set of scripts and configuration +files to test different parts of BIND. The directories are named for the +aspect of BIND they test, for example: + + dnssec/ DNSSEC tests + forward/ Forwarding tests + glue/ Glue handling tests + +etc. + +Typically each set of tests sets up 2-5 name servers and then performs one or +more tests against them. Within the test subdirectory, each name server has a +separate subdirectory containing its configuration data. These subdirectories +are named "nsN" or "ansN" (where N is a number between 1 and 8, e.g. ns1, ans2 +etc.) + +The tests are completely self-contained and do not require access to the real +DNS. Generally, one of the test servers (usually ns1) is set up as a root +nameserver and is listed in the hints file of the others. + + +Preparing to Run the Tests +=== +To enable all servers to run on the same machine, they bind to separate virtual +IP addresses on the loopback interface. ns1 runs on 10.53.0.1, ns2 on +10.53.0.2, etc. Before running any tests, you must set up these addresses by +running the command + + sh ifconfig.sh up + +as root. The interfaces can be removed by executing the command: + + sh ifconfig.sh down + +... also as root. + +The servers use unprivileged ports (above 1024) instead of the usual port 53, +so they can be run without root privileges once the interfaces have been set +up. + + +Note for MacOS Users +--- +If you wish to make the interfaces survive across reboots, copy +org.isc.bind.system and org.isc.bind.system.plist to /Library/LaunchDaemons +then run + + launchctl load /Library/LaunchDaemons/org.isc.bind.system.plist + +... as root. + + +Running the System Tests +=== + +Running an Individual Test +--- +The tests can be run individually using the following command: + + sh run.sh [flags] [] + +e.g. + + sh run.sh [flags] notify + +Optional flags are: + + -k Keep servers running after the test completes. Each test + usually starts a number of nameservers, either instances + of the "named" being tested, or custom servers (written in + Python or Perl) that feature test-specific behavior. The + servers are automatically started before the test is run + and stopped after it ends. This flag leaves them running + at the end of the test, so that additional queries can be + sent by hand. To stop the servers afterwards, use the + command "sh stop.sh ". + + -n Noclean - do not remove the output files if the test + completes successfully. By default, files created by the + test are deleted if it passes; they are not deleted if the + test fails. + + -p Sets the range of ports used by the test. A block of 100 + ports is available for each test, the number given to the + "-p" switch being the number of the start of that block + (e.g. "-p 7900" will mean that the test is able to use + ports 7900 through 7999). If not specified, the test will + have ports 5000 to 5099 available to it. + +Arguments are: + + test-name Mandatory. The name of the test, which is the name of the + subdirectory in bin/tests/system holding the test files. + + test-arguments Optional arguments that are passed to each of the test's + scripts. + + +Running All The System Tests +--- +To run all the system tests, enter the command: + + sh runall.sh [-c] [-n] [numproc] + +The optional flag "-c" forces colored output (by default system test output is +not printed in color due to run.sh being piped through "tee"). + +The optional flag "-n" has the same effect as it does for "run.sh" - it causes +the retention of all output files from all tests. + +The optional "numproc" argument specifies the maximum number of tests that can +run in parallel. The default is 1, which means that all of the tests run +sequentially. If greater than 1, up to "numproc" tests will run simultaneously, +new tests being started as tests finish. Each test will get a unique set of +ports, so there is no danger of tests interfering with one another. Parallel +running will reduce the total time taken to run the BIND system tests, but will +mean that the output from all the tests sent to the screen will be mixed up +with one another. However, the systests.output file produced at the end of the +run (in the bin/tests/system directory) will contain the output from each test +in sequential order. + +Note that it is not possible to pass arguments to tests though the "runall.sh" +script. + +A run of all the system tests can also be initiated via make: + + make [-j numproc] test + +In this case, retention of the output files after a test completes successfully +is specified by setting the environment variable SYSTEMTEST_NO_CLEAN to 1 prior +to running make, e.g. + + SYSTEMTEST_NO_CLEAN=1 make [-j numproc] test + +while setting environment variable SYSTEMTEST_FORCE_COLOR to 1 forces system +test output to be printed in color. + + +Running Multiple System Test Suites Simultaneously +--- +In some cases it may be desirable to have multiple instances of the system test +suite running simultaneously (e.g. from different terminal windows). To do +this: + +1. Each installation must have its own directory tree. The system tests create +files in the test directories, so separate directory trees are required to +avoid interference between the same test running in the different +installations. + +2. For one of the test suites, the starting port number must be specified by +setting the environment variable STARTPORT before starting the test suite. +Each test suite comprises about 100 tests, each being allocated a set of 100 +ports. The port ranges for each test are allocated sequentially, so each test +suite requires about 10,000 ports to itself. By default, the port allocation +starts at 5,000. So the following set of commands: + + Terminal Window 1: + cd /bin/tests/system + sh runall.sh 4 + + Terminal Window 2: + cd /bin/tests/system + STARTPORT=20000 sh runall.sh 4 + +... will start the test suite for installation-1 using the default base port +of 5,000, so the test suite will use ports 5,000 through 15,000 (or there +abouts). The use of "STARTPORT=20000" to prefix the run of the test suite for +installation-2 will mean the test suite uses ports 20,000 through 30,000 or so. + + +Format of Test Output +--- +All output from the system tests is in the form of lines with the following +structure: + + :: [()] + +e.g. + + I:catz:checking that dom1.example is not served by master (1) + +The meanings of the fields are as follows: + + +This indicates the type of message. This is one of: + + S Start of the test + A Start of test (retained for backwards compatibility) + T Start of test (retained for backwards compatibility) + E End of the test + I Information. A test will typically output many of these messages + during its run, indicating test progress. Note that such a message may + be of the form "I:testname:failed", indicating that a sub-test has + failed. + R Result. Each test will result in one such message, which is of the + form: + + R:: + + where is one of: + + PASS The test passed + FAIL The test failed + SKIPPED The test was not run, usually because some + prerequisites required to run the test are missing. + + +This is the name of the test from which the message emanated, which is also the +name of the subdirectory holding the test files. + + +This is text output by the test during its execution. + +() +If present, this will correlate with a file created by the test. The tests +execute commands and route the output of each command to a file. The name of +this file depends on the command and the test, but will usually be of the form: + + .out. + +e.g. nsupdate.out.test28, dig.out.q3. This aids diagnosis of problems by +allowing the output that caused the problem message to be identified. + + +Re-Running the Tests +--- +If there is a requirement to re-run a test (or the entire test suite), the +files produced by the tests should be deleted first. Normally, these files are +deleted if the test succeeds but are retained on error. The run.sh script +automatically calls a given test's clean.sh script before invoking its setup.sh +script. + +Deletion of the files produced by the set of tests (e.g. after the execution +of "runall.sh") can be carried out using the command: + + sh cleanall.sh + +or + + make testclean + +(Note that the Makefile has two other targets for cleaning up files: "clean" +will delete all the files produced by the tests, as well as the object and +executable files used by the tests. "distclean" does all the work of "clean" +as well as deleting configuration files produced by "configure".) + + +Developer Notes +=== +This section is intended for developers writing new tests. + + +Overview +--- +As noted above, each test is in a separate directory. To interact with the +test framework, the directories contain the following standard files: + +prereq.sh Run at the beginning to determine whether the test can be run at + all; if not, we see a R:SKIPPED result. This file is optional: + if not present, the test is assumed to have all its prerequisites + met. + +setup.sh Run after prereq.sh, this sets up the preconditions for the tests. + Although optional, virtually all tests will require such a file to + set up the ports they should use for the test. + +tests.sh Runs the actual tests. This file is mandatory. + +clean.sh Run at the end to clean up temporary files, but only if the test + was completed successfully and its running was not inhibited by the + "-n" switch being passed to "run.sh". Otherwise the temporary + files are left in place for inspection. + +ns These subdirectories contain test name servers that can be queried + or can interact with each other. The value of N indicates the + address the server listens on: for example, ns2 listens on + 10.53.0.2, and ns4 on 10.53.0.4. All test servers use an + unprivileged port, so they don't need to run as root. These + servers log at the highest debug level and the log is captured in + the file "named.run". + +ans Like ns[X], but these are simple mock name servers implemented in + Perl or Python. They are generally programmed to misbehave in ways + named would not so as to exercise named's ability to interoperate + with badly behaved name servers. + + +Port Usage +--- +In order for the tests to run in parallel, each test requires a unique set of +ports. These are specified by the "-p" option passed to "run.sh", which sets +environment variables that the scripts listed above can reference. + +The convention used in the system tests is that the number passed is the start +of a range of 100 ports. The test is free to use the ports as required, +although the first ten ports in the block are named and generally tests use the +named ports for their intended purpose. The names of the environment variables +are: + + PORT Number to be used for the query port. + CONTROLPORT Number to be used as the RNDC control port. + EXTRAPORT1 - EXTRAPORT8 Eight port numbers that can be used as needed. + +Two other environment variables are defined: + + LOWPORT The lowest port number in the range. + HIGHPORT The highest port number in the range. + +Since port ranges usually start on a boundary of 10, the variables are set such +that the last digit of the port number corresponds to the number of the +EXTRAPORTn variable. For example, if the port range were to start at 5200, the +port assignments would be: + + PORT = 5200 + EXTRAPORT1 = 5201 + : + EXTRAPORT8 = 5208 + CONTROLPORT = 5209 + LOWPORT = 5200 + HIGHPORT = 5299 + +When running tests in parallel (i.e. giving a value of "numproc" greater than 1 +in the "make" or "runall.sh" commands listed above), it is guaranteed that each +test will get a set of unique port numbers. + + +Writing a Test +--- +The test framework requires up to four shell scripts (listed above) as well as +a number of nameserver instances to run. Certain expectations are put on each +script: + + +General +--- +1. Each of the four scripts will be invoked with the command + + (cd ; sh