summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:59:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:59:48 +0000
commit3b9b6d0b8e7f798023c9d109c490449d528fde80 (patch)
tree2e1c188dd7b8d7475cd163de9ae02c428343669b /tests
parentInitial commit. (diff)
downloadbind9-3b9b6d0b8e7f798023c9d109c490449d528fde80.tar.xz
bind9-3b9b6d0b8e7f798023c9d109c490449d528fde80.zip
Adding upstream version 1:9.18.19.upstream/1%9.18.19upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am16
-rw-r--r--tests/Makefile.in809
-rw-r--r--tests/dns/Kdh.+002+18602.key1
-rw-r--r--tests/dns/Krsa.+008+29238.key5
-rw-r--r--tests/dns/Makefile.am132
-rw-r--r--tests/dns/Makefile.in1934
-rw-r--r--tests/dns/acl_test.c119
-rw-r--r--tests/dns/comparekeys/Kexample-d.+008+53461.key5
-rw-r--r--tests/dns/comparekeys/Kexample-d.+008+53461.private13
-rw-r--r--tests/dns/comparekeys/Kexample-e.+008+53973.key5
-rw-r--r--tests/dns/comparekeys/Kexample-e.+008+53973.private13
-rw-r--r--tests/dns/comparekeys/Kexample-n.+008+37464.key5
-rw-r--r--tests/dns/comparekeys/Kexample-n.+008+37464.private13
-rw-r--r--tests/dns/comparekeys/Kexample-p.+008+53461.key5
-rw-r--r--tests/dns/comparekeys/Kexample-p.+008+53461.private13
-rw-r--r--tests/dns/comparekeys/Kexample-private.+002+65316.key1
-rw-r--r--tests/dns/comparekeys/Kexample-private.+002+65316.private9
-rw-r--r--tests/dns/comparekeys/Kexample-q.+008+53461.key5
-rw-r--r--tests/dns/comparekeys/Kexample-q.+008+53461.private13
-rw-r--r--tests/dns/comparekeys/Kexample.+002+65316.key1
-rw-r--r--tests/dns/comparekeys/Kexample.+002+65316.private9
-rw-r--r--tests/dns/comparekeys/Kexample.+008+53461.key5
-rw-r--r--tests/dns/comparekeys/Kexample.+008+53461.private13
-rw-r--r--tests/dns/comparekeys/Kexample.+013+19786.key5
-rw-r--r--tests/dns/comparekeys/Kexample.+013+19786.private6
-rw-r--r--tests/dns/comparekeys/Kexample.+015+63663.key5
-rw-r--r--tests/dns/comparekeys/Kexample.+015+63663.private6
-rw-r--r--tests/dns/comparekeys/Kexample2.+002+19823.key1
-rw-r--r--tests/dns/comparekeys/Kexample2.+002+19823.private9
-rw-r--r--tests/dns/comparekeys/Kexample2.+008+37993.key5
-rw-r--r--tests/dns/comparekeys/Kexample2.+008+37993.private13
-rw-r--r--tests/dns/comparekeys/Kexample2.+013+16384.key5
-rw-r--r--tests/dns/comparekeys/Kexample2.+013+16384.private6
-rw-r--r--tests/dns/comparekeys/Kexample2.+015+37529.key5
-rw-r--r--tests/dns/comparekeys/Kexample2.+015+37529.private6
-rw-r--r--tests/dns/comparekeys/Kexample3.+002+17187.key1
-rw-r--r--tests/dns/comparekeys/Kexample3.+002+17187.private9
-rw-r--r--tests/dns/db_test.c372
-rw-r--r--tests/dns/dbdiff_test.c144
-rw-r--r--tests/dns/dbiterator_test.c340
-rw-r--r--tests/dns/dbversion_test.c461
-rw-r--r--tests/dns/dh_test.c102
-rw-r--r--tests/dns/dispatch_test.c698
-rw-r--r--tests/dns/dns64_test.c236
-rw-r--r--tests/dns/dnstap_test.c357
-rw-r--r--tests/dns/dst_test.c487
-rw-r--r--tests/dns/geoip_test.c396
-rw-r--r--tests/dns/keytable_test.c689
-rw-r--r--tests/dns/master_test.c582
-rw-r--r--tests/dns/mkraw.pl26
-rw-r--r--tests/dns/name_test.c731
-rw-r--r--tests/dns/nsec3_test.c155
-rw-r--r--tests/dns/nsec3param_test.c266
-rw-r--r--tests/dns/private_test.c218
-rw-r--r--tests/dns/rbt_test.c1300
-rw-r--r--tests/dns/rbtdb_test.c381
-rw-r--r--tests/dns/rdata_test.c3121
-rw-r--r--tests/dns/rdataset_test.c108
-rw-r--r--tests/dns/rdatasetstats_test.c265
-rw-r--r--tests/dns/resolver_test.c198
-rw-r--r--tests/dns/rsa_test.c233
-rw-r--r--tests/dns/sigs_test.c446
-rw-r--r--tests/dns/testdata/db/data.db22
-rw-r--r--tests/dns/testdata/dbiterator/zone1.data30
-rw-r--r--tests/dns/testdata/dbiterator/zone2.data319
-rw-r--r--tests/dns/testdata/diff/zone1.data13
-rw-r--r--tests/dns/testdata/diff/zone2.data14
-rw-r--r--tests/dns/testdata/diff/zone3.data12
-rw-r--r--tests/dns/testdata/dnstap/dnstap.savedbin0 -> 30398 bytes
-rw-r--r--tests/dns/testdata/dnstap/dnstap.text96
-rw-r--r--tests/dns/testdata/dnstap/query.auth4
-rw-r--r--tests/dns/testdata/dnstap/query.recursive4
-rw-r--r--tests/dns/testdata/dnstap/response.auth19
-rw-r--r--tests/dns/testdata/dnstap/response.recursive19
-rw-r--r--tests/dns/testdata/dst/Ktest.+008+11349.key5
-rw-r--r--tests/dns/testdata/dst/Ktest.+008+11349.private13
-rw-r--r--tests/dns/testdata/dst/Ktest.+013+49130.key5
-rw-r--r--tests/dns/testdata/dst/Ktest.+013+49130.private6
-rw-r--r--tests/dns/testdata/dst/test1.data3077
-rw-r--r--tests/dns/testdata/dst/test1.ecdsa256sig1
-rw-r--r--tests/dns/testdata/dst/test1.rsasha256sig1
-rw-r--r--tests/dns/testdata/dst/test2.data3077
-rw-r--r--tests/dns/testdata/dstrandom/random.databin0 -> 4096 bytes
-rw-r--r--tests/dns/testdata/master/master1.data11
-rw-r--r--tests/dns/testdata/master/master10.data7
-rw-r--r--tests/dns/testdata/master/master11.data6
-rw-r--r--tests/dns/testdata/master/master12.data.in1
-rw-r--r--tests/dns/testdata/master/master13.data.in1
-rw-r--r--tests/dns/testdata/master/master14.data.in1
-rw-r--r--tests/dns/testdata/master/master15.data1609
-rw-r--r--tests/dns/testdata/master/master16.data1609
-rw-r--r--tests/dns/testdata/master/master17.data14
-rw-r--r--tests/dns/testdata/master/master18.data.in10
-rw-r--r--tests/dns/testdata/master/master2.data11
-rw-r--r--tests/dns/testdata/master/master3.data11
-rw-r--r--tests/dns/testdata/master/master4.data11
-rw-r--r--tests/dns/testdata/master/master5.data11
-rw-r--r--tests/dns/testdata/master/master6.data33
-rw-r--r--tests/dns/testdata/master/master7.data17
-rw-r--r--tests/dns/testdata/master/master8.data4
-rw-r--r--tests/dns/testdata/master/master9.data4
-rw-r--r--tests/dns/testdata/nsec3/1024.db16
-rw-r--r--tests/dns/testdata/nsec3/2048.db16
-rw-r--r--tests/dns/testdata/nsec3/4096.db16
-rw-r--r--tests/dns/testdata/nsec3/min-1024.db20
-rw-r--r--tests/dns/testdata/nsec3/min-2048.db18
-rw-r--r--tests/dns/testdata/nsec3param/nsec3.db.signed73
-rw-r--r--tests/dns/testdata/zt/zone1.db22
-rw-r--r--tests/dns/testkeys/Kexample.+008+20386.key5
-rw-r--r--tests/dns/testkeys/Kexample.+008+20386.private13
-rw-r--r--tests/dns/testkeys/Kexample.+008+37464.key5
-rw-r--r--tests/dns/testkeys/Kexample.+008+37464.private13
-rw-r--r--tests/dns/time_test.c169
-rw-r--r--tests/dns/tsig_test.c578
-rw-r--r--tests/dns/update_test.c309
-rw-r--r--tests/dns/zonemgr_test.c224
-rw-r--r--tests/dns/zt_test.c352
-rw-r--r--tests/include/tests/dns.h122
-rw-r--r--tests/include/tests/isc.h119
-rw-r--r--tests/include/tests/ns.h132
-rw-r--r--tests/irs/Makefile.am16
-rw-r--r--tests/irs/Makefile.in1152
-rw-r--r--tests/irs/resconf_test.c182
-rw-r--r--tests/irs/testdata/domain.conf12
-rw-r--r--tests/irs/testdata/nameserver-v4.conf12
-rw-r--r--tests/irs/testdata/nameserver-v6-scoped.conf12
-rw-r--r--tests/irs/testdata/nameserver-v6.conf12
-rw-r--r--tests/irs/testdata/options-attempts.conf12
-rw-r--r--tests/irs/testdata/options-bad-ndots.conf13
-rw-r--r--tests/irs/testdata/options-debug.conf12
-rw-r--r--tests/irs/testdata/options-empty.conf13
-rw-r--r--tests/irs/testdata/options-ndots.conf12
-rw-r--r--tests/irs/testdata/options-timeout.conf12
-rw-r--r--tests/irs/testdata/options-unknown.conf12
-rw-r--r--tests/irs/testdata/options.conf12
-rw-r--r--tests/irs/testdata/port.conf12
-rw-r--r--tests/irs/testdata/resolv.conf19
-rw-r--r--tests/irs/testdata/search.conf12
-rw-r--r--tests/irs/testdata/sortlist-v4.conf12
-rw-r--r--tests/irs/testdata/timeout.conf12
-rw-r--r--tests/irs/testdata/unknown.conf12
-rw-r--r--tests/isc/Makefile.am115
-rw-r--r--tests/isc/Makefile.in1905
-rw-r--r--tests/isc/aes_test.c232
-rw-r--r--tests/isc/buffer_test.c308
-rw-r--r--tests/isc/counter_test.c68
-rw-r--r--tests/isc/crc64_test.c84
-rw-r--r--tests/isc/doh_test.c2307
-rw-r--r--tests/isc/errno_test.c109
-rw-r--r--tests/isc/file_test.c141
-rw-r--r--tests/isc/hash_test.c96
-rw-r--r--tests/isc/heap_test.c79
-rw-r--r--tests/isc/hmac_test.c926
-rw-r--r--tests/isc/ht_test.c322
-rw-r--r--tests/isc/lex_test.c355
-rw-r--r--tests/isc/md_test.c555
-rw-r--r--tests/isc/mem_test.c521
-rw-r--r--tests/isc/netaddr_test.c145
-rw-r--r--tests/isc/netmgr_test.c2897
-rw-r--r--tests/isc/parse_test.c56
-rw-r--r--tests/isc/pool_test.c153
-rw-r--r--tests/isc/quota_test.c341
-rw-r--r--tests/isc/radix_test.c136
-rw-r--r--tests/isc/random_test.c787
-rw-r--r--tests/isc/regex_test.c2335
-rw-r--r--tests/isc/result_test.c64
-rw-r--r--tests/isc/safe_test.c92
-rw-r--r--tests/isc/siphash_test.c170
-rw-r--r--tests/isc/sockaddr_test.c149
-rw-r--r--tests/isc/stats_test.c104
-rw-r--r--tests/isc/symtab_test.c135
-rw-r--r--tests/isc/task_test.c1408
-rw-r--r--tests/isc/taskpool_test.c164
-rw-r--r--tests/isc/testdata/file/keep0
-rw-r--r--tests/isc/time_test.c418
-rw-r--r--tests/isc/timer_test.c599
-rw-r--r--tests/isc/uv_wrap.h327
-rw-r--r--tests/isccfg/Makefile.am20
-rw-r--r--tests/isccfg/Makefile.in1174
-rw-r--r--tests/isccfg/duration_test.c244
-rw-r--r--tests/isccfg/parser_test.c230
-rw-r--r--tests/libtest/Makefile.am25
-rw-r--r--tests/libtest/Makefile.in1157
-rw-r--r--tests/libtest/dns.c501
-rw-r--r--tests/libtest/isc.c87
-rw-r--r--tests/libtest/ns.c669
-rw-r--r--tests/ns/Makefile.am25
-rw-r--r--tests/ns/Makefile.in1219
-rw-r--r--tests/ns/listenlist_test.c119
-rw-r--r--tests/ns/notify_test.c141
-rw-r--r--tests/ns/plugin_test.c166
-rw-r--r--tests/ns/query_test.c1500
-rw-r--r--tests/ns/testdata/notify/notify1.msg3
-rw-r--r--tests/ns/testdata/notify/zone1.db26
-rw-r--r--tests/ns/testdata/query/foo.db20
-rw-r--r--tests/unit-test-driver.sh.in60
196 files changed, 55432 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..8b5dcbe
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,16 @@
+include $(top_srcdir)/Makefile.top
+
+AM_CPPFLAGS += \
+ $(LIBISC_CFLAGS) \
+ $(LIBDNS_CFLAGS) \
+ $(LIBNS_CFLAGS) \
+ $(LIBUV_CFLAGS) \
+ -I$(top_srcdir)/lib/isc
+
+LDADD += \
+ $(LIBISC_LIBS) \
+ $(LIBDNS_LIBS) \
+ $(LIBNS_LIBS)
+
+SUBDIRS = libtest isc dns ns isccfg irs
+check_PROGRAMS =
diff --git a/tests/Makefile.in b/tests/Makefile.in
new file mode 100644
index 0000000..7a21334
--- /dev/null
+++ b/tests/Makefile.in
@@ -0,0 +1,809 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HOST_MACOS_TRUE@am__append_1 = \
+@HOST_MACOS_TRUE@ -Wl,-flat_namespace
+
+check_PROGRAMS =
+subdir = tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4/ax_jemalloc.m4 \
+ $(top_srcdir)/m4/ax_lib_lmdb.m4 \
+ $(top_srcdir)/m4/ax_perl_module.m4 \
+ $(top_srcdir)/m4/ax_posix_shell.m4 \
+ $(top_srcdir)/m4/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_python_module.m4 \
+ $(top_srcdir)/m4/ax_restore_flags.m4 \
+ $(top_srcdir)/m4/ax_save_flags.m4 $(top_srcdir)/m4/ax_tls.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = unit-test-driver.sh
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__extra_recursive_targets = test-recursive unit-recursive \
+ doc-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(srcdir)/unit-test-driver.sh.in $(top_srcdir)/Makefile.top
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CMOCKA_CFLAGS = @CMOCKA_CFLAGS@
+CMOCKA_LIBS = @CMOCKA_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURL = @CURL@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEVELOPER_MODE = @DEVELOPER_MODE@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FSTRM_CAPTURE = @FSTRM_CAPTURE@
+FUZZ_LDFLAGS = @FUZZ_LDFLAGS@
+FUZZ_LOG_COMPILER = @FUZZ_LOG_COMPILER@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@
+JEMALLOC_LIBS = @JEMALLOC_LIBS@
+JSON_C_CFLAGS = @JSON_C_CFLAGS@
+JSON_C_LIBS = @JSON_C_LIBS@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_CONFIG = @KRB5_CONFIG@
+KRB5_LIBS = @KRB5_LIBS@
+LATEXMK = @LATEXMK@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBNGHTTP2_CFLAGS = @LIBNGHTTP2_CFLAGS@
+LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUV_CFLAGS = @LIBUV_CFLAGS@
+LIBUV_LIBS = @LIBUV_LIBS@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIPO = @LIPO@
+LMDB_CFLAGS = @LMDB_CFLAGS@
+LMDB_LIBS = @LMDB_LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAXMINDDB_CFLAGS = @MAXMINDDB_CFLAGS@
+MAXMINDDB_LIBS = @MAXMINDDB_LIBS@
+MAXMINDDB_PREFIX = @MAXMINDDB_PREFIX@
+MKDIR_P = @MKDIR_P@
+NC = @NC@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTEST = @PYTEST@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+READLINE_CFLAGS = @READLINE_CFLAGS@
+READLINE_LIBS = @READLINE_LIBS@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINX_BUILD = @SPHINX_BUILD@
+STD_CFLAGS = @STD_CFLAGS@
+STD_CPPFLAGS = @STD_CPPFLAGS@
+STD_LDFLAGS = @STD_LDFLAGS@
+STRIP = @STRIP@
+TEST_CFLAGS = @TEST_CFLAGS@
+VERSION = @VERSION@
+XELATEX = @XELATEX@
+XSLTPROC = @XSLTPROC@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
+AM_CFLAGS = \
+ $(STD_CFLAGS)
+
+AM_CPPFLAGS = $(STD_CPPFLAGS) -include $(top_builddir)/config.h \
+ -I$(srcdir)/include $(LIBISC_CFLAGS) $(LIBDNS_CFLAGS) \
+ $(LIBNS_CFLAGS) $(LIBUV_CFLAGS) -I$(top_srcdir)/lib/isc
+AM_LDFLAGS = $(STD_LDFLAGS) $(am__append_1)
+LDADD = $(LIBISC_LIBS) $(LIBDNS_LIBS) $(LIBNS_LIBS)
+LIBISC_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib/isc/include \
+ -I$(top_builddir)/lib/isc/include
+
+LIBISC_LIBS = $(top_builddir)/lib/isc/libisc.la
+LIBDNS_CFLAGS = \
+ -I$(top_srcdir)/lib/dns/include \
+ -I$(top_builddir)/lib/dns/include
+
+LIBDNS_LIBS = \
+ $(top_builddir)/lib/dns/libdns.la
+
+LIBNS_CFLAGS = \
+ -I$(top_srcdir)/lib/ns/include
+
+LIBNS_LIBS = \
+ $(top_builddir)/lib/ns/libns.la
+
+LIBIRS_CFLAGS = \
+ -I$(top_srcdir)/lib/irs/include
+
+LIBIRS_LIBS = \
+ $(top_builddir)/lib/irs/libirs.la
+
+LIBISCCFG_CFLAGS = \
+ -I$(top_srcdir)/lib/isccfg/include
+
+LIBISCCFG_LIBS = \
+ $(top_builddir)/lib/isccfg/libisccfg.la
+
+LIBISCCC_CFLAGS = \
+ -I$(top_srcdir)/lib/isccc/include/
+
+LIBISCCC_LIBS = \
+ $(top_builddir)/lib/isccc/libisccc.la
+
+LIBBIND9_CFLAGS = \
+ -I$(top_srcdir)/lib/bind9/include
+
+LIBBIND9_LIBS = \
+ $(top_builddir)/lib/bind9/libbind9.la
+
+SUBDIRS = libtest isc dns ns isccfg irs
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.top $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/Makefile.top $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+unit-test-driver.sh: $(top_builddir)/config.status $(srcdir)/unit-test-driver.sh.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+test-local:
+unit-local:
+doc-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+doc: doc-recursive
+
+doc-am: doc-local
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+test: test-recursive
+
+test-am: test-local
+
+uninstall-am:
+
+unit: unit-recursive
+
+unit-am: unit-local
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-checkPROGRAMS clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-libtool distclean-tags distdir doc-am doc-local dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs installdirs-am \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am test-am test-local uninstall uninstall-am unit-am \
+ unit-local
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/dns/Kdh.+002+18602.key b/tests/dns/Kdh.+002+18602.key
new file mode 100644
index 0000000..09b4cf5
--- /dev/null
+++ b/tests/dns/Kdh.+002+18602.key
@@ -0,0 +1 @@
+dh. IN KEY 0 2 2 AAEBAAAAYIHI/wjtOagNga9GILSoS02IVelgLilPE/TfhtvShsiDAXqb IfxQcj2JkuOnNLs5ttb2WZXWl5/jsSjIxHMwMF2XY4gwt/lwHBf/vgYH r7aIxnKXov1jk9rymTLHGKIOtg==
diff --git a/tests/dns/Krsa.+008+29238.key b/tests/dns/Krsa.+008+29238.key
new file mode 100644
index 0000000..8a09067
--- /dev/null
+++ b/tests/dns/Krsa.+008+29238.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 29235, for rsa.
+; Created: 20160819191802 (Fri Aug 19 21:18:02 2016)
+; Publish: 20160819191802 (Fri Aug 19 21:18:02 2016)
+; Activate: 20160819191802 (Fri Aug 19 21:18:02 2016)
+rsa. IN DNSKEY 256 3 8 AwEAAdLT1R3qiqCqll3Xzh2qFMvehQ9FODsPftw5U4UjB3QwnJ/3+dph 9kZBBeaJagUBVYzoArk6XNydpp3HhSCFDcIiepL6r8XAifW3SqI1KCne OD38kSCl/Qm9P0+3CFWokGVubsSQ+3dpQZxqx5bzOXthbuzAr6X+gDUE LAyHtCQNmJ+4ktdCoj3DNYW0z/xLvrcB2Lns7H+/qWnGPL4f3hr7Vbak Oeay+4J4KGdY2LFxJUVts6QrgAA8gz4mV9YIJFP+C4B3b/Z7qgqZRxmT 0pic+fJC5+sq0l8KwavPn0n+HqVuJNvppVKMdTbsmmuk69RFGMjbFkP7 tnCiqC9Zi6s=
diff --git a/tests/dns/Makefile.am b/tests/dns/Makefile.am
new file mode 100644
index 0000000..7062c60
--- /dev/null
+++ b/tests/dns/Makefile.am
@@ -0,0 +1,132 @@
+include $(top_srcdir)/Makefile.top
+
+AM_CPPFLAGS += \
+ $(LIBISC_CFLAGS) \
+ $(LIBDNS_CFLAGS) \
+ $(LIBUV_CFLAGS) \
+ $(KRB5_CFLAGS) \
+ -DSRCDIR=\"$(abs_srcdir)\" \
+ -DBUILDDIR=\"$(abs_builddir)\" \
+ -I$(top_srcdir)/lib/dns \
+ -I$(top_srcdir)/lib/isc
+
+LDADD += \
+ $(LIBISC_LIBS) \
+ $(LIBUV_LIBS) \
+ $(LIBDNS_LIBS)
+
+check_PROGRAMS = \
+ acl_test \
+ db_test \
+ dbdiff_test \
+ dbiterator_test \
+ dbversion_test \
+ dh_test \
+ dispatch_test \
+ dns64_test \
+ dst_test \
+ keytable_test \
+ name_test \
+ nsec3_test \
+ nsec3param_test \
+ private_test \
+ rbt_test \
+ rbtdb_test \
+ rdata_test \
+ rdataset_test \
+ rdatasetstats_test \
+ resolver_test \
+ rsa_test \
+ sigs_test \
+ time_test \
+ tsig_test \
+ update_test \
+ zonemgr_test \
+ zt_test
+
+CLEANFILES =
+
+if HAVE_PERL
+
+check_PROGRAMS += \
+ master_test
+
+EXTRA_master_test_DEPENDENCIES = testdata/master/master12.data testdata/master/master13.data testdata/master/master14.data
+CLEANFILES += $(EXTRA_master_test_DEPENDENCIES)
+
+testdata/master/master12.data: testdata/master/master12.data.in
+ mkdir -p testdata/master
+ $(PERL) -w $(srcdir)/mkraw.pl < $(srcdir)/testdata/master/master12.data.in > $@
+
+testdata/master/master13.data: testdata/master/master13.data.in
+ mkdir -p testdata/master
+ $(PERL) -w $(srcdir)/mkraw.pl < $(srcdir)/testdata/master/master13.data.in > $@
+
+testdata/master/master14.data: testdata/master/master14.data.in
+ mkdir -p testdata/master
+ $(PERL) -w $(srcdir)/mkraw.pl < $(srcdir)/testdata/master/master14.data.in > $@
+
+endif
+
+if HAVE_GEOIP2
+check_PROGRAMS += \
+ geoip_test
+
+geoip_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(MAXMINDDB_CFLAGS) \
+ -DTEST_GEOIP_DATA=\"$(top_srcdir)/bin/tests/system/geoip2/data\"
+
+geoip_test_LDADD = \
+ $(LDADD) \
+ $(MAXMINDDB_LIBS)
+endif
+
+if HAVE_DNSTAP
+check_PROGRAMS += \
+ dnstap_test
+
+dnstap_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(DNSTAP_CFLAGS)
+dnstap_test_LDADD = \
+ $(LDADD) \
+ $(DNSTAP_LIBS)
+endif
+
+dh_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+dst_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+rsa_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+rdata_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+rdata_test_LDADD = \
+ $(LDADD) \
+ $(OPENSSL_LIBS)
+
+EXTRA_sigs_test_DEPENDENCIES = testdata/master/master18.data
+CLEANFILES += $(EXTRA_sigs_test_DEPENDENCIES)
+
+testdata/master/master18.data: testdata/master/master18.data.in
+ mkdir -p testdata/master
+ sed -e 's,@TOP_SRCDIR@,$(abs_srcdir),' < $(srcdir)/testdata/master/master18.data.in > $@
+
+EXTRA_DIST = \
+ Kdh.+002+18602.key \
+ Krsa.+008+29238.key \
+ comparekeys \
+ mkraw.pl \
+ testdata \
+ testkeys
+
+include $(top_srcdir)/Makefile.tests
diff --git a/tests/dns/Makefile.in b/tests/dns/Makefile.in
new file mode 100644
index 0000000..34e27a8
--- /dev/null
+++ b/tests/dns/Makefile.in
@@ -0,0 +1,1934 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HOST_MACOS_TRUE@am__append_1 = \
+@HOST_MACOS_TRUE@ -Wl,-flat_namespace
+
+check_PROGRAMS = acl_test$(EXEEXT) db_test$(EXEEXT) \
+ dbdiff_test$(EXEEXT) dbiterator_test$(EXEEXT) \
+ dbversion_test$(EXEEXT) dh_test$(EXEEXT) \
+ dispatch_test$(EXEEXT) dns64_test$(EXEEXT) dst_test$(EXEEXT) \
+ keytable_test$(EXEEXT) name_test$(EXEEXT) nsec3_test$(EXEEXT) \
+ nsec3param_test$(EXEEXT) private_test$(EXEEXT) \
+ rbt_test$(EXEEXT) rbtdb_test$(EXEEXT) rdata_test$(EXEEXT) \
+ rdataset_test$(EXEEXT) rdatasetstats_test$(EXEEXT) \
+ resolver_test$(EXEEXT) rsa_test$(EXEEXT) sigs_test$(EXEEXT) \
+ time_test$(EXEEXT) tsig_test$(EXEEXT) update_test$(EXEEXT) \
+ zonemgr_test$(EXEEXT) zt_test$(EXEEXT) $(am__EXEEXT_1) \
+ $(am__EXEEXT_2) $(am__EXEEXT_3)
+@HAVE_PERL_TRUE@am__append_2 = \
+@HAVE_PERL_TRUE@ master_test
+
+@HAVE_PERL_TRUE@am__append_3 = $(EXTRA_master_test_DEPENDENCIES)
+@HAVE_GEOIP2_TRUE@am__append_4 = \
+@HAVE_GEOIP2_TRUE@ geoip_test
+
+@HAVE_DNSTAP_TRUE@am__append_5 = \
+@HAVE_DNSTAP_TRUE@ dnstap_test
+
+subdir = tests/dns
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4/ax_jemalloc.m4 \
+ $(top_srcdir)/m4/ax_lib_lmdb.m4 \
+ $(top_srcdir)/m4/ax_perl_module.m4 \
+ $(top_srcdir)/m4/ax_posix_shell.m4 \
+ $(top_srcdir)/m4/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_python_module.m4 \
+ $(top_srcdir)/m4/ax_restore_flags.m4 \
+ $(top_srcdir)/m4/ax_save_flags.m4 $(top_srcdir)/m4/ax_tls.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_PERL_TRUE@am__EXEEXT_1 = master_test$(EXEEXT)
+@HAVE_GEOIP2_TRUE@am__EXEEXT_2 = geoip_test$(EXEEXT)
+@HAVE_DNSTAP_TRUE@am__EXEEXT_3 = dnstap_test$(EXEEXT)
+acl_test_SOURCES = acl_test.c
+acl_test_OBJECTS = acl_test.$(OBJEXT)
+acl_test_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+acl_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+db_test_SOURCES = db_test.c
+db_test_OBJECTS = db_test.$(OBJEXT)
+db_test_LDADD = $(LDADD)
+db_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+dbdiff_test_SOURCES = dbdiff_test.c
+dbdiff_test_OBJECTS = dbdiff_test.$(OBJEXT)
+dbdiff_test_LDADD = $(LDADD)
+dbdiff_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+dbiterator_test_SOURCES = dbiterator_test.c
+dbiterator_test_OBJECTS = dbiterator_test.$(OBJEXT)
+dbiterator_test_LDADD = $(LDADD)
+dbiterator_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+dbversion_test_SOURCES = dbversion_test.c
+dbversion_test_OBJECTS = dbversion_test.$(OBJEXT)
+dbversion_test_LDADD = $(LDADD)
+dbversion_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+dh_test_SOURCES = dh_test.c
+dh_test_OBJECTS = dh_test-dh_test.$(OBJEXT)
+dh_test_LDADD = $(LDADD)
+dh_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+dispatch_test_SOURCES = dispatch_test.c
+dispatch_test_OBJECTS = dispatch_test.$(OBJEXT)
+dispatch_test_LDADD = $(LDADD)
+dispatch_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+dns64_test_SOURCES = dns64_test.c
+dns64_test_OBJECTS = dns64_test.$(OBJEXT)
+dns64_test_LDADD = $(LDADD)
+dns64_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+dnstap_test_SOURCES = dnstap_test.c
+dnstap_test_OBJECTS = dnstap_test-dnstap_test.$(OBJEXT)
+am__DEPENDENCIES_2 = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+@HAVE_DNSTAP_TRUE@dnstap_test_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+@HAVE_DNSTAP_TRUE@ $(am__DEPENDENCIES_1)
+dst_test_SOURCES = dst_test.c
+dst_test_OBJECTS = dst_test-dst_test.$(OBJEXT)
+dst_test_LDADD = $(LDADD)
+dst_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+geoip_test_SOURCES = geoip_test.c
+geoip_test_OBJECTS = geoip_test-geoip_test.$(OBJEXT)
+@HAVE_GEOIP2_TRUE@geoip_test_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+@HAVE_GEOIP2_TRUE@ $(am__DEPENDENCIES_1)
+keytable_test_SOURCES = keytable_test.c
+keytable_test_OBJECTS = keytable_test.$(OBJEXT)
+keytable_test_LDADD = $(LDADD)
+keytable_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+master_test_SOURCES = master_test.c
+master_test_OBJECTS = master_test.$(OBJEXT)
+master_test_LDADD = $(LDADD)
+master_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+name_test_SOURCES = name_test.c
+name_test_OBJECTS = name_test.$(OBJEXT)
+name_test_LDADD = $(LDADD)
+name_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+nsec3_test_SOURCES = nsec3_test.c
+nsec3_test_OBJECTS = nsec3_test.$(OBJEXT)
+nsec3_test_LDADD = $(LDADD)
+nsec3_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+nsec3param_test_SOURCES = nsec3param_test.c
+nsec3param_test_OBJECTS = nsec3param_test.$(OBJEXT)
+nsec3param_test_LDADD = $(LDADD)
+nsec3param_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+private_test_SOURCES = private_test.c
+private_test_OBJECTS = private_test.$(OBJEXT)
+private_test_LDADD = $(LDADD)
+private_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+rbt_test_SOURCES = rbt_test.c
+rbt_test_OBJECTS = rbt_test.$(OBJEXT)
+rbt_test_LDADD = $(LDADD)
+rbt_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+rbtdb_test_SOURCES = rbtdb_test.c
+rbtdb_test_OBJECTS = rbtdb_test.$(OBJEXT)
+rbtdb_test_LDADD = $(LDADD)
+rbtdb_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+rdata_test_SOURCES = rdata_test.c
+rdata_test_OBJECTS = rdata_test-rdata_test.$(OBJEXT)
+rdata_test_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
+rdataset_test_SOURCES = rdataset_test.c
+rdataset_test_OBJECTS = rdataset_test.$(OBJEXT)
+rdataset_test_LDADD = $(LDADD)
+rdataset_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+rdatasetstats_test_SOURCES = rdatasetstats_test.c
+rdatasetstats_test_OBJECTS = rdatasetstats_test.$(OBJEXT)
+rdatasetstats_test_LDADD = $(LDADD)
+rdatasetstats_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+resolver_test_SOURCES = resolver_test.c
+resolver_test_OBJECTS = resolver_test.$(OBJEXT)
+resolver_test_LDADD = $(LDADD)
+resolver_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+rsa_test_SOURCES = rsa_test.c
+rsa_test_OBJECTS = rsa_test-rsa_test.$(OBJEXT)
+rsa_test_LDADD = $(LDADD)
+rsa_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+sigs_test_SOURCES = sigs_test.c
+sigs_test_OBJECTS = sigs_test.$(OBJEXT)
+sigs_test_LDADD = $(LDADD)
+sigs_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+time_test_SOURCES = time_test.c
+time_test_OBJECTS = time_test.$(OBJEXT)
+time_test_LDADD = $(LDADD)
+time_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+tsig_test_SOURCES = tsig_test.c
+tsig_test_OBJECTS = tsig_test.$(OBJEXT)
+tsig_test_LDADD = $(LDADD)
+tsig_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+update_test_SOURCES = update_test.c
+update_test_OBJECTS = update_test.$(OBJEXT)
+update_test_LDADD = $(LDADD)
+update_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+zonemgr_test_SOURCES = zonemgr_test.c
+zonemgr_test_OBJECTS = zonemgr_test.$(OBJEXT)
+zonemgr_test_LDADD = $(LDADD)
+zonemgr_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+zt_test_SOURCES = zt_test.c
+zt_test_OBJECTS = zt_test.$(OBJEXT)
+zt_test_LDADD = $(LDADD)
+zt_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(LIBDNS_LIBS) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/acl_test.Po ./$(DEPDIR)/db_test.Po \
+ ./$(DEPDIR)/dbdiff_test.Po ./$(DEPDIR)/dbiterator_test.Po \
+ ./$(DEPDIR)/dbversion_test.Po ./$(DEPDIR)/dh_test-dh_test.Po \
+ ./$(DEPDIR)/dispatch_test.Po ./$(DEPDIR)/dns64_test.Po \
+ ./$(DEPDIR)/dnstap_test-dnstap_test.Po \
+ ./$(DEPDIR)/dst_test-dst_test.Po \
+ ./$(DEPDIR)/geoip_test-geoip_test.Po \
+ ./$(DEPDIR)/keytable_test.Po ./$(DEPDIR)/master_test.Po \
+ ./$(DEPDIR)/name_test.Po ./$(DEPDIR)/nsec3_test.Po \
+ ./$(DEPDIR)/nsec3param_test.Po ./$(DEPDIR)/private_test.Po \
+ ./$(DEPDIR)/rbt_test.Po ./$(DEPDIR)/rbtdb_test.Po \
+ ./$(DEPDIR)/rdata_test-rdata_test.Po \
+ ./$(DEPDIR)/rdataset_test.Po ./$(DEPDIR)/rdatasetstats_test.Po \
+ ./$(DEPDIR)/resolver_test.Po ./$(DEPDIR)/rsa_test-rsa_test.Po \
+ ./$(DEPDIR)/sigs_test.Po ./$(DEPDIR)/time_test.Po \
+ ./$(DEPDIR)/tsig_test.Po ./$(DEPDIR)/update_test.Po \
+ ./$(DEPDIR)/zonemgr_test.Po ./$(DEPDIR)/zt_test.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = acl_test.c db_test.c dbdiff_test.c dbiterator_test.c \
+ dbversion_test.c dh_test.c dispatch_test.c dns64_test.c \
+ dnstap_test.c dst_test.c geoip_test.c keytable_test.c \
+ master_test.c name_test.c nsec3_test.c nsec3param_test.c \
+ private_test.c rbt_test.c rbtdb_test.c rdata_test.c \
+ rdataset_test.c rdatasetstats_test.c resolver_test.c \
+ rsa_test.c sigs_test.c time_test.c tsig_test.c update_test.c \
+ zonemgr_test.c zt_test.c
+DIST_SOURCES = acl_test.c db_test.c dbdiff_test.c dbiterator_test.c \
+ dbversion_test.c dh_test.c dispatch_test.c dns64_test.c \
+ dnstap_test.c dst_test.c geoip_test.c keytable_test.c \
+ master_test.c name_test.c nsec3_test.c nsec3param_test.c \
+ private_test.c rbt_test.c rbtdb_test.c rdata_test.c \
+ rdataset_test.c rdatasetstats_test.c resolver_test.c \
+ rsa_test.c sigs_test.c time_test.c tsig_test.c update_test.c \
+ zonemgr_test.c zt_test.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = test-recursive unit-recursive \
+ doc-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/Makefile.tests \
+ $(top_srcdir)/Makefile.top $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CMOCKA_CFLAGS = @CMOCKA_CFLAGS@
+CMOCKA_LIBS = @CMOCKA_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURL = @CURL@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEVELOPER_MODE = @DEVELOPER_MODE@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FSTRM_CAPTURE = @FSTRM_CAPTURE@
+FUZZ_LDFLAGS = @FUZZ_LDFLAGS@
+FUZZ_LOG_COMPILER = @FUZZ_LOG_COMPILER@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@
+JEMALLOC_LIBS = @JEMALLOC_LIBS@
+JSON_C_CFLAGS = @JSON_C_CFLAGS@
+JSON_C_LIBS = @JSON_C_LIBS@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_CONFIG = @KRB5_CONFIG@
+KRB5_LIBS = @KRB5_LIBS@
+LATEXMK = @LATEXMK@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBNGHTTP2_CFLAGS = @LIBNGHTTP2_CFLAGS@
+LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUV_CFLAGS = @LIBUV_CFLAGS@
+LIBUV_LIBS = @LIBUV_LIBS@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIPO = @LIPO@
+LMDB_CFLAGS = @LMDB_CFLAGS@
+LMDB_LIBS = @LMDB_LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAXMINDDB_CFLAGS = @MAXMINDDB_CFLAGS@
+MAXMINDDB_LIBS = @MAXMINDDB_LIBS@
+MAXMINDDB_PREFIX = @MAXMINDDB_PREFIX@
+MKDIR_P = @MKDIR_P@
+NC = @NC@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTEST = @PYTEST@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+READLINE_CFLAGS = @READLINE_CFLAGS@
+READLINE_LIBS = @READLINE_LIBS@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINX_BUILD = @SPHINX_BUILD@
+STD_CFLAGS = @STD_CFLAGS@
+STD_CPPFLAGS = @STD_CPPFLAGS@
+STD_LDFLAGS = @STD_LDFLAGS@
+STRIP = @STRIP@
+TEST_CFLAGS = @TEST_CFLAGS@
+VERSION = @VERSION@
+XELATEX = @XELATEX@
+XSLTPROC = @XSLTPROC@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
+AM_CFLAGS = $(STD_CFLAGS) -I$(top_srcdir)/tests/include $(TEST_CFLAGS)
+AM_CPPFLAGS = $(STD_CPPFLAGS) -include $(top_builddir)/config.h \
+ -I$(srcdir)/include $(LIBISC_CFLAGS) $(LIBDNS_CFLAGS) \
+ $(LIBUV_CFLAGS) $(KRB5_CFLAGS) -DSRCDIR=\"$(abs_srcdir)\" \
+ -DBUILDDIR=\"$(abs_builddir)\" -I$(top_srcdir)/lib/dns \
+ -I$(top_srcdir)/lib/isc $(CMOCKA_CFLAGS) \
+ -DNAMED_PLUGINDIR=\"$(pkglibdir)\" \
+ -DTESTS_DIR=\"$(abs_srcdir)\"
+AM_LDFLAGS = $(STD_LDFLAGS) $(am__append_1)
+LDADD = $(LIBISC_LIBS) $(LIBUV_LIBS) $(LIBDNS_LIBS) \
+ $(top_builddir)/tests/libtest/libtest.la $(CMOCKA_LIBS)
+LIBISC_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib/isc/include \
+ -I$(top_builddir)/lib/isc/include
+
+LIBISC_LIBS = $(top_builddir)/lib/isc/libisc.la
+LIBDNS_CFLAGS = \
+ -I$(top_srcdir)/lib/dns/include \
+ -I$(top_builddir)/lib/dns/include
+
+LIBDNS_LIBS = \
+ $(top_builddir)/lib/dns/libdns.la
+
+LIBNS_CFLAGS = \
+ -I$(top_srcdir)/lib/ns/include
+
+LIBNS_LIBS = \
+ $(top_builddir)/lib/ns/libns.la
+
+LIBIRS_CFLAGS = \
+ -I$(top_srcdir)/lib/irs/include
+
+LIBIRS_LIBS = \
+ $(top_builddir)/lib/irs/libirs.la
+
+LIBISCCFG_CFLAGS = \
+ -I$(top_srcdir)/lib/isccfg/include
+
+LIBISCCFG_LIBS = \
+ $(top_builddir)/lib/isccfg/libisccfg.la
+
+LIBISCCC_CFLAGS = \
+ -I$(top_srcdir)/lib/isccc/include/
+
+LIBISCCC_LIBS = \
+ $(top_builddir)/lib/isccc/libisccc.la
+
+LIBBIND9_CFLAGS = \
+ -I$(top_srcdir)/lib/bind9/include
+
+LIBBIND9_LIBS = \
+ $(top_builddir)/lib/bind9/libbind9.la
+
+CLEANFILES = $(am__append_3) $(EXTRA_sigs_test_DEPENDENCIES)
+@HAVE_PERL_TRUE@EXTRA_master_test_DEPENDENCIES = testdata/master/master12.data testdata/master/master13.data testdata/master/master14.data
+@HAVE_GEOIP2_TRUE@geoip_test_CPPFLAGS = \
+@HAVE_GEOIP2_TRUE@ $(AM_CPPFLAGS) \
+@HAVE_GEOIP2_TRUE@ $(MAXMINDDB_CFLAGS) \
+@HAVE_GEOIP2_TRUE@ -DTEST_GEOIP_DATA=\"$(top_srcdir)/bin/tests/system/geoip2/data\"
+
+@HAVE_GEOIP2_TRUE@geoip_test_LDADD = \
+@HAVE_GEOIP2_TRUE@ $(LDADD) \
+@HAVE_GEOIP2_TRUE@ $(MAXMINDDB_LIBS)
+
+@HAVE_DNSTAP_TRUE@dnstap_test_CPPFLAGS = \
+@HAVE_DNSTAP_TRUE@ $(AM_CPPFLAGS) \
+@HAVE_DNSTAP_TRUE@ $(DNSTAP_CFLAGS)
+
+@HAVE_DNSTAP_TRUE@dnstap_test_LDADD = \
+@HAVE_DNSTAP_TRUE@ $(LDADD) \
+@HAVE_DNSTAP_TRUE@ $(DNSTAP_LIBS)
+
+dh_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+dst_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+rsa_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+rdata_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+rdata_test_LDADD = \
+ $(LDADD) \
+ $(OPENSSL_LIBS)
+
+EXTRA_sigs_test_DEPENDENCIES = testdata/master/master18.data
+EXTRA_DIST = \
+ Kdh.+002+18602.key \
+ Krsa.+008+29238.key \
+ comparekeys \
+ mkraw.pl \
+ testdata \
+ testkeys
+
+@HAVE_CMOCKA_TRUE@TESTS = $(check_PROGRAMS)
+LOG_COMPILER = $(top_builddir)/tests/unit-test-driver.sh
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/dns/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tests/dns/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+acl_test$(EXEEXT): $(acl_test_OBJECTS) $(acl_test_DEPENDENCIES) $(EXTRA_acl_test_DEPENDENCIES)
+ @rm -f acl_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(acl_test_OBJECTS) $(acl_test_LDADD) $(LIBS)
+
+db_test$(EXEEXT): $(db_test_OBJECTS) $(db_test_DEPENDENCIES) $(EXTRA_db_test_DEPENDENCIES)
+ @rm -f db_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(db_test_OBJECTS) $(db_test_LDADD) $(LIBS)
+
+dbdiff_test$(EXEEXT): $(dbdiff_test_OBJECTS) $(dbdiff_test_DEPENDENCIES) $(EXTRA_dbdiff_test_DEPENDENCIES)
+ @rm -f dbdiff_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dbdiff_test_OBJECTS) $(dbdiff_test_LDADD) $(LIBS)
+
+dbiterator_test$(EXEEXT): $(dbiterator_test_OBJECTS) $(dbiterator_test_DEPENDENCIES) $(EXTRA_dbiterator_test_DEPENDENCIES)
+ @rm -f dbiterator_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dbiterator_test_OBJECTS) $(dbiterator_test_LDADD) $(LIBS)
+
+dbversion_test$(EXEEXT): $(dbversion_test_OBJECTS) $(dbversion_test_DEPENDENCIES) $(EXTRA_dbversion_test_DEPENDENCIES)
+ @rm -f dbversion_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dbversion_test_OBJECTS) $(dbversion_test_LDADD) $(LIBS)
+
+dh_test$(EXEEXT): $(dh_test_OBJECTS) $(dh_test_DEPENDENCIES) $(EXTRA_dh_test_DEPENDENCIES)
+ @rm -f dh_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dh_test_OBJECTS) $(dh_test_LDADD) $(LIBS)
+
+dispatch_test$(EXEEXT): $(dispatch_test_OBJECTS) $(dispatch_test_DEPENDENCIES) $(EXTRA_dispatch_test_DEPENDENCIES)
+ @rm -f dispatch_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dispatch_test_OBJECTS) $(dispatch_test_LDADD) $(LIBS)
+
+dns64_test$(EXEEXT): $(dns64_test_OBJECTS) $(dns64_test_DEPENDENCIES) $(EXTRA_dns64_test_DEPENDENCIES)
+ @rm -f dns64_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dns64_test_OBJECTS) $(dns64_test_LDADD) $(LIBS)
+
+dnstap_test$(EXEEXT): $(dnstap_test_OBJECTS) $(dnstap_test_DEPENDENCIES) $(EXTRA_dnstap_test_DEPENDENCIES)
+ @rm -f dnstap_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dnstap_test_OBJECTS) $(dnstap_test_LDADD) $(LIBS)
+
+dst_test$(EXEEXT): $(dst_test_OBJECTS) $(dst_test_DEPENDENCIES) $(EXTRA_dst_test_DEPENDENCIES)
+ @rm -f dst_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dst_test_OBJECTS) $(dst_test_LDADD) $(LIBS)
+
+geoip_test$(EXEEXT): $(geoip_test_OBJECTS) $(geoip_test_DEPENDENCIES) $(EXTRA_geoip_test_DEPENDENCIES)
+ @rm -f geoip_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(geoip_test_OBJECTS) $(geoip_test_LDADD) $(LIBS)
+
+keytable_test$(EXEEXT): $(keytable_test_OBJECTS) $(keytable_test_DEPENDENCIES) $(EXTRA_keytable_test_DEPENDENCIES)
+ @rm -f keytable_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(keytable_test_OBJECTS) $(keytable_test_LDADD) $(LIBS)
+
+master_test$(EXEEXT): $(master_test_OBJECTS) $(master_test_DEPENDENCIES) $(EXTRA_master_test_DEPENDENCIES)
+ @rm -f master_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(master_test_OBJECTS) $(master_test_LDADD) $(LIBS)
+
+name_test$(EXEEXT): $(name_test_OBJECTS) $(name_test_DEPENDENCIES) $(EXTRA_name_test_DEPENDENCIES)
+ @rm -f name_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(name_test_OBJECTS) $(name_test_LDADD) $(LIBS)
+
+nsec3_test$(EXEEXT): $(nsec3_test_OBJECTS) $(nsec3_test_DEPENDENCIES) $(EXTRA_nsec3_test_DEPENDENCIES)
+ @rm -f nsec3_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(nsec3_test_OBJECTS) $(nsec3_test_LDADD) $(LIBS)
+
+nsec3param_test$(EXEEXT): $(nsec3param_test_OBJECTS) $(nsec3param_test_DEPENDENCIES) $(EXTRA_nsec3param_test_DEPENDENCIES)
+ @rm -f nsec3param_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(nsec3param_test_OBJECTS) $(nsec3param_test_LDADD) $(LIBS)
+
+private_test$(EXEEXT): $(private_test_OBJECTS) $(private_test_DEPENDENCIES) $(EXTRA_private_test_DEPENDENCIES)
+ @rm -f private_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(private_test_OBJECTS) $(private_test_LDADD) $(LIBS)
+
+rbt_test$(EXEEXT): $(rbt_test_OBJECTS) $(rbt_test_DEPENDENCIES) $(EXTRA_rbt_test_DEPENDENCIES)
+ @rm -f rbt_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rbt_test_OBJECTS) $(rbt_test_LDADD) $(LIBS)
+
+rbtdb_test$(EXEEXT): $(rbtdb_test_OBJECTS) $(rbtdb_test_DEPENDENCIES) $(EXTRA_rbtdb_test_DEPENDENCIES)
+ @rm -f rbtdb_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rbtdb_test_OBJECTS) $(rbtdb_test_LDADD) $(LIBS)
+
+rdata_test$(EXEEXT): $(rdata_test_OBJECTS) $(rdata_test_DEPENDENCIES) $(EXTRA_rdata_test_DEPENDENCIES)
+ @rm -f rdata_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rdata_test_OBJECTS) $(rdata_test_LDADD) $(LIBS)
+
+rdataset_test$(EXEEXT): $(rdataset_test_OBJECTS) $(rdataset_test_DEPENDENCIES) $(EXTRA_rdataset_test_DEPENDENCIES)
+ @rm -f rdataset_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rdataset_test_OBJECTS) $(rdataset_test_LDADD) $(LIBS)
+
+rdatasetstats_test$(EXEEXT): $(rdatasetstats_test_OBJECTS) $(rdatasetstats_test_DEPENDENCIES) $(EXTRA_rdatasetstats_test_DEPENDENCIES)
+ @rm -f rdatasetstats_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rdatasetstats_test_OBJECTS) $(rdatasetstats_test_LDADD) $(LIBS)
+
+resolver_test$(EXEEXT): $(resolver_test_OBJECTS) $(resolver_test_DEPENDENCIES) $(EXTRA_resolver_test_DEPENDENCIES)
+ @rm -f resolver_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(resolver_test_OBJECTS) $(resolver_test_LDADD) $(LIBS)
+
+rsa_test$(EXEEXT): $(rsa_test_OBJECTS) $(rsa_test_DEPENDENCIES) $(EXTRA_rsa_test_DEPENDENCIES)
+ @rm -f rsa_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rsa_test_OBJECTS) $(rsa_test_LDADD) $(LIBS)
+
+sigs_test$(EXEEXT): $(sigs_test_OBJECTS) $(sigs_test_DEPENDENCIES) $(EXTRA_sigs_test_DEPENDENCIES)
+ @rm -f sigs_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sigs_test_OBJECTS) $(sigs_test_LDADD) $(LIBS)
+
+time_test$(EXEEXT): $(time_test_OBJECTS) $(time_test_DEPENDENCIES) $(EXTRA_time_test_DEPENDENCIES)
+ @rm -f time_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(time_test_OBJECTS) $(time_test_LDADD) $(LIBS)
+
+tsig_test$(EXEEXT): $(tsig_test_OBJECTS) $(tsig_test_DEPENDENCIES) $(EXTRA_tsig_test_DEPENDENCIES)
+ @rm -f tsig_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tsig_test_OBJECTS) $(tsig_test_LDADD) $(LIBS)
+
+update_test$(EXEEXT): $(update_test_OBJECTS) $(update_test_DEPENDENCIES) $(EXTRA_update_test_DEPENDENCIES)
+ @rm -f update_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(update_test_OBJECTS) $(update_test_LDADD) $(LIBS)
+
+zonemgr_test$(EXEEXT): $(zonemgr_test_OBJECTS) $(zonemgr_test_DEPENDENCIES) $(EXTRA_zonemgr_test_DEPENDENCIES)
+ @rm -f zonemgr_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(zonemgr_test_OBJECTS) $(zonemgr_test_LDADD) $(LIBS)
+
+zt_test$(EXEEXT): $(zt_test_OBJECTS) $(zt_test_DEPENDENCIES) $(EXTRA_zt_test_DEPENDENCIES)
+ @rm -f zt_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(zt_test_OBJECTS) $(zt_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acl_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/db_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbdiff_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbiterator_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbversion_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dh_test-dh_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatch_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns64_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnstap_test-dnstap_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dst_test-dst_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/geoip_test-geoip_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keytable_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/master_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/name_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3param_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/private_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rbt_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rbtdb_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdata_test-rdata_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdataset_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdatasetstats_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolver_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa_test-rsa_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sigs_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsig_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zonemgr_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zt_test.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+dh_test-dh_test.o: dh_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dh_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dh_test-dh_test.o -MD -MP -MF $(DEPDIR)/dh_test-dh_test.Tpo -c -o dh_test-dh_test.o `test -f 'dh_test.c' || echo '$(srcdir)/'`dh_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dh_test-dh_test.Tpo $(DEPDIR)/dh_test-dh_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dh_test.c' object='dh_test-dh_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dh_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dh_test-dh_test.o `test -f 'dh_test.c' || echo '$(srcdir)/'`dh_test.c
+
+dh_test-dh_test.obj: dh_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dh_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dh_test-dh_test.obj -MD -MP -MF $(DEPDIR)/dh_test-dh_test.Tpo -c -o dh_test-dh_test.obj `if test -f 'dh_test.c'; then $(CYGPATH_W) 'dh_test.c'; else $(CYGPATH_W) '$(srcdir)/dh_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dh_test-dh_test.Tpo $(DEPDIR)/dh_test-dh_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dh_test.c' object='dh_test-dh_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dh_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dh_test-dh_test.obj `if test -f 'dh_test.c'; then $(CYGPATH_W) 'dh_test.c'; else $(CYGPATH_W) '$(srcdir)/dh_test.c'; fi`
+
+dnstap_test-dnstap_test.o: dnstap_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dnstap_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dnstap_test-dnstap_test.o -MD -MP -MF $(DEPDIR)/dnstap_test-dnstap_test.Tpo -c -o dnstap_test-dnstap_test.o `test -f 'dnstap_test.c' || echo '$(srcdir)/'`dnstap_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dnstap_test-dnstap_test.Tpo $(DEPDIR)/dnstap_test-dnstap_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dnstap_test.c' object='dnstap_test-dnstap_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dnstap_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dnstap_test-dnstap_test.o `test -f 'dnstap_test.c' || echo '$(srcdir)/'`dnstap_test.c
+
+dnstap_test-dnstap_test.obj: dnstap_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dnstap_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dnstap_test-dnstap_test.obj -MD -MP -MF $(DEPDIR)/dnstap_test-dnstap_test.Tpo -c -o dnstap_test-dnstap_test.obj `if test -f 'dnstap_test.c'; then $(CYGPATH_W) 'dnstap_test.c'; else $(CYGPATH_W) '$(srcdir)/dnstap_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dnstap_test-dnstap_test.Tpo $(DEPDIR)/dnstap_test-dnstap_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dnstap_test.c' object='dnstap_test-dnstap_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dnstap_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dnstap_test-dnstap_test.obj `if test -f 'dnstap_test.c'; then $(CYGPATH_W) 'dnstap_test.c'; else $(CYGPATH_W) '$(srcdir)/dnstap_test.c'; fi`
+
+dst_test-dst_test.o: dst_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dst_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dst_test-dst_test.o -MD -MP -MF $(DEPDIR)/dst_test-dst_test.Tpo -c -o dst_test-dst_test.o `test -f 'dst_test.c' || echo '$(srcdir)/'`dst_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dst_test-dst_test.Tpo $(DEPDIR)/dst_test-dst_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dst_test.c' object='dst_test-dst_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dst_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dst_test-dst_test.o `test -f 'dst_test.c' || echo '$(srcdir)/'`dst_test.c
+
+dst_test-dst_test.obj: dst_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dst_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dst_test-dst_test.obj -MD -MP -MF $(DEPDIR)/dst_test-dst_test.Tpo -c -o dst_test-dst_test.obj `if test -f 'dst_test.c'; then $(CYGPATH_W) 'dst_test.c'; else $(CYGPATH_W) '$(srcdir)/dst_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dst_test-dst_test.Tpo $(DEPDIR)/dst_test-dst_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dst_test.c' object='dst_test-dst_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dst_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dst_test-dst_test.obj `if test -f 'dst_test.c'; then $(CYGPATH_W) 'dst_test.c'; else $(CYGPATH_W) '$(srcdir)/dst_test.c'; fi`
+
+geoip_test-geoip_test.o: geoip_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(geoip_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT geoip_test-geoip_test.o -MD -MP -MF $(DEPDIR)/geoip_test-geoip_test.Tpo -c -o geoip_test-geoip_test.o `test -f 'geoip_test.c' || echo '$(srcdir)/'`geoip_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/geoip_test-geoip_test.Tpo $(DEPDIR)/geoip_test-geoip_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='geoip_test.c' object='geoip_test-geoip_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(geoip_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o geoip_test-geoip_test.o `test -f 'geoip_test.c' || echo '$(srcdir)/'`geoip_test.c
+
+geoip_test-geoip_test.obj: geoip_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(geoip_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT geoip_test-geoip_test.obj -MD -MP -MF $(DEPDIR)/geoip_test-geoip_test.Tpo -c -o geoip_test-geoip_test.obj `if test -f 'geoip_test.c'; then $(CYGPATH_W) 'geoip_test.c'; else $(CYGPATH_W) '$(srcdir)/geoip_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/geoip_test-geoip_test.Tpo $(DEPDIR)/geoip_test-geoip_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='geoip_test.c' object='geoip_test-geoip_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(geoip_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o geoip_test-geoip_test.obj `if test -f 'geoip_test.c'; then $(CYGPATH_W) 'geoip_test.c'; else $(CYGPATH_W) '$(srcdir)/geoip_test.c'; fi`
+
+rdata_test-rdata_test.o: rdata_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(rdata_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_test-rdata_test.o -MD -MP -MF $(DEPDIR)/rdata_test-rdata_test.Tpo -c -o rdata_test-rdata_test.o `test -f 'rdata_test.c' || echo '$(srcdir)/'`rdata_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rdata_test-rdata_test.Tpo $(DEPDIR)/rdata_test-rdata_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rdata_test.c' object='rdata_test-rdata_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(rdata_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_test-rdata_test.o `test -f 'rdata_test.c' || echo '$(srcdir)/'`rdata_test.c
+
+rdata_test-rdata_test.obj: rdata_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(rdata_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_test-rdata_test.obj -MD -MP -MF $(DEPDIR)/rdata_test-rdata_test.Tpo -c -o rdata_test-rdata_test.obj `if test -f 'rdata_test.c'; then $(CYGPATH_W) 'rdata_test.c'; else $(CYGPATH_W) '$(srcdir)/rdata_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rdata_test-rdata_test.Tpo $(DEPDIR)/rdata_test-rdata_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rdata_test.c' object='rdata_test-rdata_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(rdata_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_test-rdata_test.obj `if test -f 'rdata_test.c'; then $(CYGPATH_W) 'rdata_test.c'; else $(CYGPATH_W) '$(srcdir)/rdata_test.c'; fi`
+
+rsa_test-rsa_test.o: rsa_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(rsa_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rsa_test-rsa_test.o -MD -MP -MF $(DEPDIR)/rsa_test-rsa_test.Tpo -c -o rsa_test-rsa_test.o `test -f 'rsa_test.c' || echo '$(srcdir)/'`rsa_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rsa_test-rsa_test.Tpo $(DEPDIR)/rsa_test-rsa_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rsa_test.c' object='rsa_test-rsa_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(rsa_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rsa_test-rsa_test.o `test -f 'rsa_test.c' || echo '$(srcdir)/'`rsa_test.c
+
+rsa_test-rsa_test.obj: rsa_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(rsa_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rsa_test-rsa_test.obj -MD -MP -MF $(DEPDIR)/rsa_test-rsa_test.Tpo -c -o rsa_test-rsa_test.obj `if test -f 'rsa_test.c'; then $(CYGPATH_W) 'rsa_test.c'; else $(CYGPATH_W) '$(srcdir)/rsa_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rsa_test-rsa_test.Tpo $(DEPDIR)/rsa_test-rsa_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rsa_test.c' object='rsa_test-rsa_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(rsa_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rsa_test-rsa_test.obj `if test -f 'rsa_test.c'; then $(CYGPATH_W) 'rsa_test.c'; else $(CYGPATH_W) '$(srcdir)/rsa_test.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+test-local:
+unit-local:
+doc-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS: $(check_PROGRAMS)
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+acl_test.log: acl_test$(EXEEXT)
+ @p='acl_test$(EXEEXT)'; \
+ b='acl_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+db_test.log: db_test$(EXEEXT)
+ @p='db_test$(EXEEXT)'; \
+ b='db_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dbdiff_test.log: dbdiff_test$(EXEEXT)
+ @p='dbdiff_test$(EXEEXT)'; \
+ b='dbdiff_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dbiterator_test.log: dbiterator_test$(EXEEXT)
+ @p='dbiterator_test$(EXEEXT)'; \
+ b='dbiterator_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dbversion_test.log: dbversion_test$(EXEEXT)
+ @p='dbversion_test$(EXEEXT)'; \
+ b='dbversion_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dh_test.log: dh_test$(EXEEXT)
+ @p='dh_test$(EXEEXT)'; \
+ b='dh_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dispatch_test.log: dispatch_test$(EXEEXT)
+ @p='dispatch_test$(EXEEXT)'; \
+ b='dispatch_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dns64_test.log: dns64_test$(EXEEXT)
+ @p='dns64_test$(EXEEXT)'; \
+ b='dns64_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dst_test.log: dst_test$(EXEEXT)
+ @p='dst_test$(EXEEXT)'; \
+ b='dst_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+keytable_test.log: keytable_test$(EXEEXT)
+ @p='keytable_test$(EXEEXT)'; \
+ b='keytable_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+name_test.log: name_test$(EXEEXT)
+ @p='name_test$(EXEEXT)'; \
+ b='name_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+nsec3_test.log: nsec3_test$(EXEEXT)
+ @p='nsec3_test$(EXEEXT)'; \
+ b='nsec3_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+nsec3param_test.log: nsec3param_test$(EXEEXT)
+ @p='nsec3param_test$(EXEEXT)'; \
+ b='nsec3param_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+private_test.log: private_test$(EXEEXT)
+ @p='private_test$(EXEEXT)'; \
+ b='private_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+rbt_test.log: rbt_test$(EXEEXT)
+ @p='rbt_test$(EXEEXT)'; \
+ b='rbt_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+rbtdb_test.log: rbtdb_test$(EXEEXT)
+ @p='rbtdb_test$(EXEEXT)'; \
+ b='rbtdb_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+rdata_test.log: rdata_test$(EXEEXT)
+ @p='rdata_test$(EXEEXT)'; \
+ b='rdata_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+rdataset_test.log: rdataset_test$(EXEEXT)
+ @p='rdataset_test$(EXEEXT)'; \
+ b='rdataset_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+rdatasetstats_test.log: rdatasetstats_test$(EXEEXT)
+ @p='rdatasetstats_test$(EXEEXT)'; \
+ b='rdatasetstats_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+resolver_test.log: resolver_test$(EXEEXT)
+ @p='resolver_test$(EXEEXT)'; \
+ b='resolver_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+rsa_test.log: rsa_test$(EXEEXT)
+ @p='rsa_test$(EXEEXT)'; \
+ b='rsa_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+sigs_test.log: sigs_test$(EXEEXT)
+ @p='sigs_test$(EXEEXT)'; \
+ b='sigs_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+time_test.log: time_test$(EXEEXT)
+ @p='time_test$(EXEEXT)'; \
+ b='time_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+tsig_test.log: tsig_test$(EXEEXT)
+ @p='tsig_test$(EXEEXT)'; \
+ b='tsig_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+update_test.log: update_test$(EXEEXT)
+ @p='update_test$(EXEEXT)'; \
+ b='update_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+zonemgr_test.log: zonemgr_test$(EXEEXT)
+ @p='zonemgr_test$(EXEEXT)'; \
+ b='zonemgr_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+zt_test.log: zt_test$(EXEEXT)
+ @p='zt_test$(EXEEXT)'; \
+ b='zt_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+master_test.log: master_test$(EXEEXT)
+ @p='master_test$(EXEEXT)'; \
+ b='master_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+geoip_test.log: geoip_test$(EXEEXT)
+ @p='geoip_test$(EXEEXT)'; \
+ b='geoip_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dnstap_test.log: dnstap_test$(EXEEXT)
+ @p='dnstap_test$(EXEEXT)'; \
+ b='dnstap_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/acl_test.Po
+ -rm -f ./$(DEPDIR)/db_test.Po
+ -rm -f ./$(DEPDIR)/dbdiff_test.Po
+ -rm -f ./$(DEPDIR)/dbiterator_test.Po
+ -rm -f ./$(DEPDIR)/dbversion_test.Po
+ -rm -f ./$(DEPDIR)/dh_test-dh_test.Po
+ -rm -f ./$(DEPDIR)/dispatch_test.Po
+ -rm -f ./$(DEPDIR)/dns64_test.Po
+ -rm -f ./$(DEPDIR)/dnstap_test-dnstap_test.Po
+ -rm -f ./$(DEPDIR)/dst_test-dst_test.Po
+ -rm -f ./$(DEPDIR)/geoip_test-geoip_test.Po
+ -rm -f ./$(DEPDIR)/keytable_test.Po
+ -rm -f ./$(DEPDIR)/master_test.Po
+ -rm -f ./$(DEPDIR)/name_test.Po
+ -rm -f ./$(DEPDIR)/nsec3_test.Po
+ -rm -f ./$(DEPDIR)/nsec3param_test.Po
+ -rm -f ./$(DEPDIR)/private_test.Po
+ -rm -f ./$(DEPDIR)/rbt_test.Po
+ -rm -f ./$(DEPDIR)/rbtdb_test.Po
+ -rm -f ./$(DEPDIR)/rdata_test-rdata_test.Po
+ -rm -f ./$(DEPDIR)/rdataset_test.Po
+ -rm -f ./$(DEPDIR)/rdatasetstats_test.Po
+ -rm -f ./$(DEPDIR)/resolver_test.Po
+ -rm -f ./$(DEPDIR)/rsa_test-rsa_test.Po
+ -rm -f ./$(DEPDIR)/sigs_test.Po
+ -rm -f ./$(DEPDIR)/time_test.Po
+ -rm -f ./$(DEPDIR)/tsig_test.Po
+ -rm -f ./$(DEPDIR)/update_test.Po
+ -rm -f ./$(DEPDIR)/zonemgr_test.Po
+ -rm -f ./$(DEPDIR)/zt_test.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+doc: doc-am
+
+doc-am: doc-local
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/acl_test.Po
+ -rm -f ./$(DEPDIR)/db_test.Po
+ -rm -f ./$(DEPDIR)/dbdiff_test.Po
+ -rm -f ./$(DEPDIR)/dbiterator_test.Po
+ -rm -f ./$(DEPDIR)/dbversion_test.Po
+ -rm -f ./$(DEPDIR)/dh_test-dh_test.Po
+ -rm -f ./$(DEPDIR)/dispatch_test.Po
+ -rm -f ./$(DEPDIR)/dns64_test.Po
+ -rm -f ./$(DEPDIR)/dnstap_test-dnstap_test.Po
+ -rm -f ./$(DEPDIR)/dst_test-dst_test.Po
+ -rm -f ./$(DEPDIR)/geoip_test-geoip_test.Po
+ -rm -f ./$(DEPDIR)/keytable_test.Po
+ -rm -f ./$(DEPDIR)/master_test.Po
+ -rm -f ./$(DEPDIR)/name_test.Po
+ -rm -f ./$(DEPDIR)/nsec3_test.Po
+ -rm -f ./$(DEPDIR)/nsec3param_test.Po
+ -rm -f ./$(DEPDIR)/private_test.Po
+ -rm -f ./$(DEPDIR)/rbt_test.Po
+ -rm -f ./$(DEPDIR)/rbtdb_test.Po
+ -rm -f ./$(DEPDIR)/rdata_test-rdata_test.Po
+ -rm -f ./$(DEPDIR)/rdataset_test.Po
+ -rm -f ./$(DEPDIR)/rdatasetstats_test.Po
+ -rm -f ./$(DEPDIR)/resolver_test.Po
+ -rm -f ./$(DEPDIR)/rsa_test-rsa_test.Po
+ -rm -f ./$(DEPDIR)/sigs_test.Po
+ -rm -f ./$(DEPDIR)/time_test.Po
+ -rm -f ./$(DEPDIR)/tsig_test.Po
+ -rm -f ./$(DEPDIR)/update_test.Po
+ -rm -f ./$(DEPDIR)/zonemgr_test.Po
+ -rm -f ./$(DEPDIR)/zt_test.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+test: test-am
+
+test-am: test-local
+
+uninstall-am:
+
+unit: unit-am
+
+unit-am: unit-local
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-checkPROGRAMS clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir \
+ doc-am doc-local dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am recheck tags tags-am test-am test-local \
+ uninstall uninstall-am unit-am unit-local
+
+.PRECIOUS: Makefile
+
+
+@HAVE_PERL_TRUE@testdata/master/master12.data: testdata/master/master12.data.in
+@HAVE_PERL_TRUE@ mkdir -p testdata/master
+@HAVE_PERL_TRUE@ $(PERL) -w $(srcdir)/mkraw.pl < $(srcdir)/testdata/master/master12.data.in > $@
+
+@HAVE_PERL_TRUE@testdata/master/master13.data: testdata/master/master13.data.in
+@HAVE_PERL_TRUE@ mkdir -p testdata/master
+@HAVE_PERL_TRUE@ $(PERL) -w $(srcdir)/mkraw.pl < $(srcdir)/testdata/master/master13.data.in > $@
+
+@HAVE_PERL_TRUE@testdata/master/master14.data: testdata/master/master14.data.in
+@HAVE_PERL_TRUE@ mkdir -p testdata/master
+@HAVE_PERL_TRUE@ $(PERL) -w $(srcdir)/mkraw.pl < $(srcdir)/testdata/master/master14.data.in > $@
+
+testdata/master/master18.data: testdata/master/master18.data.in
+ mkdir -p testdata/master
+ sed -e 's,@TOP_SRCDIR@,$(abs_srcdir),' < $(srcdir)/testdata/master/master18.data.in > $@
+
+unit-local: check
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/dns/acl_test.c b/tests/dns/acl_test.c
new file mode 100644
index 0000000..bb454b6
--- /dev/null
+++ b/tests/dns/acl_test.c
@@ -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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/acl.h>
+
+#include <tests/dns.h>
+
+#define BUFLEN 255
+#define BIGBUFLEN (70 * 1024)
+#define TEST_ORIGIN "test"
+
+/* test that dns_acl_isinsecure works */
+ISC_RUN_TEST_IMPL(dns_acl_isinsecure) {
+ isc_result_t result;
+ dns_acl_t *any = NULL;
+ dns_acl_t *none = NULL;
+ dns_acl_t *notnone = NULL;
+ dns_acl_t *notany = NULL;
+#if defined(HAVE_GEOIP2)
+ dns_acl_t *geoip = NULL;
+ dns_acl_t *notgeoip = NULL;
+ dns_aclelement_t *de;
+#endif /* HAVE_GEOIP2 */
+
+ UNUSED(state);
+
+ result = dns_acl_any(mctx, &any);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_acl_none(mctx, &none);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_acl_create(mctx, 1, &notnone);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_acl_create(mctx, 1, &notany);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_acl_merge(notnone, none, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_acl_merge(notany, any, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+#if defined(HAVE_GEOIP2)
+ result = dns_acl_create(mctx, 1, &geoip);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ de = geoip->elements;
+ assert_non_null(de);
+ strlcpy(de->geoip_elem.as_string, "AU",
+ sizeof(de->geoip_elem.as_string));
+ de->geoip_elem.subtype = dns_geoip_country_code;
+ de->type = dns_aclelementtype_geoip;
+ de->negative = false;
+ assert_true(geoip->length < geoip->alloc);
+ dns_acl_node_count(geoip)++;
+ de->node_num = dns_acl_node_count(geoip);
+ geoip->length++;
+
+ result = dns_acl_create(mctx, 1, &notgeoip);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_acl_merge(notgeoip, geoip, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+#endif /* HAVE_GEOIP2 */
+
+ assert_true(dns_acl_isinsecure(any)); /* any; */
+ assert_false(dns_acl_isinsecure(none)); /* none; */
+ assert_false(dns_acl_isinsecure(notany)); /* !any; */
+ assert_false(dns_acl_isinsecure(notnone)); /* !none; */
+
+#if defined(HAVE_GEOIP2)
+ assert_true(dns_acl_isinsecure(geoip)); /* geoip; */
+ assert_false(dns_acl_isinsecure(notgeoip)); /* !geoip; */
+#endif /* HAVE_GEOIP2 */
+
+ dns_acl_detach(&any);
+ dns_acl_detach(&none);
+ dns_acl_detach(&notany);
+ dns_acl_detach(&notnone);
+#if defined(HAVE_GEOIP2)
+ dns_acl_detach(&geoip);
+ dns_acl_detach(&notgeoip);
+#endif /* HAVE_GEOIP2 */
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(dns_acl_isinsecure)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/comparekeys/Kexample-d.+008+53461.key b/tests/dns/comparekeys/Kexample-d.+008+53461.key
new file mode 100644
index 0000000..5c43165
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-d.+008+53461.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 53461, for example-d.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example-d. IN DNSKEY 256 3 8 AwEAAaKYSOPDzZvfue5sU71xPCJKJpB5kZGl4vTp3OI8W+nN1YFtmVe2 2gM666AEutDAEB7cLkyoKCOH0+4Lh1ucPr6OmdWkHfk7uZv58eH0kOAV tNz2xhEF/YHSD7cnBEU9g0knGwpWuzSJKRhGhNoaVus9g1MaAn8efptz HIduIwgAeXV3BDCUpY6HbpwjDxOGCzCUYDRgcex37kYuCyW0PvlO5FQ0 DT0LpjcgBmIBpXol7sYpmKdOKJrm4x2lwGntr4K+bCdNYI2PRPJjPqAf jlvIvJylGUaqFJasw7PSMQIkgcQ4OQXVrhE8uGLdYvP1cusLuROIjdYp Pdqc5K9lCQE=
diff --git a/tests/dns/comparekeys/Kexample-d.+008+53461.private b/tests/dns/comparekeys/Kexample-d.+008+53461.private
new file mode 100644
index 0000000..a693428
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-d.+008+53461.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: ophI48PNm9+57mxTvXE8IkomkHmRkaXi9Onc4jxb6c3VgW2ZV7baAzrroAS60MAQHtwuTKgoI4fT7guHW5w+vo6Z1aQd+Tu5m/nx4fSQ4BW03PbGEQX9gdIPtycERT2DSScbCla7NIkpGEaE2hpW6z2DUxoCfx5+m3Mch24jCAB5dXcEMJSljodunCMPE4YLMJRgNGBx7HfuRi4LJbQ++U7kVDQNPQumNyAGYgGleiXuximYp04omubjHaXAae2vgr5sJ01gjY9E8mM+oB+OW8i8nKUZRqoUlqzDs9IxAiSBxDg5BdWuETy4Yt1i8/Vy6wu5E4iN1ik92pzkr2UJAQ==
+PublicExponent: AQAB
+PrivateExponent: AhR3VvVoV6OGOjiiNUt728hidEMoX4PJWtHNWqinyRek5tSnqgaXeKC3NuU0mUIjDvBps9oH4lK3yNa5fBr/nodwP4wNyTd3obR/z6JcLersxJjHi4nYX2ju8vjdsBSIulNudqlrsPhLJe0+Tff3FRfClSQmQ/JtakHo4lIx8zxiOJY8aWFeHGdWJDkAf6NStt3eVYyOyAwISfv3muaGPZKShiIOfLyTvqFqzwYFgdTWmvFqTdwgjIMc5XAwqw73WP2BPCN+fdCiMtrw0fCrhWzw/gfMJBHdOPH0diUZysAJhM0vdVKQzEi/g3YOo00fahZiPzaxNtZnLNj2mA54YQ==
+Prime1: z08i0sCcEpr4MZi4TReohPWp3F5vMQYVux8B3ltmJ3kKraXEmVEVmujhWa+ZDxhJmwKoba65vNEsUbSJN6WwJd7PVyskHb2GnWGK8NtlainFEuiS5CDxwULR4o2SI+Pij9thMQoA13ZTKc9s3E57VgcvJ7vaoD/1ZtpP7tdaerE=
+Prime2: yMid465M6bCXXUfWg7oq6A4MZUULbEPKvs+qGIersdiHfrFRGJ0Lviujs8KHaPS5rt4YmbpQU9tGbJBauY17T03qr/mQOBDx5gDkAJcJ0EUHudFslwqyn50THlJsKrFOxBYl7laY0v6CGCMyuZok8qyhiPHv5dhzSc9zwKaXZ1E=
+Exponent1: iresWJOzm6uAukczw7o59EYiFChIhOhKcDyOVoiYMX+ICqvqgqDEMTT1XbrnUzdwQT4lD8ej11msKzv/uXGwDZcq7GwcrZ3dTsAvZX2ZPdGXYlCnwejde/FHWi5bBJL/Tj2AqnzEFWjCuy5l7IDDfMwv3ImSADrr7ZfVdr85dvE=
+Exponent2: aULzs4ePfvw7foXI6mpRUDL9QKI/6NRpmDtam12VH7m63yqqr1K1808BlZ4oS1fxeMGq9/z7W9sbQpMzXQ/VU7Avl24os5v+lWxmHAES/gMSl9I5Mb5EAvXgLgdb+c3W02ohHKB9ojAXl/vr/e3X7Pmf/iGIeWFOn6WIs7kiquE=
+Coefficient: HS4bN41s6Ak9+6m3vhmLzgHtWMavnLpDkmd6wTBttbtKXHfjbvxMUt4RYeF8BXRtfIqIOZqJJngais1wQfOsgVhHrKVwX+MOThyOk4SD+pvnG6g1B+qUS1czPGP7Rf+7668wK8ZxV9w0+YDbTJgPgivD0lBnLXwT+KCLprMXTe4=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample-e.+008+53973.key b/tests/dns/comparekeys/Kexample-e.+008+53973.key
new file mode 100644
index 0000000..a4b0d03
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-e.+008+53973.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 53973, for example-e.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example-e. IN DNSKEY 256 3 8 BQEAAAABophI48PNm9+57mxTvXE8IkomkHmRkaXi9Onc4jxb6c3VgW2Z V7baAzrroAS60MAQHtwuTKgoI4fT7guHW5w+vo6Z1aQd+Tu5m/nx4fSQ 4BW03PbGEQX9gdIPtycERT2DSScbCla7NIkpGEaE2hpW6z2DUxoCfx5+ m3Mch24jCAB5dXcEMJSljodunCMPE4YLMJRgNGBx7HfuRi4LJbQ++U7k VDQNPQumNyAGYgGleiXuximYp04omubjHaXAae2vgr5sJ01gjY9E8mM+ oB+OW8i8nKUZRqoUlqzDs9IxAiSBxDg5BdWuETy4Yt1i8/Vy6wu5E4iN 1ik92pzkr2UJAQ==
diff --git a/tests/dns/comparekeys/Kexample-e.+008+53973.private b/tests/dns/comparekeys/Kexample-e.+008+53973.private
new file mode 100644
index 0000000..765ca1a
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-e.+008+53973.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: ophI48PNm9+57mxTvXE8IkomkHmRkaXi9Onc4jxb6c3VgW2ZV7baAzrroAS60MAQHtwuTKgoI4fT7guHW5w+vo6Z1aQd+Tu5m/nx4fSQ4BW03PbGEQX9gdIPtycERT2DSScbCla7NIkpGEaE2hpW6z2DUxoCfx5+m3Mch24jCAB5dXcEMJSljodunCMPE4YLMJRgNGBx7HfuRi4LJbQ++U7kVDQNPQumNyAGYgGleiXuximYp04omubjHaXAae2vgr5sJ01gjY9E8mM+oB+OW8i8nKUZRqoUlqzDs9IxAiSBxDg5BdWuETy4Yt1i8/Vy6wu5E4iN1ik92pzkr2UJAQ==
+PublicExponent: AQAAAAE=
+PrivateExponent: lFgeQHf3klxXlfkNmczDEYHXl37i2iCgZdUsqtho/3LFdfWZrxZr6ACM040dKLHiw1UdhODy5h/Zstif4Ww3LsKKBgpbMnZUTMOI9R+eQmRrhCI96XAur5AIuJCHa+jIbCiamh8xY6g0byp/sUHQxYV02I/lcTdQSeGHSOSqX3QjB835OVa18hyW6txAxM4DVGo/NvIJw2ItSl2qwHTMDHK45t4YbnKEd6suriUiveyax5dU1JtpviwHJiAFPy+L68jMo8cfr+JCLWW2OJYkrBXb8kwqaPsV0RCGZ59sePyRdSYRgNi1brBStesctVc5UfSxH6p2A6C28LdrubcXAQ==
+Prime1: z08i0sCcEpr4MZi4TReohPWp3F5vMQYVux8B3ltmJ3kKraXEmVEVmujhWa+ZDxhJmwKoba65vNEsUbSJN6WwJd7PVyskHb2GnWGK8NtlainFEuiS5CDxwULR4o2SI+Pij9thMQoA13ZTKc9s3E57VgcvJ7vaoD/1ZtpP7tdaerE=
+Prime2: yMid465M6bCXXUfWg7oq6A4MZUULbEPKvs+qGIersdiHfrFRGJ0Lviujs8KHaPS5rt4YmbpQU9tGbJBauY17T03qr/mQOBDx5gDkAJcJ0EUHudFslwqyn50THlJsKrFOxBYl7laY0v6CGCMyuZok8qyhiPHv5dhzSc9zwKaXZ1E=
+Exponent1: iresWJOzm6uAukczw7o59EYiFChIhOhKcDyOVoiYMX+ICqvqgqDEMTT1XbrnUzdwQT4lD8ej11msKzv/uXGwDZcq7GwcrZ3dTsAvZX2ZPdGXYlCnwejde/FHWi5bBJL/Tj2AqnzEFWjCuy5l7IDDfMwv3ImSADrr7ZfVdr85dvE=
+Exponent2: aULzs4ePfvw7foXI6mpRUDL9QKI/6NRpmDtam12VH7m63yqqr1K1808BlZ4oS1fxeMGq9/z7W9sbQpMzXQ/VU7Avl24os5v+lWxmHAES/gMSl9I5Mb5EAvXgLgdb+c3W02ohHKB9ojAXl/vr/e3X7Pmf/iGIeWFOn6WIs7kiquE=
+Coefficient: HS4bN41s6Ak9+6m3vhmLzgHtWMavnLpDkmd6wTBttbtKXHfjbvxMUt4RYeF8BXRtfIqIOZqJJngais1wQfOsgVhHrKVwX+MOThyOk4SD+pvnG6g1B+qUS1czPGP7Rf+7668wK8ZxV9w0+YDbTJgPgivD0lBnLXwT+KCLprMXTe4=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample-n.+008+37464.key b/tests/dns/comparekeys/Kexample-n.+008+37464.key
new file mode 100644
index 0000000..da2e16a
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-n.+008+37464.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 37464, for example-n.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example-n. IN DNSKEY 256 3 8 AwEAAbxHOF8G0xw9ekCodhL8KivuZ3o0jmGlycLiXBjBN8c5R5fjLjUh D0gy3IDbDC+kLaPhHGF/MwrSEjrgSowxZ8nrxDzsq5ZdpeUsYaNrbQEY /mqf35T/9/Ulm4v06x58v/NTugWd05Xq04aAyfm7EViyGFzmVOVfPnll h9xQtvWEWoRWPseFw+dY5/nc/+xB/IsQMihoH2rO+cek/lsP3R9DsHCG RbQ/ks/+rrp6/O+QJZyZrzsONl7mlMDXNy3Pz9J4qMW2W6Mz702LN324 7/9UsetDGGbuZfrCLMpKWXzdsJm36DOk4aMooS9111plfXaXQgQNcL5G 021utpTau+8=
diff --git a/tests/dns/comparekeys/Kexample-n.+008+37464.private b/tests/dns/comparekeys/Kexample-n.+008+37464.private
new file mode 100644
index 0000000..65689a2
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-n.+008+37464.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: vEc4XwbTHD16QKh2EvwqK+5nejSOYaXJwuJcGME3xzlHl+MuNSEPSDLcgNsML6Qto+EcYX8zCtISOuBKjDFnyevEPOyrll2l5Sxho2ttARj+ap/flP/39SWbi/TrHny/81O6BZ3TlerThoDJ+bsRWLIYXOZU5V8+eWWH3FC29YRahFY+x4XD51jn+dz/7EH8ixAyKGgfas75x6T+Ww/dH0OwcIZFtD+Sz/6uunr875AlnJmvOw42XuaUwNc3Lc/P0nioxbZbozPvTYs3fbjv/1Sx60MYZu5l+sIsykpZfN2wmbfoM6ThoyihL3XXWmV9dpdCBA1wvkbTbW62lNq77w==
+PublicExponent: AQAB
+PrivateExponent: lFgeQHf3klxXlfkNmczDEYHXl37i2iCgZdUsqtho/3LFdfWZrxZr6ACM040dKLHiw1UdhODy5h/Zstif4Ww3LsKKBgpbMnZUTMOI9R+eQmRrhCI96XAur5AIuJCHa+jIbCiamh8xY6g0byp/sUHQxYV02I/lcTdQSeGHSOSqX3QjB835OVa18hyW6txAxM4DVGo/NvIJw2ItSl2qwHTMDHK45t4YbnKEd6suriUiveyax5dU1JtpviwHJiAFPy+L68jMo8cfr+JCLWW2OJYkrBXb8kwqaPsV0RCGZ59sePyRdSYRgNi1brBStesctVc5UfSxH6p2A6C28LdrubcXAQ==
+Prime1: z08i0sCcEpr4MZi4TReohPWp3F5vMQYVux8B3ltmJ3kKraXEmVEVmujhWa+ZDxhJmwKoba65vNEsUbSJN6WwJd7PVyskHb2GnWGK8NtlainFEuiS5CDxwULR4o2SI+Pij9thMQoA13ZTKc9s3E57VgcvJ7vaoD/1ZtpP7tdaerE=
+Prime2: yMid465M6bCXXUfWg7oq6A4MZUULbEPKvs+qGIersdiHfrFRGJ0Lviujs8KHaPS5rt4YmbpQU9tGbJBauY17T03qr/mQOBDx5gDkAJcJ0EUHudFslwqyn50THlJsKrFOxBYl7laY0v6CGCMyuZok8qyhiPHv5dhzSc9zwKaXZ1E=
+Exponent1: iresWJOzm6uAukczw7o59EYiFChIhOhKcDyOVoiYMX+ICqvqgqDEMTT1XbrnUzdwQT4lD8ej11msKzv/uXGwDZcq7GwcrZ3dTsAvZX2ZPdGXYlCnwejde/FHWi5bBJL/Tj2AqnzEFWjCuy5l7IDDfMwv3ImSADrr7ZfVdr85dvE=
+Exponent2: aULzs4ePfvw7foXI6mpRUDL9QKI/6NRpmDtam12VH7m63yqqr1K1808BlZ4oS1fxeMGq9/z7W9sbQpMzXQ/VU7Avl24os5v+lWxmHAES/gMSl9I5Mb5EAvXgLgdb+c3W02ohHKB9ojAXl/vr/e3X7Pmf/iGIeWFOn6WIs7kiquE=
+Coefficient: HS4bN41s6Ak9+6m3vhmLzgHtWMavnLpDkmd6wTBttbtKXHfjbvxMUt4RYeF8BXRtfIqIOZqJJngais1wQfOsgVhHrKVwX+MOThyOk4SD+pvnG6g1B+qUS1czPGP7Rf+7668wK8ZxV9w0+YDbTJgPgivD0lBnLXwT+KCLprMXTe4=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample-p.+008+53461.key b/tests/dns/comparekeys/Kexample-p.+008+53461.key
new file mode 100644
index 0000000..20ffcfd
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-p.+008+53461.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 53461, for example-p.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example-p. IN DNSKEY 256 3 8 AwEAAaKYSOPDzZvfue5sU71xPCJKJpB5kZGl4vTp3OI8W+nN1YFtmVe2 2gM666AEutDAEB7cLkyoKCOH0+4Lh1ucPr6OmdWkHfk7uZv58eH0kOAV tNz2xhEF/YHSD7cnBEU9g0knGwpWuzSJKRhGhNoaVus9g1MaAn8efptz HIduIwgAeXV3BDCUpY6HbpwjDxOGCzCUYDRgcex37kYuCyW0PvlO5FQ0 DT0LpjcgBmIBpXol7sYpmKdOKJrm4x2lwGntr4K+bCdNYI2PRPJjPqAf jlvIvJylGUaqFJasw7PSMQIkgcQ4OQXVrhE8uGLdYvP1cusLuROIjdYp Pdqc5K9lCQE=
diff --git a/tests/dns/comparekeys/Kexample-p.+008+53461.private b/tests/dns/comparekeys/Kexample-p.+008+53461.private
new file mode 100644
index 0000000..063c925
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-p.+008+53461.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: ophI48PNm9+57mxTvXE8IkomkHmRkaXi9Onc4jxb6c3VgW2ZV7baAzrroAS60MAQHtwuTKgoI4fT7guHW5w+vo6Z1aQd+Tu5m/nx4fSQ4BW03PbGEQX9gdIPtycERT2DSScbCla7NIkpGEaE2hpW6z2DUxoCfx5+m3Mch24jCAB5dXcEMJSljodunCMPE4YLMJRgNGBx7HfuRi4LJbQ++U7kVDQNPQumNyAGYgGleiXuximYp04omubjHaXAae2vgr5sJ01gjY9E8mM+oB+OW8i8nKUZRqoUlqzDs9IxAiSBxDg5BdWuETy4Yt1i8/Vy6wu5E4iN1ik92pzkr2UJAQ==
+PublicExponent: AQAB
+PrivateExponent: lFgeQHf3klxXlfkNmczDEYHXl37i2iCgZdUsqtho/3LFdfWZrxZr6ACM040dKLHiw1UdhODy5h/Zstif4Ww3LsKKBgpbMnZUTMOI9R+eQmRrhCI96XAur5AIuJCHa+jIbCiamh8xY6g0byp/sUHQxYV02I/lcTdQSeGHSOSqX3QjB835OVa18hyW6txAxM4DVGo/NvIJw2ItSl2qwHTMDHK45t4YbnKEd6suriUiveyax5dU1JtpviwHJiAFPy+L68jMo8cfr+JCLWW2OJYkrBXb8kwqaPsV0RCGZ59sePyRdSYRgNi1brBStesctVc5UfSxH6p2A6C28LdrubcXAQ==
+Prime1: 5YpfVjEtL1owW9gSFbIMx65POr+fiktxirgy1bc5fSsVqUgG6zhbaN/VpWcNZG0Zg5xd6S7C8V3djGlnJN8wZIyjIh7+Z3WWjqbOD9oY7rC1fR+W0OvbCmZiEzOpRJ5qoMOh1MzkkanhMy0/ICpaa8eQ9zEb80oTIQpFgoLn7K0=
+Prime2: yMid465M6bCXXUfWg7oq6A4MZUULbEPKvs+qGIersdiHfrFRGJ0Lviujs8KHaPS5rt4YmbpQU9tGbJBauY17T03qr/mQOBDx5gDkAJcJ0EUHudFslwqyn50THlJsKrFOxBYl7laY0v6CGCMyuZok8qyhiPHv5dhzSc9zwKaXZ1E=
+Exponent1: iresWJOzm6uAukczw7o59EYiFChIhOhKcDyOVoiYMX+ICqvqgqDEMTT1XbrnUzdwQT4lD8ej11msKzv/uXGwDZcq7GwcrZ3dTsAvZX2ZPdGXYlCnwejde/FHWi5bBJL/Tj2AqnzEFWjCuy5l7IDDfMwv3ImSADrr7ZfVdr85dvE=
+Exponent2: aULzs4ePfvw7foXI6mpRUDL9QKI/6NRpmDtam12VH7m63yqqr1K1808BlZ4oS1fxeMGq9/z7W9sbQpMzXQ/VU7Avl24os5v+lWxmHAES/gMSl9I5Mb5EAvXgLgdb+c3W02ohHKB9ojAXl/vr/e3X7Pmf/iGIeWFOn6WIs7kiquE=
+Coefficient: HS4bN41s6Ak9+6m3vhmLzgHtWMavnLpDkmd6wTBttbtKXHfjbvxMUt4RYeF8BXRtfIqIOZqJJngais1wQfOsgVhHrKVwX+MOThyOk4SD+pvnG6g1B+qUS1czPGP7Rf+7668wK8ZxV9w0+YDbTJgPgivD0lBnLXwT+KCLprMXTe4=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample-private.+002+65316.key b/tests/dns/comparekeys/Kexample-private.+002+65316.key
new file mode 100644
index 0000000..7cc002d
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-private.+002+65316.key
@@ -0,0 +1 @@
+example-private. IN KEY 512 3 2 AAECAAAAgKVXnUOFKMvLvwO/VdY9bq+eOPBxrRWsDpcL9FJ9+hklVvii pcLOIhiKLeHI/u9vM2nhd8+opIW92+j2pB185MRgSrINQcC+XpI/xiDG HwE78bQ+2Ykb/memG+ctkVyrFGHtaJLCUGWrUHy1jbtvYeaKeS92jR/2 4oryt3N851u5
diff --git a/tests/dns/comparekeys/Kexample-private.+002+65316.private b/tests/dns/comparekeys/Kexample-private.+002+65316.private
new file mode 100644
index 0000000..1f00fa9
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-private.+002+65316.private
@@ -0,0 +1,9 @@
+Private-key-format: v1.3
+Algorithm: 2 (DH)
+Prime(p): ///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5lOB//////////8=
+Generator(g): Ag==
+Private_value(x): dLr0sfk/P1V0DfQ7Ke3IIaSM8nHjtrBRlMcQXRMVrLhbbKeCodvpSRtI0Nwtt38Df8dbGGtP676my2Ht2UHyL7rO0+ASv98NCysL0Xp6q2a7fn67iGFUBTg3jzXC89FYv4sYNeVLDGrKC3EjtGkalzgDVuzEC8CqRkWKeys3ufc=
+Public_value(y): pVedQ4Uoy8u/A79V1j1ur5448HGtFawOlwv0Un36GSVW+KKlws4iGIot4cj+728zaeF3z6ikhb3b6PakHXzkxGBKsg1BwL5ekj/GIMYfATvxtD7ZiRv+Z6Yb5y2RXKsUYe1oksJQZatQfLWNu29h5op5L3aNH/biivK3c3znW7k=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample-q.+008+53461.key b/tests/dns/comparekeys/Kexample-q.+008+53461.key
new file mode 100644
index 0000000..5d4a0e7
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-q.+008+53461.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 53461, for example-q.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example-q. IN DNSKEY 256 3 8 AwEAAaKYSOPDzZvfue5sU71xPCJKJpB5kZGl4vTp3OI8W+nN1YFtmVe2 2gM666AEutDAEB7cLkyoKCOH0+4Lh1ucPr6OmdWkHfk7uZv58eH0kOAV tNz2xhEF/YHSD7cnBEU9g0knGwpWuzSJKRhGhNoaVus9g1MaAn8efptz HIduIwgAeXV3BDCUpY6HbpwjDxOGCzCUYDRgcex37kYuCyW0PvlO5FQ0 DT0LpjcgBmIBpXol7sYpmKdOKJrm4x2lwGntr4K+bCdNYI2PRPJjPqAf jlvIvJylGUaqFJasw7PSMQIkgcQ4OQXVrhE8uGLdYvP1cusLuROIjdYp Pdqc5K9lCQE=
diff --git a/tests/dns/comparekeys/Kexample-q.+008+53461.private b/tests/dns/comparekeys/Kexample-q.+008+53461.private
new file mode 100644
index 0000000..6b2e563
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample-q.+008+53461.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: ophI48PNm9+57mxTvXE8IkomkHmRkaXi9Onc4jxb6c3VgW2ZV7baAzrroAS60MAQHtwuTKgoI4fT7guHW5w+vo6Z1aQd+Tu5m/nx4fSQ4BW03PbGEQX9gdIPtycERT2DSScbCla7NIkpGEaE2hpW6z2DUxoCfx5+m3Mch24jCAB5dXcEMJSljodunCMPE4YLMJRgNGBx7HfuRi4LJbQ++U7kVDQNPQumNyAGYgGleiXuximYp04omubjHaXAae2vgr5sJ01gjY9E8mM+oB+OW8i8nKUZRqoUlqzDs9IxAiSBxDg5BdWuETy4Yt1i8/Vy6wu5E4iN1ik92pzkr2UJAQ==
+PublicExponent: AQAB
+PrivateExponent: lFgeQHf3klxXlfkNmczDEYHXl37i2iCgZdUsqtho/3LFdfWZrxZr6ACM040dKLHiw1UdhODy5h/Zstif4Ww3LsKKBgpbMnZUTMOI9R+eQmRrhCI96XAur5AIuJCHa+jIbCiamh8xY6g0byp/sUHQxYV02I/lcTdQSeGHSOSqX3QjB835OVa18hyW6txAxM4DVGo/NvIJw2ItSl2qwHTMDHK45t4YbnKEd6suriUiveyax5dU1JtpviwHJiAFPy+L68jMo8cfr+JCLWW2OJYkrBXb8kwqaPsV0RCGZ59sePyRdSYRgNi1brBStesctVc5UfSxH6p2A6C28LdrubcXAQ==
+Prime1: z08i0sCcEpr4MZi4TReohPWp3F5vMQYVux8B3ltmJ3kKraXEmVEVmujhWa+ZDxhJmwKoba65vNEsUbSJN6WwJd7PVyskHb2GnWGK8NtlainFEuiS5CDxwULR4o2SI+Pij9thMQoA13ZTKc9s3E57VgcvJ7vaoD/1ZtpP7tdaerE=
+Prime2: 0fs3ncL5/2qzq2dmPXLYcOfc1EGSuESO0VpREP8EpTkyPKeVw5LaF9TgZRqPWlRf2T0LPoZ766xLAn090u0pLQ5fWM96NMas7kS+rxtRssat6MiQo3YfoU3ysk3xuPzrMBHyn/N42CjSG+bJEToHR7V16KsCT6dBIPkI3tj/Yos=
+Exponent1: iresWJOzm6uAukczw7o59EYiFChIhOhKcDyOVoiYMX+ICqvqgqDEMTT1XbrnUzdwQT4lD8ej11msKzv/uXGwDZcq7GwcrZ3dTsAvZX2ZPdGXYlCnwejde/FHWi5bBJL/Tj2AqnzEFWjCuy5l7IDDfMwv3ImSADrr7ZfVdr85dvE=
+Exponent2: aULzs4ePfvw7foXI6mpRUDL9QKI/6NRpmDtam12VH7m63yqqr1K1808BlZ4oS1fxeMGq9/z7W9sbQpMzXQ/VU7Avl24os5v+lWxmHAES/gMSl9I5Mb5EAvXgLgdb+c3W02ohHKB9ojAXl/vr/e3X7Pmf/iGIeWFOn6WIs7kiquE=
+Coefficient: HS4bN41s6Ak9+6m3vhmLzgHtWMavnLpDkmd6wTBttbtKXHfjbvxMUt4RYeF8BXRtfIqIOZqJJngais1wQfOsgVhHrKVwX+MOThyOk4SD+pvnG6g1B+qUS1czPGP7Rf+7668wK8ZxV9w0+YDbTJgPgivD0lBnLXwT+KCLprMXTe4=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample.+002+65316.key b/tests/dns/comparekeys/Kexample.+002+65316.key
new file mode 100644
index 0000000..c2f4703
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample.+002+65316.key
@@ -0,0 +1 @@
+example. IN KEY 512 3 2 AAECAAAAgKVXnUOFKMvLvwO/VdY9bq+eOPBxrRWsDpcL9FJ9+hklVvii pcLOIhiKLeHI/u9vM2nhd8+opIW92+j2pB185MRgSrINQcC+XpI/xiDG HwE78bQ+2Ykb/memG+ctkVyrFGHtaJLCUGWrUHy1jbtvYeaKeS92jR/2 4oryt3N851u5
diff --git a/tests/dns/comparekeys/Kexample.+002+65316.private b/tests/dns/comparekeys/Kexample.+002+65316.private
new file mode 100644
index 0000000..e872834
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample.+002+65316.private
@@ -0,0 +1,9 @@
+Private-key-format: v1.3
+Algorithm: 2 (DH)
+Prime(p): ///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5lOB//////////8=
+Generator(g): Ag==
+Private_value(x): bUMVaaSCAPT0NK7AkIa0JA1SSw83x8WxS+iePECQwr4xDDMnevNHWK1nIofUM2qNbpDe2KvFIt9tu+1UgZgOTLoQFipePtHKOjoRX6XsGNzKmL8WZOlw/QJw0D5RIn7l7tvmBCeNHINl9IWVgMLTi+wgzrJxSeGe406q23Jn4Uc=
+Public_value(y): pVedQ4Uoy8u/A79V1j1ur5448HGtFawOlwv0Un36GSVW+KKlws4iGIot4cj+728zaeF3z6ikhb3b6PakHXzkxGBKsg1BwL5ekj/GIMYfATvxtD7ZiRv+Z6Yb5y2RXKsUYe1oksJQZatQfLWNu29h5op5L3aNH/biivK3c3znW7k=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample.+008+53461.key b/tests/dns/comparekeys/Kexample.+008+53461.key
new file mode 100644
index 0000000..33c8188
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample.+008+53461.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 53461, for example.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example. IN DNSKEY 256 3 8 AwEAAaKYSOPDzZvfue5sU71xPCJKJpB5kZGl4vTp3OI8W+nN1YFtmVe2 2gM666AEutDAEB7cLkyoKCOH0+4Lh1ucPr6OmdWkHfk7uZv58eH0kOAV tNz2xhEF/YHSD7cnBEU9g0knGwpWuzSJKRhGhNoaVus9g1MaAn8efptz HIduIwgAeXV3BDCUpY6HbpwjDxOGCzCUYDRgcex37kYuCyW0PvlO5FQ0 DT0LpjcgBmIBpXol7sYpmKdOKJrm4x2lwGntr4K+bCdNYI2PRPJjPqAf jlvIvJylGUaqFJasw7PSMQIkgcQ4OQXVrhE8uGLdYvP1cusLuROIjdYp Pdqc5K9lCQE=
diff --git a/tests/dns/comparekeys/Kexample.+008+53461.private b/tests/dns/comparekeys/Kexample.+008+53461.private
new file mode 100644
index 0000000..dd4d9a4
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample.+008+53461.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: ophI48PNm9+57mxTvXE8IkomkHmRkaXi9Onc4jxb6c3VgW2ZV7baAzrroAS60MAQHtwuTKgoI4fT7guHW5w+vo6Z1aQd+Tu5m/nx4fSQ4BW03PbGEQX9gdIPtycERT2DSScbCla7NIkpGEaE2hpW6z2DUxoCfx5+m3Mch24jCAB5dXcEMJSljodunCMPE4YLMJRgNGBx7HfuRi4LJbQ++U7kVDQNPQumNyAGYgGleiXuximYp04omubjHaXAae2vgr5sJ01gjY9E8mM+oB+OW8i8nKUZRqoUlqzDs9IxAiSBxDg5BdWuETy4Yt1i8/Vy6wu5E4iN1ik92pzkr2UJAQ==
+PublicExponent: AQAB
+PrivateExponent: lFgeQHf3klxXlfkNmczDEYHXl37i2iCgZdUsqtho/3LFdfWZrxZr6ACM040dKLHiw1UdhODy5h/Zstif4Ww3LsKKBgpbMnZUTMOI9R+eQmRrhCI96XAur5AIuJCHa+jIbCiamh8xY6g0byp/sUHQxYV02I/lcTdQSeGHSOSqX3QjB835OVa18hyW6txAxM4DVGo/NvIJw2ItSl2qwHTMDHK45t4YbnKEd6suriUiveyax5dU1JtpviwHJiAFPy+L68jMo8cfr+JCLWW2OJYkrBXb8kwqaPsV0RCGZ59sePyRdSYRgNi1brBStesctVc5UfSxH6p2A6C28LdrubcXAQ==
+Prime1: z08i0sCcEpr4MZi4TReohPWp3F5vMQYVux8B3ltmJ3kKraXEmVEVmujhWa+ZDxhJmwKoba65vNEsUbSJN6WwJd7PVyskHb2GnWGK8NtlainFEuiS5CDxwULR4o2SI+Pij9thMQoA13ZTKc9s3E57VgcvJ7vaoD/1ZtpP7tdaerE=
+Prime2: yMid465M6bCXXUfWg7oq6A4MZUULbEPKvs+qGIersdiHfrFRGJ0Lviujs8KHaPS5rt4YmbpQU9tGbJBauY17T03qr/mQOBDx5gDkAJcJ0EUHudFslwqyn50THlJsKrFOxBYl7laY0v6CGCMyuZok8qyhiPHv5dhzSc9zwKaXZ1E=
+Exponent1: iresWJOzm6uAukczw7o59EYiFChIhOhKcDyOVoiYMX+ICqvqgqDEMTT1XbrnUzdwQT4lD8ej11msKzv/uXGwDZcq7GwcrZ3dTsAvZX2ZPdGXYlCnwejde/FHWi5bBJL/Tj2AqnzEFWjCuy5l7IDDfMwv3ImSADrr7ZfVdr85dvE=
+Exponent2: aULzs4ePfvw7foXI6mpRUDL9QKI/6NRpmDtam12VH7m63yqqr1K1808BlZ4oS1fxeMGq9/z7W9sbQpMzXQ/VU7Avl24os5v+lWxmHAES/gMSl9I5Mb5EAvXgLgdb+c3W02ohHKB9ojAXl/vr/e3X7Pmf/iGIeWFOn6WIs7kiquE=
+Coefficient: HS4bN41s6Ak9+6m3vhmLzgHtWMavnLpDkmd6wTBttbtKXHfjbvxMUt4RYeF8BXRtfIqIOZqJJngais1wQfOsgVhHrKVwX+MOThyOk4SD+pvnG6g1B+qUS1czPGP7Rf+7668wK8ZxV9w0+YDbTJgPgivD0lBnLXwT+KCLprMXTe4=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample.+013+19786.key b/tests/dns/comparekeys/Kexample.+013+19786.key
new file mode 100644
index 0000000..ccfcc97
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample.+013+19786.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 19786, for example.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example. IN DNSKEY 256 3 13 S35Z1XtGlnnU7BBahMJwAZXXff+JupyIDssNfJyrugLKq5R10TJ5tU3W r3VuP6aJNs6+uL2cMPVTVT1vr1Aqwg==
diff --git a/tests/dns/comparekeys/Kexample.+013+19786.private b/tests/dns/comparekeys/Kexample.+013+19786.private
new file mode 100644
index 0000000..0d72cf1
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample.+013+19786.private
@@ -0,0 +1,6 @@
+Private-key-format: v1.3
+Algorithm: 13 (ECDSAP256SHA256)
+PrivateKey: ZYcYhR5f98vI1+BFGKLIrarZrqxJM4mRy9tvwntdYoo=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample.+015+63663.key b/tests/dns/comparekeys/Kexample.+015+63663.key
new file mode 100644
index 0000000..92db9fb
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample.+015+63663.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 63663, for example.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example. IN DNSKEY 256 3 15 ZLlkI5q8XDkP3D7Zxdbmuqh4yp90mbvdcNT0xSGLDtI=
diff --git a/tests/dns/comparekeys/Kexample.+015+63663.private b/tests/dns/comparekeys/Kexample.+015+63663.private
new file mode 100644
index 0000000..c2c48f3
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample.+015+63663.private
@@ -0,0 +1,6 @@
+Private-key-format: v1.3
+Algorithm: 15 (ED25519)
+PrivateKey: rGYsnf8nPlg7kg7qRcIXYShPsTiMHTeWJInNrW9GwSQ=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample2.+002+19823.key b/tests/dns/comparekeys/Kexample2.+002+19823.key
new file mode 100644
index 0000000..9d521f7
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample2.+002+19823.key
@@ -0,0 +1 @@
+example2. IN KEY 512 3 2 AAECAAAAgCxVfxiyTe8C83ou8KXSu9WmzGwCYWB2NkdS87Kz0PgTuBay JkDDAEeR6CIYClA6PXBp2GXUPHoYWag9zVOVU85PYu0KRZF69EN0IVsA OCtgikOcr5yD4esSMwTTPk/OQ8qW/yGf1DvdpXuiu3P/wSpzVGL8tHFQ 2XURydYytol0
diff --git a/tests/dns/comparekeys/Kexample2.+002+19823.private b/tests/dns/comparekeys/Kexample2.+002+19823.private
new file mode 100644
index 0000000..f6722f6
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample2.+002+19823.private
@@ -0,0 +1,9 @@
+Private-key-format: v1.3
+Algorithm: 2 (DH)
+Prime(p): ///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5lOB//////////8=
+Generator(g): Ag==
+Private_value(x): W0EpuIMltmMuZAKcCmRe/Ix9WsHPU/GLfqbjHKCjgYdRFzwqHyVp6z+uf8EgmHBD1bbBjwfcnRse8xfqqmt/wZIRdDzjRq/oZdKtJHqFZSO+MQZ5DKrdojKU7UEl/j44heJzVO0qFkrPvWglRt+780LP0awkfetecXDxvJT+HIw=
+Public_value(y): LFV/GLJN7wLzei7wpdK71abMbAJhYHY2R1LzsrPQ+BO4FrImQMMAR5HoIhgKUDo9cGnYZdQ8ehhZqD3NU5VTzk9i7QpFkXr0Q3QhWwA4K2CKQ5yvnIPh6xIzBNM+T85Dypb/IZ/UO92le6K7c//BKnNUYvy0cVDZdRHJ1jK2iXQ=
+Created: 20211027221355
+Publish: 20211027221355
+Activate: 20211027221355
diff --git a/tests/dns/comparekeys/Kexample2.+008+37993.key b/tests/dns/comparekeys/Kexample2.+008+37993.key
new file mode 100644
index 0000000..c0e09a1
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample2.+008+37993.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 37993, for example2.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example2. IN DNSKEY 256 3 8 AwEAAaSRhPf0XhYR52Kpi0RZJgEnpidvuz2Ywdyh8k5CKwal9nM15PNc 4ZoPEVGO+ize53hq0iUkVlBhAfhQE31Fhf4zU544fezBEaz33hiajEzL ZITux9N83WfoYSNnyufvSGzNcpNM6LHKdDwMr1kr9tTgNeuiTAlPv5z9 BNtfv2B25moVm1DoxMCd8WH0jYC452a2lGM+Fbd45o02OO7V8balPwJh MM2bbeWg5G+tbvCAot93KxtavyOMKV4siv3ZH639J0dIb10L8nNrN0Ge UjkX8yU3fgeWB4Oldtzx0SHxG75NWjRLnpVzBq5GeacLc4RsN+S+nhYW 4Wv2A066w70=
diff --git a/tests/dns/comparekeys/Kexample2.+008+37993.private b/tests/dns/comparekeys/Kexample2.+008+37993.private
new file mode 100644
index 0000000..887ad2b
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample2.+008+37993.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: pJGE9/ReFhHnYqmLRFkmASemJ2+7PZjB3KHyTkIrBqX2czXk81zhmg8RUY76LN7neGrSJSRWUGEB+FATfUWF/jNTnjh97MERrPfeGJqMTMtkhO7H03zdZ+hhI2fK5+9IbM1yk0zoscp0PAyvWSv21OA166JMCU+/nP0E21+/YHbmahWbUOjEwJ3xYfSNgLjnZraUYz4Vt3jmjTY47tXxtqU/AmEwzZtt5aDkb61u8ICi33crG1q/I4wpXiyK/dkfrf0nR0hvXQvyc2s3QZ5SORfzJTd+B5YHg6V23PHRIfEbvk1aNEuelXMGrkZ5pwtzhGw35L6eFhbha/YDTrrDvQ==
+PublicExponent: AQAB
+PrivateExponent: O/HFvYwFuYRMBGQ9lmfisAkBPNw2F/nMo9FZsafohENvwgefngX3J2bVqB+sgSuwpOxEH8NcrWqojQqeDsOES1Pm4XsyY0rwZVDkVZH2CQMNWl6f6ylQfMjomTz1bAZ9GyS612zsVdapADaeqJybDG+fNHWpvLqP0V9YpY/65efTvrA3Qu+XpDvLaJ34yjkeEGUgysNP3KkDTeJTY/ksKi6ODtdzbKpufjZS8b6BL97XcFcNGiwu/gNPCvtmm/H+tXaNYyijG7bNGPOpHFhlMCT13o8XLrR/OGty6VY6PpjaEnvlZUZnWHUwn/JmNoZRJoXAAEerk3nS+tOhRmcrAQ==
+Prime1: 2W8JHYaTn7XefxxwaDZWFrVtHnnd0vUZvBBNA1PJeRfDr+yPxyWcgYx1OBxKkJsYGiob0i992W2HXuz2KS81yBCtH/uLK1Y+mkjgme4MWZupZ0RsKA1TkgIrJs174Dv3P/yqc+/R4eiwUGt10493MS1PJFF0CmisDzgjai/JLIM=
+Prime2: wcIKikgzOsq2A2Hl7qPCeA3oKTc66eFVNvB/KH91/hNFKNm0kAvhHrNe9rSoU+JywCNbX/Fs7X6SuHHJaRs+KpSBadnqfwEIngCq2Y00nT3sbETx4VNbXFD6MPPo3MWDi61/TCyrtBujutavo5ghj2oVzNGqMT3UyhaVNrJp2r8=
+Exponent1: GsEO3hMxFvXJ6toU+r202hZ41scoBE0kXX+j+kTVBZFnAr6Y8mguWcJuqfjRM/nhfVaxFavCUH6pqYR+xZKJi5SBuO26shpqmZFeEZK48k21Cn/gzwzUu6KIrL2cAHtgcP8l+h4INUPsbfjLBr0gbWyl0FI1dRJsGXNO6EH4/wE=
+Exponent2: WrgcsUQ+4E8bS5ghzUtVeVqhkfKvHeSIPpH6J58OQukI36iXNz6op/Q6CW7qxWPocHfdh52Fb+lsjvmP4SuFPvCLa2FBvzdfroMHe5b2xIzCzqq1Sdf6lc3AZv080WmVPuf8C1F7D3hFf+yXDhTj2b9E98JPWoDlyb0rHhIJKAc=
+Coefficient: aVDpGheH0UJ8aWPRIRHyjMTCIPB8zmhfwugpV11Z/OXNb2uaNRcnVKujs1mlSydoIfFQSuFf3iPs7ytaJUfcQJ+k1QAtssJC1HXF14t0p5o99QxuQLgmNtPHD7m2aeAyFJoycF24UmDnFmOPSNm1fnJs9LrBPFZFdTBGhl8plEo=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample2.+013+16384.key b/tests/dns/comparekeys/Kexample2.+013+16384.key
new file mode 100644
index 0000000..b6351ad
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample2.+013+16384.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 16384, for example2.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example2. IN DNSKEY 256 3 13 p+ohRFVh6wmdAhbU/cF2FYoE/i49FxnvKwif0Co0D7RhBui4AMFOsFYu 9AIqEBaCGurjGYl7WDYRrjRMRjWW1g==
diff --git a/tests/dns/comparekeys/Kexample2.+013+16384.private b/tests/dns/comparekeys/Kexample2.+013+16384.private
new file mode 100644
index 0000000..74a371c
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample2.+013+16384.private
@@ -0,0 +1,6 @@
+Private-key-format: v1.3
+Algorithm: 13 (ECDSAP256SHA256)
+PrivateKey: ZNsU73iCEeC837TA59nT/QDtd3oYsrYDWy8jfazZQkA=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample2.+015+37529.key b/tests/dns/comparekeys/Kexample2.+015+37529.key
new file mode 100644
index 0000000..9a8cf77
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample2.+015+37529.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 37529, for example2.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example2. IN DNSKEY 256 3 15 zyiLjDymEPN90rwi/y0mWXLnUm0Nq7T9Kc8VoubF2Io=
diff --git a/tests/dns/comparekeys/Kexample2.+015+37529.private b/tests/dns/comparekeys/Kexample2.+015+37529.private
new file mode 100644
index 0000000..aa70804
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample2.+015+37529.private
@@ -0,0 +1,6 @@
+Private-key-format: v1.3
+Algorithm: 15 (ED25519)
+PrivateKey: pUR2VLqbi4XtBNImbVDRHrjugMMmaXmy6noV0/jy/rA=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/comparekeys/Kexample3.+002+17187.key b/tests/dns/comparekeys/Kexample3.+002+17187.key
new file mode 100644
index 0000000..0260293
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample3.+002+17187.key
@@ -0,0 +1 @@
+example3. IN KEY 512 3 2 AIDzVP5SeKpxZmlbok6AbdFT5aCVAg3AnQln24CKoc0IXRyTdnhmIEWw VatzRrUY0V6SSwwe3740yk46/TdSvVmZkakw52yn3M661ra5L8kouAK4 rpyM6uulsS0dyjyRzomHJg2zwOukzHBVINFheKsJ25MvdPpp9E64IVji jp/x3wABBQCAFb1Je3cKpt/4gS+KRx9hxFOF5c64ytC9tf0hp2hP4OiP YCu8o5C3qh+PexZAx58m6cSaFlzf3DZ3GGsvamDj5H8YpvP4FeRVva9V jH4VeU4/VtbdNweDUHwAguGJ77MXw+bruHhpbsFVSxHrnNg99WHghaRy YzfFzphJHKBxACo=
diff --git a/tests/dns/comparekeys/Kexample3.+002+17187.private b/tests/dns/comparekeys/Kexample3.+002+17187.private
new file mode 100644
index 0000000..47ef4bc
--- /dev/null
+++ b/tests/dns/comparekeys/Kexample3.+002+17187.private
@@ -0,0 +1,9 @@
+Private-key-format: v1.3
+Algorithm: 2 (DH)
+Prime(p): 81T+UniqcWZpW6JOgG3RU+WglQINwJ0JZ9uAiqHNCF0ck3Z4ZiBFsFWrc0a1GNFekksMHt++NMpOOv03Ur1ZmZGpMOdsp9zOuta2uS/JKLgCuK6cjOrrpbEtHco8kc6JhyYNs8DrpMxwVSDRYXirCduTL3T6afROuCFY4o6f8d8=
+Generator(g): BQ==
+Private_value(x): ccA7JRCvjAE1ASWTtObkvO5k58oKdJ+bzcd/H3cOQsPAhItUc8Pfca2ILWYzDfs+nl+WKLfODQ9cRUabp4SUh0GKPnqJVM1UgDXwme/98NEtVFhs2VawT40wHLkcdPN9jACH11l28u1qsDVb7MRj2UXGC/oszRwQ7s3rN1UlHO8=
+Public_value(y): Fb1Je3cKpt/4gS+KRx9hxFOF5c64ytC9tf0hp2hP4OiPYCu8o5C3qh+PexZAx58m6cSaFlzf3DZ3GGsvamDj5H8YpvP4FeRVva9VjH4VeU4/VtbdNweDUHwAguGJ77MXw+bruHhpbsFVSxHrnNg99WHghaRyYzfFzphJHKBxACo=
+Created: 20211027221447
+Publish: 20211027221447
+Activate: 20211027221447
diff --git a/tests/dns/db_test.c b/tests/dns/db_test.c
new file mode 100644
index 0000000..787ac85
--- /dev/null
+++ b/tests/dns/db_test.c
@@ -0,0 +1,372 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/journal.h>
+#include <dns/name.h>
+#include <dns/rdatalist.h>
+
+#include <tests/dns.h>
+
+#define BUFLEN 255
+#define BIGBUFLEN (64 * 1024)
+#define TEST_ORIGIN "test"
+
+/*
+ * Individual unit tests
+ */
+
+/* test multiple calls to dns_db_getoriginnode */
+ISC_RUN_TEST_IMPL(getoriginnode) {
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+ dns_rdataclass_in, 0, NULL, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_getoriginnode(db, &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_db_detachnode(db, &node);
+
+ result = dns_db_getoriginnode(db, &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_db_detachnode(db, &node);
+
+ dns_db_detach(&db);
+}
+
+/* test getservestalettl and setservestalettl */
+ISC_RUN_TEST_IMPL(getsetservestalettl) {
+ dns_db_t *db = NULL;
+ isc_result_t result;
+ dns_ttl_t ttl;
+
+ UNUSED(state);
+
+ result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_cache,
+ dns_rdataclass_in, 0, NULL, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ ttl = 5000;
+ result = dns_db_getservestalettl(db, &ttl);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(ttl, 0);
+
+ ttl = 6 * 3600;
+ result = dns_db_setservestalettl(db, ttl);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ ttl = 5000;
+ result = dns_db_getservestalettl(db, &ttl);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(ttl, 6 * 3600);
+
+ dns_db_detach(&db);
+}
+
+/* check DNS_DBFIND_STALEOK works */
+ISC_RUN_TEST_IMPL(dns_dbfind_staleok) {
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_fixedname_t example_fixed;
+ dns_fixedname_t found_fixed;
+ dns_name_t *example;
+ dns_name_t *found;
+ dns_rdatalist_t rdatalist;
+ dns_rdataset_t rdataset;
+ int count;
+ int pass;
+ isc_result_t result;
+ unsigned char data[] = { 0x0a, 0x00, 0x00, 0x01 };
+
+ UNUSED(state);
+
+ result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_cache,
+ dns_rdataclass_in, 0, NULL, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ example = dns_fixedname_initname(&example_fixed);
+ found = dns_fixedname_initname(&found_fixed);
+
+ result = dns_name_fromstring(example, "example", 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Pass 0: default; no stale processing permitted.
+ * Pass 1: stale processing for 1 second.
+ * Pass 2: stale turned off after being on.
+ */
+ for (pass = 0; pass < 3; pass++) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ /* 10.0.0.1 */
+ rdata.data = data;
+ rdata.length = 4;
+ rdata.rdclass = dns_rdataclass_in;
+ rdata.type = dns_rdatatype_a;
+
+ dns_rdatalist_init(&rdatalist);
+ rdatalist.ttl = 2;
+ rdatalist.type = dns_rdatatype_a;
+ rdatalist.rdclass = dns_rdataclass_in;
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+
+ switch (pass) {
+ case 0:
+ /* default: stale processing off */
+ break;
+ case 1:
+ /* turn on stale processing */
+ result = dns_db_setservestalettl(db, 1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ break;
+ case 2:
+ /* turn off stale processing */
+ result = dns_db_setservestalettl(db, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ break;
+ }
+
+ dns_rdataset_init(&rdataset);
+ result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_findnode(db, example, true, &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_addrdataset(db, node, NULL, 0, &rdataset, 0,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_db_detachnode(db, &node);
+ dns_rdataset_disassociate(&rdataset);
+
+ result = dns_db_find(db, example, NULL, dns_rdatatype_a, 0, 0,
+ &node, found, &rdataset, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * May loop for up to 2 seconds performing non stale lookups.
+ */
+ count = 0;
+ do {
+ count++;
+ assert_in_range(count, 1, 21); /* loop sanity */
+ assert_int_equal(rdataset.attributes &
+ DNS_RDATASETATTR_STALE,
+ 0);
+ assert_true(rdataset.ttl > 0);
+ dns_db_detachnode(db, &node);
+ dns_rdataset_disassociate(&rdataset);
+
+ usleep(100000); /* 100 ms */
+
+ result = dns_db_find(db, example, NULL, dns_rdatatype_a,
+ 0, 0, &node, found, &rdataset,
+ NULL);
+ } while (result == ISC_R_SUCCESS);
+
+ assert_int_equal(result, ISC_R_NOTFOUND);
+
+ /*
+ * Check whether we can get stale data.
+ */
+ result = dns_db_find(db, example, NULL, dns_rdatatype_a,
+ DNS_DBFIND_STALEOK, 0, &node, found,
+ &rdataset, NULL);
+ switch (pass) {
+ case 0:
+ assert_int_equal(result, ISC_R_NOTFOUND);
+ break;
+ case 1:
+ /*
+ * Should loop for 1 second with stale lookups then
+ * stop.
+ */
+ count = 0;
+ do {
+ count++;
+ assert_in_range(count, 0, 49); /* loop sanity */
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(rdataset.attributes &
+ DNS_RDATASETATTR_STALE,
+ DNS_RDATASETATTR_STALE);
+ dns_db_detachnode(db, &node);
+ dns_rdataset_disassociate(&rdataset);
+
+ usleep(100000); /* 100 ms */
+
+ result = dns_db_find(
+ db, example, NULL, dns_rdatatype_a,
+ DNS_DBFIND_STALEOK, 0, &node, found,
+ &rdataset, NULL);
+ } while (result == ISC_R_SUCCESS);
+ /*
+ * usleep(100000) can be slightly less than 10ms so
+ * allow the count to reach 11.
+ */
+ assert_in_range(count, 1, 11);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+ break;
+ case 2:
+ assert_int_equal(result, ISC_R_NOTFOUND);
+ break;
+ }
+ }
+
+ dns_db_detach(&db);
+}
+
+/* database class */
+ISC_RUN_TEST_IMPL(class) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+
+ UNUSED(state);
+
+ result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+ dns_rdataclass_in, 0, NULL, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_load(db, TESTS_DIR "/testdata/db/data.db",
+ dns_masterformat_text, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_int_equal(dns_db_class(db), dns_rdataclass_in);
+
+ dns_db_detach(&db);
+}
+
+/* database type */
+ISC_RUN_TEST_IMPL(dbtype) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+
+ UNUSED(state);
+
+ /* DB has zone semantics */
+ result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+ dns_rdataclass_in, 0, NULL, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_db_load(db, TESTS_DIR "/testdata/db/data.db",
+ dns_masterformat_text, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(dns_db_iszone(db));
+ assert_false(dns_db_iscache(db));
+ dns_db_detach(&db);
+
+ /* DB has cache semantics */
+ result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_cache,
+ dns_rdataclass_in, 0, NULL, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_db_load(db, TESTS_DIR "/testdata/db/data.db",
+ dns_masterformat_text, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(dns_db_iscache(db));
+ assert_false(dns_db_iszone(db));
+ dns_db_detach(&db);
+}
+
+/* database versions */
+ISC_RUN_TEST_IMPL(version) {
+ isc_result_t result;
+ dns_fixedname_t fname, ffound;
+ dns_name_t *name, *foundname;
+ dns_db_t *db = NULL;
+ dns_dbversion_t *ver = NULL, *new = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+
+ UNUSED(state);
+
+ result = dns_test_loaddb(&db, dns_dbtype_zone, "test.test",
+ TESTS_DIR "/testdata/db/data.db");
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Open current version for reading */
+ dns_db_currentversion(db, &ver);
+ dns_test_namefromstring("b.test.test", &fname);
+ name = dns_fixedname_name(&fname);
+ foundname = dns_fixedname_initname(&ffound);
+ dns_rdataset_init(&rdataset);
+ result = dns_db_find(db, name, ver, dns_rdatatype_a, 0, 0, &node,
+ foundname, &rdataset, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_rdataset_disassociate(&rdataset);
+ dns_db_detachnode(db, &node);
+ dns_db_closeversion(db, &ver, false);
+
+ /* Open new version for writing */
+ dns_db_currentversion(db, &ver);
+ dns_test_namefromstring("b.test.test", &fname);
+ name = dns_fixedname_name(&fname);
+ foundname = dns_fixedname_initname(&ffound);
+ dns_rdataset_init(&rdataset);
+ result = dns_db_find(db, name, ver, dns_rdatatype_a, 0, 0, &node,
+ foundname, &rdataset, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_newversion(db, &new);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Delete the rdataset from the new version */
+ result = dns_db_deleterdataset(db, node, new, dns_rdatatype_a, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_rdataset_disassociate(&rdataset);
+ dns_db_detachnode(db, &node);
+
+ /* This should fail now */
+ result = dns_db_find(db, name, new, dns_rdatatype_a, 0, 0, &node,
+ foundname, &rdataset, NULL);
+ assert_int_equal(result, DNS_R_NXDOMAIN);
+
+ dns_db_closeversion(db, &new, true);
+
+ /* But this should still succeed */
+ result = dns_db_find(db, name, ver, dns_rdatatype_a, 0, 0, &node,
+ foundname, &rdataset, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_rdataset_disassociate(&rdataset);
+ dns_db_detachnode(db, &node);
+ dns_db_closeversion(db, &ver, false);
+
+ dns_db_detach(&db);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(getoriginnode)
+ISC_TEST_ENTRY(getsetservestalettl)
+ISC_TEST_ENTRY(dns_dbfind_staleok)
+ISC_TEST_ENTRY(class)
+ISC_TEST_ENTRY(dbtype)
+ISC_TEST_ENTRY(version)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/dbdiff_test.c b/tests/dns/dbdiff_test.c
new file mode 100644
index 0000000..f0fb880
--- /dev/null
+++ b/tests/dns/dbdiff_test.c
@@ -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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/journal.h>
+#include <dns/name.h>
+
+#include <tests/dns.h>
+
+#define BUFLEN 255
+#define BIGBUFLEN (64 * 1024)
+#define TEST_ORIGIN "test"
+
+static void
+test_create(const char *oldfile, dns_db_t **old, const char *newfile,
+ dns_db_t **newdb) {
+ isc_result_t result;
+
+ result = dns_test_loaddb(old, dns_dbtype_zone, TEST_ORIGIN, oldfile);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_test_loaddb(newdb, dns_dbtype_zone, TEST_ORIGIN, newfile);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+/* dns_db_diffx of identical content */
+ISC_RUN_TEST_IMPL(diffx_same) {
+ dns_db_t *newdb = NULL, *olddb = NULL;
+ isc_result_t result;
+ dns_diff_t diff;
+
+ UNUSED(state);
+
+ test_create(TESTS_DIR "/testdata/diff/zone1.data", &olddb,
+ TESTS_DIR "/testdata/diff/zone1.data", &newdb);
+
+ dns_diff_init(mctx, &diff);
+
+ result = dns_db_diffx(&diff, newdb, NULL, olddb, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_true(ISC_LIST_EMPTY(diff.tuples));
+
+ dns_diff_clear(&diff);
+ dns_db_detach(&newdb);
+ dns_db_detach(&olddb);
+}
+
+/* dns_db_diffx of zone with record added */
+ISC_RUN_TEST_IMPL(diffx_add) {
+ dns_db_t *newdb = NULL, *olddb = NULL;
+ dns_difftuple_t *tuple;
+ isc_result_t result;
+ dns_diff_t diff;
+ int count = 0;
+
+ UNUSED(state);
+
+ test_create(TESTS_DIR "/testdata/diff/zone1.data", &olddb,
+ TESTS_DIR "/testdata/diff/zone2.data", &newdb);
+
+ dns_diff_init(mctx, &diff);
+
+ result = dns_db_diffx(&diff, newdb, NULL, olddb, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_false(ISC_LIST_EMPTY(diff.tuples));
+ for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL;
+ tuple = ISC_LIST_NEXT(tuple, link))
+ {
+ assert_int_equal(tuple->op, DNS_DIFFOP_ADD);
+ count++;
+ }
+ assert_int_equal(count, 1);
+
+ dns_diff_clear(&diff);
+ dns_db_detach(&newdb);
+ dns_db_detach(&olddb);
+}
+
+/* dns_db_diffx of zone with record removed */
+ISC_RUN_TEST_IMPL(diffx_remove) {
+ dns_db_t *newdb = NULL, *olddb = NULL;
+ dns_difftuple_t *tuple;
+ isc_result_t result;
+ dns_diff_t diff;
+ int count = 0;
+
+ UNUSED(state);
+
+ test_create(TESTS_DIR "/testdata/diff/zone1.data", &olddb,
+ TESTS_DIR "/testdata/diff/zone3.data", &newdb);
+
+ dns_diff_init(mctx, &diff);
+
+ result = dns_db_diffx(&diff, newdb, NULL, olddb, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_false(ISC_LIST_EMPTY(diff.tuples));
+ for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL;
+ tuple = ISC_LIST_NEXT(tuple, link))
+ {
+ assert_int_equal(tuple->op, DNS_DIFFOP_DEL);
+ count++;
+ }
+ assert_int_equal(count, 1);
+
+ dns_diff_clear(&diff);
+ dns_db_detach(&newdb);
+ dns_db_detach(&olddb);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(diffx_same)
+ISC_TEST_ENTRY(diffx_add)
+ISC_TEST_ENTRY(diffx_remove)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/dbiterator_test.c b/tests/dns/dbiterator_test.c
new file mode 100644
index 0000000..f0277b1
--- /dev/null
+++ b/tests/dns/dbiterator_test.c
@@ -0,0 +1,340 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/name.h>
+
+#include <tests/dns.h>
+
+#define BUFLEN 255
+#define BIGBUFLEN (64 * 1024)
+#define TEST_ORIGIN "test"
+
+static isc_result_t
+make_name(const char *src, dns_name_t *name) {
+ isc_buffer_t b;
+ isc_buffer_constinit(&b, src, strlen(src));
+ isc_buffer_add(&b, strlen(src));
+ return (dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
+}
+
+/* create: make sure we can create a dbiterator */
+static void
+test_create(const char *filename) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ dns_dbiterator_t *iter = NULL;
+
+ result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN, filename);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_createiterator(db, 0, &iter);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_dbiterator_destroy(&iter);
+ dns_db_detach(&db);
+}
+
+ISC_RUN_TEST_IMPL(create) {
+ UNUSED(state);
+
+ test_create(TESTS_DIR "/testdata/dbiterator/zone1.data");
+}
+
+ISC_RUN_TEST_IMPL(create_nsec3) {
+ UNUSED(state);
+
+ test_create(TESTS_DIR "/testdata/dbiterator/zone2.data");
+}
+
+/* walk: walk a database */
+static void
+test_walk(const char *filename, int nodes) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ dns_dbiterator_t *iter = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_name_t *name;
+ dns_fixedname_t f;
+ int i = 0;
+
+ name = dns_fixedname_initname(&f);
+
+ result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN, filename);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_createiterator(db, 0, &iter);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (result = dns_dbiterator_first(iter); result == ISC_R_SUCCESS;
+ result = dns_dbiterator_next(iter))
+ {
+ result = dns_dbiterator_current(iter, &node, name);
+ if (result == DNS_R_NEWORIGIN) {
+ result = ISC_R_SUCCESS;
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_db_detachnode(db, &node);
+ i++;
+ }
+
+ assert_int_equal(i, nodes);
+
+ dns_dbiterator_destroy(&iter);
+ dns_db_detach(&db);
+}
+
+ISC_RUN_TEST_IMPL(walk) {
+ UNUSED(state);
+
+ test_walk(TESTS_DIR "/testdata/dbiterator/zone1.data", 12);
+}
+
+ISC_RUN_TEST_IMPL(walk_nsec3) {
+ UNUSED(state);
+
+ test_walk(TESTS_DIR "/testdata/dbiterator/zone2.data", 33);
+}
+
+/* reverse: walk database backwards */
+static void
+test_reverse(const char *filename) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ dns_dbiterator_t *iter = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_name_t *name;
+ dns_fixedname_t f;
+ int i = 0;
+
+ name = dns_fixedname_initname(&f);
+
+ result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN, filename);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_createiterator(db, 0, &iter);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (result = dns_dbiterator_last(iter); result == ISC_R_SUCCESS;
+ result = dns_dbiterator_prev(iter))
+ {
+ result = dns_dbiterator_current(iter, &node, name);
+ if (result == DNS_R_NEWORIGIN) {
+ result = ISC_R_SUCCESS;
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_db_detachnode(db, &node);
+ i++;
+ }
+
+ assert_int_equal(i, 12);
+
+ dns_dbiterator_destroy(&iter);
+ dns_db_detach(&db);
+}
+
+ISC_RUN_TEST_IMPL(reverse) {
+ UNUSED(state);
+
+ test_reverse(TESTS_DIR "/testdata/dbiterator/zone1.data");
+}
+
+ISC_RUN_TEST_IMPL(reverse_nsec3) {
+ UNUSED(state);
+
+ test_reverse(TESTS_DIR "/testdata/dbiterator/zone2.data");
+}
+
+/* seek: walk database starting at a particular node */
+static void
+test_seek_node(const char *filename, int nodes) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ dns_dbiterator_t *iter = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_name_t *name, *seekname;
+ dns_fixedname_t f1, f2;
+ int i = 0;
+
+ name = dns_fixedname_initname(&f1);
+ seekname = dns_fixedname_initname(&f2);
+
+ result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN, filename);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_createiterator(db, 0, &iter);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = make_name("c." TEST_ORIGIN, seekname);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dbiterator_seek(iter, seekname);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ while (result == ISC_R_SUCCESS) {
+ result = dns_dbiterator_current(iter, &node, name);
+ if (result == DNS_R_NEWORIGIN) {
+ result = ISC_R_SUCCESS;
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_db_detachnode(db, &node);
+ result = dns_dbiterator_next(iter);
+ i++;
+ }
+
+ assert_int_equal(i, nodes);
+
+ dns_dbiterator_destroy(&iter);
+ dns_db_detach(&db);
+}
+
+ISC_RUN_TEST_IMPL(seek_node) {
+ UNUSED(state);
+
+ test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data", 9);
+}
+
+ISC_RUN_TEST_IMPL(seek_node_nsec3) {
+ UNUSED(state);
+
+ test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data", 30);
+}
+
+/*
+ * seek_emty: walk database starting at an empty nonterminal node
+ * (should fail)
+ */
+static void
+test_seek_empty(const char *filename) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ dns_dbiterator_t *iter = NULL;
+ dns_name_t *seekname;
+ dns_fixedname_t f1;
+
+ seekname = dns_fixedname_initname(&f1);
+
+ result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN, filename);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_createiterator(db, 0, &iter);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = make_name("d." TEST_ORIGIN, seekname);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dbiterator_seek(iter, seekname);
+ assert_int_equal(result, DNS_R_PARTIALMATCH);
+
+ dns_dbiterator_destroy(&iter);
+ dns_db_detach(&db);
+}
+
+ISC_RUN_TEST_IMPL(seek_empty) {
+ UNUSED(state);
+
+ test_seek_empty(TESTS_DIR "/testdata/dbiterator/zone1.data");
+}
+
+ISC_RUN_TEST_IMPL(seek_empty_nsec3) {
+ UNUSED(state);
+
+ test_seek_empty(TESTS_DIR "/testdata/dbiterator/zone2.data");
+}
+
+/*
+ * seek_nx: walk database starting at a nonexistent node
+ */
+static void
+test_seek_nx(const char *filename) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ dns_dbiterator_t *iter = NULL;
+ dns_name_t *seekname;
+ dns_fixedname_t f1;
+
+ seekname = dns_fixedname_initname(&f1);
+
+ result = dns_test_loaddb(&db, dns_dbtype_cache, TEST_ORIGIN, filename);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_createiterator(db, 0, &iter);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = make_name("nonexistent." TEST_ORIGIN, seekname);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dbiterator_seek(iter, seekname);
+ assert_int_equal(result, DNS_R_PARTIALMATCH);
+
+ result = make_name("nonexistent.", seekname);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dbiterator_seek(iter, seekname);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+
+ dns_dbiterator_destroy(&iter);
+ dns_db_detach(&db);
+}
+
+ISC_RUN_TEST_IMPL(seek_nx) {
+ UNUSED(state);
+
+ test_seek_nx(TESTS_DIR "/testdata/dbiterator/zone1.data");
+}
+
+ISC_RUN_TEST_IMPL(seek_nx_nsec3) {
+ UNUSED(state);
+
+ test_seek_nx(TESTS_DIR "/testdata/dbiterator/zone2.data");
+}
+
+/*
+ * XXX:
+ * dns_dbiterator API calls that are not yet part of this unit test:
+ *
+ * dns_dbiterator_pause
+ * dns_dbiterator_origin
+ * dns_dbiterator_setcleanmode
+ */
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(create)
+ISC_TEST_ENTRY(create_nsec3)
+ISC_TEST_ENTRY(walk)
+ISC_TEST_ENTRY(walk_nsec3)
+ISC_TEST_ENTRY(reverse)
+ISC_TEST_ENTRY(reverse_nsec3)
+ISC_TEST_ENTRY(seek_node)
+ISC_TEST_ENTRY(seek_node_nsec3)
+ISC_TEST_ENTRY(seek_empty)
+ISC_TEST_ENTRY(seek_empty_nsec3)
+ISC_TEST_ENTRY(seek_nx)
+ISC_TEST_ENTRY(seek_nx_nsec3)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/dbversion_test.c b/tests/dns/dbversion_test.c
new file mode 100644
index 0000000..4d52166
--- /dev/null
+++ b/tests/dns/dbversion_test.c
@@ -0,0 +1,461 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/file.h>
+#include <isc/result.h>
+#include <isc/serial.h>
+#include <isc/stdtime.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/nsec3.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+
+#include <tests/dns.h>
+
+static char tempname[11] = "dtXXXXXXXX";
+static dns_db_t *db1 = NULL, *db2 = NULL;
+static dns_dbversion_t *v1 = NULL, *v2 = NULL;
+
+/*
+ * The code below enables us to trap assertion failures for testing
+ * purposes. local_callback() is set as the callback function for
+ * isc_assertion_failed(). It calls mock_assert() so that CMOCKA
+ * will be able to see it, then returns to the calling function via
+ * longjmp() so that the abort() call in isc_assertion_failed() will
+ * never be reached. Use check_assertion() to check for assertions
+ * instead of expect_assert_failure().
+ */
+jmp_buf assertion;
+
+#define check_assertion(function_call) \
+ do { \
+ const int r = setjmp(assertion); \
+ if (r == 0) { \
+ expect_assert_failure(function_call); \
+ } \
+ } while (false);
+
+static void
+local_callback(const char *file, int line, isc_assertiontype_t type,
+ const char *cond) {
+ UNUSED(type);
+
+ mock_assert(1, cond, file, line);
+ longjmp(assertion, 1);
+}
+
+static int
+setup_test(void **state) {
+ isc_result_t res;
+
+ UNUSED(state);
+
+ isc_assertion_setcallback(local_callback);
+
+ res = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+ dns_rdataclass_in, 0, NULL, &db1);
+ assert_int_equal(res, ISC_R_SUCCESS);
+ dns_db_newversion(db1, &v1);
+ assert_non_null(v1);
+
+ res = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+ dns_rdataclass_in, 0, NULL, &db2);
+ assert_int_equal(res, ISC_R_SUCCESS);
+ dns_db_newversion(db2, &v2);
+ assert_non_null(v1);
+
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ UNUSED(state);
+
+ if (strcmp(tempname, "dtXXXXXXXX") != 0) {
+ unlink(tempname);
+ }
+
+ if (v1 != NULL) {
+ dns_db_closeversion(db1, &v1, false);
+ assert_null(v1);
+ }
+ if (db1 != NULL) {
+ dns_db_detach(&db1);
+ assert_null(db1);
+ }
+
+ if (v2 != NULL) {
+ dns_db_closeversion(db2, &v2, false);
+ assert_null(v2);
+ }
+ if (db2 != NULL) {
+ dns_db_detach(&db2);
+ assert_null(db2);
+ }
+
+ return (0);
+}
+
+/*
+ * Check dns_db_attachversion() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(attachversion) {
+ dns_dbversion_t *v = NULL;
+
+ UNUSED(state);
+
+ dns_db_attachversion(db1, v1, &v);
+ assert_ptr_equal(v, v1);
+ dns_db_closeversion(db1, &v, false);
+ assert_null(v);
+
+ check_assertion(dns_db_attachversion(db1, v2, &v));
+}
+
+/*
+ * Check dns_db_closeversion() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(closeversion) {
+ UNUSED(state);
+
+ assert_non_null(v1);
+ dns_db_closeversion(db1, &v1, false);
+ assert_null(v1);
+
+ check_assertion(dns_db_closeversion(db1, &v2, false));
+}
+
+/*
+ * Check dns_db_find() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(find) {
+ isc_result_t res;
+ dns_rdataset_t rdataset;
+ dns_fixedname_t fixed;
+ dns_name_t *name = NULL;
+
+ UNUSED(state);
+
+ name = dns_fixedname_initname(&fixed);
+
+ dns_rdataset_init(&rdataset);
+ res = dns_db_find(db1, dns_rootname, v1, dns_rdatatype_soa, 0, 0, NULL,
+ name, &rdataset, NULL);
+ assert_int_equal(res, DNS_R_NXDOMAIN);
+
+ if (dns_rdataset_isassociated(&rdataset)) {
+ dns_rdataset_disassociate(&rdataset);
+ }
+
+ dns_rdataset_init(&rdataset);
+ check_assertion((void)dns_db_find(db1, dns_rootname, v2,
+ dns_rdatatype_soa, 0, 0, NULL, name,
+ &rdataset, NULL));
+}
+
+/*
+ * Check dns_db_allrdatasets() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(allrdatasets) {
+ isc_result_t res;
+ dns_dbnode_t *node = NULL;
+ dns_rdatasetiter_t *iterator = NULL;
+
+ UNUSED(state);
+
+ res = dns_db_findnode(db1, dns_rootname, false, &node);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ res = dns_db_allrdatasets(db1, node, v1, 0, 0, &iterator);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ check_assertion(dns_db_allrdatasets(db1, node, v2, 0, 0, &iterator));
+
+ dns_rdatasetiter_destroy(&iterator);
+ assert_null(iterator);
+
+ dns_db_detachnode(db1, &node);
+ assert_null(node);
+}
+
+/*
+ * Check dns_db_findrdataset() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(findrdataset) {
+ isc_result_t res;
+ dns_rdataset_t rdataset;
+ dns_dbnode_t *node = NULL;
+
+ UNUSED(state);
+
+ res = dns_db_findnode(db1, dns_rootname, false, &node);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ dns_rdataset_init(&rdataset);
+ res = dns_db_findrdataset(db1, node, v1, dns_rdatatype_soa, 0, 0,
+ &rdataset, NULL);
+ assert_int_equal(res, ISC_R_NOTFOUND);
+
+ if (dns_rdataset_isassociated(&rdataset)) {
+ dns_rdataset_disassociate(&rdataset);
+ }
+
+ dns_rdataset_init(&rdataset);
+ check_assertion(dns_db_findrdataset(db1, node, v2, dns_rdatatype_soa, 0,
+ 0, &rdataset, NULL));
+
+ dns_db_detachnode(db1, &node);
+ assert_null(node);
+}
+
+/*
+ * Check dns_db_deleterdataset() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(deleterdataset) {
+ isc_result_t res;
+ dns_dbnode_t *node = NULL;
+
+ UNUSED(state);
+
+ res = dns_db_findnode(db1, dns_rootname, false, &node);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ res = dns_db_deleterdataset(db1, node, v1, dns_rdatatype_soa, 0);
+ assert_int_equal(res, DNS_R_UNCHANGED);
+
+ check_assertion(
+ dns_db_deleterdataset(db1, node, v2, dns_rdatatype_soa, 0));
+ dns_db_detachnode(db1, &node);
+ assert_null(node);
+}
+
+/*
+ * Check dns_db_subtractrdataset() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(subtract) {
+ isc_result_t res;
+ dns_rdataset_t rdataset;
+ dns_rdatalist_t rdatalist;
+ dns_dbnode_t *node = NULL;
+
+ UNUSED(state);
+
+ dns_rdataset_init(&rdataset);
+ dns_rdatalist_init(&rdatalist);
+
+ rdatalist.rdclass = dns_rdataclass_in;
+
+ res = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ res = dns_db_findnode(db1, dns_rootname, false, &node);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ res = dns_db_subtractrdataset(db1, node, v1, &rdataset, 0, NULL);
+ assert_int_equal(res, DNS_R_UNCHANGED);
+
+ if (dns_rdataset_isassociated(&rdataset)) {
+ dns_rdataset_disassociate(&rdataset);
+ }
+
+ dns_rdataset_init(&rdataset);
+ res = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ check_assertion(
+ dns_db_subtractrdataset(db1, node, v2, &rdataset, 0, NULL));
+
+ dns_db_detachnode(db1, &node);
+ assert_null(node);
+}
+
+/*
+ * Check dns_db_dump() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(dump) {
+ isc_result_t res;
+ FILE *f = NULL;
+
+ UNUSED(state);
+
+ res = isc_file_openunique(tempname, &f);
+ fclose(f);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ res = dns_db_dump(db1, v1, tempname);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ check_assertion(dns_db_dump(db1, v2, tempname));
+}
+
+/*
+ * Check dns_db_addrdataset() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(addrdataset) {
+ isc_result_t res;
+ dns_rdataset_t rdataset;
+ dns_dbnode_t *node = NULL;
+ dns_rdatalist_t rdatalist;
+
+ UNUSED(state);
+
+ dns_rdataset_init(&rdataset);
+ dns_rdatalist_init(&rdatalist);
+
+ rdatalist.rdclass = dns_rdataclass_in;
+
+ res = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ res = dns_db_findnode(db1, dns_rootname, false, &node);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ res = dns_db_addrdataset(db1, node, v1, 0, &rdataset, 0, NULL);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ check_assertion(
+ dns_db_addrdataset(db1, node, v2, 0, &rdataset, 0, NULL));
+
+ dns_db_detachnode(db1, &node);
+ assert_null(node);
+}
+
+/*
+ * Check dns_db_getnsec3parameters() passes with matching db and version,
+ * and asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(getnsec3parameters) {
+ isc_result_t res;
+ dns_hash_t hash;
+ uint8_t flags;
+ uint16_t iterations;
+ unsigned char salt[DNS_NSEC3_SALTSIZE];
+ size_t salt_length = sizeof(salt);
+
+ UNUSED(state);
+
+ res = dns_db_getnsec3parameters(db1, v1, &hash, &flags, &iterations,
+ salt, &salt_length);
+ assert_int_equal(res, ISC_R_NOTFOUND);
+
+ check_assertion(dns_db_getnsec3parameters(
+ db1, v2, &hash, &flags, &iterations, salt, &salt_length));
+}
+
+/*
+ * Check dns_db_resigned() passes with matching db and version, and
+ * asserts with mis-matching db and version.
+ */
+ISC_RUN_TEST_IMPL(resigned) {
+ isc_result_t res;
+ dns_rdataset_t rdataset, added;
+ dns_dbnode_t *node = NULL;
+ dns_rdatalist_t rdatalist;
+ dns_rdata_rrsig_t rrsig;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_buffer_t b;
+ unsigned char buf[1024];
+
+ UNUSED(state);
+
+ /*
+ * Create a dummy RRSIG record and set a resigning time.
+ */
+ dns_rdataset_init(&added);
+ dns_rdataset_init(&rdataset);
+ dns_rdatalist_init(&rdatalist);
+ isc_buffer_init(&b, buf, sizeof(buf));
+
+ DNS_RDATACOMMON_INIT(&rrsig, dns_rdatatype_rrsig, dns_rdataclass_in);
+ rrsig.covered = dns_rdatatype_a;
+ rrsig.algorithm = 100;
+ rrsig.labels = 0;
+ rrsig.originalttl = 0;
+ rrsig.timeexpire = 3600;
+ rrsig.timesigned = 0;
+ rrsig.keyid = 0;
+ dns_name_init(&rrsig.signer, NULL);
+ dns_name_clone(dns_rootname, &rrsig.signer);
+ rrsig.siglen = 0;
+ rrsig.signature = NULL;
+
+ res = dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
+ dns_rdatatype_rrsig, &rrsig, &b);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ rdatalist.rdclass = dns_rdataclass_in;
+ rdatalist.type = dns_rdatatype_rrsig;
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+
+ res = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ rdataset.attributes |= DNS_RDATASETATTR_RESIGN;
+ rdataset.resign = 7200;
+
+ res = dns_db_findnode(db1, dns_rootname, false, &node);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ res = dns_db_addrdataset(db1, node, v1, 0, &rdataset, 0, &added);
+ assert_int_equal(res, ISC_R_SUCCESS);
+
+ dns_db_detachnode(db1, &node);
+ assert_null(node);
+
+ check_assertion(dns_db_resigned(db1, &added, v2));
+
+ dns_db_resigned(db1, &added, v1);
+
+ dns_rdataset_disassociate(&added);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(dump, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(find, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(allrdatasets, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(findrdataset, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(deleterdataset, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(subtract, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(addrdataset, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(getnsec3parameters, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(resigned, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(attachversion, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(closeversion, setup_test, teardown_test)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/dh_test.c b/tests/dns/dh_test.c
new file mode 100644
index 0000000..5f4edd9
--- /dev/null
+++ b/tests/dns/dh_test.c
@@ -0,0 +1,102 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * As a workaround, include an OpenSSL header file before including cmocka.h,
+ * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a
+ * redefined malloc in cmocka.h.
+ */
+#include <openssl/err.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/name.h>
+
+#include "dst_internal.h"
+
+#include <tests/dns.h>
+
+static int
+setup_test(void **state) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dst_lib_init(mctx, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ UNUSED(state);
+
+ dst_lib_destroy();
+
+ return (0);
+}
+
+/* OpenSSL DH_compute_key() failure */
+ISC_RUN_TEST_IMPL(dh_computesecret) {
+ dst_key_t *key = NULL;
+ isc_buffer_t buf;
+ unsigned char array[1024];
+ isc_result_t result;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ UNUSED(state);
+
+ name = dns_fixedname_initname(&fname);
+ isc_buffer_constinit(&buf, "dh.", 3);
+ isc_buffer_add(&buf, 3);
+ result = dns_name_fromtext(name, &buf, NULL, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dst_key_fromfile(name, 18602, DST_ALG_DH,
+ DST_TYPE_PUBLIC | DST_TYPE_KEY, TESTS_DIR,
+ mctx, &key);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_init(&buf, array, sizeof(array));
+ result = dst_key_computesecret(key, key, &buf);
+ assert_int_equal(result, DST_R_NOTPRIVATEKEY);
+ result = key->func->computesecret(key, key, &buf);
+ assert_int_equal(result, DST_R_COMPUTESECRETFAILURE);
+
+ dst_key_free(&key);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(dh_computesecret, setup_test, teardown_test)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/dispatch_test.c b/tests/dns/dispatch_test.c
new file mode 100644
index 0000000..c101744
--- /dev/null
+++ b/tests/dns/dispatch_test.c
@@ -0,0 +1,698 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <uv.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/managers.h>
+#include <isc/refcount.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <dns/dispatch.h>
+#include <dns/name.h>
+#include <dns/view.h>
+
+#include <tests/dns.h>
+
+uv_sem_t sem;
+
+/* Timeouts in miliseconds */
+#define T_SERVER_INIT 5000
+#define T_SERVER_IDLE 5000
+#define T_SERVER_KEEPALIVE 5000
+#define T_SERVER_ADVERTISED 5000
+
+#define T_CLIENT_INIT 2000
+#define T_CLIENT_IDLE 2000
+#define T_CLIENT_KEEPALIVE 2000
+#define T_CLIENT_ADVERTISED 2000
+
+#define T_CLIENT_CONNECT 1000
+
+dns_dispatchmgr_t *dispatchmgr = NULL;
+dns_dispatchset_t *dset = NULL;
+isc_nm_t *connect_nm = NULL;
+static isc_sockaddr_t udp_server_addr;
+static isc_sockaddr_t udp_connect_addr;
+static isc_sockaddr_t tcp_server_addr;
+static isc_sockaddr_t tcp_connect_addr;
+
+const struct in6_addr in6addr_blackhole = { { { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1 } } };
+
+static int
+setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
+ socklen_t addrlen = sizeof(*addr);
+ uv_os_sock_t fd;
+ int r;
+
+ isc_sockaddr_fromin6(addr, &in6addr_loopback, 0);
+
+ fd = socket(AF_INET6, family, 0);
+ if (fd < 0) {
+ perror("setup_ephemeral_port: socket()");
+ return (-1);
+ }
+
+ r = bind(fd, (const struct sockaddr *)&addr->type.sa,
+ sizeof(addr->type.sin6));
+ if (r != 0) {
+ perror("setup_ephemeral_port: bind()");
+ close(fd);
+ return (r);
+ }
+
+ r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen);
+ if (r != 0) {
+ perror("setup_ephemeral_port: getsockname()");
+ close(fd);
+ return (r);
+ }
+
+#if IPV6_RECVERR
+#define setsockopt_on(socket, level, name) \
+ setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
+
+ r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR);
+ if (r != 0) {
+ perror("setup_ephemeral_port");
+ close(fd);
+ return (r);
+ }
+#endif
+
+ return (fd);
+}
+
+static void
+reset_testdata(void);
+
+static int
+_setup(void **state) {
+ uv_os_sock_t sock = -1;
+ int r;
+
+ udp_connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0);
+
+ tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
+
+ udp_server_addr = (isc_sockaddr_t){ .length = 0 };
+ sock = setup_ephemeral_port(&udp_server_addr, SOCK_DGRAM);
+ if (sock < 0) {
+ return (-1);
+ }
+ close(sock);
+
+ tcp_server_addr = (isc_sockaddr_t){ .length = 0 };
+ sock = setup_ephemeral_port(&tcp_server_addr, SOCK_STREAM);
+ if (sock < 0) {
+ return (-1);
+ }
+ close(sock);
+
+ setup_managers(state);
+
+ /* Create a secondary network manager */
+ isc_managers_create(mctx, workers, 0, &connect_nm, NULL, NULL);
+
+ isc_nm_settimeouts(netmgr, T_SERVER_INIT, T_SERVER_IDLE,
+ T_SERVER_KEEPALIVE, T_SERVER_ADVERTISED);
+
+ /*
+ * Use shorter client-side timeouts, to ensure that clients
+ * time out before the server.
+ */
+ isc_nm_settimeouts(connect_nm, T_CLIENT_INIT, T_CLIENT_IDLE,
+ T_CLIENT_KEEPALIVE, T_CLIENT_ADVERTISED);
+
+ r = uv_sem_init(&sem, 0);
+ assert_int_equal(r, 0);
+
+ reset_testdata();
+
+ return (0);
+}
+
+static int
+_teardown(void **state) {
+ uv_sem_destroy(&sem);
+
+ isc_managers_destroy(&connect_nm, NULL, NULL);
+ assert_null(connect_nm);
+
+ teardown_managers(state);
+
+ return (0);
+}
+
+static isc_result_t
+make_dispatchset(unsigned int ndisps) {
+ isc_result_t result;
+ isc_sockaddr_t any;
+ dns_dispatch_t *disp = NULL;
+
+ result = dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ isc_sockaddr_any(&any);
+ result = dns_dispatch_createudp(dispatchmgr, &any, &disp);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ result = dns_dispatchset_create(mctx, disp, &dset, ndisps);
+ dns_dispatch_detach(&disp);
+
+ return (result);
+}
+
+static void
+reset(void) {
+ if (dset != NULL) {
+ dns_dispatchset_destroy(&dset);
+ }
+ if (dispatchmgr != NULL) {
+ dns_dispatchmgr_detach(&dispatchmgr);
+ }
+}
+
+/* create dispatch set */
+ISC_RUN_TEST_IMPL(dispatchset_create) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = make_dispatchset(1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ reset();
+
+ result = make_dispatchset(10);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ reset();
+}
+
+/* test dispatch set round-robin */
+ISC_RUN_TEST_IMPL(dispatchset_get) {
+ isc_result_t result;
+ dns_dispatch_t *d1, *d2, *d3, *d4, *d5;
+
+ UNUSED(state);
+
+ result = make_dispatchset(1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ d1 = dns_dispatchset_get(dset);
+ d2 = dns_dispatchset_get(dset);
+ d3 = dns_dispatchset_get(dset);
+ d4 = dns_dispatchset_get(dset);
+ d5 = dns_dispatchset_get(dset);
+
+ assert_ptr_equal(d1, d2);
+ assert_ptr_equal(d2, d3);
+ assert_ptr_equal(d3, d4);
+ assert_ptr_equal(d4, d5);
+
+ reset();
+
+ result = make_dispatchset(4);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ d1 = dns_dispatchset_get(dset);
+ d2 = dns_dispatchset_get(dset);
+ d3 = dns_dispatchset_get(dset);
+ d4 = dns_dispatchset_get(dset);
+ d5 = dns_dispatchset_get(dset);
+
+ assert_ptr_equal(d1, d5);
+ assert_ptr_not_equal(d1, d2);
+ assert_ptr_not_equal(d2, d3);
+ assert_ptr_not_equal(d3, d4);
+ assert_ptr_not_equal(d4, d5);
+
+ reset();
+}
+
+struct {
+ atomic_uint_fast32_t responses;
+ atomic_uint_fast32_t result;
+} testdata;
+
+static dns_dispatch_t *dispatch = NULL;
+static dns_dispentry_t *dispentry = NULL;
+static atomic_bool first = true;
+
+static void
+reset_testdata(void) {
+ atomic_init(&testdata.responses, 0);
+ atomic_init(&testdata.result, ISC_R_UNSET);
+}
+
+static void
+server_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
+ UNUSED(handle);
+ UNUSED(eresult);
+ UNUSED(cbarg);
+
+ return;
+}
+
+static void
+nameserver(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
+ void *cbarg) {
+ isc_region_t response;
+ static unsigned char buf1[16];
+ static unsigned char buf2[16];
+
+ UNUSED(eresult);
+ UNUSED(cbarg);
+
+ memmove(buf1, region->base, 12);
+ memset(buf1 + 12, 0, 4);
+ buf1[2] |= 0x80; /* qr=1 */
+
+ memmove(buf2, region->base, 12);
+ memset(buf2 + 12, 1, 4);
+ buf2[2] |= 0x80; /* qr=1 */
+
+ /*
+ * send message to be discarded.
+ */
+ response.base = buf1;
+ response.length = sizeof(buf1);
+ isc_nm_send(handle, &response, server_senddone, NULL);
+
+ /*
+ * send nextitem message.
+ */
+ response.base = buf2;
+ response.length = sizeof(buf2);
+ isc_nm_send(handle, &response, server_senddone, NULL);
+}
+
+static isc_result_t
+accept_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
+ UNUSED(handle);
+ UNUSED(cbarg);
+
+ return (eresult);
+}
+
+static void
+noop_nameserver(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *cbarg) {
+ UNUSED(handle);
+ UNUSED(eresult);
+ UNUSED(region);
+ UNUSED(cbarg);
+}
+
+static void
+response_getnext(isc_result_t result, isc_region_t *region, void *arg) {
+ UNUSED(region);
+ UNUSED(arg);
+
+ atomic_fetch_add_relaxed(&testdata.responses, 1);
+
+ if (atomic_compare_exchange_strong(&first, &(bool){ true }, false)) {
+ result = dns_dispatch_getnext(dispentry);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ } else {
+ uv_sem_post(&sem);
+ }
+}
+
+static void
+response(isc_result_t eresult, isc_region_t *region, void *arg) {
+ UNUSED(region);
+ UNUSED(arg);
+
+ switch (eresult) {
+ case ISC_R_EOF:
+ case ISC_R_CANCELED:
+ case ISC_R_SHUTTINGDOWN:
+ break;
+ default:
+ atomic_fetch_add_relaxed(&testdata.responses, 1);
+ atomic_store_relaxed(&testdata.result, eresult);
+ }
+
+ uv_sem_post(&sem);
+}
+
+static void
+response_timeout(isc_result_t eresult, isc_region_t *region, void *arg) {
+ UNUSED(region);
+ UNUSED(arg);
+
+ atomic_store_relaxed(&testdata.result, eresult);
+
+ uv_sem_post(&sem);
+}
+
+static void
+connected(isc_result_t eresult, isc_region_t *region, void *cbarg) {
+ isc_region_t *r = (isc_region_t *)cbarg;
+
+ UNUSED(eresult);
+ UNUSED(region);
+
+ dns_dispatch_send(dispentry, r);
+}
+
+static void
+client_senddone(isc_result_t eresult, isc_region_t *region, void *cbarg) {
+ UNUSED(eresult);
+ UNUSED(region);
+ UNUSED(cbarg);
+
+ return;
+}
+
+static void
+timeout_connected(isc_result_t eresult, isc_region_t *region, void *cbarg) {
+ UNUSED(region);
+ UNUSED(cbarg);
+
+ atomic_store_relaxed(&testdata.result, eresult);
+
+ uv_sem_post(&sem);
+}
+
+ISC_RUN_TEST_IMPL(dispatch_timeout_tcp_connect) {
+ isc_result_t result;
+ isc_region_t region;
+ unsigned char rbuf[12] = { 0 };
+ unsigned char message[12] = { 0 };
+ uint16_t id;
+
+ UNUSED(state);
+
+ tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_blackhole, 0);
+
+ result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr,
+ &tcp_server_addr, &dispatch);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ region.base = rbuf;
+ region.length = sizeof(rbuf);
+
+ result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
+ &tcp_server_addr, timeout_connected,
+ client_senddone, response, &region, &id,
+ &dispentry);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(message, 0, sizeof(message));
+ message[0] = (id >> 8) & 0xff;
+ message[1] = id & 0xff;
+
+ region.base = message;
+ region.length = sizeof(message);
+
+ dns_dispatch_connect(dispentry);
+
+ uv_sem_wait(&sem);
+
+ dns_dispatch_done(&dispentry);
+
+ dns_dispatch_detach(&dispatch);
+ dns_dispatchmgr_detach(&dispatchmgr);
+
+ /* Skip if the IPv6 is not available or not blackholed */
+
+ result = atomic_load_acquire(&testdata.result);
+ if (result == ISC_R_ADDRNOTAVAIL || result == ISC_R_CONNREFUSED) {
+ skip();
+ return;
+ }
+
+ assert_int_equal(result, ISC_R_TIMEDOUT);
+}
+
+ISC_RUN_TEST_IMPL(dispatch_timeout_tcp_response) {
+ isc_result_t result;
+ isc_region_t region;
+ unsigned char rbuf[12] = { 0 };
+ unsigned char message[12] = { 0 };
+ uint16_t id;
+ isc_nmsocket_t *sock = NULL;
+
+ UNUSED(state);
+
+ tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
+
+ result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr,
+ &tcp_server_addr, &dispatch);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listentcpdns(netmgr, &tcp_server_addr, noop_nameserver,
+ NULL, accept_cb, NULL, 0, 0, NULL, &sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ region.base = rbuf;
+ region.length = sizeof(rbuf);
+
+ result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
+ &tcp_server_addr, connected, client_senddone,
+ response_timeout, &region, &id, &dispentry);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(message, 0, sizeof(message));
+ message[0] = (id >> 8) & 0xff;
+ message[1] = id & 0xff;
+
+ region.base = message;
+ region.length = sizeof(message);
+
+ dns_dispatch_connect(dispentry);
+
+ uv_sem_wait(&sem);
+
+ assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_TIMEDOUT);
+
+ isc_nm_stoplistening(sock);
+ isc_nmsocket_close(&sock);
+ assert_null(sock);
+
+ dns_dispatch_done(&dispentry);
+
+ dns_dispatch_detach(&dispatch);
+ dns_dispatchmgr_detach(&dispatchmgr);
+}
+
+ISC_RUN_TEST_IMPL(dispatch_tcp_response) {
+ isc_result_t result;
+ isc_region_t region;
+ unsigned char rbuf[12] = { 0 };
+ unsigned char message[12] = { 0 };
+ uint16_t id;
+ isc_nmsocket_t *sock = NULL;
+
+ UNUSED(state);
+
+ tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
+
+ result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr,
+ &tcp_server_addr, &dispatch);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listentcpdns(netmgr, &tcp_server_addr, nameserver, NULL,
+ accept_cb, NULL, 0, 0, NULL, &sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ region.base = rbuf;
+ region.length = sizeof(rbuf);
+
+ result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
+ &tcp_server_addr, connected, client_senddone,
+ response, &region, &id, &dispentry);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(message, 0, sizeof(message));
+ message[0] = (id >> 8) & 0xff;
+ message[1] = id & 0xff;
+
+ region.base = message;
+ region.length = sizeof(message);
+
+ dns_dispatch_connect(dispentry);
+
+ uv_sem_wait(&sem);
+
+ assert_in_range(atomic_load_acquire(&testdata.responses), 1, 2);
+ assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_SUCCESS);
+
+ /* Cleanup */
+
+ isc_nm_stoplistening(sock);
+ isc_nmsocket_close(&sock);
+ assert_null(sock);
+
+ dns_dispatch_done(&dispentry);
+
+ dns_dispatch_detach(&dispatch);
+ dns_dispatchmgr_detach(&dispatchmgr);
+}
+
+ISC_RUN_TEST_IMPL(dispatch_timeout_udp_response) {
+ isc_result_t result;
+ isc_region_t region;
+ unsigned char rbuf[12] = { 0 };
+ unsigned char message[12] = { 0 };
+ uint16_t id;
+ isc_nmsocket_t *sock = NULL;
+
+ UNUSED(state);
+
+ udp_connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0);
+
+ result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dispatch_createudp(dispatchmgr, &tcp_connect_addr,
+ &dispatch);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenudp(netmgr, &udp_server_addr, noop_nameserver,
+ NULL, 0, &sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ region.base = rbuf;
+ region.length = sizeof(rbuf);
+
+ result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
+ &udp_server_addr, connected, client_senddone,
+ response_timeout, &region, &id, &dispentry);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(message, 0, sizeof(message));
+ message[0] = (id >> 8) & 0xff;
+ message[1] = id & 0xff;
+
+ region.base = message;
+ region.length = sizeof(message);
+
+ dns_dispatch_connect(dispentry);
+
+ uv_sem_wait(&sem);
+
+ assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_TIMEDOUT);
+
+ isc_nm_stoplistening(sock);
+ isc_nmsocket_close(&sock);
+ assert_null(sock);
+
+ dns_dispatch_done(&dispentry);
+
+ dns_dispatch_detach(&dispatch);
+ dns_dispatchmgr_detach(&dispatchmgr);
+}
+
+/* test dispatch getnext */
+ISC_RUN_TEST_IMPL(dispatch_getnext) {
+ isc_result_t result;
+ isc_region_t region;
+ isc_nmsocket_t *sock = NULL;
+ unsigned char message[12] = { 0 };
+ unsigned char rbuf[12] = { 0 };
+ uint16_t id;
+
+ UNUSED(state);
+
+ result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dispatch_createudp(dispatchmgr, &udp_connect_addr,
+ &dispatch);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Create a local udp nameserver on the loopback.
+ */
+ result = isc_nm_listenudp(netmgr, &udp_server_addr, nameserver, NULL, 0,
+ &sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ region.base = rbuf;
+ region.length = sizeof(rbuf);
+ result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
+ &udp_server_addr, connected, client_senddone,
+ response_getnext, &region, &id, &dispentry);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(message, 0, sizeof(message));
+ message[0] = (id >> 8) & 0xff;
+ message[1] = id & 0xff;
+
+ region.base = message;
+ region.length = sizeof(message);
+
+ dns_dispatch_connect(dispentry);
+
+ uv_sem_wait(&sem);
+
+ assert_int_equal(atomic_load_acquire(&testdata.responses), 2);
+
+ /* Cleanup */
+ isc_nm_stoplistening(sock);
+ isc_nmsocket_close(&sock);
+ assert_null(sock);
+
+ dns_dispatch_done(&dispentry);
+ dns_dispatch_detach(&dispatch);
+ dns_dispatchmgr_detach(&dispatchmgr);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(dispatch_timeout_tcp_connect, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dispatch_timeout_tcp_response, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dispatch_tcp_response, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dispatch_timeout_udp_response, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dispatchset_create, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dispatchset_get, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dispatch_getnext, _setup, _teardown)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/dns64_test.c b/tests/dns/dns64_test.c
new file mode 100644
index 0000000..5834991
--- /dev/null
+++ b/tests/dns/dns64_test.c
@@ -0,0 +1,236 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/netaddr.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/dns64.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+
+#include <tests/dns.h>
+
+static void
+multiple_prefixes(void) {
+ size_t i, count;
+ /*
+ * Two prefix, non consectutive.
+ */
+ unsigned char aaaa[4][16] = {
+ { 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0, 0, 192, 0, 0, 171 },
+ { 0, 0, 0, 0, 192, 55, 0, 170, 0, 0, 0, 0, 192, 0, 0, 170 },
+ { 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0, 0, 192, 0, 0, 170 },
+ { 0, 0, 0, 0, 192, 55, 0, 170, 0, 0, 0, 0, 192, 0, 0, 171 },
+ };
+ dns_rdataset_t rdataset;
+ dns_rdatalist_t rdatalist;
+ dns_rdata_t rdata[4] = { DNS_RDATA_INIT, DNS_RDATA_INIT, DNS_RDATA_INIT,
+ DNS_RDATA_INIT };
+ isc_netprefix_t prefix[2];
+ unsigned char p1[] = { 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0, 0 };
+ unsigned char p2[] = { 0, 0, 0, 0, 192, 55, 0, 170, 0, 0, 0, 0 };
+ isc_result_t result;
+ bool have_p1, have_p2;
+
+ /*
+ * Construct AAAA rdataset containing 2 prefixes.
+ */
+ dns_rdatalist_init(&rdatalist);
+ for (i = 0; i < 4; i++) {
+ isc_region_t region;
+ region.base = aaaa[i];
+ region.length = 16;
+ dns_rdata_fromregion(&rdata[i], dns_rdataclass_in,
+ dns_rdatatype_aaaa, &region);
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata[i], link);
+ }
+ rdatalist.type = rdata[0].type;
+ rdatalist.rdclass = rdata[0].rdclass;
+ rdatalist.ttl = 0;
+ dns_rdataset_init(&rdataset);
+ result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ count = ARRAY_SIZE(prefix);
+ memset(&prefix, 0, sizeof(prefix));
+ result = dns_dns64_findprefix(&rdataset, prefix, &count);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(count, 2);
+ have_p1 = have_p2 = false;
+ for (i = 0; i < count; i++) {
+ assert_int_equal(prefix[i].prefixlen, 96);
+ assert_int_equal(prefix[i].addr.family, AF_INET6);
+ if (memcmp(prefix[i].addr.type.in6.s6_addr, p1, 12) == 0) {
+ have_p1 = true;
+ }
+ if (memcmp(prefix[i].addr.type.in6.s6_addr, p2, 12) == 0) {
+ have_p2 = true;
+ }
+ }
+ assert_true(have_p1);
+ assert_true(have_p2);
+
+ /*
+ * Check that insufficient prefix space returns ISC_R_NOSPACE
+ * and that the prefix is populated.
+ */
+ count = 1;
+ memset(&prefix, 0, sizeof(prefix));
+ result = dns_dns64_findprefix(&rdataset, prefix, &count);
+ assert_int_equal(result, ISC_R_NOSPACE);
+ assert_int_equal(count, 2);
+ have_p1 = have_p2 = false;
+ assert_int_equal(prefix[0].prefixlen, 96);
+ assert_int_equal(prefix[0].addr.family, AF_INET6);
+ if (memcmp(prefix[0].addr.type.in6.s6_addr, p1, 12) == 0) {
+ have_p1 = true;
+ }
+ if (memcmp(prefix[0].addr.type.in6.s6_addr, p2, 12) == 0) {
+ have_p2 = true;
+ }
+ if (!have_p2) {
+ assert_true(have_p1);
+ }
+ if (!have_p1) {
+ assert_true(have_p2);
+ }
+ assert_true(have_p1 != have_p2);
+}
+
+ISC_RUN_TEST_IMPL(dns64_findprefix) {
+ unsigned int i, j, o;
+ isc_result_t result;
+ struct {
+ unsigned char prefix[12];
+ unsigned int prefixlen;
+ isc_result_t result;
+ } tests[] = {
+ /* The WKP with various lengths. */
+ { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 32,
+ ISC_R_SUCCESS },
+ { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 40,
+ ISC_R_SUCCESS },
+ { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 48,
+ ISC_R_SUCCESS },
+ { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 56,
+ ISC_R_SUCCESS },
+ { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 64,
+ ISC_R_SUCCESS },
+ { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 96,
+ ISC_R_SUCCESS },
+ /*
+ * Prefix with the mapped addresses also appearing in the
+ * prefix.
+ */
+ { { 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0, 0 },
+ 96,
+ ISC_R_SUCCESS },
+ { { 0, 0, 0, 0, 192, 0, 0, 171, 0, 0, 0, 0 },
+ 96,
+ ISC_R_SUCCESS },
+ /* Bad prefix, MBZ != 0. */
+ { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 1, 0, 0, 0 },
+ 96,
+ ISC_R_NOTFOUND },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ size_t count = 2;
+ dns_rdataset_t rdataset;
+ dns_rdatalist_t rdatalist;
+ dns_rdata_t rdata[2] = { DNS_RDATA_INIT, DNS_RDATA_INIT };
+ struct in6_addr ina6[2];
+ isc_netprefix_t prefix[2];
+ unsigned char aa[] = { 192, 0, 0, 170 };
+ unsigned char ab[] = { 192, 0, 0, 171 };
+ isc_region_t region;
+
+ /*
+ * Construct rdata.
+ */
+ memset(ina6[0].s6_addr, 0, sizeof(ina6[0].s6_addr));
+ memset(ina6[1].s6_addr, 0, sizeof(ina6[1].s6_addr));
+ memmove(ina6[0].s6_addr, tests[i].prefix, 12);
+ memmove(ina6[1].s6_addr, tests[i].prefix, 12);
+ o = tests[i].prefixlen / 8;
+ for (j = 0; j < 4; j++) {
+ if ((o + j) == 8U) {
+ o++; /* skip mbz */
+ }
+ ina6[0].s6_addr[j + o] = aa[j];
+ ina6[1].s6_addr[j + o] = ab[j];
+ }
+ region.base = ina6[0].s6_addr;
+ region.length = sizeof(ina6[0].s6_addr);
+ dns_rdata_fromregion(&rdata[0], dns_rdataclass_in,
+ dns_rdatatype_aaaa, &region);
+ region.base = ina6[1].s6_addr;
+ region.length = sizeof(ina6[1].s6_addr);
+ dns_rdata_fromregion(&rdata[1], dns_rdataclass_in,
+ dns_rdatatype_aaaa, &region);
+
+ dns_rdatalist_init(&rdatalist);
+ rdatalist.type = rdata[0].type;
+ rdatalist.rdclass = rdata[0].rdclass;
+ rdatalist.ttl = 0;
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata[0], link);
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata[1], link);
+ dns_rdataset_init(&rdataset);
+ result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_dns64_findprefix(&rdataset, prefix, &count);
+ assert_int_equal(result, tests[i].result);
+ if (tests[i].result == ISC_R_SUCCESS) {
+ assert_int_equal(count, 1);
+ assert_int_equal(prefix[0].prefixlen,
+ tests[i].prefixlen);
+ assert_int_equal(prefix[0].addr.family, AF_INET6);
+ assert_memory_equal(prefix[0].addr.type.in6.s6_addr,
+ tests[i].prefix,
+ tests[i].prefixlen / 8);
+ }
+ }
+
+ /*
+ * Test multiple prefixes.
+ */
+ multiple_prefixes();
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(dns64_findprefix)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/dnstap_test.c b/tests/dns/dnstap_test.c
new file mode 100644
index 0000000..73b3304
--- /dev/null
+++ b/tests/dns/dnstap_test.c
@@ -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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+#include <fstrm.h>
+
+#include <protobuf-c/protobuf-c.h>
+
+#include <isc/buffer.h>
+#include <isc/file.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <dns/dnstap.h>
+#include <dns/view.h>
+
+#include <tests/dns.h>
+
+#define TAPFILE TESTS_DIR "/testdata/dnstap/dnstap.file"
+#define TAPSOCK TESTS_DIR "/testdata/dnstap/dnstap.sock"
+
+#define TAPSAVED TESTS_DIR "/testdata/dnstap/dnstap.saved"
+#define TAPTEXT TESTS_DIR "/testdata/dnstap/dnstap.text"
+
+static int
+cleanup(void **state __attribute__((__unused__))) {
+ (void)isc_file_remove(TAPFILE);
+ (void)isc_file_remove(TAPSOCK);
+
+ return (0);
+}
+
+static int
+setup(void **state) {
+ /*
+ * Make sure files are cleaned up before the test runs.
+ */
+ cleanup(state);
+
+ /*
+ * Make sure text conversions match the time zone in which
+ * the testdata was originally generated.
+ */
+ setenv("TZ", "PDT8", 1);
+ return (0);
+}
+
+/* set up dnstap environment */
+ISC_RUN_TEST_IMPL(dns_dt_create) {
+ isc_result_t result;
+ dns_dtenv_t *dtenv = NULL;
+ struct fstrm_iothr_options *fopt;
+
+ fopt = fstrm_iothr_options_init();
+ assert_non_null(fopt);
+ fstrm_iothr_options_set_num_input_queues(fopt, 1);
+
+ result = dns_dt_create(mctx, dns_dtmode_file, TAPFILE, &fopt, NULL,
+ &dtenv);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ if (dtenv != NULL) {
+ dns_dt_detach(&dtenv);
+ }
+ if (fopt != NULL) {
+ fstrm_iothr_options_destroy(&fopt);
+ }
+
+ assert_true(isc_file_exists(TAPFILE));
+
+ fopt = fstrm_iothr_options_init();
+ assert_non_null(fopt);
+ fstrm_iothr_options_set_num_input_queues(fopt, 1);
+
+ result = dns_dt_create(mctx, dns_dtmode_unix, TAPSOCK, &fopt, NULL,
+ &dtenv);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ if (dtenv != NULL) {
+ dns_dt_detach(&dtenv);
+ }
+ if (fopt != NULL) {
+ fstrm_iothr_options_destroy(&fopt);
+ }
+
+ /* 'create' should succeed, but the file shouldn't exist yet */
+ assert_false(isc_file_exists(TAPSOCK));
+
+ fopt = fstrm_iothr_options_init();
+ assert_non_null(fopt);
+ fstrm_iothr_options_set_num_input_queues(fopt, 1);
+
+ result = dns_dt_create(mctx, 33, TAPSOCK, &fopt, NULL, &dtenv);
+ assert_int_equal(result, ISC_R_FAILURE);
+ assert_null(dtenv);
+ if (dtenv != NULL) {
+ dns_dt_detach(&dtenv);
+ }
+ if (fopt != NULL) {
+ fstrm_iothr_options_destroy(&fopt);
+ }
+}
+
+/* send dnstap messages */
+ISC_RUN_TEST_IMPL(dns_dt_send) {
+ isc_result_t result;
+ dns_dtenv_t *dtenv = NULL;
+ dns_dthandle_t *handle = NULL;
+ uint8_t *data;
+ size_t dsize;
+ unsigned char zone[DNS_NAME_MAXWIRE];
+ unsigned char qambuffer[4096], rambuffer[4096];
+ unsigned char qrmbuffer[4096], rrmbuffer[4096];
+ isc_buffer_t zb, qamsg, ramsg, qrmsg, rrmsg;
+ size_t qasize, qrsize, rasize, rrsize;
+ dns_fixedname_t zfname;
+ dns_name_t *zname;
+ dns_dtmsgtype_t dt;
+ dns_view_t *view = NULL;
+ dns_compress_t cctx;
+ isc_region_t zr;
+ isc_sockaddr_t qaddr;
+ isc_sockaddr_t raddr;
+ struct in_addr in;
+ isc_stdtime_t now;
+ isc_time_t p, f;
+ struct fstrm_iothr_options *fopt;
+
+ result = dns_test_makeview("test", false, &view);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ fopt = fstrm_iothr_options_init();
+ assert_non_null(fopt);
+ fstrm_iothr_options_set_num_input_queues(fopt, 1);
+
+ result = dns_dt_create(mctx, dns_dtmode_file, TAPFILE, &fopt, NULL,
+ &dtenv);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_dt_attach(dtenv, &view->dtenv);
+ view->dttypes = DNS_DTTYPE_ALL;
+
+ /*
+ * Set up some test data
+ */
+ zname = dns_fixedname_initname(&zfname);
+ isc_buffer_constinit(&zb, "example.com.", 12);
+ isc_buffer_add(&zb, 12);
+ result = dns_name_fromtext(zname, &zb, NULL, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(&zr, 0, sizeof(zr));
+ isc_buffer_init(&zb, zone, sizeof(zone));
+ result = dns_compress_init(&cctx, -1, mctx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_compress_setmethods(&cctx, DNS_COMPRESS_NONE);
+ result = dns_name_towire(zname, &cctx, &zb);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_compress_invalidate(&cctx);
+ isc_buffer_usedregion(&zb, &zr);
+
+ in.s_addr = inet_addr("10.53.0.1");
+ isc_sockaddr_fromin(&qaddr, &in, 2112);
+ in.s_addr = inet_addr("10.53.0.2");
+ isc_sockaddr_fromin(&raddr, &in, 2112);
+
+ isc_stdtime_get(&now);
+ isc_time_set(&p, now - 3600, 0); /* past */
+ isc_time_set(&f, now + 3600, 0); /* future */
+
+ result = dns_test_getdata(TESTS_DIR "/testdata/dnstap/query.auth",
+ qambuffer, sizeof(qambuffer), &qasize);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_buffer_init(&qamsg, qambuffer, qasize);
+ isc_buffer_add(&qamsg, qasize);
+
+ result = dns_test_getdata(TESTS_DIR "/testdata/dnstap/response.auth",
+ rambuffer, sizeof(rambuffer), &rasize);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_buffer_init(&ramsg, rambuffer, rasize);
+ isc_buffer_add(&ramsg, rasize);
+
+ result = dns_test_getdata(TESTS_DIR "/testdata/dnstap/query.recursive",
+ qrmbuffer, sizeof(qrmbuffer), &qrsize);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_buffer_init(&qrmsg, qrmbuffer, qrsize);
+ isc_buffer_add(&qrmsg, qrsize);
+
+ result = dns_test_getdata(TESTS_DIR
+ "/testdata/dnstap/response.recursive",
+ rrmbuffer, sizeof(rrmbuffer), &rrsize);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_buffer_init(&rrmsg, rrmbuffer, rrsize);
+ isc_buffer_add(&rrmsg, rrsize);
+
+ for (dt = DNS_DTTYPE_SQ; dt <= DNS_DTTYPE_TR; dt <<= 1) {
+ isc_buffer_t *m;
+ isc_sockaddr_t *q = &qaddr, *r = &raddr;
+
+ switch (dt) {
+ case DNS_DTTYPE_AQ:
+ m = &qamsg;
+ break;
+ case DNS_DTTYPE_AR:
+ m = &ramsg;
+ break;
+ default:
+ m = &qrmsg;
+ if ((dt & DNS_DTTYPE_RESPONSE) != 0) {
+ m = &ramsg;
+ }
+ break;
+ }
+
+ dns_dt_send(view, dt, q, r, false, &zr, &p, &f, m);
+ dns_dt_send(view, dt, q, r, false, &zr, NULL, &f, m);
+ dns_dt_send(view, dt, q, r, false, &zr, &p, NULL, m);
+ dns_dt_send(view, dt, q, r, false, &zr, NULL, NULL, m);
+ dns_dt_send(view, dt, q, r, true, &zr, &p, &f, m);
+ dns_dt_send(view, dt, q, r, true, &zr, NULL, &f, m);
+ dns_dt_send(view, dt, q, r, true, &zr, &p, NULL, m);
+ dns_dt_send(view, dt, q, r, true, &zr, NULL, NULL, m);
+ }
+
+ dns_dt_detach(&view->dtenv);
+ dns_dt_detach(&dtenv);
+ dns_view_detach(&view);
+
+ result = dns_dt_open(TAPFILE, dns_dtmode_file, mctx, &handle);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ while (dns_dt_getframe(handle, &data, &dsize) == ISC_R_SUCCESS) {
+ dns_dtdata_t *dtdata = NULL;
+ isc_region_t r;
+ static dns_dtmsgtype_t expected = DNS_DTTYPE_SQ;
+ static int n = 0;
+
+ r.base = data;
+ r.length = dsize;
+
+ result = dns_dt_parse(mctx, &r, &dtdata);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS) {
+ n++;
+ continue;
+ }
+
+ assert_int_equal(dtdata->type, expected);
+ if (++n % 8 == 0) {
+ expected <<= 1;
+ }
+
+ dns_dtdata_free(&dtdata);
+ }
+
+ if (fopt != NULL) {
+ fstrm_iothr_options_destroy(&fopt);
+ }
+ if (handle != NULL) {
+ dns_dt_close(&handle);
+ }
+}
+
+/* dnstap message to text */
+ISC_RUN_TEST_IMPL(dns_dt_totext) {
+ isc_result_t result;
+ dns_dthandle_t *handle = NULL;
+ uint8_t *data;
+ size_t dsize;
+ FILE *fp = NULL;
+
+ UNUSED(state);
+
+ result = dns_dt_open(TAPSAVED, dns_dtmode_file, mctx, &handle);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_stdio_open(TAPTEXT, "r", &fp);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ while (dns_dt_getframe(handle, &data, &dsize) == ISC_R_SUCCESS) {
+ dns_dtdata_t *dtdata = NULL;
+ isc_buffer_t *b = NULL;
+ isc_region_t r;
+ char s[BUFSIZ], *p;
+
+ r.base = data;
+ r.length = dsize;
+
+ /* read the corresponding line of text */
+ p = fgets(s, sizeof(s), fp);
+ assert_ptr_equal(p, s);
+ if (p == NULL) {
+ break;
+ }
+
+ p = strchr(p, '\n');
+ if (p != NULL) {
+ *p = '\0';
+ }
+
+ /* parse dnstap frame */
+ result = dns_dt_parse(mctx, &r, &dtdata);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS) {
+ continue;
+ }
+
+ isc_buffer_allocate(mctx, &b, 2048);
+ assert_non_null(b);
+ if (b == NULL) {
+ break;
+ }
+
+ /* convert to text and compare */
+ result = dns_dt_datatotext(dtdata, &b);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_string_equal((char *)isc_buffer_base(b), s);
+
+ dns_dtdata_free(&dtdata);
+ isc_buffer_free(&b);
+ }
+
+ if (handle != NULL) {
+ dns_dt_close(&handle);
+ }
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(dns_dt_create, setup, cleanup)
+ISC_TEST_ENTRY_CUSTOM(dns_dt_send, setup, cleanup)
+ISC_TEST_ENTRY_CUSTOM(dns_dt_totext, setup, cleanup)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/dst_test.c b/tests/dns/dst_test.c
new file mode 100644
index 0000000..283a7ba
--- /dev/null
+++ b/tests/dns/dst_test.c
@@ -0,0 +1,487 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * As a workaround, include an OpenSSL header file before including cmocka.h,
+ * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a
+ * redefined malloc in cmocka.h.
+ */
+#include <openssl/err.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/file.h>
+#include <isc/hex.h>
+#include <isc/result.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dst/dst.h>
+
+#include "dst_internal.h"
+
+#include <tests/dns.h>
+
+static int
+setup_test(void **state) {
+ UNUSED(state);
+
+ dst_lib_init(mctx, NULL);
+
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ UNUSED(state);
+
+ dst_lib_destroy();
+
+ return (0);
+}
+
+/* Read sig in file at path to buf. Check signature ineffability */
+static isc_result_t
+sig_fromfile(const char *path, isc_buffer_t *buf) {
+ isc_result_t result;
+ size_t rval, len;
+ FILE *fp = NULL;
+ unsigned char val;
+ char *p, *data;
+ off_t size;
+
+ result = isc_stdio_open(path, "rb", &fp);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_file_getsizefd(fileno(fp), &size);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ data = isc_mem_get(mctx, (size + 1));
+ assert_non_null(data);
+
+ len = (size_t)size;
+ p = data;
+ while (len != 0U) {
+ result = isc_stdio_read(p, 1, len, fp, &rval);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ len -= rval;
+ p += rval;
+ }
+ isc_stdio_close(fp);
+
+ p = data;
+ len = size;
+ while (len > 0U) {
+ if ((*p == '\r') || (*p == '\n')) {
+ ++p;
+ --len;
+ continue;
+ } else if (len < 2U) {
+ goto err;
+ }
+ if (('0' <= *p) && (*p <= '9')) {
+ val = *p - '0';
+ } else if (('A' <= *p) && (*p <= 'F')) {
+ val = *p - 'A' + 10;
+ } else {
+ result = ISC_R_BADHEX;
+ goto err;
+ }
+ ++p;
+ val <<= 4;
+ --len;
+ if (('0' <= *p) && (*p <= '9')) {
+ val |= (*p - '0');
+ } else if (('A' <= *p) && (*p <= 'F')) {
+ val |= (*p - 'A' + 10);
+ } else {
+ result = ISC_R_BADHEX;
+ goto err;
+ }
+ ++p;
+ --len;
+ isc_buffer_putuint8(buf, val);
+ }
+
+ result = ISC_R_SUCCESS;
+
+err:
+ isc_mem_put(mctx, data, size + 1);
+ return (result);
+}
+
+static void
+check_sig(const char *datapath, const char *sigpath, const char *keyname,
+ dns_keytag_t id, dns_secalg_t alg, int type, bool expect) {
+ isc_result_t result;
+ size_t rval, len;
+ FILE *fp;
+ dst_key_t *key = NULL;
+ unsigned char sig[512];
+ unsigned char *p;
+ unsigned char *data;
+ off_t size;
+ isc_buffer_t b;
+ isc_buffer_t databuf, sigbuf;
+ isc_region_t datareg, sigreg;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ dst_context_t *ctx = NULL;
+
+ /*
+ * Read data from file in a form usable by dst_verify.
+ */
+ result = isc_stdio_open(datapath, "rb", &fp);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_file_getsizefd(fileno(fp), &size);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ data = isc_mem_get(mctx, (size + 1));
+ assert_non_null(data);
+
+ p = data;
+ len = (size_t)size;
+ do {
+ result = isc_stdio_read(p, 1, len, fp, &rval);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ len -= rval;
+ p += rval;
+ } while (len);
+ isc_stdio_close(fp);
+
+ /*
+ * Read key from file in a form usable by dst_verify.
+ */
+ name = dns_fixedname_initname(&fname);
+ isc_buffer_constinit(&b, keyname, strlen(keyname));
+ isc_buffer_add(&b, strlen(keyname));
+ result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dst_key_fromfile(name, id, alg, type,
+ TESTS_DIR "/testdata/dst", mctx, &key);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_init(&databuf, data, (unsigned int)size);
+ isc_buffer_add(&databuf, (unsigned int)size);
+ isc_buffer_usedregion(&databuf, &datareg);
+
+ memset(sig, 0, sizeof(sig));
+ isc_buffer_init(&sigbuf, sig, sizeof(sig));
+
+ /*
+ * Read precomputed signature from file in a form usable by dst_verify.
+ */
+ result = sig_fromfile(sigpath, &sigbuf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Verify that the key signed the data.
+ */
+ isc_buffer_remainingregion(&sigbuf, &sigreg);
+
+ result = dst_context_create(key, mctx, DNS_LOGCATEGORY_GENERAL, false,
+ 0, &ctx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dst_context_adddata(ctx, &datareg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dst_context_verify(ctx, &sigreg);
+
+ /*
+ * Compute the expected signature and emit it
+ * so the precomputed signature can be updated.
+ * This should only be done if the covered data
+ * is updated.
+ */
+ if (expect && result != ISC_R_SUCCESS) {
+ isc_result_t result2;
+
+ dst_context_destroy(&ctx);
+ result2 = dst_context_create(key, mctx, DNS_LOGCATEGORY_GENERAL,
+ false, 0, &ctx);
+ assert_int_equal(result2, ISC_R_SUCCESS);
+
+ result2 = dst_context_adddata(ctx, &datareg);
+ assert_int_equal(result2, ISC_R_SUCCESS);
+
+ char sigbuf2[4096];
+ isc_buffer_t sigb;
+ isc_buffer_init(&sigb, sigbuf2, sizeof(sigbuf2));
+
+ result2 = dst_context_sign(ctx, &sigb);
+ assert_int_equal(result2, ISC_R_SUCCESS);
+
+ isc_region_t r;
+ isc_buffer_usedregion(&sigb, &r);
+
+ char hexbuf[4096] = { 0 };
+ isc_buffer_t hb;
+ isc_buffer_init(&hb, hexbuf, sizeof(hexbuf));
+
+ isc_hex_totext(&r, 0, "", &hb);
+
+ fprintf(stderr, "# %s:\n# %s\n", sigpath, hexbuf);
+ }
+
+ isc_mem_put(mctx, data, size + 1);
+ dst_context_destroy(&ctx);
+ dst_key_free(&key);
+
+ assert_true((expect && (result == ISC_R_SUCCESS)) ||
+ (!expect && (result != ISC_R_SUCCESS)));
+
+ return;
+}
+
+ISC_RUN_TEST_IMPL(sig_test) {
+ struct {
+ const char *datapath;
+ const char *sigpath;
+ const char *keyname;
+ dns_keytag_t keyid;
+ dns_secalg_t alg;
+ bool expect;
+ } testcases[] = {
+ { TESTS_DIR "/testdata/dst/test1.data",
+ TESTS_DIR "/testdata/dst/test1.ecdsa256sig", "test.", 49130,
+ DST_ALG_ECDSA256, true },
+ { TESTS_DIR "/testdata/dst/test1.data",
+ TESTS_DIR "/testdata/dst/test1.rsasha256sig", "test.", 11349,
+ DST_ALG_RSASHA256, true },
+ { /* wrong sig */
+ TESTS_DIR "/testdata/dst/test1.data",
+ TESTS_DIR "/testdata/dst/test1.ecdsa256sig", "test.", 11349,
+ DST_ALG_RSASHA256, false },
+ { /* wrong data */
+ TESTS_DIR "/testdata/dst/test2.data",
+ TESTS_DIR "/testdata/dst/test1.ecdsa256sig", "test.", 49130,
+ DST_ALG_ECDSA256, false },
+ };
+ unsigned int i;
+
+ for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
+ if (!dst_algorithm_supported(testcases[i].alg)) {
+ continue;
+ }
+
+ check_sig(testcases[i].datapath, testcases[i].sigpath,
+ testcases[i].keyname, testcases[i].keyid,
+ testcases[i].alg, DST_TYPE_PRIVATE | DST_TYPE_PUBLIC,
+ testcases[i].expect);
+ }
+}
+
+static void
+check_cmp(const char *key1_name, dns_keytag_t key1_id, const char *key2_name,
+ dns_keytag_t key2_id, dns_secalg_t alg, int type, bool expect) {
+ isc_result_t result;
+ dst_key_t *key1 = NULL;
+ dst_key_t *key2 = NULL;
+ isc_buffer_t b1;
+ isc_buffer_t b2;
+ dns_fixedname_t fname1;
+ dns_fixedname_t fname2;
+ dns_name_t *name1;
+ dns_name_t *name2;
+
+ /*
+ * Read key1 from the file.
+ */
+ name1 = dns_fixedname_initname(&fname1);
+ isc_buffer_constinit(&b1, key1_name, strlen(key1_name));
+ isc_buffer_add(&b1, strlen(key1_name));
+ result = dns_name_fromtext(name1, &b1, dns_rootname, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dst_key_fromfile(name1, key1_id, alg, type,
+ TESTS_DIR "/comparekeys", mctx, &key1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Read key2 from the file.
+ */
+ name2 = dns_fixedname_initname(&fname2);
+ isc_buffer_constinit(&b2, key2_name, strlen(key2_name));
+ isc_buffer_add(&b2, strlen(key2_name));
+ result = dns_name_fromtext(name2, &b2, dns_rootname, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dst_key_fromfile(name2, key2_id, alg, type,
+ TESTS_DIR "/comparekeys", mctx, &key2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Compare the keys (for public-only keys).
+ */
+ if ((type & DST_TYPE_PRIVATE) == 0) {
+ assert_true(dst_key_pubcompare(key1, key2, false) == expect);
+ }
+
+ /*
+ * Compare the keys (for both public-only keys and keypairs).
+ */
+ assert_true(dst_key_compare(key1, key2) == expect);
+
+ /*
+ * Free the keys
+ */
+ dst_key_free(&key2);
+ dst_key_free(&key1);
+
+ return;
+}
+
+ISC_RUN_TEST_IMPL(cmp_test) {
+ struct {
+ const char *key1_name;
+ dns_keytag_t key1_id;
+ const char *key2_name;
+ dns_keytag_t key2_id;
+ dns_secalg_t alg;
+ int type;
+ bool expect;
+ } testcases[] = {
+ /* RSA Keypair: self */
+ { "example.", 53461, "example.", 53461, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, true },
+
+ /* RSA Keypair: different key */
+ { "example.", 53461, "example2.", 37993, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, false },
+
+ /* RSA Keypair: different PublicExponent (e) */
+ { "example.", 53461, "example-e.", 53973, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, false },
+
+ /* RSA Keypair: different Modulus (n) */
+ { "example.", 53461, "example-n.", 37464, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, false },
+
+ /* RSA Keypair: different PrivateExponent (d) */
+ { "example.", 53461, "example-d.", 53461, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, false },
+
+ /* RSA Keypair: different Prime1 (p) */
+ { "example.", 53461, "example-p.", 53461, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, false },
+
+ /* RSA Keypair: different Prime2 (q) */
+ { "example.", 53461, "example-q.", 53461, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, false },
+
+ /* RSA Public Key: self */
+ { "example.", 53461, "example.", 53461, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC, true },
+
+ /* RSA Public Key: different key */
+ { "example.", 53461, "example2.", 37993, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC, false },
+
+ /* RSA Public Key: different PublicExponent (e) */
+ { "example.", 53461, "example-e.", 53973, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC, false },
+
+ /* RSA Public Key: different Modulus (n) */
+ { "example.", 53461, "example-n.", 37464, DST_ALG_RSASHA256,
+ DST_TYPE_PUBLIC, false },
+
+ /* ECDSA Keypair: self */
+ { "example.", 19786, "example.", 19786, DST_ALG_ECDSA256,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, true },
+
+ /* ECDSA Keypair: different key */
+ { "example.", 19786, "example2.", 16384, DST_ALG_ECDSA256,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, false },
+
+ /* ECDSA Public Key: self */
+ { "example.", 19786, "example.", 19786, DST_ALG_ECDSA256,
+ DST_TYPE_PUBLIC, true },
+
+ /* ECDSA Public Key: different key */
+ { "example.", 19786, "example2.", 16384, DST_ALG_ECDSA256,
+ DST_TYPE_PUBLIC, false },
+
+ /* EdDSA Keypair: self */
+ { "example.", 63663, "example.", 63663, DST_ALG_ED25519,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, true },
+
+ /* EdDSA Keypair: different key */
+ { "example.", 63663, "example2.", 37529, DST_ALG_ED25519,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, false },
+
+ /* EdDSA Public Key: self */
+ { "example.", 63663, "example.", 63663, DST_ALG_ED25519,
+ DST_TYPE_PUBLIC, true },
+
+ /* EdDSA Public Key: different key */
+ { "example.", 63663, "example2.", 37529, DST_ALG_ED25519,
+ DST_TYPE_PUBLIC, false },
+
+ /* DH Keypair: self */
+ { "example.", 65316, "example.", 65316, DST_ALG_DH,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY, true },
+
+ /* DH Keypair: different key */
+ { "example.", 65316, "example2.", 19823, DST_ALG_DH,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY, false },
+
+ /* DH Keypair: different key (with generator=5) */
+ { "example.", 65316, "example3.", 17187, DST_ALG_DH,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY, false },
+
+ /* DH Keypair: different private key */
+ { "example.", 65316, "example-private.", 65316, DST_ALG_DH,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY, false },
+
+ /* DH Public Key: self */
+ { "example.", 65316, "example.", 65316, DST_ALG_DH,
+ DST_TYPE_PUBLIC | DST_TYPE_KEY, true },
+
+ /* DH Public Key: different key */
+ { "example.", 65316, "example2.", 19823, DST_ALG_DH,
+ DST_TYPE_PUBLIC | DST_TYPE_KEY, false },
+
+ /* DH Public Key: different key (with generator=5) */
+ { "example.", 65316, "example3.", 17187, DST_ALG_DH,
+ DST_TYPE_PUBLIC | DST_TYPE_KEY, false },
+ };
+ unsigned int i;
+
+ for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
+ if (!dst_algorithm_supported(testcases[i].alg)) {
+ continue;
+ }
+
+ check_cmp(testcases[i].key1_name, testcases[i].key1_id,
+ testcases[i].key2_name, testcases[i].key2_id,
+ testcases[i].alg, testcases[i].type,
+ testcases[i].expect);
+ }
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(sig_test, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(cmp_test, setup_test, teardown_test)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/geoip_test.c b/tests/dns/geoip_test.c
new file mode 100644
index 0000000..2f5b166
--- /dev/null
+++ b/tests/dns/geoip_test.c
@@ -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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+#include <maxminddb.h>
+
+#include <isc/dir.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <dns/geoip.h>
+
+#include "geoip2.c"
+
+#include <tests/dns.h>
+
+static dns_geoip_databases_t geoip;
+
+static MMDB_s geoip_country, geoip_city, geoip_as, geoip_isp, geoip_domain;
+
+static void
+load_geoip(const char *dir);
+static void
+close_geoip(void);
+
+static int
+setup_test(void **state) {
+ UNUSED(state);
+
+ /* Use databases from the geoip system test */
+ load_geoip(TEST_GEOIP_DATA);
+
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ UNUSED(state);
+
+ close_geoip();
+
+ return (0);
+}
+
+static MMDB_s *
+open_geoip2(const char *dir, const char *dbfile, MMDB_s *mmdb) {
+ char pathbuf[PATH_MAX];
+ int ret;
+
+ snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dir, dbfile);
+ ret = MMDB_open(pathbuf, MMDB_MODE_MMAP, mmdb);
+ if (ret == MMDB_SUCCESS) {
+ return (mmdb);
+ }
+
+ return (NULL);
+}
+
+static void
+load_geoip(const char *dir) {
+ geoip.country = open_geoip2(dir, "GeoIP2-Country.mmdb", &geoip_country);
+ geoip.city = open_geoip2(dir, "GeoIP2-City.mmdb", &geoip_city);
+ geoip.as = open_geoip2(dir, "GeoLite2-ASN.mmdb", &geoip_as);
+ geoip.isp = open_geoip2(dir, "GeoIP2-ISP.mmdb", &geoip_isp);
+ geoip.domain = open_geoip2(dir, "GeoIP2-Domain.mmdb", &geoip_domain);
+}
+
+static void
+close_geoip(void) {
+ MMDB_close(&geoip_country);
+ MMDB_close(&geoip_city);
+ MMDB_close(&geoip_as);
+ MMDB_close(&geoip_isp);
+ MMDB_close(&geoip_domain);
+}
+
+static bool
+/* Check if an MMDB entry of a given subtype exists for the given IP */
+entry_exists(dns_geoip_subtype_t subtype, const char *addr) {
+ struct in6_addr in6;
+ struct in_addr in4;
+ isc_netaddr_t na;
+ MMDB_s *db;
+
+ if (inet_pton(AF_INET6, addr, &in6) == 1) {
+ isc_netaddr_fromin6(&na, &in6);
+ } else if (inet_pton(AF_INET, addr, &in4) == 1) {
+ isc_netaddr_fromin(&na, &in4);
+ } else {
+ UNREACHABLE();
+ }
+
+ db = geoip2_database(&geoip, fix_subtype(&geoip, subtype));
+
+ return (db != NULL && get_entry_for(db, &na) != NULL);
+}
+
+/*
+ * Baseline test - check if get_entry_for() works as expected, i.e. that its
+ * return values are consistent with the contents of the test MMDBs found in
+ * bin/tests/system/geoip2/data/ (10.53.0.1 and fd92:7065:b8e:ffff::1 should be
+ * present in all databases, 192.0.2.128 should only be present in the country
+ * database, ::1 should be absent from all databases).
+ */
+ISC_RUN_TEST_IMPL(baseline) {
+ dns_geoip_subtype_t subtype;
+
+ UNUSED(state);
+
+ subtype = dns_geoip_city_name;
+
+ assert_true(entry_exists(subtype, "10.53.0.1"));
+ assert_false(entry_exists(subtype, "192.0.2.128"));
+ assert_true(entry_exists(subtype, "fd92:7065:b8e:ffff::1"));
+ assert_false(entry_exists(subtype, "::1"));
+
+ subtype = dns_geoip_country_name;
+
+ assert_true(entry_exists(subtype, "10.53.0.1"));
+ assert_true(entry_exists(subtype, "192.0.2.128"));
+ assert_true(entry_exists(subtype, "fd92:7065:b8e:ffff::1"));
+ assert_false(entry_exists(subtype, "::1"));
+
+ subtype = dns_geoip_domain_name;
+
+ assert_true(entry_exists(subtype, "10.53.0.1"));
+ assert_false(entry_exists(subtype, "192.0.2.128"));
+ assert_true(entry_exists(subtype, "fd92:7065:b8e:ffff::1"));
+ assert_false(entry_exists(subtype, "::1"));
+
+ subtype = dns_geoip_isp_name;
+
+ assert_true(entry_exists(subtype, "10.53.0.1"));
+ assert_false(entry_exists(subtype, "192.0.2.128"));
+ assert_true(entry_exists(subtype, "fd92:7065:b8e:ffff::1"));
+ assert_false(entry_exists(subtype, "::1"));
+
+ subtype = dns_geoip_as_asnum;
+
+ assert_true(entry_exists(subtype, "10.53.0.1"));
+ assert_false(entry_exists(subtype, "192.0.2.128"));
+ assert_true(entry_exists(subtype, "fd92:7065:b8e:ffff::1"));
+ assert_false(entry_exists(subtype, "::1"));
+}
+
+static bool
+do_lookup_string(const char *addr, dns_geoip_subtype_t subtype,
+ const char *string) {
+ dns_geoip_elem_t elt;
+ struct in_addr in4;
+ isc_netaddr_t na;
+ int n;
+
+ n = inet_pton(AF_INET, addr, &in4);
+ assert_int_equal(n, 1);
+ isc_netaddr_fromin(&na, &in4);
+
+ elt.subtype = subtype;
+ strlcpy(elt.as_string, string, sizeof(elt.as_string));
+
+ return (dns_geoip_match(&na, &geoip, &elt));
+}
+
+static bool
+do_lookup_string_v6(const char *addr, dns_geoip_subtype_t subtype,
+ const char *string) {
+ dns_geoip_elem_t elt;
+ struct in6_addr in6;
+ isc_netaddr_t na;
+ int n;
+
+ n = inet_pton(AF_INET6, addr, &in6);
+ assert_int_equal(n, 1);
+ isc_netaddr_fromin6(&na, &in6);
+
+ elt.subtype = subtype;
+ strlcpy(elt.as_string, string, sizeof(elt.as_string));
+
+ return (dns_geoip_match(&na, &geoip, &elt));
+}
+
+/* GeoIP country matching */
+ISC_RUN_TEST_IMPL(country) {
+ bool match;
+
+ UNUSED(state);
+
+ if (geoip.country == NULL) {
+ skip();
+ }
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_country_code, "AU");
+ assert_true(match);
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_country_name,
+ "Australia");
+ assert_true(match);
+
+ match = do_lookup_string("192.0.2.128", dns_geoip_country_code, "O1");
+ assert_true(match);
+
+ match = do_lookup_string("192.0.2.128", dns_geoip_country_name,
+ "Other");
+ assert_true(match);
+}
+
+/* GeoIP country (ipv6) matching */
+ISC_RUN_TEST_IMPL(country_v6) {
+ bool match;
+
+ UNUSED(state);
+
+ if (geoip.country == NULL) {
+ skip();
+ }
+
+ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
+ dns_geoip_country_code, "AU");
+ assert_true(match);
+
+ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
+ dns_geoip_country_name, "Australia");
+ assert_true(match);
+}
+
+/* GeoIP city (ipv4) matching */
+ISC_RUN_TEST_IMPL(city) {
+ bool match;
+
+ UNUSED(state);
+
+ if (geoip.city == NULL) {
+ skip();
+ }
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_city_continentcode,
+ "NA");
+ assert_true(match);
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_city_countrycode, "US");
+ assert_true(match);
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_city_countryname,
+ "United States");
+ assert_true(match);
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_city_region, "CA");
+ assert_true(match);
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_city_regionname,
+ "California");
+ assert_true(match);
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_city_name,
+ "Redwood City");
+ assert_true(match);
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_city_postalcode,
+ "94063");
+ assert_true(match);
+}
+
+/* GeoIP city (ipv6) matching */
+ISC_RUN_TEST_IMPL(city_v6) {
+ bool match;
+
+ UNUSED(state);
+
+ if (geoip.city == NULL) {
+ skip();
+ }
+
+ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
+ dns_geoip_city_continentcode, "NA");
+ assert_true(match);
+
+ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
+ dns_geoip_city_countrycode, "US");
+ assert_true(match);
+
+ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
+ dns_geoip_city_countryname,
+ "United States");
+ assert_true(match);
+
+ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
+ dns_geoip_city_region, "CA");
+ assert_true(match);
+
+ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
+ dns_geoip_city_regionname, "California");
+ assert_true(match);
+
+ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
+ dns_geoip_city_name, "Redwood City");
+ assert_true(match);
+
+ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
+ dns_geoip_city_postalcode, "94063");
+ assert_true(match);
+}
+
+/* GeoIP asnum matching */
+ISC_RUN_TEST_IMPL(asnum) {
+ bool match;
+
+ UNUSED(state);
+
+ if (geoip.as == NULL) {
+ skip();
+ }
+
+ match = do_lookup_string("10.53.0.3", dns_geoip_as_asnum, "AS100003");
+ assert_true(match);
+}
+
+/* GeoIP isp matching */
+ISC_RUN_TEST_IMPL(isp) {
+ bool match;
+
+ UNUSED(state);
+
+ if (geoip.isp == NULL) {
+ skip();
+ }
+
+ match = do_lookup_string("10.53.0.1", dns_geoip_isp_name,
+ "One Systems, Inc.");
+ assert_true(match);
+}
+
+/* GeoIP org matching */
+ISC_RUN_TEST_IMPL(org) {
+ bool match;
+
+ UNUSED(state);
+
+ if (geoip.as == NULL) {
+ skip();
+ }
+
+ match = do_lookup_string("10.53.0.2", dns_geoip_org_name,
+ "Two Technology Ltd.");
+ assert_true(match);
+}
+
+/* GeoIP domain matching */
+ISC_RUN_TEST_IMPL(domain) {
+ bool match;
+
+ UNUSED(state);
+
+ if (geoip.domain == NULL) {
+ skip();
+ }
+
+ match = do_lookup_string("10.53.0.5", dns_geoip_domain_name, "five.es");
+ assert_true(match);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(baseline, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(country, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(country_v6, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(city, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(city_v6, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(asnum, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(isp, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(org, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(domain, setup_test, teardown_test)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/keytable_test.c b/tests/dns/keytable_test.c
new file mode 100644
index 0000000..615f90e
--- /dev/null
+++ b/tests/dns/keytable_test.c
@@ -0,0 +1,689 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/base64.h>
+#include <isc/buffer.h>
+#include <isc/md.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/keytable.h>
+#include <dns/name.h>
+#include <dns/nta.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatastruct.h>
+#include <dns/rootns.h>
+#include <dns/view.h>
+
+#include <dst/dst.h>
+
+#include <tests/dns.h>
+
+dns_keytable_t *keytable = NULL;
+dns_ntatable_t *ntatable = NULL;
+
+static const char *keystr1 = "BQEAAAABok+vaUC9neRv8yeT/"
+ "FEGgN7svR8s7VBUVSBd8NsAiV8AlaAg "
+ "O5FHar3JQd95i/puZos6Vi6at9/"
+ "JBbN8qVmO2AuiXxVqfxMKxIcy+LEB "
+ "0Vw4NaSJ3N3uaVREso6aTSs98H/"
+ "25MjcwLOr7SFfXA7bGhZatLtYY/xu kp6Km5hMfkE=";
+
+static const char *keystr2 = "BQEAAAABwuHz9Cem0BJ0JQTO7C/a3McR6hMaufljs1dfG/"
+ "inaJpYv7vH "
+ "XTrAOm/MeKp+/x6eT4QLru0KoZkvZJnqTI8JyaFTw2OM/"
+ "ItBfh/hL2lm "
+ "Cft2O7n3MfeqYtvjPnY7dWghYW4sVfH7VVEGm958o9nfi7953"
+ "2Qeklxh x8pXWdeAaRU=";
+
+static dns_view_t *view = NULL;
+
+/*
+ * Test utilities. In general, these assume input parameters are valid
+ * (checking with assert_int_equal, thus aborting if not) and unlikely run time
+ * errors (such as memory allocation failure) won't happen. This helps keep
+ * the test code concise.
+ */
+
+/*
+ * Utility to convert C-string to dns_name_t. Return a pointer to
+ * static data, and so is not thread safe.
+ */
+static dns_name_t *
+str2name(const char *namestr) {
+ static dns_fixedname_t fname;
+ static dns_name_t *name;
+ static isc_buffer_t namebuf;
+ void *deconst_namestr;
+
+ name = dns_fixedname_initname(&fname);
+ DE_CONST(namestr, deconst_namestr); /* OK, since we don't modify it */
+ isc_buffer_init(&namebuf, deconst_namestr, strlen(deconst_namestr));
+ isc_buffer_add(&namebuf, strlen(namestr));
+ assert_int_equal(
+ dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL),
+ ISC_R_SUCCESS);
+
+ return (name);
+}
+
+static void
+create_keystruct(uint16_t flags, uint8_t proto, uint8_t alg, const char *keystr,
+ dns_rdata_dnskey_t *keystruct) {
+ unsigned char keydata[4096];
+ isc_buffer_t keydatabuf;
+ isc_region_t r;
+ const dns_rdataclass_t rdclass = dns_rdataclass_in;
+
+ keystruct->common.rdclass = rdclass;
+ keystruct->common.rdtype = dns_rdatatype_dnskey;
+ keystruct->mctx = mctx;
+ ISC_LINK_INIT(&keystruct->common, link);
+ keystruct->flags = flags;
+ keystruct->protocol = proto;
+ keystruct->algorithm = alg;
+
+ isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
+ assert_int_equal(isc_base64_decodestring(keystr, &keydatabuf),
+ ISC_R_SUCCESS);
+ isc_buffer_usedregion(&keydatabuf, &r);
+ keystruct->datalen = r.length;
+ keystruct->data = isc_mem_allocate(mctx, r.length);
+ memmove(keystruct->data, r.base, r.length);
+}
+
+static void
+create_dsstruct(dns_name_t *name, uint16_t flags, uint8_t proto, uint8_t alg,
+ const char *keystr, unsigned char *digest,
+ dns_rdata_ds_t *dsstruct) {
+ isc_result_t result;
+ unsigned char rrdata[4096];
+ isc_buffer_t rrdatabuf;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_dnskey_t dnskey;
+
+ /*
+ * Populate DNSKEY rdata structure.
+ */
+ create_keystruct(flags, proto, alg, keystr, &dnskey);
+
+ /*
+ * Convert to wire format.
+ */
+ isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
+ result = dns_rdata_fromstruct(&rdata, dnskey.common.rdclass,
+ dnskey.common.rdtype, &dnskey,
+ &rrdatabuf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Build DS rdata struct.
+ */
+ result = dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, digest,
+ dsstruct);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_rdata_freestruct(&dnskey);
+}
+
+/* Common setup: create a keytable and ntatable to test with a few keys */
+static void
+create_tables(void) {
+ unsigned char digest[ISC_MAX_MD_SIZE];
+ dns_rdata_ds_t ds;
+ dns_fixedname_t fn;
+ dns_name_t *keyname = dns_fixedname_name(&fn);
+ isc_stdtime_t now;
+
+ assert_int_equal(dns_test_makeview("view", false, &view),
+ ISC_R_SUCCESS);
+
+ assert_int_equal(dns_keytable_create(mctx, &keytable), ISC_R_SUCCESS);
+ assert_int_equal(
+ dns_ntatable_create(view, taskmgr, timermgr, &ntatable),
+ ISC_R_SUCCESS);
+
+ /* Add a normal key */
+ dns_test_namefromstring("example.com", &fn);
+ create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
+ assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds,
+ NULL, NULL),
+ ISC_R_SUCCESS);
+
+ /* Add an initializing managed key */
+ dns_test_namefromstring("managed.com", &fn);
+ create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
+ assert_int_equal(dns_keytable_add(keytable, true, true, keyname, &ds,
+ NULL, NULL),
+ ISC_R_SUCCESS);
+
+ /* Add a null key */
+ assert_int_equal(
+ dns_keytable_marksecure(keytable, str2name("null.example")),
+ ISC_R_SUCCESS);
+
+ /* Add a negative trust anchor, duration 1 hour */
+ isc_stdtime_get(&now);
+ assert_int_equal(dns_ntatable_add(ntatable,
+ str2name("insecure.example"), false,
+ now, 3600),
+ ISC_R_SUCCESS);
+}
+
+static void
+destroy_tables(void) {
+ if (ntatable != NULL) {
+ dns_ntatable_detach(&ntatable);
+ }
+ if (keytable != NULL) {
+ dns_keytable_detach(&keytable);
+ }
+
+ dns_view_detach(&view);
+}
+
+/* add keys to the keytable */
+ISC_RUN_TEST_IMPL(dns_keytable_add) {
+ dns_keynode_t *keynode = NULL;
+ dns_keynode_t *null_keynode = NULL;
+ unsigned char digest[ISC_MAX_MD_SIZE];
+ dns_rdata_ds_t ds;
+ dns_fixedname_t fn;
+ dns_name_t *keyname = dns_fixedname_name(&fn);
+
+ UNUSED(state);
+
+ create_tables();
+
+ /*
+ * Getting the keynode for the example.com key should succeed.
+ */
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("example.com"), &keynode),
+ ISC_R_SUCCESS);
+
+ /*
+ * Try to add the same key. This should have no effect but
+ * report success.
+ */
+ dns_test_namefromstring("example.com", &fn);
+ create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
+ assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds,
+ NULL, NULL),
+ ISC_R_SUCCESS);
+ dns_keytable_detachkeynode(keytable, &keynode);
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("example.com"), &keynode),
+ ISC_R_SUCCESS);
+
+ /* Add another key (different keydata) */
+ dns_keytable_detachkeynode(keytable, &keynode);
+ create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds);
+ assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds,
+ NULL, NULL),
+ ISC_R_SUCCESS);
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("example.com"), &keynode),
+ ISC_R_SUCCESS);
+ dns_keytable_detachkeynode(keytable, &keynode);
+
+ /*
+ * Get the keynode for the managed.com key. Ensure the
+ * retrieved key is an initializing key, then mark it as trusted using
+ * dns_keynode_trust() and ensure the latter works as expected.
+ */
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("managed.com"), &keynode),
+ ISC_R_SUCCESS);
+ assert_int_equal(dns_keynode_initial(keynode), true);
+ dns_keynode_trust(keynode);
+ assert_int_equal(dns_keynode_initial(keynode), false);
+ dns_keytable_detachkeynode(keytable, &keynode);
+
+ /*
+ * Add a different managed key for managed.com, marking it as an
+ * initializing key. Since there is already a trusted key at the
+ * node, the node should *not* be marked as initializing.
+ */
+ dns_test_namefromstring("managed.com", &fn);
+ create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds);
+ assert_int_equal(dns_keytable_add(keytable, true, true, keyname, &ds,
+ NULL, NULL),
+ ISC_R_SUCCESS);
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("managed.com"), &keynode),
+ ISC_R_SUCCESS);
+ assert_int_equal(dns_keynode_initial(keynode), false);
+ dns_keytable_detachkeynode(keytable, &keynode);
+
+ /*
+ * Add the same managed key again, but this time mark it as a
+ * non-initializing key. Ensure the previously added key is upgraded
+ * to a non-initializing key and make sure there are still two key
+ * nodes for managed.com, both containing non-initializing keys.
+ */
+ assert_int_equal(dns_keytable_add(keytable, true, false, keyname, &ds,
+ NULL, NULL),
+ ISC_R_SUCCESS);
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("managed.com"), &keynode),
+ ISC_R_SUCCESS);
+ assert_int_equal(dns_keynode_initial(keynode), false);
+ dns_keytable_detachkeynode(keytable, &keynode);
+
+ /*
+ * Add a managed key at a new node, two.com, marking it as an
+ * initializing key.
+ */
+ dns_test_namefromstring("two.com", &fn);
+ create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
+ assert_int_equal(dns_keytable_add(keytable, true, true, keyname, &ds,
+ NULL, NULL),
+ ISC_R_SUCCESS);
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("two.com"), &keynode),
+ ISC_R_SUCCESS);
+ assert_int_equal(dns_keynode_initial(keynode), true);
+ dns_keytable_detachkeynode(keytable, &keynode);
+
+ /*
+ * Add a different managed key for two.com, marking it as a
+ * non-initializing key. Since there is already an iniitalizing
+ * trust anchor for two.com and we haven't run dns_keynode_trust(),
+ * the initialization status should not change.
+ */
+ create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds);
+ assert_int_equal(dns_keytable_add(keytable, true, false, keyname, &ds,
+ NULL, NULL),
+ ISC_R_SUCCESS);
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("two.com"), &keynode),
+ ISC_R_SUCCESS);
+ assert_int_equal(dns_keynode_initial(keynode), true);
+ dns_keytable_detachkeynode(keytable, &keynode);
+
+ /*
+ * Add a normal key to a name that has a null key. The null key node
+ * will be updated with the normal key.
+ */
+ assert_int_equal(dns_keytable_find(keytable, str2name("null.example"),
+ &null_keynode),
+ ISC_R_SUCCESS);
+ dns_test_namefromstring("null.example", &fn);
+ create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds);
+ assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds,
+ NULL, NULL),
+ ISC_R_SUCCESS);
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("null.example"), &keynode),
+ ISC_R_SUCCESS);
+ assert_ptr_equal(keynode, null_keynode); /* should be the same node */
+ dns_keytable_detachkeynode(keytable, &null_keynode);
+
+ /*
+ * Try to add a null key to a name that already has a key. It's
+ * effectively no-op, so the same key node is still there.
+ * (Note: this and above checks confirm that if a name has a null key
+ * that's the only key for the name).
+ */
+ assert_int_equal(
+ dns_keytable_marksecure(keytable, str2name("null.example")),
+ ISC_R_SUCCESS);
+ assert_int_equal(dns_keytable_find(keytable, str2name("null.example"),
+ &null_keynode),
+ ISC_R_SUCCESS);
+ assert_ptr_equal(keynode, null_keynode);
+ dns_keytable_detachkeynode(keytable, &null_keynode);
+
+ dns_keytable_detachkeynode(keytable, &keynode);
+ destroy_tables();
+}
+
+/* delete keys from the keytable */
+ISC_RUN_TEST_IMPL(dns_keytable_delete) {
+ create_tables();
+
+ /* dns_keytable_delete requires exact match */
+ assert_int_equal(dns_keytable_delete(keytable, str2name("example.org"),
+ NULL, NULL),
+ ISC_R_NOTFOUND);
+ assert_int_equal(dns_keytable_delete(keytable,
+ str2name("s.example.com"), NULL,
+ NULL),
+ ISC_R_NOTFOUND);
+ assert_int_equal(dns_keytable_delete(keytable, str2name("example.com"),
+ NULL, NULL),
+ ISC_R_SUCCESS);
+
+ /* works also for nodes with a null key */
+ assert_int_equal(dns_keytable_delete(keytable, str2name("null.example"),
+ NULL, NULL),
+ ISC_R_SUCCESS);
+
+ /* or a negative trust anchor */
+ assert_int_equal(
+ dns_ntatable_delete(ntatable, str2name("insecure.example")),
+ ISC_R_SUCCESS);
+
+ destroy_tables();
+}
+
+/* delete key nodes from the keytable */
+ISC_RUN_TEST_IMPL(dns_keytable_deletekey) {
+ dns_rdata_dnskey_t dnskey;
+ dns_fixedname_t fn;
+ dns_name_t *keyname = dns_fixedname_name(&fn);
+
+ UNUSED(state);
+
+ create_tables();
+
+ /* key name doesn't match */
+ dns_test_namefromstring("example.org", &fn);
+ create_keystruct(257, 3, 5, keystr1, &dnskey);
+ assert_int_equal(dns_keytable_deletekey(keytable, keyname, &dnskey),
+ ISC_R_NOTFOUND);
+ dns_rdata_freestruct(&dnskey);
+
+ /* subdomain match is the same as no match */
+ dns_test_namefromstring("sub.example.org", &fn);
+ create_keystruct(257, 3, 5, keystr1, &dnskey);
+ assert_int_equal(dns_keytable_deletekey(keytable, keyname, &dnskey),
+ ISC_R_NOTFOUND);
+ dns_rdata_freestruct(&dnskey);
+
+ /* name matches but key doesn't match (resulting in PARTIALMATCH) */
+ dns_test_namefromstring("example.com", &fn);
+ create_keystruct(257, 3, 5, keystr2, &dnskey);
+ assert_int_equal(dns_keytable_deletekey(keytable, keyname, &dnskey),
+ DNS_R_PARTIALMATCH);
+ dns_rdata_freestruct(&dnskey);
+
+ /*
+ * exact match: should return SUCCESS on the first try, then
+ * PARTIALMATCH on the second (because the name existed but
+ * not a matching key).
+ */
+ create_keystruct(257, 3, 5, keystr1, &dnskey);
+ assert_int_equal(dns_keytable_deletekey(keytable, keyname, &dnskey),
+ ISC_R_SUCCESS);
+ assert_int_equal(dns_keytable_deletekey(keytable, keyname, &dnskey),
+ DNS_R_PARTIALMATCH);
+
+ /*
+ * after deleting the node, any deletekey or delete attempt should
+ * result in NOTFOUND.
+ */
+ assert_int_equal(dns_keytable_delete(keytable, keyname, NULL, NULL),
+ ISC_R_SUCCESS);
+ assert_int_equal(dns_keytable_deletekey(keytable, keyname, &dnskey),
+ ISC_R_NOTFOUND);
+ dns_rdata_freestruct(&dnskey);
+
+ /*
+ * A null key node for a name is not deleted when searched by key;
+ * it must be deleted by dns_keytable_delete()
+ */
+ dns_test_namefromstring("null.example", &fn);
+ create_keystruct(257, 3, 5, keystr1, &dnskey);
+ assert_int_equal(dns_keytable_deletekey(keytable, keyname, &dnskey),
+ DNS_R_PARTIALMATCH);
+ assert_int_equal(dns_keytable_delete(keytable, keyname, NULL, NULL),
+ ISC_R_SUCCESS);
+ dns_rdata_freestruct(&dnskey);
+
+ destroy_tables();
+}
+
+/* check find-variant operations */
+ISC_RUN_TEST_IMPL(dns_keytable_find) {
+ dns_keynode_t *keynode = NULL;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ UNUSED(state);
+
+ create_tables();
+
+ /*
+ * dns_keytable_find() requires exact name match. It matches node
+ * that has a null key, too.
+ */
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("example.org"), &keynode),
+ ISC_R_NOTFOUND);
+ assert_int_equal(dns_keytable_find(keytable,
+ str2name("sub.example.com"),
+ &keynode),
+ ISC_R_NOTFOUND);
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("example.com"), &keynode),
+ ISC_R_SUCCESS);
+ dns_keytable_detachkeynode(keytable, &keynode);
+ assert_int_equal(
+ dns_keytable_find(keytable, str2name("null.example"), &keynode),
+ ISC_R_SUCCESS);
+ dns_keytable_detachkeynode(keytable, &keynode);
+
+ /*
+ * dns_keytable_finddeepestmatch() allows partial match. Also match
+ * nodes with a null key.
+ */
+ name = dns_fixedname_initname(&fname);
+ assert_int_equal(dns_keytable_finddeepestmatch(
+ keytable, str2name("example.com"), name),
+ ISC_R_SUCCESS);
+ assert_true(dns_name_equal(name, str2name("example.com")));
+ assert_int_equal(dns_keytable_finddeepestmatch(
+ keytable, str2name("s.example.com"), name),
+ ISC_R_SUCCESS);
+ assert_true(dns_name_equal(name, str2name("example.com")));
+ assert_int_equal(dns_keytable_finddeepestmatch(
+ keytable, str2name("example.org"), name),
+ ISC_R_NOTFOUND);
+ assert_int_equal(dns_keytable_finddeepestmatch(
+ keytable, str2name("null.example"), name),
+ ISC_R_SUCCESS);
+ assert_true(dns_name_equal(name, str2name("null.example")));
+
+ destroy_tables();
+}
+
+/* check issecuredomain() */
+ISC_RUN_TEST_IMPL(dns_keytable_issecuredomain) {
+ bool issecure;
+ const char **n;
+ const char *names[] = { "example.com", "sub.example.com",
+ "null.example", "sub.null.example", NULL };
+
+ UNUSED(state);
+ create_tables();
+
+ /*
+ * Domains that are an exact or partial match of a key name are
+ * considered secure. It's the case even if the key is null
+ * (validation will then fail, but that's actually the intended effect
+ * of installing a null key).
+ */
+ for (n = names; *n != NULL; n++) {
+ assert_int_equal(dns_keytable_issecuredomain(keytable,
+ str2name(*n), NULL,
+ &issecure),
+ ISC_R_SUCCESS);
+ assert_true(issecure);
+ }
+
+ /*
+ * If the key table has no entry (not even a null one) for a domain or
+ * any of its ancestors, that domain is considered insecure.
+ */
+ assert_int_equal(dns_keytable_issecuredomain(keytable,
+ str2name("example.org"),
+ NULL, &issecure),
+ ISC_R_SUCCESS);
+ assert_false(issecure);
+
+ destroy_tables();
+}
+
+/* check dns_keytable_dump() */
+ISC_RUN_TEST_IMPL(dns_keytable_dump) {
+ FILE *f = fopen("/dev/null", "w");
+
+ UNUSED(state);
+
+ create_tables();
+
+ /*
+ * Right now, we only confirm the dump attempt doesn't cause disruption
+ * (so we don't check the dump content).
+ */
+ assert_int_equal(dns_keytable_dump(keytable, f), ISC_R_SUCCESS);
+ fclose(f);
+
+ destroy_tables();
+}
+
+/* check negative trust anchors */
+ISC_RUN_TEST_IMPL(dns_keytable_nta) {
+ isc_result_t result;
+ bool issecure, covered;
+ dns_fixedname_t fn;
+ dns_name_t *keyname = dns_fixedname_name(&fn);
+ unsigned char digest[ISC_MAX_MD_SIZE];
+ dns_rdata_ds_t ds;
+ dns_view_t *myview = NULL;
+ isc_stdtime_t now;
+
+ UNUSED(state);
+
+ result = dns_test_makeview("view", false, &myview);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &myview->task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_view_initsecroots(myview, mctx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_view_getsecroots(myview, &keytable);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_view_initntatable(myview, taskmgr, timermgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_view_getntatable(myview, &ntatable);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_test_namefromstring("example", &fn);
+ create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
+ result = dns_keytable_add(keytable, false, false, keyname, &ds, NULL,
+ NULL),
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_stdtime_get(&now);
+ result = dns_ntatable_add(ntatable, str2name("insecure.example"), false,
+ now, 1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Should be secure */
+ result = dns_view_issecuredomain(myview,
+ str2name("test.secure.example"), now,
+ true, &covered, &issecure);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_false(covered);
+ assert_true(issecure);
+
+ /* Should not be secure */
+ result = dns_view_issecuredomain(myview,
+ str2name("test.insecure.example"), now,
+ true, &covered, &issecure);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(covered);
+ assert_false(issecure);
+
+ /* NTA covered */
+ covered = dns_view_ntacovers(myview, now, str2name("insecure.example"),
+ dns_rootname);
+ assert_true(covered);
+
+ /* Not NTA covered */
+ covered = dns_view_ntacovers(myview, now, str2name("secure.example"),
+ dns_rootname);
+ assert_false(covered);
+
+ /* As of now + 2, the NTA should be clear */
+ result = dns_view_issecuredomain(myview,
+ str2name("test.insecure.example"),
+ now + 2, true, &covered, &issecure);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_false(covered);
+ assert_true(issecure);
+
+ /* Now check deletion */
+ result = dns_view_issecuredomain(myview, str2name("test.new.example"),
+ now, true, &covered, &issecure);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_false(covered);
+ assert_true(issecure);
+
+ result = dns_ntatable_add(ntatable, str2name("new.example"), false, now,
+ 3600);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_view_issecuredomain(myview, str2name("test.new.example"),
+ now, true, &covered, &issecure);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(covered);
+ assert_false(issecure);
+
+ result = dns_ntatable_delete(ntatable, str2name("new.example"));
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_view_issecuredomain(myview, str2name("test.new.example"),
+ now, true, &covered, &issecure);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_false(covered);
+ assert_true(issecure);
+
+ /* Clean up */
+ dns_ntatable_detach(&ntatable);
+ dns_keytable_detach(&keytable);
+ dns_view_detach(&myview);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(dns_keytable_add, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(dns_keytable_delete, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(dns_keytable_deletekey, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(dns_keytable_find, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(dns_keytable_issecuredomain, setup_managers,
+ teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(dns_keytable_dump, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(dns_keytable_nta, setup_managers, teardown_managers)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/master_test.c b/tests/dns/master_test.c
new file mode 100644
index 0000000..eaebddd
--- /dev/null
+++ b/tests/dns/master_test.c
@@ -0,0 +1,582 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/dir.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/cache.h>
+#include <dns/callbacks.h>
+#include <dns/db.h>
+#include <dns/master.h>
+#include <dns/masterdump.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+
+#include <tests/dns.h>
+
+static void
+nullmsg(dns_rdatacallbacks_t *cb, const char *fmt, ...) {
+ UNUSED(cb);
+ UNUSED(fmt);
+}
+
+#define BUFLEN 255
+#define BIGBUFLEN (70 * 1024)
+#define TEST_ORIGIN "test"
+
+static dns_masterrawheader_t header;
+static bool headerset;
+
+dns_name_t dns_origin;
+char origin[sizeof(TEST_ORIGIN)];
+unsigned char name_buf[BUFLEN];
+dns_rdatacallbacks_t callbacks;
+char *include_file = NULL;
+
+static void
+rawdata_callback(dns_zone_t *zone, dns_masterrawheader_t *header);
+
+static isc_result_t
+add_callback(void *arg, const dns_name_t *owner, dns_rdataset_t *dataset) {
+ char buf[BIGBUFLEN];
+ isc_buffer_t target;
+ isc_result_t result;
+
+ UNUSED(arg);
+
+ isc_buffer_init(&target, buf, BIGBUFLEN);
+ result = dns_rdataset_totext(dataset, owner, false, false, &target);
+ return (result);
+}
+
+static void
+rawdata_callback(dns_zone_t *zone, dns_masterrawheader_t *h) {
+ UNUSED(zone);
+ header = *h;
+ headerset = true;
+}
+
+static isc_result_t
+setup_master(void (*warn)(struct dns_rdatacallbacks *, const char *, ...),
+ void (*error)(struct dns_rdatacallbacks *, const char *, ...)) {
+ isc_result_t result;
+ int len;
+ isc_buffer_t source;
+ isc_buffer_t target;
+
+ strlcpy(origin, TEST_ORIGIN, sizeof(origin));
+ len = strlen(origin);
+ isc_buffer_init(&source, origin, len);
+ isc_buffer_add(&source, len);
+ isc_buffer_setactive(&source, len);
+ isc_buffer_init(&target, name_buf, BUFLEN);
+ dns_name_init(&dns_origin, NULL);
+ dns_master_initrawheader(&header);
+
+ result = dns_name_fromtext(&dns_origin, &source, dns_rootname, 0,
+ &target);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ dns_rdatacallbacks_init_stdio(&callbacks);
+ callbacks.add = add_callback;
+ callbacks.rawdata = rawdata_callback;
+ callbacks.zone = NULL;
+ if (warn != NULL) {
+ callbacks.warn = warn;
+ }
+ if (error != NULL) {
+ callbacks.error = error;
+ }
+ headerset = false;
+ return (result);
+}
+
+static isc_result_t
+test_master(const char *workdir, const char *testfile,
+ dns_masterformat_t format,
+ void (*warn)(struct dns_rdatacallbacks *, const char *, ...),
+ void (*error)(struct dns_rdatacallbacks *, const char *, ...)) {
+ isc_result_t result;
+
+ result = setup_master(warn, error);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ dns_rdatacallbacks_init_stdio(&callbacks);
+ callbacks.add = add_callback;
+ callbacks.rawdata = rawdata_callback;
+ callbacks.zone = NULL;
+ if (warn != NULL) {
+ callbacks.warn = warn;
+ }
+ if (error != NULL) {
+ callbacks.error = error;
+ }
+
+ if (workdir != NULL) {
+ result = isc_dir_chdir(workdir);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+ }
+
+ result = dns_master_loadfile(testfile, &dns_origin, &dns_origin,
+ dns_rdataclass_in, true, 0, &callbacks,
+ NULL, NULL, mctx, format, 0);
+
+ return (result);
+}
+
+static void
+include_callback(const char *filename, void *arg) {
+ char **argp = (char **)arg;
+ *argp = isc_mem_strdup(mctx, filename);
+}
+
+/*
+ * Successful load test:
+ * dns_master_loadfile() loads a valid master file and returns success
+ */
+ISC_RUN_TEST_IMPL(load) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master1.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+/*
+ * Unexpected end of file test:
+ * dns_master_loadfile() returns DNS_R_UNEXPECTED when file ends too soon
+ */
+ISC_RUN_TEST_IMPL(unexpected) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master2.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_UNEXPECTEDEND);
+}
+
+/*
+ * No owner test:
+ * dns_master_loadfile() accepts broken zones with no TTL for first record
+ * if it is an SOA
+ */
+ISC_RUN_TEST_IMPL(noowner) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master3.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, DNS_R_NOOWNER);
+}
+
+/*
+ * No TTL test:
+ * dns_master_loadfile() returns DNS_R_NOOWNER when no owner name is
+ * specified
+ */
+ISC_RUN_TEST_IMPL(nottl) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master4.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+/*
+ * Bad class test:
+ * dns_master_loadfile() returns DNS_R_BADCLASS when record class doesn't
+ * match zone class
+ */
+ISC_RUN_TEST_IMPL(badclass) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master5.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, DNS_R_BADCLASS);
+}
+
+/*
+ * Too big rdata test:
+ * dns_master_loadfile() returns ISC_R_NOSPACE when record is too big
+ */
+ISC_RUN_TEST_IMPL(toobig) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master15.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_NOSPACE);
+}
+
+/*
+ * Maximum rdata test:
+ * dns_master_loadfile() returns ISC_R_SUCCESS when record is maximum size
+ */
+ISC_RUN_TEST_IMPL(maxrdata) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master16.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+/*
+ * DNSKEY test:
+ * dns_master_loadfile() understands DNSKEY with key material
+ */
+ISC_RUN_TEST_IMPL(dnskey) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master6.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+/*
+ * DNSKEY with no key material test:
+ * dns_master_loadfile() understands DNSKEY with no key material
+ *
+ * RFC 4034 removed the ability to signal NOKEY, so empty key material should
+ * be rejected.
+ */
+ISC_RUN_TEST_IMPL(dnsnokey) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master7.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_UNEXPECTEDEND);
+}
+
+/*
+ * Include test:
+ * dns_master_loadfile() understands $INCLUDE
+ */
+ISC_RUN_TEST_IMPL(include) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master8.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, DNS_R_SEENINCLUDE);
+}
+
+/*
+ * Include file list test:
+ * dns_master_loadfile4() returns names of included file
+ */
+ISC_RUN_TEST_IMPL(master_includelist) {
+ isc_result_t result;
+ char *filename = NULL;
+
+ UNUSED(state);
+
+ result = setup_master(nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_dir_chdir(SRCDIR);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_master_loadfile(
+ TESTS_DIR "/testdata/master/master8.data", &dns_origin,
+ &dns_origin, dns_rdataclass_in, 0, true, &callbacks,
+ include_callback, &filename, mctx, dns_masterformat_text, 0);
+ assert_int_equal(result, DNS_R_SEENINCLUDE);
+ assert_non_null(filename);
+ if (filename != NULL) {
+ assert_string_equal(filename, "testdata/master/master6.data");
+ isc_mem_free(mctx, filename);
+ }
+}
+
+/*
+ * Include failure test:
+ * dns_master_loadfile() understands $INCLUDE failures
+ */
+ISC_RUN_TEST_IMPL(includefail) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master9.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, DNS_R_BADCLASS);
+}
+
+/*
+ * Non-empty blank lines test:
+ * dns_master_loadfile() handles non-empty blank lines
+ */
+ISC_RUN_TEST_IMPL(blanklines) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master10.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+/*
+ * SOA leading zeroes test:
+ * dns_master_loadfile() allows leading zeroes in SOA
+ */
+
+ISC_RUN_TEST_IMPL(leadingzero) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master11.data",
+ dns_masterformat_text, nullmsg, nullmsg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+/* masterfile totext tests */
+ISC_RUN_TEST_IMPL(totext) {
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+ dns_rdatalist_t rdatalist;
+ isc_buffer_t target;
+ unsigned char buf[BIGBUFLEN];
+
+ UNUSED(state);
+
+ /* First, test with an empty rdataset */
+ dns_rdatalist_init(&rdatalist);
+ rdatalist.rdclass = dns_rdataclass_in;
+ rdatalist.type = dns_rdatatype_none;
+ rdatalist.covers = dns_rdatatype_none;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_init(&target, buf, BIGBUFLEN);
+ result = dns_master_rdatasettotext(dns_rootname, &rdataset,
+ &dns_master_style_debug, NULL,
+ &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_buffer_usedlength(&target), 0);
+
+ /*
+ * XXX: We will also need to add tests for dumping various
+ * rdata types, classes, etc, and comparing the results against
+ * known-good output.
+ */
+}
+
+/*
+ * Raw load test:
+ * dns_master_loadfile() loads a valid raw file and returns success
+ */
+ISC_RUN_TEST_IMPL(loadraw) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ /* Raw format version 0 */
+ result = test_master(BUILDDIR, "testdata/master/master12.data",
+ dns_masterformat_raw, nullmsg, nullmsg);
+ assert_string_equal(isc_result_totext(result), "success");
+ assert_true(headerset);
+ assert_int_equal(header.flags, 0);
+
+ /* Raw format version 1, no source serial */
+ result = test_master(BUILDDIR, "testdata/master/master13.data",
+ dns_masterformat_raw, nullmsg, nullmsg);
+ assert_string_equal(isc_result_totext(result), "success");
+ assert_true(headerset);
+ assert_int_equal(header.flags, 0);
+
+ /* Raw format version 1, source serial == 2011120101 */
+ result = test_master(BUILDDIR, "testdata/master/master14.data",
+ dns_masterformat_raw, nullmsg, nullmsg);
+ assert_string_equal(isc_result_totext(result), "success");
+ assert_true(headerset);
+ assert_true((header.flags & DNS_MASTERRAW_SOURCESERIALSET) != 0);
+ assert_int_equal(header.sourceserial, 2011120101);
+}
+
+/*
+ * Raw dump test:
+ * dns_master_dump*() functions dump valid raw files
+ */
+ISC_RUN_TEST_IMPL(dumpraw) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ dns_dbversion_t *version = NULL;
+ char myorigin[sizeof(TEST_ORIGIN)];
+ dns_name_t dnsorigin;
+ isc_buffer_t source, target;
+ unsigned char namebuf[BUFLEN];
+ int len;
+
+ UNUSED(state);
+
+ strlcpy(myorigin, TEST_ORIGIN, sizeof(myorigin));
+ len = strlen(myorigin);
+ isc_buffer_init(&source, myorigin, len);
+ isc_buffer_add(&source, len);
+ isc_buffer_setactive(&source, len);
+ isc_buffer_init(&target, namebuf, BUFLEN);
+ dns_name_init(&dnsorigin, NULL);
+ result = dns_name_fromtext(&dnsorigin, &source, dns_rootname, 0,
+ &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_create(mctx, "rbt", &dnsorigin, dns_dbtype_zone,
+ dns_rdataclass_in, 0, NULL, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_dir_chdir(SRCDIR);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_db_load(db, TESTS_DIR "/testdata/master/master1.data",
+ dns_masterformat_text, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_dir_chdir(BUILDDIR);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_db_currentversion(db, &version);
+
+ result = dns_master_dump(mctx, db, version, &dns_master_style_default,
+ "test.dump", dns_masterformat_raw, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = test_master(NULL, "test.dump", dns_masterformat_raw, nullmsg,
+ nullmsg);
+ assert_string_equal(isc_result_totext(result), "success");
+ assert_true(headerset);
+ assert_int_equal(header.flags, 0);
+
+ dns_master_initrawheader(&header);
+ header.sourceserial = 12345;
+ header.flags |= DNS_MASTERRAW_SOURCESERIALSET;
+
+ unlink("test.dump");
+ result = dns_master_dump(mctx, db, version, &dns_master_style_default,
+ "test.dump", dns_masterformat_raw, &header);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = test_master(NULL, "test.dump", dns_masterformat_raw, nullmsg,
+ nullmsg);
+ assert_string_equal(isc_result_totext(result), "success");
+ assert_true(headerset);
+ assert_true((header.flags & DNS_MASTERRAW_SOURCESERIALSET) != 0);
+ assert_int_equal(header.sourceserial, 12345);
+
+ unlink("test.dump");
+ dns_db_closeversion(db, &version, false);
+ dns_db_detach(&db);
+}
+
+static const char *warn_expect_value;
+static bool warn_expect_result;
+
+static void
+warn_expect(struct dns_rdatacallbacks *mycallbacks, const char *fmt, ...) {
+ char buf[4096];
+ va_list ap;
+
+ UNUSED(mycallbacks);
+
+ warn_expect_result = false;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ if (warn_expect_value != NULL && strstr(buf, warn_expect_value) != NULL)
+ {
+ warn_expect_result = true;
+ }
+}
+
+/*
+ * Origin change test:
+ * dns_master_loadfile() rejects zones with inherited name following $ORIGIN
+ */
+ISC_RUN_TEST_IMPL(neworigin) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ warn_expect_value = "record with inherited owner";
+ result = test_master(SRCDIR, TESTS_DIR "/testdata/master/master17.data",
+ dns_masterformat_text, warn_expect, nullmsg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(warn_expect_result);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(load)
+ISC_TEST_ENTRY(unexpected)
+ISC_TEST_ENTRY(noowner)
+ISC_TEST_ENTRY(nottl)
+ISC_TEST_ENTRY(badclass)
+ISC_TEST_ENTRY(dnskey)
+ISC_TEST_ENTRY(dnsnokey)
+ISC_TEST_ENTRY(include)
+ISC_TEST_ENTRY(master_includelist)
+ISC_TEST_ENTRY(includefail)
+ISC_TEST_ENTRY(blanklines)
+ISC_TEST_ENTRY(leadingzero)
+ISC_TEST_ENTRY(totext)
+ISC_TEST_ENTRY(loadraw)
+ISC_TEST_ENTRY(dumpraw)
+ISC_TEST_ENTRY(toobig)
+ISC_TEST_ENTRY(maxrdata)
+ISC_TEST_ENTRY(neworigin)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/mkraw.pl b/tests/dns/mkraw.pl
new file mode 100644
index 0000000..5e0db75
--- /dev/null
+++ b/tests/dns/mkraw.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Convert a hexdump to binary format.
+#
+# To convert binary data to the input format for this command,
+# use the following:
+#
+# perl -e 'while (read(STDIN, my $byte, 1)) {
+# print unpack("H2", $byte);
+# }
+# print "\n";' < file > file.in
+
+use strict;
+chomp(my $line = <STDIN>);
+print pack("H*", $line);
diff --git a/tests/dns/name_test.c b/tests/dns/name_test.c
new file mode 100644
index 0000000..511ee3c
--- /dev/null
+++ b/tests/dns/name_test.c
@@ -0,0 +1,731 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/commandline.h>
+#include <isc/mem.h>
+#include <isc/os.h>
+#include <isc/print.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include <dns/compress.h>
+#include <dns/fixedname.h>
+#include <dns/name.h>
+
+#include <tests/dns.h>
+
+/* Set to true (or use -v option) for verbose output */
+static bool verbose = false;
+
+/* dns_name_fullcompare test */
+ISC_RUN_TEST_IMPL(fullcompare) {
+ dns_fixedname_t fixed1;
+ dns_fixedname_t fixed2;
+ dns_name_t *name1;
+ dns_name_t *name2;
+ dns_namereln_t relation;
+ int i;
+ isc_result_t result;
+ struct {
+ const char *name1;
+ const char *name2;
+ dns_namereln_t relation;
+ int order;
+ unsigned int nlabels;
+ } data[] = {
+ /* relative */
+ { "", "", dns_namereln_equal, 0, 0 },
+ { "foo", "", dns_namereln_subdomain, 1, 0 },
+ { "", "foo", dns_namereln_contains, -1, 0 },
+ { "foo", "bar", dns_namereln_none, 4, 0 },
+ { "bar", "foo", dns_namereln_none, -4, 0 },
+ { "bar.foo", "foo", dns_namereln_subdomain, 1, 1 },
+ { "foo", "bar.foo", dns_namereln_contains, -1, 1 },
+ { "baz.bar.foo", "bar.foo", dns_namereln_subdomain, 1, 2 },
+ { "bar.foo", "baz.bar.foo", dns_namereln_contains, -1, 2 },
+ { "foo.example", "bar.example", dns_namereln_commonancestor, 4,
+ 1 },
+
+ /* absolute */
+ { ".", ".", dns_namereln_equal, 0, 1 },
+ { "foo.", "bar.", dns_namereln_commonancestor, 4, 1 },
+ { "bar.", "foo.", dns_namereln_commonancestor, -4, 1 },
+ { "foo.example.", "bar.example.", dns_namereln_commonancestor,
+ 4, 2 },
+ { "bar.foo.", "foo.", dns_namereln_subdomain, 1, 2 },
+ { "foo.", "bar.foo.", dns_namereln_contains, -1, 2 },
+ { "baz.bar.foo.", "bar.foo.", dns_namereln_subdomain, 1, 3 },
+ { "bar.foo.", "baz.bar.foo.", dns_namereln_contains, -1, 3 },
+ { NULL, NULL, dns_namereln_none, 0, 0 }
+ };
+
+ UNUSED(state);
+
+ name1 = dns_fixedname_initname(&fixed1);
+ name2 = dns_fixedname_initname(&fixed2);
+ for (i = 0; data[i].name1 != NULL; i++) {
+ int order = 3000;
+ unsigned int nlabels = 3000;
+
+ if (data[i].name1[0] == 0) {
+ dns_fixedname_init(&fixed1);
+ } else {
+ result = dns_name_fromstring2(name1, data[i].name1,
+ NULL, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+ if (data[i].name2[0] == 0) {
+ dns_fixedname_init(&fixed2);
+ } else {
+ result = dns_name_fromstring2(name2, data[i].name2,
+ NULL, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+ relation = dns_name_fullcompare(name1, name1, &order, &nlabels);
+ assert_int_equal(relation, dns_namereln_equal);
+ assert_int_equal(order, 0);
+ assert_int_equal(nlabels, name1->labels);
+
+ /* Some random initializer */
+ order = 3001;
+ nlabels = 3001;
+
+ relation = dns_name_fullcompare(name1, name2, &order, &nlabels);
+ assert_int_equal(relation, data[i].relation);
+ assert_int_equal(order, data[i].order);
+ assert_int_equal(nlabels, data[i].nlabels);
+ }
+}
+
+static void
+compress_test(dns_name_t *name1, dns_name_t *name2, dns_name_t *name3,
+ unsigned char *expected, unsigned int length,
+ dns_compress_t *cctx, dns_decompress_t *dctx) {
+ isc_buffer_t source;
+ isc_buffer_t target;
+ dns_name_t name;
+ unsigned char buf1[1024];
+ unsigned char buf2[1024];
+
+ isc_buffer_init(&source, buf1, sizeof(buf1));
+ isc_buffer_init(&target, buf2, sizeof(buf2));
+
+ assert_int_equal(dns_name_towire(name1, cctx, &source), ISC_R_SUCCESS);
+
+ assert_int_equal(dns_name_towire(name2, cctx, &source), ISC_R_SUCCESS);
+ assert_int_equal(dns_name_towire(name2, cctx, &source), ISC_R_SUCCESS);
+ assert_int_equal(dns_name_towire(name3, cctx, &source), ISC_R_SUCCESS);
+
+ isc_buffer_setactive(&source, source.used);
+
+ dns_name_init(&name, NULL);
+ RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, 0, &target) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, 0, &target) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, 0, &target) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, 0, &target) ==
+ ISC_R_SUCCESS);
+ dns_decompress_invalidate(dctx);
+
+ assert_int_equal(target.used, length);
+ assert_true(memcmp(target.base, expected, target.used) == 0);
+}
+
+/* name compression test */
+ISC_RUN_TEST_IMPL(compression) {
+ unsigned int allowed;
+ dns_compress_t cctx;
+ dns_decompress_t dctx;
+ dns_name_t name1;
+ dns_name_t name2;
+ dns_name_t name3;
+ isc_region_t r;
+ unsigned char plain1[] = "\003yyy\003foo";
+ unsigned char plain2[] = "\003bar\003yyy\003foo";
+ unsigned char plain3[] = "\003xxx\003bar\003foo";
+ unsigned char plain[] = "\003yyy\003foo\0\003bar\003yyy\003foo\0\003"
+ "bar\003yyy\003foo\0\003xxx\003bar\003foo";
+
+ UNUSED(state);
+
+ dns_name_init(&name1, NULL);
+ r.base = plain1;
+ r.length = sizeof(plain1);
+ dns_name_fromregion(&name1, &r);
+
+ dns_name_init(&name2, NULL);
+ r.base = plain2;
+ r.length = sizeof(plain2);
+ dns_name_fromregion(&name2, &r);
+
+ dns_name_init(&name3, NULL);
+ r.base = plain3;
+ r.length = sizeof(plain3);
+ dns_name_fromregion(&name3, &r);
+
+ /* Test 1: NONE */
+ allowed = DNS_COMPRESS_NONE;
+ assert_int_equal(dns_compress_init(&cctx, -1, mctx), ISC_R_SUCCESS);
+ dns_compress_setmethods(&cctx, allowed);
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_STRICT);
+ dns_decompress_setmethods(&dctx, allowed);
+
+ compress_test(&name1, &name2, &name3, plain, sizeof(plain), &cctx,
+ &dctx);
+
+ dns_compress_rollback(&cctx, 0);
+ dns_compress_invalidate(&cctx);
+
+ /* Test2: GLOBAL14 */
+ allowed = DNS_COMPRESS_GLOBAL14;
+ assert_int_equal(dns_compress_init(&cctx, -1, mctx), ISC_R_SUCCESS);
+ dns_compress_setmethods(&cctx, allowed);
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_STRICT);
+ dns_decompress_setmethods(&dctx, allowed);
+
+ compress_test(&name1, &name2, &name3, plain, sizeof(plain), &cctx,
+ &dctx);
+
+ dns_compress_rollback(&cctx, 0);
+ dns_compress_invalidate(&cctx);
+
+ /* Test3: ALL */
+ allowed = DNS_COMPRESS_ALL;
+ assert_int_equal(dns_compress_init(&cctx, -1, mctx), ISC_R_SUCCESS);
+ dns_compress_setmethods(&cctx, allowed);
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_STRICT);
+ dns_decompress_setmethods(&dctx, allowed);
+
+ compress_test(&name1, &name2, &name3, plain, sizeof(plain), &cctx,
+ &dctx);
+
+ dns_compress_rollback(&cctx, 0);
+ dns_compress_invalidate(&cctx);
+
+ /* Test4: NONE disabled */
+ allowed = DNS_COMPRESS_NONE;
+ assert_int_equal(dns_compress_init(&cctx, -1, mctx), ISC_R_SUCCESS);
+ dns_compress_setmethods(&cctx, allowed);
+ dns_compress_disable(&cctx);
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_STRICT);
+ dns_decompress_setmethods(&dctx, allowed);
+
+ compress_test(&name1, &name2, &name3, plain, sizeof(plain), &cctx,
+ &dctx);
+
+ dns_compress_rollback(&cctx, 0);
+ dns_compress_invalidate(&cctx);
+
+ /* Test5: GLOBAL14 disabled */
+ allowed = DNS_COMPRESS_GLOBAL14;
+ assert_int_equal(dns_compress_init(&cctx, -1, mctx), ISC_R_SUCCESS);
+ dns_compress_setmethods(&cctx, allowed);
+ dns_compress_disable(&cctx);
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_STRICT);
+ dns_decompress_setmethods(&dctx, allowed);
+
+ compress_test(&name1, &name2, &name3, plain, sizeof(plain), &cctx,
+ &dctx);
+
+ dns_compress_rollback(&cctx, 0);
+ dns_compress_invalidate(&cctx);
+
+ /* Test6: ALL disabled */
+ allowed = DNS_COMPRESS_ALL;
+ assert_int_equal(dns_compress_init(&cctx, -1, mctx), ISC_R_SUCCESS);
+ dns_compress_setmethods(&cctx, allowed);
+ dns_compress_disable(&cctx);
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_STRICT);
+ dns_decompress_setmethods(&dctx, allowed);
+
+ compress_test(&name1, &name2, &name3, plain, sizeof(plain), &cctx,
+ &dctx);
+
+ dns_compress_rollback(&cctx, 0);
+ dns_compress_invalidate(&cctx);
+}
+
+/* is trust-anchor-telemetry test */
+ISC_RUN_TEST_IMPL(istat) {
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ isc_result_t result;
+ size_t i;
+ struct {
+ const char *name;
+ bool istat;
+ } data[] = { { ".", false },
+ { "_ta-", false },
+ { "_ta-1234", true },
+ { "_TA-1234", true },
+ { "+TA-1234", false },
+ { "_fa-1234", false },
+ { "_td-1234", false },
+ { "_ta_1234", false },
+ { "_ta-g234", false },
+ { "_ta-1h34", false },
+ { "_ta-12i4", false },
+ { "_ta-123j", false },
+ { "_ta-1234-abcf", true },
+ { "_ta-1234-abcf-ED89", true },
+ { "_ta-12345-abcf-ED89", false },
+ { "_ta-.example", false },
+ { "_ta-1234.example", true },
+ { "_ta-1234-abcf.example", true },
+ { "_ta-1234-abcf-ED89.example", true },
+ { "_ta-12345-abcf-ED89.example", false },
+ { "_ta-1234-abcfe-ED89.example", false },
+ { "_ta-1234-abcf-EcD89.example", false } };
+
+ UNUSED(state);
+
+ name = dns_fixedname_initname(&fixed);
+
+ for (i = 0; i < (sizeof(data) / sizeof(data[0])); i++) {
+ result = dns_name_fromstring(name, data[i].name, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(dns_name_istat(name), data[i].istat);
+ }
+}
+
+/* dns_nane_init */
+ISC_RUN_TEST_IMPL(init) {
+ dns_name_t name;
+ unsigned char offsets[1];
+
+ UNUSED(state);
+
+ dns_name_init(&name, offsets);
+
+ assert_null(name.ndata);
+ assert_int_equal(name.length, 0);
+ assert_int_equal(name.labels, 0);
+ assert_int_equal(name.attributes, 0);
+ assert_ptr_equal(name.offsets, offsets);
+ assert_null(name.buffer);
+}
+
+/* dns_nane_invalidate */
+ISC_RUN_TEST_IMPL(invalidate) {
+ dns_name_t name;
+ unsigned char offsets[1];
+
+ UNUSED(state);
+
+ dns_name_init(&name, offsets);
+ dns_name_invalidate(&name);
+
+ assert_null(name.ndata);
+ assert_int_equal(name.length, 0);
+ assert_int_equal(name.labels, 0);
+ assert_int_equal(name.attributes, 0);
+ assert_null(name.offsets);
+ assert_null(name.buffer);
+}
+
+/* dns_nane_setbuffer/hasbuffer */
+ISC_RUN_TEST_IMPL(buffer) {
+ dns_name_t name;
+ unsigned char buf[BUFSIZ];
+ isc_buffer_t b;
+
+ UNUSED(state);
+
+ isc_buffer_init(&b, buf, BUFSIZ);
+ dns_name_init(&name, NULL);
+ dns_name_setbuffer(&name, &b);
+ assert_ptr_equal(name.buffer, &b);
+ assert_true(dns_name_hasbuffer(&name));
+}
+
+/* dns_nane_isabsolute */
+ISC_RUN_TEST_IMPL(isabsolute) {
+ struct {
+ const char *namestr;
+ bool expect;
+ } testcases[] = { { "x", false },
+ { "a.b.c.d.", true },
+ { "x.z", false } };
+ unsigned int i;
+
+ UNUSED(state);
+
+ for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
+ isc_result_t result;
+ dns_name_t name;
+ unsigned char data[BUFSIZ];
+ isc_buffer_t b, nb;
+ size_t len;
+
+ len = strlen(testcases[i].namestr);
+ isc_buffer_constinit(&b, testcases[i].namestr, len);
+ isc_buffer_add(&b, len);
+
+ dns_name_init(&name, NULL);
+ isc_buffer_init(&nb, data, BUFSIZ);
+ dns_name_setbuffer(&name, &nb);
+ result = dns_name_fromtext(&name, &b, NULL, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_int_equal(dns_name_isabsolute(&name),
+ testcases[i].expect);
+ }
+}
+
+/* dns_nane_hash */
+ISC_RUN_TEST_IMPL(hash) {
+ struct {
+ const char *name1;
+ const char *name2;
+ bool expect;
+ bool expecti;
+ } testcases[] = {
+ { "a.b.c.d", "A.B.C.D", true, false },
+ { "a.b.c.d.", "A.B.C.D.", true, false },
+ { "a.b.c.d", "a.b.c.d", true, true },
+ { "A.B.C.D.", "A.B.C.D.", true, false },
+ { "x.y.z.w", "a.b.c.d", false, false },
+ { "x.y.z.w.", "a.b.c.d.", false, false },
+ };
+ unsigned int i;
+
+ UNUSED(state);
+
+ for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
+ isc_result_t result;
+ dns_fixedname_t f1, f2;
+ dns_name_t *n1, *n2;
+ unsigned int h1, h2;
+
+ n1 = dns_fixedname_initname(&f1);
+ n2 = dns_fixedname_initname(&f2);
+
+ result = dns_name_fromstring2(n1, testcases[i].name1, NULL, 0,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_name_fromstring2(n2, testcases[i].name2, NULL, 0,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Check case-insensitive hashing first */
+ h1 = dns_name_hash(n1, false);
+ h2 = dns_name_hash(n2, false);
+
+ if (verbose) {
+ print_message("# %s hashes to %u, "
+ "%s to %u, case insensitive\n",
+ testcases[i].name1, h1,
+ testcases[i].name2, h2);
+ }
+
+ assert_int_equal((h1 == h2), testcases[i].expect);
+
+ /* Now case-sensitive */
+ h1 = dns_name_hash(n1, false);
+ h2 = dns_name_hash(n2, false);
+
+ if (verbose) {
+ print_message("# %s hashes to %u, "
+ "%s to %u, case sensitive\n",
+ testcases[i].name1, h1,
+ testcases[i].name2, h2);
+ }
+
+ assert_int_equal((h1 == h2), testcases[i].expect);
+ }
+}
+
+/* dns_nane_issubdomain */
+ISC_RUN_TEST_IMPL(issubdomain) {
+ struct {
+ const char *name1;
+ const char *name2;
+ bool expect;
+ } testcases[] = {
+ { "c.d", "a.b.c.d", false }, { "c.d.", "a.b.c.d.", false },
+ { "b.c.d", "c.d", true }, { "a.b.c.d.", "c.d.", true },
+ { "a.b.c", "a.b.c", true }, { "a.b.c.", "a.b.c.", true },
+ { "x.y.z", "a.b.c", false }
+ };
+ unsigned int i;
+
+ UNUSED(state);
+
+ for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
+ isc_result_t result;
+ dns_fixedname_t f1, f2;
+ dns_name_t *n1, *n2;
+
+ n1 = dns_fixedname_initname(&f1);
+ n2 = dns_fixedname_initname(&f2);
+
+ result = dns_name_fromstring2(n1, testcases[i].name1, NULL, 0,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_name_fromstring2(n2, testcases[i].name2, NULL, 0,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ if (verbose) {
+ print_message("# check: %s %s a subdomain of %s\n",
+ testcases[i].name1,
+ testcases[i].expect ? "is" : "is not",
+ testcases[i].name2);
+ }
+
+ assert_int_equal(dns_name_issubdomain(n1, n2),
+ testcases[i].expect);
+ }
+}
+
+/* dns_nane_countlabels */
+ISC_RUN_TEST_IMPL(countlabels) {
+ struct {
+ const char *namestr;
+ unsigned int expect;
+ } testcases[] = {
+ { "c.d", 2 }, { "c.d.", 3 }, { "a.b.c.d.", 5 },
+ { "a.b.c.d", 4 }, { "a.b.c", 3 }, { ".", 1 },
+ };
+ unsigned int i;
+
+ UNUSED(state);
+
+ for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
+ isc_result_t result;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ name = dns_fixedname_initname(&fname);
+
+ result = dns_name_fromstring2(name, testcases[i].namestr, NULL,
+ 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ if (verbose) {
+ print_message("# %s: expect %u labels\n",
+ testcases[i].namestr,
+ testcases[i].expect);
+ }
+
+ assert_int_equal(dns_name_countlabels(name),
+ testcases[i].expect);
+ }
+}
+
+/* dns_nane_getlabel */
+ISC_RUN_TEST_IMPL(getlabel) {
+ struct {
+ const char *name1;
+ unsigned int pos1;
+ const char *name2;
+ unsigned int pos2;
+ } testcases[] = {
+ { "c.d", 1, "a.b.c.d", 3 },
+ { "a.b.c.d", 3, "c.d", 1 },
+ { "a.b.c.", 3, "A.B.C.", 3 },
+ };
+ unsigned int i;
+
+ UNUSED(state);
+
+ for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
+ isc_result_t result;
+ dns_fixedname_t f1, f2;
+ dns_name_t *n1, *n2;
+ dns_label_t l1, l2;
+ unsigned int j;
+
+ n1 = dns_fixedname_initname(&f1);
+ n2 = dns_fixedname_initname(&f2);
+
+ result = dns_name_fromstring2(n1, testcases[i].name1, NULL, 0,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_name_fromstring2(n2, testcases[i].name2, NULL, 0,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_name_getlabel(n1, testcases[i].pos1, &l1);
+ dns_name_getlabel(n2, testcases[i].pos2, &l2);
+ assert_int_equal(l1.length, l2.length);
+
+ for (j = 0; j < l1.length; j++) {
+ assert_int_equal(l1.base[j], l2.base[j]);
+ }
+ }
+}
+
+/* dns_nane_getlabelsequence */
+ISC_RUN_TEST_IMPL(getlabelsequence) {
+ struct {
+ const char *name1;
+ unsigned int pos1;
+ const char *name2;
+ unsigned int pos2;
+ unsigned int range;
+ } testcases[] = {
+ { "c.d", 1, "a.b.c.d", 3, 1 },
+ { "a.b.c.d.e", 2, "c.d", 0, 2 },
+ { "a.b.c", 0, "a.b.c", 0, 3 },
+ };
+ unsigned int i;
+
+ UNUSED(state);
+
+ for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
+ isc_result_t result;
+ dns_name_t t1, t2;
+ dns_fixedname_t f1, f2;
+ dns_name_t *n1, *n2;
+
+ /* target names */
+ dns_name_init(&t1, NULL);
+ dns_name_init(&t2, NULL);
+
+ /* source names */
+ n1 = dns_fixedname_initname(&f1);
+ n2 = dns_fixedname_initname(&f2);
+
+ result = dns_name_fromstring2(n1, testcases[i].name1, NULL, 0,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_name_fromstring2(n2, testcases[i].name2, NULL, 0,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_name_getlabelsequence(n1, testcases[i].pos1,
+ testcases[i].range, &t1);
+ dns_name_getlabelsequence(n2, testcases[i].pos2,
+ testcases[i].range, &t2);
+
+ assert_true(dns_name_equal(&t1, &t2));
+ }
+}
+
+#ifdef DNS_BENCHMARK_TESTS
+
+/*
+ * XXXMUKS: Don't delete this code. It is useful in benchmarking the
+ * name parser, but we don't require it as part of the unit test runs.
+ */
+
+/* Benchmark dns_name_fromwire() implementation */
+
+ISC_RUN_TEST_IMPL(fromwire_thread(void *arg) {
+ unsigned int maxval = 32000000;
+ uint8_t data[] = { 3, 'w', 'w', 'w', 7, 'e', 'x',
+ 'a', 'm', 'p', 'l', 'e', 7, 'i',
+ 'n', 'v', 'a', 'l', 'i', 'd', 0 };
+ unsigned char output_data[DNS_NAME_MAXWIRE];
+ isc_buffer_t source, target;
+ unsigned int i;
+ dns_decompress_t dctx;
+
+ UNUSED(arg);
+
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_STRICT);
+ dns_decompress_setmethods(&dctx, DNS_COMPRESS_NONE);
+
+ isc_buffer_init(&source, data, sizeof(data));
+ isc_buffer_add(&source, sizeof(data));
+ isc_buffer_init(&target, output_data, sizeof(output_data));
+
+ /* Parse 32 million names in each thread */
+ for (i = 0; i < maxval; i++) {
+ dns_name_t name;
+
+ isc_buffer_clear(&source);
+ isc_buffer_clear(&target);
+ isc_buffer_add(&source, sizeof(data));
+ isc_buffer_setactive(&source, sizeof(data));
+
+ dns_name_init(&name, NULL);
+ (void)dns_name_fromwire(&name, &source, &dctx, 0, &target);
+ }
+
+ return (NULL);
+}
+
+ISC_RUN_TEST_IMPL(benchmark) {
+ isc_result_t result;
+ unsigned int i;
+ isc_time_t ts1, ts2;
+ double t;
+ unsigned int nthreads;
+ isc_thread_t threads[32];
+
+ UNUSED(state);
+
+ debug_mem_record = false;
+
+ result = isc_time_now(&ts1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ nthreads = ISC_MIN(isc_os_ncpus(), 32);
+ nthreads = ISC_MAX(nthreads, 1);
+ for (i = 0; i < nthreads; i++) {
+ isc_thread_create(fromwire_thread, NULL, &threads[i]);
+ }
+
+ for (i = 0; i < nthreads; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ result = isc_time_now(&ts2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ t = isc_time_microdiff(&ts2, &ts1);
+
+ printf("%u dns_name_fromwire() calls, %f seconds, %f calls/second\n",
+ nthreads * 32000000, t / 1000000.0,
+ (nthreads * 32000000) / (t / 1000000.0));
+}
+
+#endif /* DNS_BENCHMARK_TESTS */
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(fullcompare)
+ISC_TEST_ENTRY(compression)
+ISC_TEST_ENTRY(istat)
+ISC_TEST_ENTRY(init)
+ISC_TEST_ENTRY(invalidate)
+ISC_TEST_ENTRY(buffer)
+ISC_TEST_ENTRY(isabsolute)
+ISC_TEST_ENTRY(hash)
+ISC_TEST_ENTRY(issubdomain)
+ISC_TEST_ENTRY(countlabels)
+ISC_TEST_ENTRY(getlabel)
+ISC_TEST_ENTRY(getlabelsequence)
+#ifdef DNS_BENCHMARK_TESTS
+ISC_TEST_ENTRY(benchmark)
+#endif /* DNS_BENCHMARK_TESTS */
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/nsec3_test.c b/tests/dns/nsec3_test.c
new file mode 100644
index 0000000..c2fcacd
--- /dev/null
+++ b/tests/dns/nsec3_test.c
@@ -0,0 +1,155 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/nsec3.h>
+
+#include <tests/dns.h>
+
+static void
+iteration_test(const char *file, unsigned int expected) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ unsigned int iterations;
+
+ result = dns_test_loaddb(&db, dns_dbtype_zone, "test", file);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ iterations = dns_nsec3_maxiterations();
+
+ assert_int_equal(iterations, expected);
+
+ dns_db_detach(&db);
+}
+
+/*%
+ * Structure containing parameters for nsec3param_salttotext_test().
+ */
+typedef struct {
+ const char *nsec3param_text; /* NSEC3PARAM RDATA in text form */
+ const char *expected_salt; /* string expected in target buffer */
+} nsec3param_salttotext_test_params_t;
+
+/*%
+ * Check whether dns_nsec3param_salttotext() handles supplied text form
+ * NSEC3PARAM RDATA correctly: test whether the result of calling the former is
+ * as expected and whether it properly checks available buffer space.
+ *
+ * Assumes supplied text form NSEC3PARAM RDATA is valid as testing handling of
+ * invalid NSEC3PARAM RDATA is out of scope of this unit test.
+ */
+static void
+nsec3param_salttotext_test(const nsec3param_salttotext_test_params_t *params) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_nsec3param_t nsec3param;
+ unsigned char buf[1024];
+ isc_result_t result;
+ char salt[64];
+ size_t length;
+
+ /*
+ * Prepare a dns_rdata_nsec3param_t structure for testing.
+ */
+ result = dns_test_rdatafromstring(
+ &rdata, dns_rdataclass_in, dns_rdatatype_nsec3param, buf,
+ sizeof(buf), params->nsec3param_text, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Check typical use.
+ */
+ result = dns_nsec3param_salttotext(&nsec3param, salt, sizeof(salt));
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(salt, params->expected_salt);
+
+ /*
+ * Ensure available space in the buffer is checked before the salt is
+ * printed to it and that the amount of space checked for includes the
+ * terminating NULL byte.
+ */
+ length = strlen(params->expected_salt);
+ assert_true(length < sizeof(salt) - 1); /* prevent buffer overwrite */
+ assert_true(length > 0U); /* prevent length underflow */
+
+ result = dns_nsec3param_salttotext(&nsec3param, salt, length - 1);
+ assert_int_equal(result, ISC_R_NOSPACE);
+
+ result = dns_nsec3param_salttotext(&nsec3param, salt, length);
+ assert_int_equal(result, ISC_R_NOSPACE);
+
+ result = dns_nsec3param_salttotext(&nsec3param, salt, length + 1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+/*
+ * check that appropriate max iterations is returned for different
+ * key size mixes
+ */
+ISC_RUN_TEST_IMPL(max_iterations) {
+ UNUSED(state);
+
+ iteration_test(TESTS_DIR "/testdata/nsec3/1024.db", 150);
+ iteration_test(TESTS_DIR "/testdata/nsec3/2048.db", 150);
+ iteration_test(TESTS_DIR "/testdata/nsec3/4096.db", 150);
+ iteration_test(TESTS_DIR "/testdata/nsec3/min-1024.db", 150);
+ iteration_test(TESTS_DIR "/testdata/nsec3/min-2048.db", 150);
+}
+
+/* check dns_nsec3param_salttotext() */
+ISC_RUN_TEST_IMPL(nsec3param_salttotext) {
+ size_t i;
+
+ const nsec3param_salttotext_test_params_t tests[] = {
+ /*
+ * Tests with non-empty salts.
+ */
+ { "0 0 10 0123456789abcdef", "0123456789ABCDEF" },
+ { "0 1 11 0123456789abcdef", "0123456789ABCDEF" },
+ { "1 0 12 42", "42" },
+ { "1 1 13 42", "42" },
+ /*
+ * Test with empty salt.
+ */
+ { "0 0 0 -", "-" },
+ };
+
+ UNUSED(state);
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ nsec3param_salttotext_test(&tests[i]);
+ }
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(max_iterations)
+ISC_TEST_ENTRY(nsec3param_salttotext)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/nsec3param_test.c b/tests/dns/nsec3param_test.c
new file mode 100644
index 0000000..50c8b85
--- /dev/null
+++ b/tests/dns/nsec3param_test.c
@@ -0,0 +1,266 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/hex.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/nsec3.h>
+
+#include "zone_p.h"
+
+#include <tests/dns.h>
+
+#define HASH 1
+#define FLAGS 0
+#define ITER 5
+#define SALTLEN 4
+#define SALT "FEDCBA98"
+
+/*%
+ * Structures containing parameters for nsec3param_salttotext_test().
+ */
+typedef struct {
+ dns_hash_t hash;
+ unsigned char flags;
+ dns_iterations_t iterations;
+ unsigned char salt_length;
+ const char *salt;
+} nsec3param_rdata_test_params_t;
+
+typedef struct {
+ nsec3param_rdata_test_params_t lookup;
+ nsec3param_rdata_test_params_t expect;
+ bool resalt;
+ isc_result_t expected_result;
+} nsec3param_change_test_params_t;
+
+static void
+decode_salt(const char *string, unsigned char *salt, size_t saltlen) {
+ isc_buffer_t buf;
+ isc_result_t result;
+
+ isc_buffer_init(&buf, salt, saltlen);
+ result = isc_hex_decodestring(string, &buf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+static void
+copy_params(nsec3param_rdata_test_params_t from, dns_rdata_nsec3param_t *to,
+ unsigned char *saltbuf, size_t saltlen) {
+ to->hash = from.hash;
+ to->flags = from.flags;
+ to->iterations = from.iterations;
+ to->salt_length = from.salt_length;
+ if (from.salt == NULL) {
+ to->salt = NULL;
+ } else if (strcmp(from.salt, "-") == 0) {
+ DE_CONST("-", to->salt);
+ } else {
+ decode_salt(from.salt, saltbuf, saltlen);
+ to->salt = saltbuf;
+ }
+}
+
+static nsec3param_rdata_test_params_t
+rdata_fromparams(uint8_t hash, uint8_t flags, uint16_t iter, uint8_t saltlen,
+ const char *salt) {
+ nsec3param_rdata_test_params_t nsec3param;
+ nsec3param.hash = hash;
+ nsec3param.flags = flags;
+ nsec3param.iterations = iter;
+ nsec3param.salt_length = saltlen;
+ nsec3param.salt = salt;
+ return (nsec3param);
+}
+
+/*%
+ * Check whether zone_lookup_nsec3param() finds the correct NSEC3PARAM
+ * and sets the correct parameters to use in dns_zone_setnsec3param().
+ */
+static void
+nsec3param_change_test(const nsec3param_change_test_params_t *test) {
+ dns_zone_t *zone = NULL;
+ dns_rdata_nsec3param_t param, lookup, expect;
+ isc_result_t result;
+ unsigned char lookupsalt[255];
+ unsigned char expectsalt[255];
+ unsigned char saltbuf[255];
+
+ /*
+ * Prepare a zone along with its signing keys.
+ */
+ result = dns_test_makezone("nsec3", &zone, NULL, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_zone_setfile(
+ zone, TESTS_DIR "/testdata/nsec3param/nsec3.db.signed",
+ dns_masterformat_text, &dns_master_style_default);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_zone_load(zone, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Copy parameters.
+ */
+ copy_params(test->lookup, &lookup, lookupsalt, sizeof(lookupsalt));
+ copy_params(test->expect, &expect, expectsalt, sizeof(expectsalt));
+
+ /*
+ * Test dns__zone_lookup_nsec3param().
+ */
+ result = dns__zone_lookup_nsec3param(zone, &lookup, &param, saltbuf,
+ test->resalt);
+ assert_int_equal(result, test->expected_result);
+ assert_int_equal(param.hash, expect.hash);
+ assert_int_equal(param.flags, expect.flags);
+ assert_int_equal(param.iterations, expect.iterations);
+ assert_int_equal(param.salt_length, expect.salt_length);
+ assert_non_null(param.salt);
+ if (expect.salt != NULL) {
+ int ret = memcmp(param.salt, expect.salt, expect.salt_length);
+ assert_true(ret == 0);
+ } else {
+ /*
+ * We don't know what the new salt is, but we can compare it
+ * to the previous salt and test that it has changed.
+ */
+ unsigned char salt[SALTLEN];
+ int ret;
+ decode_salt(SALT, salt, SALTLEN);
+ ret = memcmp(param.salt, salt, SALTLEN);
+ assert_false(ret == 0);
+ }
+
+ /*
+ * Detach.
+ */
+ dns_zone_detach(&zone);
+}
+
+ISC_RUN_TEST_IMPL(nsec3param_change) {
+ size_t i;
+
+ /*
+ * Define tests.
+ */
+ const nsec3param_change_test_params_t tests[] = {
+ /*
+ * 1. Change nothing (don't care about salt).
+ * This should return ISC_R_SUCCESS because we are already
+ * using these NSEC3 parameters.
+ */
+ { rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL),
+ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT), false,
+ ISC_R_SUCCESS },
+ /*
+ * 2. Change nothing, but force a resalt.
+ * This should change the salt. Set 'expect.salt' to NULL to
+ * test a new salt has been generated.
+ */
+ { rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL),
+ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL), true,
+ DNS_R_NSEC3RESALT },
+ /*
+ * 3. Change iterations.
+ * The NSEC3 paarameters are not found, and there is no
+ * need to resalt because an explicit salt has been set,
+ * and resalt is not enforced.
+ */
+ { rdata_fromparams(HASH, FLAGS, 10, SALTLEN, SALT),
+ rdata_fromparams(HASH, FLAGS, 10, SALTLEN, SALT), false,
+ ISC_R_NOTFOUND },
+ /*
+ * 4. Change iterations, don't care about the salt.
+ * We don't care about the salt. Since we need to change the
+ * NSEC3 parameters, we will also resalt.
+ */
+ { rdata_fromparams(HASH, FLAGS, 10, SALTLEN, NULL),
+ rdata_fromparams(HASH, FLAGS, 10, SALTLEN, NULL), false,
+ DNS_R_NSEC3RESALT },
+ /*
+ * 5. Change salt length.
+ * Changing salt length means we need to resalt.
+ */
+ { rdata_fromparams(HASH, FLAGS, ITER, 16, NULL),
+ rdata_fromparams(HASH, FLAGS, ITER, 16, NULL), false,
+ DNS_R_NSEC3RESALT },
+ /*
+ * 6. Set explicit salt.
+ * A different salt, so the NSEC3 parameters are not found.
+ * No need to resalt because an explicit salt is available.
+ */
+ { rdata_fromparams(HASH, FLAGS, ITER, 4, "12345678"),
+ rdata_fromparams(HASH, FLAGS, ITER, 4, "12345678"), false,
+ ISC_R_NOTFOUND },
+ /*
+ * 7. Same salt.
+ * Nothing changed, so expect ISC_R_SUCCESS as a result.
+ */
+ { rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT),
+ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT), false,
+ ISC_R_SUCCESS },
+ /*
+ * 8. Same salt, and force resalt.
+ * Nothing changed, but a resalt is enforced.
+ */
+ { rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT),
+ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL), true,
+ DNS_R_NSEC3RESALT },
+ /*
+ * 9. No salt.
+ * Change parameters to use no salt. These parameters are
+ * not found, and no new salt needs to be generated.
+ */
+ { rdata_fromparams(HASH, FLAGS, ITER, 0, NULL),
+ rdata_fromparams(HASH, FLAGS, ITER, 0, "-"), true,
+ ISC_R_NOTFOUND },
+ /*
+ * 10. No salt, explicit.
+ * Same as above, but set no salt explicitly.
+ */
+ { rdata_fromparams(HASH, FLAGS, ITER, 0, "-"),
+ rdata_fromparams(HASH, FLAGS, ITER, 0, "-"), true,
+ ISC_R_NOTFOUND },
+ };
+
+ UNUSED(state);
+
+ /*
+ * Run tests.
+ */
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ nsec3param_change_test(&tests[i]);
+ }
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(nsec3param_change)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/private_test.c b/tests/dns/private_test.c
new file mode 100644
index 0000000..9f3a87f
--- /dev/null
+++ b/tests/dns/private_test.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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/util.h>
+
+#include <dns/nsec3.h>
+#include <dns/private.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatatype.h>
+
+#include <dst/dst.h>
+
+#include <tests/dns.h>
+
+static dns_rdatatype_t privatetype = 65534;
+
+static int
+setup_test(void **state) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dst_lib_init(mctx, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ UNUSED(state);
+
+ dst_lib_destroy();
+
+ return (0);
+}
+
+typedef struct {
+ unsigned char alg;
+ dns_keytag_t keyid;
+ bool remove;
+ bool complete;
+} signing_testcase_t;
+
+typedef struct {
+ unsigned char hash;
+ unsigned char flags;
+ unsigned int iterations;
+ unsigned long salt;
+ bool remove;
+ bool pending;
+ bool nonsec;
+} nsec3_testcase_t;
+
+static void
+make_signing(signing_testcase_t *testcase, dns_rdata_t *private,
+ unsigned char *buf, size_t len) {
+ dns_rdata_init(private);
+
+ buf[0] = testcase->alg;
+ buf[1] = (testcase->keyid & 0xff00) >> 8;
+ buf[2] = (testcase->keyid & 0xff);
+ buf[3] = testcase->remove;
+ buf[4] = testcase->complete;
+ private->data = buf;
+ private->length = len;
+ private->type = privatetype;
+ private->rdclass = dns_rdataclass_in;
+}
+
+static void
+make_nsec3(nsec3_testcase_t *testcase, dns_rdata_t *private,
+ unsigned char *pbuf) {
+ dns_rdata_nsec3param_t params;
+ dns_rdata_t nsec3param = DNS_RDATA_INIT;
+ unsigned char bufdata[BUFSIZ];
+ isc_buffer_t buf;
+ uint32_t salt;
+ unsigned char *sp;
+ int slen = 4;
+
+ /* for simplicity, we're using a maximum salt length of 4 */
+ salt = htonl(testcase->salt);
+ sp = (unsigned char *)&salt;
+ while (slen > 0 && *sp == '\0') {
+ slen--;
+ sp++;
+ }
+
+ params.common.rdclass = dns_rdataclass_in;
+ params.common.rdtype = dns_rdatatype_nsec3param;
+ params.hash = testcase->hash;
+ params.iterations = testcase->iterations;
+ params.salt = sp;
+ params.salt_length = slen;
+
+ params.flags = testcase->flags;
+ if (testcase->remove) {
+ params.flags |= DNS_NSEC3FLAG_REMOVE;
+ if (testcase->nonsec) {
+ params.flags |= DNS_NSEC3FLAG_NONSEC;
+ }
+ } else {
+ params.flags |= DNS_NSEC3FLAG_CREATE;
+ if (testcase->pending) {
+ params.flags |= DNS_NSEC3FLAG_INITIAL;
+ }
+ }
+
+ isc_buffer_init(&buf, bufdata, sizeof(bufdata));
+ dns_rdata_fromstruct(&nsec3param, dns_rdataclass_in,
+ dns_rdatatype_nsec3param, &params, &buf);
+
+ dns_rdata_init(private);
+
+ dns_nsec3param_toprivate(&nsec3param, private, privatetype, pbuf,
+ DNS_NSEC3PARAM_BUFFERSIZE + 1);
+}
+
+/* convert private signing records to text */
+ISC_RUN_TEST_IMPL(private_signing_totext) {
+ dns_rdata_t private;
+ int i;
+
+ signing_testcase_t testcases[] = { { DST_ALG_RSASHA512, 12345, 0, 0 },
+ { DST_ALG_RSASHA256, 54321, 1, 0 },
+ { DST_ALG_NSEC3RSASHA1, 22222, 0,
+ 1 },
+ { DST_ALG_RSASHA1, 33333, 1, 1 } };
+ const char *results[] = { "Signing with key 12345/RSASHA512",
+ "Removing signatures for key 54321/RSASHA256",
+ "Done signing with key 22222/NSEC3RSASHA1",
+ ("Done removing signatures for key "
+ "33333/RSASHA1") };
+ int ncases = 4;
+
+ UNUSED(state);
+
+ for (i = 0; i < ncases; i++) {
+ unsigned char data[5];
+ char output[BUFSIZ];
+ isc_buffer_t buf;
+
+ isc_buffer_init(&buf, output, sizeof(output));
+
+ make_signing(&testcases[i], &private, data, sizeof(data));
+ dns_private_totext(&private, &buf);
+ assert_string_equal(output, results[i]);
+ }
+}
+
+/* convert private chain records to text */
+ISC_RUN_TEST_IMPL(private_nsec3_totext) {
+ dns_rdata_t private;
+ int i;
+
+ nsec3_testcase_t testcases[] = {
+ { 1, 0, 1, 0xbeef, 0, 0, 0 },
+ { 1, 1, 10, 0xdadd, 0, 0, 0 },
+ { 1, 0, 20, 0xbead, 0, 1, 0 },
+ { 1, 0, 30, 0xdeaf, 1, 0, 0 },
+ { 1, 0, 100, 0xfeedabee, 1, 0, 1 },
+ };
+ const char *results[] = { "Creating NSEC3 chain 1 0 1 BEEF",
+ "Creating NSEC3 chain 1 1 10 DADD",
+ "Pending NSEC3 chain 1 0 20 BEAD",
+ ("Removing NSEC3 chain 1 0 30 DEAF / "
+ "creating NSEC chain"),
+ "Removing NSEC3 chain 1 0 100 FEEDABEE" };
+ int ncases = 5;
+
+ UNUSED(state);
+
+ for (i = 0; i < ncases; i++) {
+ unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1];
+ char output[BUFSIZ];
+ isc_buffer_t buf;
+
+ isc_buffer_init(&buf, output, sizeof(output));
+
+ make_nsec3(&testcases[i], &private, data);
+ dns_private_totext(&private, &buf);
+ assert_string_equal(output, results[i]);
+ }
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(private_signing_totext, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(private_nsec3_totext, setup_test, teardown_test)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/rbt_test.c b/tests/dns/rbt_test.c
new file mode 100644
index 0000000..c66c365
--- /dev/null
+++ b/tests/dns/rbt_test.c
@@ -0,0 +1,1300 @@
+/*
+ * 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 <ctype.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/file.h>
+#include <isc/hash.h>
+#include <isc/mem.h>
+#include <isc/os.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/result.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/compress.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/name.h>
+#include <dns/rbt.h>
+
+#include <dst/dst.h>
+
+#include <tests/dns.h>
+
+typedef struct {
+ dns_rbt_t *rbt;
+ dns_rbt_t *rbt_distances;
+} test_context_t;
+
+/* The initial structure of domain tree will be as follows:
+ *
+ * .
+ * |
+ * b
+ * / \
+ * a d.e.f
+ * / | \
+ * c | g.h
+ * | |
+ * w.y i
+ * / | \ \
+ * x | z k
+ * | |
+ * p j
+ * / \
+ * o q
+ */
+
+/* The full absolute names of the nodes in the tree (the tree also
+ * contains "." which is not included in this list).
+ */
+static const char *const domain_names[] = {
+ "c", "b", "a", "x.d.e.f",
+ "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
+ "j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"
+};
+
+static const size_t domain_names_count =
+ (sizeof(domain_names) / sizeof(domain_names[0]));
+
+/* These are set as the node data for the tree used in distances check
+ * (for the names in domain_names[] above).
+ */
+static const int node_distances[] = { 3, 1, 2, 2, 2, 3, 1, 2, 1, 1, 2, 2 };
+
+/*
+ * The domain order should be:
+ * ., a, b, c, d.e.f, x.d.e.f, w.y.d.e.f, o.w.y.d.e.f, p.w.y.d.e.f,
+ * q.w.y.d.e.f, z.d.e.f, j.z.d.e.f, g.h, i.g.h, k.g.h
+ * . (no data, can't be found)
+ * |
+ * b
+ * / \
+ * a d.e.f
+ * / | \
+ * c | g.h
+ * | |
+ * w.y i
+ * / | \ \
+ * x | z k
+ * | |
+ * p j
+ * / \
+ * o q
+ */
+
+static const char *const ordered_names[] = {
+ "a", "b", "c", "d.e.f", "x.d.e.f",
+ "w.y.d.e.f", "o.w.y.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "z.d.e.f",
+ "j.z.d.e.f", "g.h", "i.g.h", "k.g.h"
+};
+
+static const size_t ordered_names_count =
+ (sizeof(ordered_names) / sizeof(*ordered_names));
+
+static void
+delete_data(void *data, void *arg) {
+ UNUSED(arg);
+
+ isc_mem_put(mctx, data, sizeof(size_t));
+}
+
+static test_context_t *
+test_context_setup(void) {
+ test_context_t *ctx;
+ isc_result_t result;
+ size_t i;
+
+ ctx = isc_mem_get(mctx, sizeof(*ctx));
+ assert_non_null(ctx);
+
+ ctx->rbt = NULL;
+ result = dns_rbt_create(mctx, delete_data, NULL, &ctx->rbt);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ ctx->rbt_distances = NULL;
+ result = dns_rbt_create(mctx, delete_data, NULL, &ctx->rbt_distances);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (i = 0; i < domain_names_count; i++) {
+ size_t *n;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ dns_test_namefromstring(domain_names[i], &fname);
+
+ name = dns_fixedname_name(&fname);
+
+ n = isc_mem_get(mctx, sizeof(size_t));
+ assert_non_null(n);
+ *n = i + 1;
+ result = dns_rbt_addname(ctx->rbt, name, n);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ n = isc_mem_get(mctx, sizeof(size_t));
+ assert_non_null(n);
+ *n = node_distances[i];
+ result = dns_rbt_addname(ctx->rbt_distances, name, n);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ return (ctx);
+}
+
+static void
+test_context_teardown(test_context_t *ctx) {
+ dns_rbt_destroy(&ctx->rbt);
+ dns_rbt_destroy(&ctx->rbt_distances);
+
+ isc_mem_put(mctx, ctx, sizeof(*ctx));
+}
+
+/*
+ * Walk the tree and ensure that all the test nodes are present.
+ */
+static void
+check_test_data(dns_rbt_t *rbt) {
+ dns_fixedname_t fixed;
+ isc_result_t result;
+ dns_name_t *foundname;
+ size_t i;
+
+ foundname = dns_fixedname_initname(&fixed);
+
+ for (i = 0; i < domain_names_count; i++) {
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ size_t *n;
+
+ dns_test_namefromstring(domain_names[i], &fname);
+
+ name = dns_fixedname_name(&fname);
+ n = NULL;
+ result = dns_rbt_findname(rbt, name, 0, foundname, (void *)&n);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(*n, i + 1);
+ }
+}
+
+/* Test the creation of an rbt */
+ISC_RUN_TEST_IMPL(rbt_create) {
+ test_context_t *ctx;
+ bool tree_ok;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ ctx = test_context_setup();
+
+ check_test_data(ctx->rbt);
+
+ tree_ok = dns__rbt_checkproperties(ctx->rbt);
+ assert_true(tree_ok);
+
+ test_context_teardown(ctx);
+}
+
+/* Test dns_rbt_nodecount() on a tree */
+ISC_RUN_TEST_IMPL(rbt_nodecount) {
+ test_context_t *ctx;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ ctx = test_context_setup();
+
+ assert_int_equal(15, dns_rbt_nodecount(ctx->rbt));
+
+ test_context_teardown(ctx);
+}
+
+/* Test dns_rbtnode_get_distance() on a tree */
+ISC_RUN_TEST_IMPL(rbtnode_get_distance) {
+ isc_result_t result;
+ test_context_t *ctx;
+ const char *name_str = "a";
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ dns_rbtnode_t *node = NULL;
+ dns_rbtnodechain_t chain;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ ctx = test_context_setup();
+
+ dns_test_namefromstring(name_str, &fname);
+ name = dns_fixedname_name(&fname);
+
+ dns_rbtnodechain_init(&chain);
+
+ result = dns_rbt_findnode(ctx->rbt_distances, name, NULL, &node, &chain,
+ 0, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ while (node != NULL) {
+ const size_t *distance = (const size_t *)node->data;
+ if (distance != NULL) {
+ assert_int_equal(*distance,
+ dns__rbtnode_getdistance(node));
+ }
+ result = dns_rbtnodechain_next(&chain, NULL, NULL);
+ if (result == ISC_R_NOMORE) {
+ break;
+ }
+ dns_rbtnodechain_current(&chain, NULL, NULL, &node);
+ }
+
+ assert_int_equal(result, ISC_R_NOMORE);
+
+ dns_rbtnodechain_invalidate(&chain);
+
+ test_context_teardown(ctx);
+}
+
+/*
+ * Test tree balance, inserting names in random order.
+ *
+ * This test checks an important performance-related property of
+ * the red-black tree, which is important for us: the longest
+ * path from a sub-tree's root to a node is no more than
+ * 2log(n). This check verifies that the tree is balanced.
+ */
+ISC_RUN_TEST_IMPL(rbt_check_distance_random) {
+ dns_rbt_t *mytree = NULL;
+ const unsigned int log_num_nodes = 16;
+ isc_result_t result;
+ bool tree_ok;
+ int i;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ result = dns_rbt_create(mctx, delete_data, NULL, &mytree);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Names are inserted in random order. */
+
+ /* Make a large 65536 node top-level domain tree, i.e., the
+ * following code inserts names such as:
+ *
+ * savoucnsrkrqzpkqypbygwoiliawpbmz.
+ * wkadamcbbpjtundbxcmuayuycposvngx.
+ * wzbpznemtooxdpjecdxynsfztvnuyfao.
+ * yueojmhyffslpvfmgyfwioxegfhepnqq.
+ */
+ for (i = 0; i < (1 << log_num_nodes); i++) {
+ size_t *n;
+ char namebuf[34];
+
+ n = isc_mem_get(mctx, sizeof(size_t));
+ assert_non_null(n);
+ *n = i + 1;
+
+ while (1) {
+ int j;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ for (j = 0; j < 32; j++) {
+ uint32_t v = isc_random_uniform(26);
+ namebuf[j] = 'a' + v;
+ }
+ namebuf[32] = '.';
+ namebuf[33] = 0;
+
+ dns_test_namefromstring(namebuf, &fname);
+ name = dns_fixedname_name(&fname);
+
+ result = dns_rbt_addname(mytree, name, n);
+ if (result == ISC_R_SUCCESS) {
+ break;
+ }
+ }
+ }
+
+ /* 1 (root . node) + (1 << log_num_nodes) */
+ assert_int_equal(1U + (1U << log_num_nodes), dns_rbt_nodecount(mytree));
+
+ /* The distance from each node to its sub-tree root must be less
+ * than 2 * log(n).
+ */
+ assert_true((2U * log_num_nodes) >= dns__rbt_getheight(mytree));
+
+ /* Also check RB tree properties */
+ tree_ok = dns__rbt_checkproperties(mytree);
+ assert_true(tree_ok);
+
+ dns_rbt_destroy(&mytree);
+}
+
+/*
+ * Test tree balance, inserting names in sorted order.
+ *
+ * This test checks an important performance-related property of
+ * the red-black tree, which is important for us: the longest
+ * path from a sub-tree's root to a node is no more than
+ * 2log(n). This check verifies that the tree is balanced.
+ */
+ISC_RUN_TEST_IMPL(rbt_check_distance_ordered) {
+ dns_rbt_t *mytree = NULL;
+ const unsigned int log_num_nodes = 16;
+ isc_result_t result;
+ bool tree_ok;
+ int i;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ result = dns_rbt_create(mctx, delete_data, NULL, &mytree);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Names are inserted in sorted order. */
+
+ /* Make a large 65536 node top-level domain tree, i.e., the
+ * following code inserts names such as:
+ *
+ * name00000000.
+ * name00000001.
+ * name00000002.
+ * name00000003.
+ */
+ for (i = 0; i < (1 << log_num_nodes); i++) {
+ size_t *n;
+ char namebuf[14];
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ n = isc_mem_get(mctx, sizeof(size_t));
+ assert_non_null(n);
+ *n = i + 1;
+
+ snprintf(namebuf, sizeof(namebuf), "name%08x.", i);
+ dns_test_namefromstring(namebuf, &fname);
+ name = dns_fixedname_name(&fname);
+
+ result = dns_rbt_addname(mytree, name, n);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ /* 1 (root . node) + (1 << log_num_nodes) */
+ assert_int_equal(1U + (1U << log_num_nodes), dns_rbt_nodecount(mytree));
+
+ /* The distance from each node to its sub-tree root must be less
+ * than 2 * log(n).
+ */
+ assert_true((2U * log_num_nodes) >= dns__rbt_getheight(mytree));
+
+ /* Also check RB tree properties */
+ tree_ok = dns__rbt_checkproperties(mytree);
+ assert_true(tree_ok);
+
+ dns_rbt_destroy(&mytree);
+}
+
+static isc_result_t
+insert_helper(dns_rbt_t *rbt, const char *namestr, dns_rbtnode_t **node) {
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ dns_test_namefromstring(namestr, &fname);
+ name = dns_fixedname_name(&fname);
+
+ return (dns_rbt_addnode(rbt, name, node));
+}
+
+static bool
+compare_labelsequences(dns_rbtnode_t *node, const char *labelstr) {
+ dns_name_t name;
+ isc_result_t result;
+ char *nodestr = NULL;
+ bool is_equal;
+
+ dns_name_init(&name, NULL);
+ dns_rbt_namefromnode(node, &name);
+
+ result = dns_name_tostring(&name, &nodestr, mctx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ is_equal = strcmp(labelstr, nodestr) == 0 ? true : false;
+
+ isc_mem_free(mctx, nodestr);
+
+ return (is_equal);
+}
+
+/* Test insertion into a tree */
+ISC_RUN_TEST_IMPL(rbt_insert) {
+ isc_result_t result;
+ test_context_t *ctx;
+ dns_rbtnode_t *node;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ ctx = test_context_setup();
+
+ /* Check node count before beginning. */
+ assert_int_equal(15, dns_rbt_nodecount(ctx->rbt));
+
+ /* Try to insert a node that already exists. */
+ node = NULL;
+ result = insert_helper(ctx->rbt, "d.e.f", &node);
+ assert_int_equal(result, ISC_R_EXISTS);
+
+ /* Node count must not have changed. */
+ assert_int_equal(15, dns_rbt_nodecount(ctx->rbt));
+
+ /* Try to insert a node that doesn't exist. */
+ node = NULL;
+ result = insert_helper(ctx->rbt, "0", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(compare_labelsequences(node, "0"));
+
+ /* Node count must have increased. */
+ assert_int_equal(16, dns_rbt_nodecount(ctx->rbt));
+
+ /* Another. */
+ node = NULL;
+ result = insert_helper(ctx->rbt, "example.com", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(node);
+ assert_null(node->data);
+
+ /* Node count must have increased. */
+ assert_int_equal(17, dns_rbt_nodecount(ctx->rbt));
+
+ /* Re-adding it should return EXISTS */
+ node = NULL;
+ result = insert_helper(ctx->rbt, "example.com", &node);
+ assert_int_equal(result, ISC_R_EXISTS);
+
+ /* Node count must not have changed. */
+ assert_int_equal(17, dns_rbt_nodecount(ctx->rbt));
+
+ /* Fission the node d.e.f */
+ node = NULL;
+ result = insert_helper(ctx->rbt, "k.e.f", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(compare_labelsequences(node, "k"));
+
+ /* Node count must have incremented twice ("d.e.f" fissioned to
+ * "d" and "e.f", and the newly added "k").
+ */
+ assert_int_equal(19, dns_rbt_nodecount(ctx->rbt));
+
+ /* Fission the node "g.h" */
+ node = NULL;
+ result = insert_helper(ctx->rbt, "h", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(compare_labelsequences(node, "h"));
+
+ /* Node count must have incremented ("g.h" fissioned to "g" and
+ * "h").
+ */
+ assert_int_equal(20, dns_rbt_nodecount(ctx->rbt));
+
+ /* Add child domains */
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "m.p.w.y.d.e.f", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(compare_labelsequences(node, "m"));
+ assert_int_equal(21, dns_rbt_nodecount(ctx->rbt));
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "n.p.w.y.d.e.f", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(compare_labelsequences(node, "n"));
+ assert_int_equal(22, dns_rbt_nodecount(ctx->rbt));
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "l.a", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(compare_labelsequences(node, "l"));
+ assert_int_equal(23, dns_rbt_nodecount(ctx->rbt));
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "r.d.e.f", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ node = NULL;
+ result = insert_helper(ctx->rbt, "s.d.e.f", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(25, dns_rbt_nodecount(ctx->rbt));
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "h.w.y.d.e.f", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Add more nodes one by one to cover left and right rotation
+ * functions.
+ */
+ node = NULL;
+ result = insert_helper(ctx->rbt, "f", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "m", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "nm", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "om", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "k", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "l", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "fe", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "ge", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "i", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "ae", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "n", &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ test_context_teardown(ctx);
+}
+
+/*
+ * Test removal from a tree
+ *
+ * This testcase checks that after node removal, the binary-search tree is
+ * valid and all nodes that are supposed to exist are present in the
+ * correct order. It mainly tests DomainTree as a BST, and not particularly
+ * as a red-black tree. This test checks node deletion when upper nodes
+ * have data.
+ */
+ISC_RUN_TEST_IMPL(rbt_remove) {
+ isc_result_t result;
+ size_t j;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ /*
+ * Delete single nodes and check if the rest of the nodes exist.
+ */
+ for (j = 0; j < ordered_names_count; j++) {
+ dns_rbt_t *mytree = NULL;
+ dns_rbtnode_t *node;
+ size_t i;
+ size_t *n;
+ bool tree_ok;
+ dns_rbtnodechain_t chain;
+ size_t start_node;
+
+ /* Create a tree. */
+ result = dns_rbt_create(mctx, delete_data, NULL, &mytree);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Insert test data into the tree. */
+ for (i = 0; i < domain_names_count; i++) {
+ node = NULL;
+ result = insert_helper(mytree, domain_names[i], &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ /* Check that all names exist in order. */
+ for (i = 0; i < ordered_names_count; i++) {
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ dns_test_namefromstring(ordered_names[i], &fname);
+
+ name = dns_fixedname_name(&fname);
+ node = NULL;
+ result = dns_rbt_findnode(mytree, name, NULL, &node,
+ NULL, DNS_RBTFIND_EMPTYDATA,
+ NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Add node data */
+ assert_non_null(node);
+ assert_null(node->data);
+
+ n = isc_mem_get(mctx, sizeof(size_t));
+ assert_non_null(n);
+ *n = i;
+
+ node->data = n;
+ }
+
+ /* Now, delete the j'th node from the tree. */
+ {
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ dns_test_namefromstring(ordered_names[j], &fname);
+
+ name = dns_fixedname_name(&fname);
+
+ result = dns_rbt_deletename(mytree, name, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ /* Check RB tree properties. */
+ tree_ok = dns__rbt_checkproperties(mytree);
+ assert_true(tree_ok);
+
+ dns_rbtnodechain_init(&chain);
+
+ /* Now, walk through nodes in order. */
+ if (j == 0) {
+ /*
+ * Node for ordered_names[0] was already deleted
+ * above. We start from node 1.
+ */
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ dns_test_namefromstring(ordered_names[0], &fname);
+ name = dns_fixedname_name(&fname);
+ node = NULL;
+ result = dns_rbt_findnode(mytree, name, NULL, &node,
+ NULL, 0, NULL, NULL);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+
+ dns_test_namefromstring(ordered_names[1], &fname);
+ name = dns_fixedname_name(&fname);
+ node = NULL;
+ result = dns_rbt_findnode(mytree, name, NULL, &node,
+ &chain, 0, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ start_node = 1;
+ } else {
+ /* Start from node 0. */
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ dns_test_namefromstring(ordered_names[0], &fname);
+ name = dns_fixedname_name(&fname);
+ node = NULL;
+ result = dns_rbt_findnode(mytree, name, NULL, &node,
+ &chain, 0, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ start_node = 0;
+ }
+
+ /*
+ * node and chain have been set by the code above at
+ * this point.
+ */
+ for (i = start_node; i < ordered_names_count; i++) {
+ dns_fixedname_t fname_j, fname_i;
+ dns_name_t *name_j, *name_i;
+
+ dns_test_namefromstring(ordered_names[j], &fname_j);
+ name_j = dns_fixedname_name(&fname_j);
+ dns_test_namefromstring(ordered_names[i], &fname_i);
+ name_i = dns_fixedname_name(&fname_i);
+
+ if (dns_name_equal(name_i, name_j)) {
+ /*
+ * This may be true for the last node if
+ * we seek ahead in the loop using
+ * dns_rbtnodechain_next() below.
+ */
+ if (node == NULL) {
+ break;
+ }
+
+ /* All ordered nodes have data
+ * initially. If any node is empty, it
+ * means it was removed, but an empty
+ * node exists because it is a
+ * super-domain. Just skip it.
+ */
+ if (node->data == NULL) {
+ result = dns_rbtnodechain_next(
+ &chain, NULL, NULL);
+ if (result == ISC_R_NOMORE) {
+ node = NULL;
+ } else {
+ dns_rbtnodechain_current(
+ &chain, NULL, NULL,
+ &node);
+ }
+ }
+ continue;
+ }
+
+ assert_non_null(node);
+
+ n = (size_t *)node->data;
+ if (n != NULL) {
+ /* printf("n=%zu, i=%zu\n", *n, i); */
+ assert_int_equal(*n, i);
+ }
+
+ result = dns_rbtnodechain_next(&chain, NULL, NULL);
+ if (result == ISC_R_NOMORE) {
+ node = NULL;
+ } else {
+ dns_rbtnodechain_current(&chain, NULL, NULL,
+ &node);
+ }
+ }
+
+ /* We should have reached the end of the tree. */
+ assert_null(node);
+
+ dns_rbt_destroy(&mytree);
+ }
+}
+
+static void
+insert_nodes(dns_rbt_t *mytree, char **names, size_t *names_count,
+ uint32_t num_names) {
+ uint32_t i;
+ dns_rbtnode_t *node;
+
+ for (i = 0; i < num_names; i++) {
+ size_t *n;
+ char namebuf[34];
+
+ n = isc_mem_get(mctx, sizeof(size_t));
+ assert_non_null(n);
+
+ *n = i; /* Unused value */
+
+ while (1) {
+ int j;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ isc_result_t result;
+
+ for (j = 0; j < 32; j++) {
+ uint32_t v = isc_random_uniform(26);
+ namebuf[j] = 'a' + v;
+ }
+ namebuf[32] = '.';
+ namebuf[33] = 0;
+
+ dns_test_namefromstring(namebuf, &fname);
+ name = dns_fixedname_name(&fname);
+
+ node = NULL;
+ result = dns_rbt_addnode(mytree, name, &node);
+ if (result == ISC_R_SUCCESS) {
+ node->data = n;
+ names[*names_count] = isc_mem_strdup(mctx,
+ namebuf);
+ assert_non_null(names[*names_count]);
+ *names_count += 1;
+ break;
+ }
+ }
+ }
+}
+
+static void
+remove_nodes(dns_rbt_t *mytree, char **names, size_t *names_count,
+ uint32_t num_names) {
+ uint32_t i;
+
+ UNUSED(mytree);
+
+ for (i = 0; i < num_names; i++) {
+ uint32_t node;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ isc_result_t result;
+
+ node = isc_random_uniform(*names_count);
+
+ dns_test_namefromstring(names[node], &fname);
+ name = dns_fixedname_name(&fname);
+
+ result = dns_rbt_deletename(mytree, name, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_mem_free(mctx, names[node]);
+ if (*names_count > 0) {
+ names[node] = names[*names_count - 1];
+ names[*names_count - 1] = NULL;
+ *names_count -= 1;
+ }
+ }
+}
+
+static void
+check_tree(dns_rbt_t *mytree, char **names, size_t names_count) {
+ bool tree_ok;
+
+ UNUSED(names);
+
+ assert_int_equal(names_count + 1, dns_rbt_nodecount(mytree));
+
+ /*
+ * The distance from each node to its sub-tree root must be less
+ * than 2 * log_2(1024).
+ */
+ assert_true((2 * 10) >= dns__rbt_getheight(mytree));
+
+ /* Also check RB tree properties */
+ tree_ok = dns__rbt_checkproperties(mytree);
+ assert_true(tree_ok);
+}
+
+/*
+ * Test insert and remove in a loop.
+ *
+ * What is the best way to test our red-black tree code? It is
+ * not a good method to test every case handled in the actual
+ * code itself. This is because our approach itself may be
+ * incorrect.
+ *
+ * We test our code at the interface level here by exercising the
+ * tree randomly multiple times, checking that red-black tree
+ * properties are valid, and all the nodes that are supposed to be
+ * in the tree exist and are in order.
+ *
+ * NOTE: These tests are run within a single tree level in the
+ * forest. The number of nodes in the tree level doesn't grow
+ * over 1024.
+ */
+ISC_RUN_TEST_IMPL(rbt_insert_and_remove) {
+ isc_result_t result;
+ dns_rbt_t *mytree = NULL;
+ size_t *n;
+ char *names[1024];
+ size_t names_count;
+ int i;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ result = dns_rbt_create(mctx, delete_data, NULL, &mytree);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ n = isc_mem_get(mctx, sizeof(size_t));
+ assert_non_null(n);
+ result = dns_rbt_addname(mytree, dns_rootname, n);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(names, 0, sizeof(names));
+ names_count = 0;
+
+ /* Repeat the insert/remove test some 4096 times */
+ for (i = 0; i < 4096; i++) {
+ uint32_t num_names;
+
+ if (names_count < 1024) {
+ num_names = isc_random_uniform(1024 - names_count);
+ num_names++;
+ } else {
+ num_names = 0;
+ }
+
+ insert_nodes(mytree, names, &names_count, num_names);
+ check_tree(mytree, names, names_count);
+
+ if (names_count > 0) {
+ num_names = isc_random_uniform(names_count);
+ num_names++;
+ } else {
+ num_names = 0;
+ }
+
+ remove_nodes(mytree, names, &names_count, num_names);
+ check_tree(mytree, names, names_count);
+ }
+
+ /* Remove the rest of the nodes */
+ remove_nodes(mytree, names, &names_count, names_count);
+ check_tree(mytree, names, names_count);
+
+ for (i = 0; i < 1024; i++) {
+ if (names[i] != NULL) {
+ isc_mem_free(mctx, names[i]);
+ }
+ }
+
+ result = dns_rbt_deletename(mytree, dns_rootname, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(dns_rbt_nodecount(mytree), 0);
+
+ dns_rbt_destroy(&mytree);
+}
+
+/* Test findname return values */
+ISC_RUN_TEST_IMPL(rbt_findname) {
+ isc_result_t result;
+ test_context_t *ctx = NULL;
+ dns_fixedname_t fname, found;
+ dns_name_t *name = NULL, *foundname = NULL;
+ size_t *n = NULL;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ ctx = test_context_setup();
+
+ /* Try to find a name that exists. */
+ dns_test_namefromstring("d.e.f", &fname);
+ name = dns_fixedname_name(&fname);
+
+ foundname = dns_fixedname_initname(&found);
+
+ result = dns_rbt_findname(ctx->rbt, name, DNS_RBTFIND_EMPTYDATA,
+ foundname, (void *)&n);
+ assert_true(dns_name_equal(foundname, name));
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Now without EMPTYDATA */
+ result = dns_rbt_findname(ctx->rbt, name, 0, foundname, (void *)&n);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+
+ /* Now one that partially matches */
+ dns_test_namefromstring("d.e.f.g.h.i.j", &fname);
+ name = dns_fixedname_name(&fname);
+ result = dns_rbt_findname(ctx->rbt, name, DNS_RBTFIND_EMPTYDATA,
+ foundname, (void *)&n);
+ assert_int_equal(result, DNS_R_PARTIALMATCH);
+
+ /* Now one that doesn't match */
+ dns_test_namefromstring("1.2", &fname);
+ name = dns_fixedname_name(&fname);
+ result = dns_rbt_findname(ctx->rbt, name, DNS_RBTFIND_EMPTYDATA,
+ foundname, (void *)&n);
+ assert_int_equal(result, DNS_R_PARTIALMATCH);
+ assert_true(dns_name_equal(foundname, dns_rootname));
+
+ test_context_teardown(ctx);
+}
+
+/* Test addname return values */
+ISC_RUN_TEST_IMPL(rbt_addname) {
+ isc_result_t result;
+ test_context_t *ctx = NULL;
+ dns_fixedname_t fname;
+ dns_name_t *name = NULL;
+ size_t *n;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ ctx = test_context_setup();
+
+ n = isc_mem_get(mctx, sizeof(size_t));
+ assert_non_null(n);
+ *n = 1;
+
+ dns_test_namefromstring("d.e.f.g.h.i.j.k", &fname);
+ name = dns_fixedname_name(&fname);
+
+ /* Add a name that doesn't exist */
+ result = dns_rbt_addname(ctx->rbt, name, n);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Now add again, should get ISC_R_EXISTS */
+ n = isc_mem_get(mctx, sizeof(size_t));
+ assert_non_null(n);
+ *n = 2;
+ result = dns_rbt_addname(ctx->rbt, name, n);
+ assert_int_equal(result, ISC_R_EXISTS);
+ isc_mem_put(mctx, n, sizeof(size_t));
+
+ test_context_teardown(ctx);
+}
+
+/* Test deletename return values */
+ISC_RUN_TEST_IMPL(rbt_deletename) {
+ isc_result_t result;
+ test_context_t *ctx = NULL;
+ dns_fixedname_t fname;
+ dns_name_t *name = NULL;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ ctx = test_context_setup();
+
+ /* Delete a name that doesn't exist */
+ dns_test_namefromstring("z.x.y.w", &fname);
+ name = dns_fixedname_name(&fname);
+ result = dns_rbt_deletename(ctx->rbt, name, false);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+
+ /* Now one that does */
+ dns_test_namefromstring("d.e.f", &fname);
+ name = dns_fixedname_name(&fname);
+ result = dns_rbt_deletename(ctx->rbt, name, false);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+
+ test_context_teardown(ctx);
+}
+
+/* Test nodechain */
+ISC_RUN_TEST_IMPL(rbt_nodechain) {
+ isc_result_t result;
+ test_context_t *ctx;
+ dns_fixedname_t fname, found, expect;
+ dns_name_t *name, *foundname, *expected;
+ dns_rbtnode_t *node = NULL;
+ dns_rbtnodechain_t chain;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ ctx = test_context_setup();
+
+ dns_rbtnodechain_init(&chain);
+
+ dns_test_namefromstring("a", &fname);
+ name = dns_fixedname_name(&fname);
+
+ result = dns_rbt_findnode(ctx->rbt, name, NULL, &node, &chain, 0, NULL,
+ NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ foundname = dns_fixedname_initname(&found);
+
+ dns_test_namefromstring("a", &expect);
+ expected = dns_fixedname_name(&expect);
+ UNUSED(expected);
+
+ result = dns_rbtnodechain_first(&chain, ctx->rbt, foundname, NULL);
+ assert_int_equal(result, DNS_R_NEWORIGIN);
+ assert_int_equal(dns_name_countlabels(foundname), 0);
+
+ result = dns_rbtnodechain_prev(&chain, NULL, NULL);
+ assert_int_equal(result, ISC_R_NOMORE);
+
+ result = dns_rbtnodechain_next(&chain, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_rbtnodechain_next(&chain, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_rbtnodechain_last(&chain, ctx->rbt, NULL, NULL);
+ assert_int_equal(result, DNS_R_NEWORIGIN);
+
+ result = dns_rbtnodechain_next(&chain, NULL, NULL);
+ assert_int_equal(result, ISC_R_NOMORE);
+
+ result = dns_rbtnodechain_last(&chain, ctx->rbt, NULL, NULL);
+ assert_int_equal(result, DNS_R_NEWORIGIN);
+
+ result = dns_rbtnodechain_prev(&chain, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_rbtnodechain_invalidate(&chain);
+
+ test_context_teardown(ctx);
+}
+
+/* Test addname return values */
+ISC_RUN_TEST_IMPL(rbtnode_namelen) {
+ isc_result_t result;
+ test_context_t *ctx = NULL;
+ dns_rbtnode_t *node;
+ unsigned int len;
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ ctx = test_context_setup();
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, ".", &node);
+ len = dns__rbtnode_namelen(node);
+ assert_int_equal(result, ISC_R_EXISTS);
+ assert_int_equal(len, 1);
+ node = NULL;
+
+ result = insert_helper(ctx->rbt, "a.b.c.d.e.f.g.h.i.j.k.l.m", &node);
+ len = dns__rbtnode_namelen(node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(len, 27);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "isc.org", &node);
+ len = dns__rbtnode_namelen(node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(len, 9);
+
+ node = NULL;
+ result = insert_helper(ctx->rbt, "example.com", &node);
+ len = dns__rbtnode_namelen(node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(len, 13);
+
+ test_context_teardown(ctx);
+}
+
+#if defined(DNS_BENCHMARK_TESTS) && !defined(__SANITIZE_THREAD__)
+
+/*
+ * XXXMUKS: Don't delete this code. It is useful in benchmarking the
+ * RBT, but we don't require it as part of the unit test runs.
+ */
+
+static dns_fixedname_t *fnames;
+static dns_name_t **names;
+static int *values;
+
+static void *
+find_thread(void *arg) {
+ dns_rbt_t *mytree;
+ isc_result_t result;
+ dns_rbtnode_t *node;
+ unsigned int j, i;
+ unsigned int start = 0;
+
+ mytree = (dns_rbt_t *)arg;
+ while (start == 0) {
+ start = random() % 4000000;
+ }
+
+ /* Query 32 million random names from it in each thread */
+ for (j = 0; j < 8; j++) {
+ for (i = start; i != start - 1; i = (i + 1) % 4000000) {
+ node = NULL;
+ result = dns_rbt_findnode(mytree, names[i], NULL, &node,
+ NULL, DNS_RBTFIND_EMPTYDATA,
+ NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(node);
+ assert_int_equal(values[i], (intptr_t)node->data);
+ }
+ }
+
+ return (NULL);
+}
+
+/* Benchmark RBT implementation */
+ISC_RUN_TEST_IMPL(benchmark) {
+ isc_result_t result;
+ char namestr[sizeof("name18446744073709551616.example.org.")];
+ unsigned int r;
+ dns_rbt_t *mytree;
+ dns_rbtnode_t *node;
+ unsigned int i;
+ unsigned int maxvalue = 1000000;
+ isc_time_t ts1, ts2;
+ double t;
+ unsigned int nthreads;
+ isc_thread_t threads[32];
+
+ srandom(time(NULL));
+
+ debug_mem_record = false;
+
+ fnames = (dns_fixedname_t *)malloc(4000000 * sizeof(dns_fixedname_t));
+ names = (dns_name_t **)malloc(4000000 * sizeof(dns_name_t *));
+ values = (int *)malloc(4000000 * sizeof(int));
+
+ for (i = 0; i < 4000000; i++) {
+ r = ((unsigned long)random()) % maxvalue;
+ snprintf(namestr, sizeof(namestr), "name%u.example.org.", r);
+ dns_test_namefromstring(namestr, &fnames[i]);
+ names[i] = dns_fixedname_name(&fnames[i]);
+ values[i] = r;
+ }
+
+ /* Create a tree. */
+ mytree = NULL;
+ result = dns_rbt_create(mctx, NULL, NULL, &mytree);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Insert test data into the tree. */
+ for (i = 0; i < maxvalue; i++) {
+ snprintf(namestr, sizeof(namestr), "name%u.example.org.", i);
+ node = NULL;
+ result = insert_helper(mytree, namestr, &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ node->data = (void *)(intptr_t)i;
+ }
+
+ result = isc_time_now(&ts1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ nthreads = ISC_MIN(isc_os_ncpus(), 32);
+ nthreads = ISC_MAX(nthreads, 1);
+ for (i = 0; i < nthreads; i++) {
+ isc_thread_create(find_thread, mytree, &threads[i]);
+ }
+
+ for (i = 0; i < nthreads; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ result = isc_time_now(&ts2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ t = isc_time_microdiff(&ts2, &ts1);
+
+ printf("%u findnode calls, %f seconds, %f calls/second\n",
+ nthreads * 8 * 4000000, t / 1000000.0,
+ (nthreads * 8 * 4000000) / (t / 1000000.0));
+
+ free(values);
+ free(names);
+ free(fnames);
+
+ dns_rbt_destroy(&mytree);
+}
+#endif /* defined(DNS_BENCHMARK_TESTS) && !defined(__SANITIZE_THREAD__) */
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(rbt_create)
+ISC_TEST_ENTRY(rbt_nodecount)
+ISC_TEST_ENTRY(rbtnode_get_distance)
+ISC_TEST_ENTRY(rbt_check_distance_random)
+ISC_TEST_ENTRY(rbt_check_distance_ordered)
+ISC_TEST_ENTRY(rbt_insert)
+ISC_TEST_ENTRY(rbt_remove)
+ISC_TEST_ENTRY(rbt_insert_and_remove)
+ISC_TEST_ENTRY(rbt_findname)
+ISC_TEST_ENTRY(rbt_addname)
+ISC_TEST_ENTRY(rbt_deletename)
+ISC_TEST_ENTRY(rbt_nodechain)
+ISC_TEST_ENTRY(rbtnode_namelen)
+#if defined(DNS_BENCHMARK_TESTS) && !defined(__SANITIZE_THREAD__)
+ISC_TEST_ENTRY(benchmark)
+#endif /* defined(DNS_BENCHMARK_TESTS) && !defined(__SANITIZE_THREAD__) */
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/rbtdb_test.c b/tests/dns/rbtdb_test.c
new file mode 100644
index 0000000..59a5786
--- /dev/null
+++ b/tests/dns/rbtdb_test.c
@@ -0,0 +1,381 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/util.h>
+
+#include <dns/rbt.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#define KEEP_BEFORE
+
+/* Include the main file */
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#undef CHECK
+#include "rbtdb.c"
+#pragma GCC diagnostic pop
+
+#undef CHECK
+#include <tests/dns.h>
+
+const char *ownercase_vectors[12][2] = {
+ {
+ "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz",
+ "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz",
+ },
+ {
+ "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz",
+ "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ",
+ },
+ {
+ "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ",
+ "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz",
+ },
+ {
+ "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ",
+ "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz",
+ },
+ {
+ "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVxXyYzZ",
+ "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvxxyyzz",
+ },
+ {
+ "WwW.ExAmPlE.OrG",
+ "wWw.eXaMpLe.oRg",
+ },
+ {
+ "_SIP.tcp.example.org",
+ "_sip.TCP.example.org",
+ },
+ {
+ "bind-USERS.lists.example.org",
+ "bind-users.lists.example.org",
+ },
+ {
+ "a0123456789.example.org",
+ "A0123456789.example.org",
+ },
+ {
+ "\\000.example.org",
+ "\\000.example.org",
+ },
+ {
+ "wWw.\\000.isc.org",
+ "www.\\000.isc.org",
+ },
+ {
+ "\255.example.org",
+ "\255.example.ORG",
+ }
+};
+
+static bool
+ownercase_test_one(const char *str1, const char *str2) {
+ isc_result_t result;
+ rbtdb_nodelock_t node_locks[1];
+ dns_rbtdb_t rbtdb = { .node_locks = node_locks };
+ dns_rbtnode_t rbtnode = { .locknum = 0 };
+ rdatasetheader_t header = { 0 };
+ unsigned char *raw = (unsigned char *)(&header) + sizeof(header);
+ dns_rdataset_t rdataset = {
+ .magic = DNS_RDATASET_MAGIC,
+ .private1 = &rbtdb,
+ .private2 = &rbtnode,
+ .private3 = raw,
+ .methods = &rdataset_methods,
+ };
+
+ isc_buffer_t b;
+ dns_fixedname_t fname1, fname2;
+ dns_name_t *name1, *name2;
+
+ memset(node_locks, 0, sizeof(node_locks));
+ /* Minimal initialization of the mock objects */
+ NODE_INITLOCK(&rbtdb.node_locks[0].lock);
+
+ name1 = dns_fixedname_initname(&fname1);
+ isc_buffer_constinit(&b, str1, strlen(str1));
+ isc_buffer_add(&b, strlen(str1));
+ result = dns_name_fromtext(name1, &b, dns_rootname, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ name2 = dns_fixedname_initname(&fname2);
+ isc_buffer_constinit(&b, str2, strlen(str2));
+ isc_buffer_add(&b, strlen(str2));
+ result = dns_name_fromtext(name2, &b, dns_rootname, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Store the case from name1 */
+ dns_rdataset_setownercase(&rdataset, name1);
+
+ assert_true(CASESET(&header));
+
+ /* Retrieve the case to name2 */
+ dns_rdataset_getownercase(&rdataset, name2);
+
+ NODE_DESTROYLOCK(&rbtdb.node_locks[0].lock);
+
+ return (dns_name_caseequal(name1, name2));
+}
+
+ISC_RUN_TEST_IMPL(ownercase) {
+ UNUSED(state);
+
+ for (size_t n = 0; n < ARRAY_SIZE(ownercase_vectors); n++) {
+ assert_true(ownercase_test_one(ownercase_vectors[n][0],
+ ownercase_vectors[n][1]));
+ }
+
+ assert_false(ownercase_test_one("W.example.org", "\\000.example.org"));
+
+ /* Ö and ö in ISO Latin 1 */
+ assert_false(ownercase_test_one("\\216", "\\246"));
+}
+
+ISC_RUN_TEST_IMPL(setownercase) {
+ isc_result_t result;
+ rbtdb_nodelock_t node_locks[1];
+ dns_rbtdb_t rbtdb = { .node_locks = node_locks };
+ dns_rbtnode_t rbtnode = { .locknum = 0 };
+ rdatasetheader_t header = { 0 };
+ unsigned char *raw = (unsigned char *)(&header) + sizeof(header);
+ dns_rdataset_t rdataset = {
+ .magic = DNS_RDATASET_MAGIC,
+ .private1 = &rbtdb,
+ .private2 = &rbtnode,
+ .private3 = raw,
+ .methods = &rdataset_methods,
+ };
+ const char *str1 =
+ "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
+
+ isc_buffer_t b;
+ dns_fixedname_t fname1, fname2;
+ dns_name_t *name1, *name2;
+
+ UNUSED(state);
+
+ /* Minimal initialization of the mock objects */
+ memset(node_locks, 0, sizeof(node_locks));
+ NODE_INITLOCK(&rbtdb.node_locks[0].lock);
+
+ name1 = dns_fixedname_initname(&fname1);
+ isc_buffer_constinit(&b, str1, strlen(str1));
+ isc_buffer_add(&b, strlen(str1));
+ result = dns_name_fromtext(name1, &b, dns_rootname, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ name2 = dns_fixedname_initname(&fname2);
+ isc_buffer_constinit(&b, str1, strlen(str1));
+ isc_buffer_add(&b, strlen(str1));
+ result = dns_name_fromtext(name2, &b, dns_rootname, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_false(CASESET(&header));
+
+ /* Retrieve the case to name2 */
+ dns_rdataset_getownercase(&rdataset, name2);
+
+ NODE_DESTROYLOCK(&rbtdb.node_locks[0].lock);
+
+ assert_true(dns_name_caseequal(name1, name2));
+}
+
+/*
+ * No operation water() callback. We need it to cause overmem condition, but
+ * nothing has to be done in the callback.
+ */
+static void
+overmempurge_water(void *arg, int mark) {
+ UNUSED(arg);
+ UNUSED(mark);
+}
+
+/*
+ * Add to a cache DB 'db' an rdataset of type 'rtype' at a name
+ * <idx>.example.com. The rdataset would contain one data, and rdata_len is
+ * its length. 'rtype' is supposed to be some private type whose data can be
+ * arbitrary (and it doesn't matter in this test).
+ */
+static void
+overmempurge_addrdataset(dns_db_t *db, isc_stdtime_t now, int idx,
+ dns_rdatatype_t rtype, size_t rdata_len,
+ bool longname) {
+ isc_result_t result;
+ dns_rdata_t rdata;
+ dns_dbnode_t *node = NULL;
+ dns_rdatalist_t rdatalist;
+ dns_rdataset_t rdataset;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ char namebuf[DNS_NAME_FORMATSIZE];
+ unsigned char rdatabuf[65535] = { 0 }; /* large enough for any valid
+ RDATA */
+
+ REQUIRE(rdata_len <= sizeof(rdatabuf));
+
+ if (longname) {
+ /*
+ * Build a longest possible name (in wire format) that would
+ * result in a new rbt node with the long name data.
+ */
+ snprintf(namebuf, sizeof(namebuf),
+ "%010d.%010dabcdef%010dabcdef%010dabcdef%010dabcde."
+ "%010dabcdef%010dabcdef%010dabcdef%010dabcde."
+ "%010dabcdef%010dabcdef%010dabcdef%010dabcde."
+ "%010dabcdef%010dabcdef%010dabcdef01.",
+ idx, idx, idx, idx, idx, idx, idx, idx, idx, idx, idx,
+ idx, idx, idx, idx, idx);
+ } else {
+ snprintf(namebuf, sizeof(namebuf), "%d.example.com.", idx);
+ }
+ dns_test_namefromstring(namebuf, &fname);
+ name = dns_fixedname_name(&fname);
+
+ result = dns_db_findnode(db, name, true, &node);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(node);
+
+ dns_rdata_init(&rdata);
+ rdata.length = rdata_len;
+ rdata.data = rdatabuf;
+ rdata.rdclass = dns_rdataclass_in;
+ rdata.type = rtype;
+
+ dns_rdatalist_init(&rdatalist);
+ rdatalist.rdclass = dns_rdataclass_in;
+ rdatalist.type = rtype;
+ rdatalist.ttl = 3600;
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+
+ dns_rdataset_init(&rdataset);
+ dns_rdatalist_tordataset(&rdatalist, &rdataset);
+
+ result = dns_db_addrdataset(db, node, NULL, now, &rdataset, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_db_detachnode(db, &node);
+}
+
+ISC_RUN_TEST_IMPL(overmempurge_bigrdata) {
+ size_t maxcache = 2097152U; /* 2MB - same as DNS_CACHE_MINSIZE */
+ size_t hiwater = maxcache - (maxcache >> 3); /* borrowed from cache.c */
+ size_t lowater = maxcache - (maxcache >> 2); /* ditto */
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ isc_mem_t *mctx2 = NULL;
+ isc_stdtime_t now;
+ size_t i;
+
+ isc_stdtime_get(&now);
+ isc_mem_create(&mctx2);
+
+ result = dns_db_create(mctx2, "rbt", dns_rootname, dns_dbtype_cache,
+ dns_rdataclass_in, 0, NULL, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_mem_setwater(mctx2, overmempurge_water, NULL, hiwater, lowater);
+
+ /*
+ * Add cache entries with minimum size of data until 'overmem'
+ * condition is triggered.
+ * This should eventually happen, but we also limit the number of
+ * iteration to avoid an infinite loop in case something gets wrong.
+ */
+ for (i = 0; !isc_mem_isovermem(mctx2) && i < (maxcache / 10); i++) {
+ overmempurge_addrdataset(db, now, i, 50053, 0, false);
+ }
+ assert_true(isc_mem_isovermem(mctx2));
+
+ /*
+ * Then try to add the same number of entries, each has very large data.
+ * 'overmem purge' should keep the total cache size from not exceeding
+ * the 'hiwater' mark too much. So we should be able to assume the
+ * cache size doesn't reach the "max".
+ */
+ while (i-- > 0) {
+ overmempurge_addrdataset(db, now, i, 50054, 65535, false);
+ assert_true(isc_mem_inuse(mctx2) < maxcache);
+ }
+
+ dns_db_detach(&db);
+ isc_mem_destroy(&mctx2);
+}
+
+ISC_RUN_TEST_IMPL(overmempurge_longname) {
+ size_t maxcache = 2097152U; /* 2MB - same as DNS_CACHE_MINSIZE */
+ size_t hiwater = maxcache - (maxcache >> 3); /* borrowed from cache.c */
+ size_t lowater = maxcache - (maxcache >> 2); /* ditto */
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ isc_mem_t *mctx2 = NULL;
+ isc_stdtime_t now;
+ size_t i;
+
+ isc_stdtime_get(&now);
+ isc_mem_create(&mctx2);
+
+ result = dns_db_create(mctx2, "rbt", dns_rootname, dns_dbtype_cache,
+ dns_rdataclass_in, 0, NULL, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_mem_setwater(mctx2, overmempurge_water, NULL, hiwater, lowater);
+
+ /*
+ * Add cache entries with minimum size of data until 'overmem'
+ * condition is triggered.
+ * This should eventually happen, but we also limit the number of
+ * iteration to avoid an infinite loop in case something gets wrong.
+ */
+ for (i = 0; !isc_mem_isovermem(mctx2) && i < (maxcache / 10); i++) {
+ overmempurge_addrdataset(db, now, i, 50053, 0, false);
+ }
+ assert_true(isc_mem_isovermem(mctx2));
+
+ /*
+ * Then try to add the same number of entries, each has very large data.
+ * 'overmem purge' should keep the total cache size from not exceeding
+ * the 'hiwater' mark too much. So we should be able to assume the
+ * cache size doesn't reach the "max".
+ */
+ while (i-- > 0) {
+ overmempurge_addrdataset(db, now, i, 50054, 0, true);
+ assert_true(isc_mem_inuse(mctx2) < maxcache);
+ }
+
+ dns_db_detach(&db);
+ isc_mem_destroy(&mctx2);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(ownercase)
+ISC_TEST_ENTRY(setownercase)
+ISC_TEST_ENTRY(overmempurge_bigrdata)
+ISC_TEST_ENTRY(overmempurge_longname)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/rdata_test.c b/tests/dns/rdata_test.c
new file mode 100644
index 0000000..73e4526
--- /dev/null
+++ b/tests/dns/rdata_test.c
@@ -0,0 +1,3121 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+
+#include <openssl_shim.h>
+
+#include <openssl/err.h>
+
+#include <isc/cmocka.h>
+#include <isc/commandline.h>
+#include <isc/hex.h>
+#include <isc/lex.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <dns/rdata.h>
+
+#include <tests/dns.h>
+
+static bool debug = false;
+
+/*
+ * An array of these structures is passed to compare_ok().
+ */
+struct compare_ok {
+ const char *text1; /* text passed to fromtext_*() */
+ const char *text2; /* text passed to fromtext_*() */
+ int answer; /* -1, 0, 1 */
+ int lineno; /* source line defining this RDATA */
+};
+typedef struct compare_ok compare_ok_t;
+
+struct textvsunknown {
+ const char *text1;
+ const char *text2;
+};
+typedef struct textvsunknown textvsunknown_t;
+
+/*
+ * An array of these structures is passed to check_text_ok().
+ */
+typedef struct text_ok {
+ const char *text_in; /* text passed to fromtext_*() */
+ const char *text_out; /* text expected from totext_*();
+ * NULL indicates text_in is invalid */
+ unsigned int loop;
+} text_ok_t;
+
+/*
+ * An array of these structures is passed to check_wire_ok().
+ */
+typedef struct wire_ok {
+ unsigned char data[512]; /* RDATA in wire format */
+ size_t len; /* octets of data to parse */
+ bool ok; /* is this RDATA valid? */
+ unsigned int loop;
+} wire_ok_t;
+
+#define COMPARE(r1, r2, answer) \
+ { \
+ r1, r2, answer, __LINE__ \
+ }
+#define COMPARE_SENTINEL() \
+ { \
+ NULL, NULL, 0, __LINE__ \
+ }
+
+#define TEXT_VALID_CHANGED(data_in, data_out) \
+ { \
+ data_in, data_out, 0 \
+ }
+#define TEXT_VALID(data) \
+ { \
+ data, data, 0 \
+ }
+#define TEXT_VALID_LOOP(loop, data) \
+ { \
+ data, data, loop \
+ }
+#define TEXT_VALID_LOOPCHG(loop, data_in, data_out) \
+ { \
+ data_in, data_out, loop \
+ }
+#define TEXT_INVALID(data) \
+ { \
+ data, NULL, 0 \
+ }
+#define TEXT_SENTINEL() TEXT_INVALID(NULL)
+
+#define VARGC(...) (sizeof((unsigned char[]){ __VA_ARGS__ }))
+#define WIRE_TEST(ok, loop, ...) \
+ { \
+ { __VA_ARGS__ }, VARGC(__VA_ARGS__), ok, loop \
+ }
+#define WIRE_VALID(...) WIRE_TEST(true, 0, __VA_ARGS__)
+#define WIRE_VALID_LOOP(loop, ...) WIRE_TEST(true, loop, __VA_ARGS__)
+/*
+ * WIRE_INVALID() test cases must always have at least one octet specified to
+ * distinguish them from WIRE_SENTINEL(). Use the 'empty_ok' parameter passed
+ * to check_wire_ok() for indicating whether empty RDATA is allowed for a given
+ * RR type or not.
+ */
+#define WIRE_INVALID(FIRST, ...) WIRE_TEST(false, 0, FIRST, __VA_ARGS__)
+#define WIRE_SENTINEL() WIRE_TEST(false, 0)
+
+static void
+detect_uncleared_libcrypto_error(void) {
+ const char *file, *func, *data;
+ int line, flags;
+ long err;
+ bool leak = false;
+ while ((err = ERR_get_error_all(&file, &line, &func, &data, &flags)) !=
+ 0L)
+ {
+ fprintf(stderr,
+ "# Uncleared libcrypto error: %s:%d %s %s %ld %x\n",
+ file, line, func, data, err, flags);
+ leak = true;
+ }
+ assert_false(leak);
+}
+
+/*
+ * Call dns_rdata_fromwire() for data in 'src', which is 'srclen' octets in
+ * size and represents RDATA of given 'type' and 'class'. Store the resulting
+ * uncompressed wire form in 'dst', which is 'dstlen' octets in size, and make
+ * 'rdata' refer to that uncompressed wire form.
+ */
+static isc_result_t
+wire_to_rdata(const unsigned char *src, size_t srclen, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, unsigned char *dst, size_t dstlen,
+ dns_rdata_t *rdata) {
+ isc_buffer_t source, target;
+ dns_decompress_t dctx;
+ isc_result_t result;
+
+ /*
+ * Set up len-octet buffer pointing at data.
+ */
+ isc_buffer_constinit(&source, src, srclen);
+ isc_buffer_add(&source, srclen);
+ isc_buffer_setactive(&source, srclen);
+
+ /*
+ * Initialize target buffer.
+ */
+ isc_buffer_init(&target, dst, dstlen);
+
+ /*
+ * Try converting input data into uncompressed wire form.
+ */
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
+ result = dns_rdata_fromwire(rdata, rdclass, type, &source, &dctx, 0,
+ &target);
+ dns_decompress_invalidate(&dctx);
+ detect_uncleared_libcrypto_error();
+
+ return (result);
+}
+
+/*
+ * Call dns_rdata_towire() for rdata and write to result to dst.
+ */
+static isc_result_t
+rdata_towire(dns_rdata_t *rdata, unsigned char *dst, size_t dstlen,
+ size_t *length) {
+ isc_buffer_t target;
+ dns_compress_t cctx;
+ isc_result_t result;
+
+ /*
+ * Initialize target buffer.
+ */
+ isc_buffer_init(&target, dst, dstlen);
+
+ /*
+ * Try converting input data into uncompressed wire form.
+ */
+ dns_compress_init(&cctx, -1, mctx);
+ result = dns_rdata_towire(rdata, &cctx, &target);
+ detect_uncleared_libcrypto_error();
+ dns_compress_invalidate(&cctx);
+
+ *length = isc_buffer_usedlength(&target);
+
+ return (result);
+}
+
+static isc_result_t
+additionaldata_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
+ dns_rdataset_t *found) {
+ UNUSED(arg);
+ UNUSED(name);
+ UNUSED(qtype);
+ UNUSED(found);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * call dns_rdata_additionaldata() for rdata.
+ */
+static isc_result_t
+rdata_additionadata(dns_rdata_t *rdata) {
+ return (dns_rdata_additionaldata(rdata, dns_rootname, additionaldata_cb,
+ NULL));
+}
+
+/*
+ * Call dns_rdata_checknames() with various owner names chosen to
+ * match well known forms.
+ *
+ * We are currently only checking that the calls do not trigger
+ * assertion failures.
+ *
+ * XXXMPA A future extension could be to record the expected
+ * result and the expected value of 'bad'.
+ */
+static void
+rdata_checknames(dns_rdata_t *rdata) {
+ dns_fixedname_t fixed, bfixed;
+ dns_name_t *name, *bad;
+ isc_result_t result;
+
+ name = dns_fixedname_initname(&fixed);
+ bad = dns_fixedname_initname(&bfixed);
+
+ (void)dns_rdata_checknames(rdata, dns_rootname, NULL);
+ (void)dns_rdata_checknames(rdata, dns_rootname, bad);
+
+ result = dns_name_fromstring(name, "example.net", 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ (void)dns_rdata_checknames(rdata, name, NULL);
+ (void)dns_rdata_checknames(rdata, name, bad);
+
+ result = dns_name_fromstring(name, "in-addr.arpa", 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ (void)dns_rdata_checknames(rdata, name, NULL);
+ (void)dns_rdata_checknames(rdata, name, bad);
+
+ result = dns_name_fromstring(name, "ip6.arpa", 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ (void)dns_rdata_checknames(rdata, name, NULL);
+ (void)dns_rdata_checknames(rdata, name, bad);
+}
+
+/*
+ * Test whether converting rdata to a type-specific struct and then back to
+ * rdata results in the same uncompressed wire form. This checks whether
+ * tostruct_*() and fromstruct_*() routines for given RR class and type behave
+ * consistently.
+ *
+ * This function is called for every correctly processed input RDATA, from both
+ * check_text_ok_single() and check_wire_ok_single().
+ */
+static void
+check_struct_conversions(dns_rdata_t *rdata, size_t structsize,
+ unsigned int loop) {
+ dns_rdataclass_t rdclass = rdata->rdclass;
+ dns_rdatatype_t type = rdata->type;
+ isc_result_t result;
+ isc_buffer_t target;
+ void *rdata_struct;
+ char buf[1024];
+ unsigned int count = 0;
+
+ rdata_struct = isc_mem_allocate(mctx, structsize);
+ assert_non_null(rdata_struct);
+
+ /*
+ * Convert from uncompressed wire form into type-specific struct.
+ */
+ result = dns_rdata_tostruct(rdata, rdata_struct, NULL);
+ detect_uncleared_libcrypto_error();
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Convert from type-specific struct into uncompressed wire form.
+ */
+ isc_buffer_init(&target, buf, sizeof(buf));
+ result = dns_rdata_fromstruct(NULL, rdclass, type, rdata_struct,
+ &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Ensure results are consistent.
+ */
+ assert_int_equal(isc_buffer_usedlength(&target), rdata->length);
+
+ assert_memory_equal(buf, rdata->data, rdata->length);
+
+ /*
+ * Check that one can walk hip rendezvous servers and
+ * https/svcb parameters.
+ */
+ switch (type) {
+ case dns_rdatatype_hip: {
+ dns_rdata_hip_t *hip = rdata_struct;
+
+ for (result = dns_rdata_hip_first(hip); result == ISC_R_SUCCESS;
+ result = dns_rdata_hip_next(hip))
+ {
+ dns_name_t name;
+ dns_name_init(&name, NULL);
+ dns_rdata_hip_current(hip, &name);
+ assert_int_not_equal(dns_name_countlabels(&name), 0);
+ assert_true(dns_name_isabsolute(&name));
+ count++;
+ }
+ assert_int_equal(result, ISC_R_NOMORE);
+ assert_int_equal(count, loop);
+ break;
+ }
+ case dns_rdatatype_https: {
+ dns_rdata_in_https_t *https = rdata_struct;
+
+ for (result = dns_rdata_in_https_first(https);
+ result == ISC_R_SUCCESS;
+ result = dns_rdata_in_https_next(https))
+ {
+ isc_region_t region;
+ dns_rdata_in_https_current(https, &region);
+ assert_true(region.length >= 4);
+ count++;
+ }
+ assert_int_equal(result, ISC_R_NOMORE);
+ assert_int_equal(count, loop);
+ break;
+ }
+ case dns_rdatatype_svcb: {
+ dns_rdata_in_svcb_t *svcb = rdata_struct;
+
+ for (result = dns_rdata_in_svcb_first(svcb);
+ result == ISC_R_SUCCESS;
+ result = dns_rdata_in_svcb_next(svcb))
+ {
+ isc_region_t region;
+ dns_rdata_in_svcb_current(svcb, &region);
+ assert_true(region.length >= 4);
+ count++;
+ }
+ assert_int_equal(result, ISC_R_NOMORE);
+ assert_int_equal(count, loop);
+ break;
+ }
+ }
+
+ isc_mem_free(mctx, rdata_struct);
+}
+
+/*
+ * Check whether converting supplied text form RDATA into uncompressed wire
+ * form succeeds (tests fromtext_*()). If so, try converting it back into text
+ * form and see if it results in the original text (tests totext_*()).
+ */
+static void
+check_text_ok_single(const text_ok_t *text_ok, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, size_t structsize) {
+ unsigned char buf_fromtext[1024], buf_fromwire[1024], buf_towire[1024];
+ dns_rdata_t rdata = DNS_RDATA_INIT, rdata2 = DNS_RDATA_INIT;
+ char buf_totext[1024] = { 0 };
+ isc_buffer_t target;
+ isc_result_t result;
+ size_t length = 0;
+
+ if (debug) {
+ fprintf(stdout, "#check_text_ok_single(%s)\n",
+ text_ok->text_in);
+ }
+ /*
+ * Try converting text form RDATA into uncompressed wire form.
+ */
+ result = dns_test_rdatafromstring(&rdata, rdclass, type, buf_fromtext,
+ sizeof(buf_fromtext),
+ text_ok->text_in, false);
+ /*
+ * Check whether result is as expected.
+ */
+ if (text_ok->text_out != NULL) {
+ if (debug && result != ISC_R_SUCCESS) {
+ fprintf(stdout, "# '%s'\n", text_ok->text_in);
+ fprintf(stdout, "# result=%s\n",
+ isc_result_totext(result));
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+ } else {
+ if (debug && result == ISC_R_SUCCESS) {
+ fprintf(stdout, "#'%s'\n", text_ok->text_in);
+ }
+ assert_int_not_equal(result, ISC_R_SUCCESS);
+ }
+
+ /*
+ * If text form RDATA was not parsed correctly, performing any
+ * additional checks is pointless.
+ */
+ if (result != ISC_R_SUCCESS) {
+ return;
+ }
+
+ /*
+ * Try converting uncompressed wire form RDATA back into text form and
+ * check whether the resulting text is the same as the original one.
+ */
+ isc_buffer_init(&target, buf_totext, sizeof(buf_totext));
+ result = dns_rdata_totext(&rdata, NULL, &target);
+ detect_uncleared_libcrypto_error();
+ if (result != ISC_R_SUCCESS && debug) {
+ size_t i;
+ fprintf(stdout, "# dns_rdata_totext -> %s",
+ isc_result_totext(result));
+ for (i = 0; i < rdata.length; i++) {
+ if ((i % 16) == 0) {
+ fprintf(stdout, "\n#");
+ }
+ fprintf(stdout, " %02x", rdata.data[i]);
+ }
+ fprintf(stdout, "\n");
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+ /*
+ * Ensure buf_totext is properly NUL terminated as dns_rdata_totext()
+ * may attempt different output formats writing into the apparently
+ * unused part of the buffer.
+ */
+ isc_buffer_putuint8(&target, 0);
+ if (debug && strcmp(buf_totext, text_ok->text_out) != 0) {
+ fprintf(stdout, "# '%s' != '%s'\n", buf_totext,
+ text_ok->text_out);
+ }
+ assert_string_equal(buf_totext, text_ok->text_out);
+
+ if (debug) {
+ fprintf(stdout, "#dns_rdata_totext -> '%s'\n", buf_totext);
+ }
+
+ /*
+ * Ensure that fromtext_*() output is valid input for fromwire_*().
+ */
+ result = wire_to_rdata(rdata.data, rdata.length, rdclass, type,
+ buf_fromwire, sizeof(buf_fromwire), &rdata2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(rdata.length, rdata2.length);
+ assert_memory_equal(rdata.data, buf_fromwire, rdata.length);
+
+ /*
+ * Ensure that fromtext_*() output is valid input for towire_*().
+ */
+ result = rdata_towire(&rdata, buf_towire, sizeof(buf_towire), &length);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(rdata.length, length);
+ assert_memory_equal(rdata.data, buf_towire, length);
+
+ /*
+ * Test that additionaldata_*() succeeded.
+ */
+ result = rdata_additionadata(&rdata);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Exercise checknames_*().
+ */
+ rdata_checknames(&rdata);
+
+ /*
+ * Perform two-way conversion checks between uncompressed wire form and
+ * type-specific struct.
+ */
+ check_struct_conversions(&rdata, structsize, text_ok->loop);
+}
+
+/*
+ * Test whether converting rdata to text form and then parsing the result of
+ * that conversion again results in the same uncompressed wire form. This
+ * checks whether totext_*() output is parsable by fromtext_*() for given RR
+ * class and type.
+ *
+ * This function is called for every input RDATA which is successfully parsed
+ * by check_wire_ok_single() and whose type is not a meta-type.
+ */
+static void
+check_text_conversions(dns_rdata_t *rdata) {
+ char buf_totext[1024] = { 0 };
+ unsigned char buf_fromtext[1024];
+ isc_result_t result;
+ isc_buffer_t target;
+ dns_rdata_t rdata2 = DNS_RDATA_INIT;
+
+ /*
+ * Convert uncompressed wire form RDATA into text form. This
+ * conversion must succeed since input RDATA was successfully
+ * parsed by check_wire_ok_single().
+ */
+ isc_buffer_init(&target, buf_totext, sizeof(buf_totext));
+ result = dns_rdata_totext(rdata, NULL, &target);
+ detect_uncleared_libcrypto_error();
+ assert_int_equal(result, ISC_R_SUCCESS);
+ /*
+ * Ensure buf_totext is properly NUL terminated as dns_rdata_totext()
+ * may attempt different output formats writing into the apparently
+ * unused part of the buffer.
+ */
+ isc_buffer_putuint8(&target, 0);
+ if (debug) {
+ fprintf(stdout, "#'%s'\n", buf_totext);
+ }
+
+ /*
+ * Try parsing text form RDATA output by dns_rdata_totext() again.
+ */
+ result = dns_test_rdatafromstring(&rdata2, rdata->rdclass, rdata->type,
+ buf_fromtext, sizeof(buf_fromtext),
+ buf_totext, false);
+ if (debug && result != ISC_R_SUCCESS) {
+ fprintf(stdout, "# result = %s\n", isc_result_totext(result));
+ fprintf(stdout, "# '%s'\n", buf_fromtext);
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(rdata2.length, rdata->length);
+ assert_memory_equal(buf_fromtext, rdata->data, rdata->length);
+}
+
+/*
+ * Test whether converting rdata to multi-line text form and then parsing the
+ * result of that conversion again results in the same uncompressed wire form.
+ * This checks whether multi-line totext_*() output is parsable by fromtext_*()
+ * for given RR class and type.
+ *
+ * This function is called for every input RDATA which is successfully parsed
+ * by check_wire_ok_single() and whose type is not a meta-type.
+ */
+static void
+check_multiline_text_conversions(dns_rdata_t *rdata) {
+ char buf_totext[1024] = { 0 };
+ unsigned char buf_fromtext[1024];
+ isc_result_t result;
+ isc_buffer_t target;
+ dns_rdata_t rdata2 = DNS_RDATA_INIT;
+ unsigned int flags;
+
+ /*
+ * Convert uncompressed wire form RDATA into multi-line text form.
+ * This conversion must succeed since input RDATA was successfully
+ * parsed by check_wire_ok_single().
+ */
+ isc_buffer_init(&target, buf_totext, sizeof(buf_totext));
+ flags = dns_master_styleflags(&dns_master_style_default);
+ result = dns_rdata_tofmttext(rdata, dns_rootname, flags, 80 - 32, 4,
+ "\n", &target);
+ detect_uncleared_libcrypto_error();
+ assert_int_equal(result, ISC_R_SUCCESS);
+ /*
+ * Ensure buf_totext is properly NUL terminated as
+ * dns_rdata_tofmttext() may attempt different output formats
+ * writing into the apparently unused part of the buffer.
+ */
+ isc_buffer_putuint8(&target, 0);
+ if (debug) {
+ fprintf(stdout, "#'%s'\n", buf_totext);
+ }
+
+ /*
+ * Try parsing multi-line text form RDATA output by
+ * dns_rdata_tofmttext() again.
+ */
+ result = dns_test_rdatafromstring(&rdata2, rdata->rdclass, rdata->type,
+ buf_fromtext, sizeof(buf_fromtext),
+ buf_totext, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(rdata2.length, rdata->length);
+ assert_memory_equal(buf_fromtext, rdata->data, rdata->length);
+}
+
+/*
+ * Test whether supplied wire form RDATA is properly handled as being either
+ * valid or invalid for an RR of given rdclass and type.
+ */
+static void
+check_wire_ok_single(const wire_ok_t *wire_ok, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, size_t structsize) {
+ unsigned char buf[1024], buf_towire[1024];
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ size_t length = 0;
+
+ /*
+ * Try converting wire data into uncompressed wire form.
+ */
+ result = wire_to_rdata(wire_ok->data, wire_ok->len, rdclass, type, buf,
+ sizeof(buf), &rdata);
+ /*
+ * Check whether result is as expected.
+ */
+ if (wire_ok->ok) {
+ assert_int_equal(result, ISC_R_SUCCESS);
+ } else {
+ assert_int_not_equal(result, ISC_R_SUCCESS);
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ return;
+ }
+
+ /*
+ * If data was parsed correctly, perform two-way conversion checks
+ * between uncompressed wire form and type-specific struct.
+ *
+ * If the RR type is not a meta-type, additionally perform two-way
+ * conversion checks between:
+ *
+ * - uncompressed wire form and text form,
+ * - uncompressed wire form and multi-line text form.
+ */
+ check_struct_conversions(&rdata, structsize, wire_ok->loop);
+ if (!dns_rdatatype_ismeta(rdata.type)) {
+ check_text_conversions(&rdata);
+ check_multiline_text_conversions(&rdata);
+ }
+
+ /*
+ * Ensure that fromwire_*() output is valid input for towire_*().
+ */
+ result = rdata_towire(&rdata, buf_towire, sizeof(buf_towire), &length);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(rdata.length, length);
+ assert_memory_equal(rdata.data, buf_towire, length);
+
+ /*
+ * Test that additionaldata_*() succeeded.
+ */
+ result = rdata_additionadata(&rdata);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Exercise checknames_*().
+ */
+ rdata_checknames(&rdata);
+}
+
+/*
+ * Test fromtext_*() and totext_*() routines for given RR class and type for
+ * each text form RDATA in the supplied array. See the comment for
+ * check_text_ok_single() for an explanation of how exactly these routines are
+ * tested.
+ */
+static void
+check_text_ok(const text_ok_t *text_ok, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, size_t structsize) {
+ size_t i;
+
+ /*
+ * Check all entries in the supplied array.
+ */
+ for (i = 0; text_ok[i].text_in != NULL; i++) {
+ check_text_ok_single(&text_ok[i], rdclass, type, structsize);
+ }
+}
+
+/*
+ * For each wire form RDATA in the supplied array, check whether it is properly
+ * handled as being either valid or invalid for an RR of given rdclass and
+ * type, then check whether trying to process a zero-length wire data buffer
+ * yields the expected result. This checks whether the fromwire_*() routine
+ * for given RR class and type behaves as expected.
+ */
+static void
+check_wire_ok(const wire_ok_t *wire_ok, bool empty_ok, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, size_t structsize) {
+ wire_ok_t empty_wire = WIRE_TEST(empty_ok, 0);
+ size_t i;
+
+ /*
+ * Check all entries in the supplied array.
+ */
+ for (i = 0; wire_ok[i].len != 0; i++) {
+ if (debug) {
+ fprintf(stderr, "calling check_wire_ok_single on %zu\n",
+ i);
+ }
+ check_wire_ok_single(&wire_ok[i], rdclass, type, structsize);
+ }
+
+ /*
+ * Check empty wire data.
+ */
+ check_wire_ok_single(&empty_wire, rdclass, type, structsize);
+}
+
+/*
+ * Check that two records compare as expected with dns_rdata_compare().
+ */
+static void
+check_compare_ok_single(const compare_ok_t *compare_ok,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type) {
+ dns_rdata_t rdata1 = DNS_RDATA_INIT, rdata2 = DNS_RDATA_INIT;
+ unsigned char buf1[1024], buf2[1024];
+ isc_result_t result;
+ int answer;
+
+ result = dns_test_rdatafromstring(&rdata1, rdclass, type, buf1,
+ sizeof(buf1), compare_ok->text1,
+ false);
+ if (result != ISC_R_SUCCESS) {
+ fail_msg("# line %d: '%s': expected success, got failure",
+ compare_ok->lineno, compare_ok->text1);
+ }
+
+ result = dns_test_rdatafromstring(&rdata2, rdclass, type, buf2,
+ sizeof(buf2), compare_ok->text2,
+ false);
+
+ if (result != ISC_R_SUCCESS) {
+ fail_msg("# line %d: '%s': expected success, got failure",
+ compare_ok->lineno, compare_ok->text2);
+ }
+
+ answer = dns_rdata_compare(&rdata1, &rdata2);
+ detect_uncleared_libcrypto_error();
+ if (compare_ok->answer == 0 && answer != 0) {
+ fail_msg("# line %d: dns_rdata_compare('%s', '%s'): "
+ "expected equal, got %s",
+ compare_ok->lineno, compare_ok->text1,
+ compare_ok->text2,
+ (answer > 0) ? "greater than" : "less than");
+ }
+ if (compare_ok->answer < 0 && answer >= 0) {
+ fail_msg("# line %d: dns_rdata_compare('%s', '%s'): "
+ "expected less than, got %s",
+ compare_ok->lineno, compare_ok->text1,
+ compare_ok->text2,
+ (answer == 0) ? "equal" : "greater than");
+ }
+ if (compare_ok->answer > 0 && answer <= 0) {
+ fail_msg("line %d: dns_rdata_compare('%s', '%s'): "
+ "expected greater than, got %s",
+ compare_ok->lineno, compare_ok->text1,
+ compare_ok->text2,
+ (answer == 0) ? "equal" : "less than");
+ }
+}
+
+/*
+ * Check that all the records sets in compare_ok compare as expected
+ * with dns_rdata_compare().
+ */
+static void
+check_compare_ok(const compare_ok_t *compare_ok, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type) {
+ size_t i;
+ /*
+ * Check all entries in the supplied array.
+ */
+ for (i = 0; compare_ok[i].text1 != NULL; i++) {
+ check_compare_ok_single(&compare_ok[i], rdclass, type);
+ }
+}
+
+/*
+ * Test whether supplied sets of text form and/or wire form RDATA are handled
+ * as expected.
+ *
+ * The empty_ok argument denotes whether an attempt to parse a zero-length wire
+ * data buffer should succeed or not (it is valid for some RR types). There is
+ * no point in performing a similar check for empty text form RDATA, because
+ * dns_rdata_fromtext() returns ISC_R_UNEXPECTEDEND before calling fromtext_*()
+ * for the given RR class and type.
+ */
+static void
+check_rdata(const text_ok_t *text_ok, const wire_ok_t *wire_ok,
+ const compare_ok_t *compare_ok, bool empty_ok,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type, size_t structsize) {
+ if (text_ok != NULL) {
+ check_text_ok(text_ok, rdclass, type, structsize);
+ }
+ if (wire_ok != NULL) {
+ check_wire_ok(wire_ok, empty_ok, rdclass, type, structsize);
+ }
+ if (compare_ok != NULL) {
+ check_compare_ok(compare_ok, rdclass, type);
+ }
+}
+
+/*
+ * Check presentation vs unknown format of the record.
+ */
+static void
+check_textvsunknown_single(const textvsunknown_t *textvsunknown,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type) {
+ dns_rdata_t rdata1 = DNS_RDATA_INIT, rdata2 = DNS_RDATA_INIT;
+ unsigned char buf1[1024], buf2[1024];
+ isc_result_t result;
+
+ result = dns_test_rdatafromstring(&rdata1, rdclass, type, buf1,
+ sizeof(buf1), textvsunknown->text1,
+ false);
+ if (debug && result != ISC_R_SUCCESS) {
+ fprintf(stdout, "# '%s'\n", textvsunknown->text1);
+ fprintf(stdout, "# result=%s\n", isc_result_totext(result));
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_test_rdatafromstring(&rdata2, rdclass, type, buf2,
+ sizeof(buf2), textvsunknown->text2,
+ false);
+ if (debug && result != ISC_R_SUCCESS) {
+ fprintf(stdout, "# '%s'\n", textvsunknown->text2);
+ fprintf(stdout, "# result=%s\n", isc_result_totext(result));
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+ if (debug && rdata1.length != rdata2.length) {
+ fprintf(stdout, "# '%s'\n", textvsunknown->text1);
+ fprintf(stdout, "# rdata1.length (%u) != rdata2.length (%u)\n",
+ rdata1.length, rdata2.length);
+ }
+ assert_int_equal(rdata1.length, rdata2.length);
+ if (debug && memcmp(rdata1.data, rdata2.data, rdata1.length) != 0) {
+ unsigned int i;
+ fprintf(stdout, "# '%s'\n", textvsunknown->text1);
+ for (i = 0; i < rdata1.length; i++) {
+ if (rdata1.data[i] != rdata2.data[i]) {
+ fprintf(stderr, "# %u: %02x != %02x\n", i,
+ rdata1.data[i], rdata2.data[i]);
+ }
+ }
+ }
+ assert_memory_equal(rdata1.data, rdata2.data, rdata1.length);
+}
+
+static void
+check_textvsunknown(const textvsunknown_t *textvsunknown,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type) {
+ size_t i;
+
+ /*
+ * Check all entries in the supplied array.
+ */
+ for (i = 0; textvsunknown[i].text1 != NULL; i++) {
+ check_textvsunknown_single(&textvsunknown[i], rdclass, type);
+ }
+}
+
+/*
+ * Common tests for RR types based on KEY that require key data:
+ *
+ * - CDNSKEY (RFC 7344)
+ * - DNSKEY (RFC 4034)
+ * - RKEY (draft-reid-dnsext-rkey-00)
+ */
+static void
+key_required(void **state, dns_rdatatype_t type, size_t size) {
+ wire_ok_t wire_ok[] = { /*
+ * RDATA must be at least 5 octets in size:
+ *
+ * - 2 octets for Flags,
+ * - 1 octet for Protocol,
+ * - 1 octet for Algorithm,
+ * - Public Key must not be empty.
+ *
+ * RFC 2535 section 3.1.2 allows the Public Key
+ * to be empty if bits 0-1 of Flags are both
+ * set, but that only applies to KEY records:
+ * for the RR types tested here, the Public Key
+ * must not be empty.
+ */
+ WIRE_INVALID(0x00),
+ WIRE_INVALID(0x00, 0x00),
+ WIRE_INVALID(0x00, 0x00, 0x00),
+ WIRE_INVALID(0xc0, 0x00, 0x00, 0x00),
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00),
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00),
+ WIRE_SENTINEL()
+ };
+
+ UNUSED(state);
+
+ check_rdata(NULL, wire_ok, NULL, false, dns_rdataclass_in, type, size);
+}
+
+/* APL RDATA manipulations */
+ISC_RUN_TEST_IMPL(apl) {
+ text_ok_t text_ok[] = {
+ /* empty list */
+ TEXT_VALID(""),
+ /* min,max prefix IPv4 */
+ TEXT_VALID("1:0.0.0.0/0"), TEXT_VALID("1:127.0.0.1/32"),
+ /* min,max prefix IPv6 */
+ TEXT_VALID("2:::/0"), TEXT_VALID("2:::1/128"),
+ /* negated */
+ TEXT_VALID("!1:0.0.0.0/0"), TEXT_VALID("!1:127.0.0.1/32"),
+ TEXT_VALID("!2:::/0"), TEXT_VALID("!2:::1/128"),
+ /* bits set after prefix length - not disallowed */
+ TEXT_VALID("1:127.0.0.0/0"), TEXT_VALID("2:8000::/0"),
+ /* multiple */
+ TEXT_VALID("1:0.0.0.0/0 1:127.0.0.1/32"),
+ TEXT_VALID("1:0.0.0.0/0 !1:127.0.0.1/32"),
+ /* family 0, prefix 0, positive */
+ TEXT_VALID("\\# 4 00000000"),
+ /* family 0, prefix 0, negative */
+ TEXT_VALID("\\# 4 00000080"),
+ /* prefix too long */
+ TEXT_INVALID("1:0.0.0.0/33"), TEXT_INVALID("2:::/129"),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL()
+ };
+ wire_ok_t wire_ok[] = { /* zero length */
+ WIRE_VALID(),
+ /* prefix too big IPv4 */
+ WIRE_INVALID(0x00, 0x01, 33U, 0x00),
+ /* prefix too big IPv6 */
+ WIRE_INVALID(0x00, 0x02, 129U, 0x00),
+ /* trailing zero octet in afdpart */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x01, 0x00),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, true, dns_rdataclass_in,
+ dns_rdatatype_apl, sizeof(dns_rdata_in_apl_t));
+}
+
+/*
+ * http://broadband-forum.org/ftp/pub/approved-specs/af-saa-0069.000.pdf
+ *
+ * ATMA RR’s have the following RDATA format:
+ *
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | FORMAT | |
+ * +--+--+--+--+--+--+--+--+ |
+ * / ADDRESS /
+ * | |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *
+ * The fields have the following meaning:
+ *
+ * * FORMAT: One octet that indicates the format of ADDRESS. The two
+ * possible values for FORMAT are value 0 indicating ATM End System Address
+ * (AESA) format and value 1 indicating E.164 format.
+ *
+ * * ADDRESS: Variable length string of octets containing the ATM address of
+ * the node to which this RR pertains.
+ *
+ * When the format value is 0, indicating that the address is in AESA format,
+ * the address is coded as described in ISO 8348/AD 2 using the preferred
+ * binary encoding of the ISO NSAP format. When the format value is 1,
+ * indicating that the address is in E.164 format, the Address/Number Digits
+ * appear in the order in which they would be entered on a numeric keypad.
+ * Digits are coded in IA5 characters with the leftmost bit of each digit set
+ * to 0. This ATM address appears in ATM End System Address Octets field (AESA
+ * format) or the Address/Number Digits field (E.164 format) of the Called
+ * party number information element [ATMUNI3.1]. Subaddress information is
+ * intentionally not included because E.164 subaddress information is used for
+ * routing.
+ *
+ * ATMA RRs cause no additional section processing.
+ */
+ISC_RUN_TEST_IMPL(atma) {
+ text_ok_t text_ok[] = { TEXT_VALID("00"),
+ TEXT_VALID_CHANGED("0.0", "00"),
+ /*
+ * multiple consecutive periods
+ */
+ TEXT_INVALID("0..0"),
+ /*
+ * trailing period
+ */
+ TEXT_INVALID("00."),
+ /*
+ * leading period
+ */
+ TEXT_INVALID(".00"),
+ /*
+ * Not full octets.
+ */
+ TEXT_INVALID("000"),
+ /*
+ * E.164
+ */
+ TEXT_VALID("+61200000000"),
+ /*
+ * E.164 with periods
+ */
+ TEXT_VALID_CHANGED("+61.2.0000.0000", "+6120000"
+ "0000"),
+ /*
+ * E.164 with period at end
+ */
+ TEXT_INVALID("+61200000000."),
+ /*
+ * E.164 with multiple consecutive periods
+ */
+ TEXT_INVALID("+612..00000000"),
+ /*
+ * E.164 with period before the leading digit.
+ */
+ TEXT_INVALID("+.61200000000"),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL() };
+ wire_ok_t wire_ok[] = {
+ /*
+ * Too short.
+ */
+ WIRE_INVALID(0x00), WIRE_INVALID(0x01),
+ /*
+ * all digits
+ */
+ WIRE_VALID(0x01, '6', '1', '2', '0', '0', '0'),
+ /*
+ * non digit
+ */
+ WIRE_INVALID(0x01, '+', '6', '1', '2', '0', '0', '0'),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_atma, sizeof(dns_rdata_in_atma_t));
+}
+
+/* AMTRELAY RDATA manipulations */
+ISC_RUN_TEST_IMPL(amtrelay) {
+ text_ok_t text_ok[] = {
+ TEXT_INVALID(""), TEXT_INVALID("0"), TEXT_INVALID("0 0"),
+ /* gateway type 0 */
+ TEXT_VALID("0 0 0"), TEXT_VALID("0 1 0"),
+ TEXT_INVALID("0 2 0"), /* discovery out of range */
+ TEXT_VALID("255 1 0"), /* max precedence */
+ TEXT_INVALID("256 1 0"), /* precedence out of range */
+
+ /* IPv4 gateway */
+ TEXT_INVALID("0 0 1"), /* no address */
+ TEXT_VALID("0 0 1 0.0.0.0"),
+ TEXT_INVALID("0 0 1 0.0.0.0 x"), /* extra */
+ TEXT_INVALID("0 0 1 0.0.0.0.0"), /* bad address */
+ TEXT_INVALID("0 0 1 ::"), /* bad address */
+ TEXT_INVALID("0 0 1 ."), /* bad address */
+
+ /* IPv6 gateway */
+ TEXT_INVALID("0 0 2"), /* no address */
+ TEXT_VALID("0 0 2 ::"), TEXT_INVALID("0 0 2 :: xx"), /* extra */
+ TEXT_INVALID("0 0 2 0.0.0.0"), /* bad address */
+ TEXT_INVALID("0 0 2 ."), /* bad address */
+
+ /* hostname gateway */
+ TEXT_INVALID("0 0 3"), /* no name */
+ /* IPv4 is a valid name */
+ TEXT_VALID_CHANGED("0 0 3 0.0.0.0", "0 0 3 0.0.0.0."),
+ /* IPv6 is a valid name */
+ TEXT_VALID_CHANGED("0 0 3 ::", "0 0 3 ::."),
+ TEXT_VALID_CHANGED("0 0 3 example", "0 0 3 example."),
+ TEXT_VALID("0 0 3 example."),
+ TEXT_INVALID("0 0 3 example. x"), /* extra */
+
+ /* unknown gateway */
+ TEXT_VALID("\\# 2 0004"), TEXT_VALID("\\# 2 0084"),
+ TEXT_VALID("\\# 2 007F"), TEXT_VALID("\\# 3 000400"),
+ TEXT_VALID("\\# 3 008400"), TEXT_VALID("\\# 3 00FF00"),
+
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL()
+ };
+ wire_ok_t wire_ok[] = {
+ WIRE_INVALID(0x00), WIRE_VALID(0x00, 0x00),
+ WIRE_VALID(0x00, 0x80), WIRE_INVALID(0x00, 0x00, 0x00),
+ WIRE_INVALID(0x00, 0x80, 0x00),
+
+ WIRE_INVALID(0x00, 0x01), WIRE_INVALID(0x00, 0x01, 0x00),
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x00),
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x00),
+ WIRE_VALID(0x00, 0x01, 0x00, 0x00, 0x00, 0x00),
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00),
+
+ WIRE_INVALID(0x00, 0x02), WIRE_INVALID(0x00, 0x02, 0x00),
+ WIRE_VALID(0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15),
+ WIRE_INVALID(0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16),
+
+ WIRE_INVALID(0x00, 0x03), WIRE_VALID(0x00, 0x03, 0x00),
+ WIRE_INVALID(0x00, 0x03, 0x00, 0x00), /* extra */
+
+ WIRE_VALID(0x00, 0x04), WIRE_VALID(0x00, 0x04, 0x00),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_amtrelay, sizeof(dns_rdata_amtrelay_t));
+}
+
+ISC_RUN_TEST_IMPL(cdnskey) {
+ key_required(state, dns_rdatatype_cdnskey, sizeof(dns_rdata_cdnskey_t));
+}
+
+/*
+ * CSYNC tests.
+ *
+ * RFC 7477:
+ *
+ * 2.1. The CSYNC Resource Record Format
+ *
+ * 2.1.1. The CSYNC Resource Record Wire Format
+ *
+ * The CSYNC RDATA consists of the following fields:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SOA Serial |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Flags | Type Bit Map /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * / Type Bit Map (continued) /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 2.1.1.1. The SOA Serial Field
+ *
+ * The SOA Serial field contains a copy of the 32-bit SOA serial number
+ * from the child zone. If the soaminimum flag is set, parental agents
+ * querying children's authoritative servers MUST NOT act on data from
+ * zones advertising an SOA serial number less than this value. See
+ * [RFC1982] for properly implementing "less than" logic. If the
+ * soaminimum flag is not set, parental agents MUST ignore the value in
+ * the SOA Serial field. Clients can set the field to any value if the
+ * soaminimum flag is unset, such as the number zero.
+ *
+ * (...)
+ *
+ * 2.1.1.2. The Flags Field
+ *
+ * The Flags field contains 16 bits of boolean flags that define
+ * operations that affect the processing of the CSYNC record. The flags
+ * defined in this document are as follows:
+ *
+ * 0x00 0x01: "immediate"
+ *
+ * 0x00 0x02: "soaminimum"
+ *
+ * The definitions for how the flags are to be used can be found in
+ * Section 3.
+ *
+ * The remaining flags are reserved for use by future specifications.
+ * Undefined flags MUST be set to 0 by CSYNC publishers. Parental
+ * agents MUST NOT process a CSYNC record if it contains a 1 value for a
+ * flag that is unknown to or unsupported by the parental agent.
+ *
+ * 2.1.1.2.1. The Type Bit Map Field
+ *
+ * The Type Bit Map field indicates the record types to be processed by
+ * the parental agent, according to the procedures in Section 3. The
+ * Type Bit Map field is encoded in the same way as the Type Bit Map
+ * field of the NSEC record, described in [RFC4034], Section 4.1.2. If
+ * a bit has been set that a parental agent implementation does not
+ * understand, the parental agent MUST NOT act upon the record.
+ * Specifically, a parental agent must not simply copy the data, and it
+ * must understand the semantics associated with a bit in the Type Bit
+ * Map field that has been set to 1.
+ */
+ISC_RUN_TEST_IMPL(csync) {
+ text_ok_t text_ok[] = { TEXT_INVALID(""),
+ TEXT_INVALID("0"),
+ TEXT_VALID("0 0"),
+ TEXT_VALID("0 0 A"),
+ TEXT_VALID("0 0 NS"),
+ TEXT_VALID("0 0 AAAA"),
+ TEXT_VALID("0 0 A AAAA"),
+ TEXT_VALID("0 0 A NS AAAA"),
+ TEXT_INVALID("0 0 A NS AAAA BOGUS"),
+ TEXT_SENTINEL() };
+ wire_ok_t wire_ok[] = {
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00),
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00, 0x00),
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00),
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00),
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Serial + flags only.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Bad type map.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Bad type map.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Good type map.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x02),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_csync, sizeof(dns_rdata_csync_t));
+}
+
+ISC_RUN_TEST_IMPL(dnskey) {
+ key_required(state, dns_rdatatype_dnskey, sizeof(dns_rdata_dnskey_t));
+}
+
+/*
+ * DOA tests.
+ *
+ * draft-durand-doa-over-dns-03:
+ *
+ * 3.2. DOA RDATA Wire Format
+ *
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * 0: | |
+ * | DOA-ENTERPRISE |
+ * | |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * 4: | |
+ * | DOA-TYPE |
+ * | |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * 8: | DOA-LOCATION | DOA-MEDIA-TYPE /
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * 10: / /
+ * / DOA-MEDIA-TYPE (continued) /
+ * / /
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * / /
+ * / DOA-DATA /
+ * / /
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * DOA-ENTERPRISE: a 32-bit unsigned integer in network order.
+ *
+ * DOA-TYPE: a 32-bit unsigned integer in network order.
+ *
+ * DOA-LOCATION: an 8-bit unsigned integer.
+ *
+ * DOA-MEDIA-TYPE: A <character-string> (see [RFC1035]). The first
+ * octet of the <character-string> contains the number of characters to
+ * follow.
+ *
+ * DOA-DATA: A variable length blob of binary data. The length of the
+ * DOA-DATA is not contained within the wire format of the RR and has to
+ * be computed from the RDLENGTH of the entire RR once other fields have
+ * been taken into account.
+ *
+ * 3.3. DOA RDATA Presentation Format
+ *
+ * The DOA-ENTERPRISE field is presented as an unsigned 32-bit decimal
+ * integer with range 0 - 4,294,967,295.
+ *
+ * The DOA-TYPE field is presented as an unsigned 32-bit decimal integer
+ * with range 0 - 4,294,967,295.
+ *
+ * The DOA-LOCATION field is presented as an unsigned 8-bit decimal
+ * integer with range 0 - 255.
+ *
+ * The DOA-MEDIA-TYPE field is presented as a single <character-string>.
+ *
+ * The DOA-DATA is presented as Base64 encoded data [RFC4648] unless the
+ * DOA-DATA is empty in which case it is presented as a single dash
+ * character ("-", ASCII 45). White space is permitted within Base64
+ * data.
+ */
+ISC_RUN_TEST_IMPL(doa) {
+ text_ok_t text_ok[] = {
+ /*
+ * Valid, non-empty DOA-DATA.
+ */
+ TEXT_VALID("0 0 1 \"text/plain\" Zm9v"),
+ /*
+ * Valid, non-empty DOA-DATA with whitespace in between.
+ */
+ TEXT_VALID_CHANGED("0 0 1 \"text/plain\" Zm 9v", "0 0 1 "
+ "\"text/"
+ "plain\" "
+ "Zm9v"),
+ /*
+ * Valid, unquoted DOA-MEDIA-TYPE, non-empty DOA-DATA.
+ */
+ TEXT_VALID_CHANGED("0 0 1 text/plain Zm9v", "0 0 1 "
+ "\"text/plain\" "
+ "Zm9v"),
+ /*
+ * Invalid, quoted non-empty DOA-DATA.
+ */
+ TEXT_INVALID("0 0 1 \"text/plain\" \"Zm9v\""),
+ /*
+ * Valid, empty DOA-DATA.
+ */
+ TEXT_VALID("0 0 1 \"text/plain\" -"),
+ /*
+ * Invalid, quoted empty DOA-DATA.
+ */
+ TEXT_INVALID("0 0 1 \"text/plain\" \"-\""),
+ /*
+ * Invalid, missing "-" in empty DOA-DATA.
+ */
+ TEXT_INVALID("0 0 1 \"text/plain\""),
+ /*
+ * Valid, undefined DOA-LOCATION.
+ */
+ TEXT_VALID("0 0 100 \"text/plain\" Zm9v"),
+ /*
+ * Invalid, DOA-LOCATION too big.
+ */
+ TEXT_INVALID("0 0 256 \"text/plain\" ZM9v"),
+ /*
+ * Valid, empty DOA-MEDIA-TYPE, non-empty DOA-DATA.
+ */
+ TEXT_VALID("0 0 2 \"\" aHR0cHM6Ly93d3cuaXNjLm9yZy8="),
+ /*
+ * Valid, empty DOA-MEDIA-TYPE, empty DOA-DATA.
+ */
+ TEXT_VALID("0 0 1 \"\" -"),
+ /*
+ * Valid, DOA-MEDIA-TYPE with a space.
+ */
+ TEXT_VALID("0 0 1 \"plain text\" Zm9v"),
+ /*
+ * Invalid, missing DOA-MEDIA-TYPE.
+ */
+ TEXT_INVALID("1234567890 1234567890 1"),
+ /*
+ * Valid, DOA-DATA over 255 octets.
+ */
+ TEXT_VALID("1234567890 1234567890 1 \"image/gif\" "
+ "R0lGODlhKAAZAOMCAGZmZgBmmf///zOZzMz//5nM/zNmmWbM"
+ "/5nMzMzMzACZ/////////////////////yH5BAEKAA8ALAAA"
+ "AAAoABkAAATH8IFJK5U2a4337F5ogRkpnoCJrly7PrCKyh8c"
+ "3HgAhzT35MDbbtO7/IJIHbGiOiaTxVTpSVWWLqNq1UVyapNS"
+ "1wd3OAxug0LhnCubcVhsxysQnOt4ATpvvzHlFzl1AwODhWeF"
+ "AgRpen5/UhheAYMFdUB4SFcpGEGGdQeCAqBBLTuSk30EeXd9"
+ "pEsAbKGxjHqDSE0Sp6ixN4N1BJmbc7lIhmsBich1awPAjkY1"
+ "SZR8bJWrz382SGqIBQQFQd4IsUTaX+ceuudPEQA7"),
+ /*
+ * Invalid, bad Base64 in DOA-DATA.
+ */
+ TEXT_INVALID("1234567890 1234567890 1 \"image/gif\" R0lGODl"),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL()
+ };
+ wire_ok_t wire_ok[] = {
+ /*
+ * Valid, empty DOA-MEDIA-TYPE, empty DOA-DATA.
+ */
+ WIRE_VALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x01,
+ 0x00),
+ /*
+ * Invalid, missing DOA-MEDIA-TYPE.
+ */
+ WIRE_INVALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78,
+ 0x01),
+ /*
+ * Invalid, malformed DOA-MEDIA-TYPE length.
+ */
+ WIRE_INVALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78,
+ 0x01, 0xff),
+ /*
+ * Valid, empty DOA-DATA.
+ */
+ WIRE_VALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x01,
+ 0x03, 0x66, 0x6f, 0x6f),
+ /*
+ * Valid, non-empty DOA-DATA.
+ */
+ WIRE_VALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x01,
+ 0x03, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72),
+ /*
+ * Valid, DOA-DATA over 255 octets.
+ */
+ WIRE_VALID(0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x01,
+ 0x06, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x00, 0x66,
+ 0x99, 0xff, 0xff, 0xff, 0x33, 0x99, 0xcc, 0xcc, 0xff,
+ 0xff, 0x99, 0xcc, 0xff, 0x33, 0x66, 0x99, 0x66, 0xcc,
+ 0xff, 0x99, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x99,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x21, 0xf9,
+ 0x04, 0x01, 0x0a, 0x00, 0x0f, 0x00, 0x2c, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0x00, 0x19, 0x00, 0x00, 0x04, 0xc7,
+ 0xf0, 0x81, 0x49, 0x2b, 0x95, 0x36, 0x6b, 0x8d, 0xf7,
+ 0xec, 0x5e, 0x68, 0x81, 0x19, 0x29, 0x9e, 0x80, 0x89,
+ 0xae, 0x5c, 0xbb, 0x3e, 0xb0, 0x8a, 0xca, 0x1f, 0x1c,
+ 0xdc, 0x78, 0x00, 0x87, 0x34, 0xf7, 0xe4, 0xc0, 0xdb,
+ 0x6e, 0xd3, 0xbb, 0xfc, 0x82, 0x48, 0x1d, 0xb1, 0xa2,
+ 0x3a, 0x26, 0x93, 0xc5, 0x54, 0xe9, 0x49, 0x55, 0x96,
+ 0x2e, 0xa3, 0x6a, 0xd5, 0x45, 0x72, 0x6a, 0x93, 0x52,
+ 0xd7, 0x07, 0x77, 0x38, 0x0c, 0x6e, 0x83, 0x42, 0xe1,
+ 0x9c, 0x2b, 0x9b, 0x71, 0x58, 0x6c, 0xc7, 0x2b, 0x10,
+ 0x9c, 0xeb, 0x78, 0x01, 0x3a, 0x6f, 0xbf, 0x31, 0xe5,
+ 0x17, 0x39, 0x75, 0x03, 0x03, 0x83, 0x85, 0x67, 0x85,
+ 0x02, 0x04, 0x69, 0x7a, 0x7e, 0x7f, 0x52, 0x18, 0x5e,
+ 0x01, 0x83, 0x05, 0x75, 0x40, 0x78, 0x48, 0x57, 0x29,
+ 0x18, 0x41, 0x86, 0x75, 0x07, 0x82, 0x02, 0xa0, 0x41,
+ 0x2d, 0x3b, 0x92, 0x93, 0x7d, 0x04, 0x79, 0x77, 0x7d,
+ 0xa4, 0x4b, 0x00, 0x6c, 0xa1, 0xb1, 0x8c, 0x7a, 0x83,
+ 0x48, 0x4d, 0x12, 0xa7, 0xa8, 0xb1, 0x37, 0x83, 0x75,
+ 0x04, 0x99, 0x9b, 0x73, 0xb9, 0x48, 0x86, 0x6b, 0x01,
+ 0x89, 0xc8, 0x75, 0x6b, 0x03, 0xc0, 0x8e, 0x46, 0x35,
+ 0x49, 0x94, 0x7c, 0x6c, 0x95, 0xab, 0xcf, 0x7f, 0x36,
+ 0x48, 0x6a, 0x88, 0x05, 0x04, 0x05, 0x41, 0xde, 0x08,
+ 0xb1, 0x44, 0xda, 0x5f, 0xe7, 0x1e, 0xba, 0xe7, 0x4f,
+ 0x11, 0x00, 0x3b),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_doa, sizeof(dns_rdata_doa_t));
+}
+
+/*
+ * DS tests.
+ *
+ * RFC 4034:
+ *
+ * 5.1. DS RDATA Wire Format
+ *
+ * The RDATA for a DS RR consists of a 2 octet Key Tag field, a 1 octet
+ * Algorithm field, a 1 octet Digest Type field, and a Digest field.
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Key Tag | Algorithm | Digest Type |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * / /
+ * / Digest /
+ * / /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 5.1.1. The Key Tag Field
+ *
+ * The Key Tag field lists the key tag of the DNSKEY RR referred to by
+ * the DS record, in network byte order.
+ *
+ * The Key Tag used by the DS RR is identical to the Key Tag used by
+ * RRSIG RRs. Appendix B describes how to compute a Key Tag.
+ *
+ * 5.1.2. The Algorithm Field
+ *
+ * The Algorithm field lists the algorithm number of the DNSKEY RR
+ * referred to by the DS record.
+ *
+ * The algorithm number used by the DS RR is identical to the algorithm
+ * number used by RRSIG and DNSKEY RRs. Appendix A.1 lists the
+ * algorithm number types.
+ *
+ * 5.1.3. The Digest Type Field
+ *
+ * The DS RR refers to a DNSKEY RR by including a digest of that DNSKEY
+ * RR. The Digest Type field identifies the algorithm used to construct
+ * the digest. Appendix A.2 lists the possible digest algorithm types.
+ *
+ * 5.1.4. The Digest Field
+ *
+ * The DS record refers to a DNSKEY RR by including a digest of that
+ * DNSKEY RR.
+ *
+ * The digest is calculated by concatenating the canonical form of the
+ * fully qualified owner name of the DNSKEY RR with the DNSKEY RDATA,
+ * and then applying the digest algorithm.
+ *
+ * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
+ *
+ * "|" denotes concatenation
+ *
+ * DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
+ *
+ * The size of the digest may vary depending on the digest algorithm and
+ * DNSKEY RR size. As of the time of this writing, the only defined
+ * digest algorithm is SHA-1, which produces a 20 octet digest.
+ */
+ISC_RUN_TEST_IMPL(ds) {
+ text_ok_t text_ok[] = {
+ /*
+ * Invalid, empty record.
+ */
+ TEXT_INVALID(""),
+ /*
+ * Invalid, no algorithm.
+ */
+ TEXT_INVALID("0"),
+ /*
+ * Invalid, no digest type.
+ */
+ TEXT_INVALID("0 0"),
+ /*
+ * Invalid, no digest.
+ */
+ TEXT_INVALID("0 0 0"),
+ /*
+ * Valid, 1-octet digest for a reserved digest type.
+ */
+ TEXT_VALID("0 0 0 00"),
+ /*
+ * Invalid, short SHA-1 digest.
+ */
+ TEXT_INVALID("0 0 1 00"),
+ TEXT_INVALID("0 0 1 4FDCE83016EDD29077621FE568F8DADDB5809B"),
+ /*
+ * Valid, 20-octet SHA-1 digest.
+ */
+ TEXT_VALID("0 0 1 4FDCE83016EDD29077621FE568F8DADDB5809B6A"),
+ /*
+ * Invalid, excessively long SHA-1 digest.
+ */
+ TEXT_INVALID("0 0 1 4FDCE83016EDD29077621FE568F8DADDB5809B"
+ "6A00"),
+ /*
+ * Invalid, short SHA-256 digest.
+ */
+ TEXT_INVALID("0 0 2 00"),
+ TEXT_INVALID("0 0 2 D001BD422FFDA9B745425B71DC17D007E69186"
+ "9BD59C5F237D9BF85434C313"),
+ /*
+ * Valid, 32-octet SHA-256 digest.
+ */
+ TEXT_VALID_CHANGED("0 0 2 "
+ "D001BD422FFDA9B745425B71DC17D007E691869B"
+ "D59C5F237D9BF85434C3133F",
+ "0 0 2 "
+ "D001BD422FFDA9B745425B71DC17D007E691869B"
+ "D59C5F237D9BF854 34C3133F"),
+ /*
+ * Invalid, excessively long SHA-256 digest.
+ */
+ TEXT_INVALID("0 0 2 D001BD422FFDA9B745425B71DC17D007E69186"
+ "9BD59C5F237D9BF85434C3133F00"),
+ /*
+ * Valid, GOST is no longer supported, hence no length checks.
+ */
+ TEXT_VALID("0 0 3 00"),
+ /*
+ * Invalid, short SHA-384 digest.
+ */
+ TEXT_INVALID("0 0 4 00"),
+ TEXT_INVALID("0 0 4 AC748D6C5AA652904A8763D64B7DFFFFA98152"
+ "BE12128D238BEBB4814B648F5A841E15CAA2DE348891"
+ "A37A699F65E5"),
+ /*
+ * Valid, 48-octet SHA-384 digest.
+ */
+ TEXT_VALID_CHANGED("0 0 4 "
+ "AC748D6C5AA652904A8763D64B7DFFFFA98152BE"
+ "12128D238BEBB4814B648F5A841E15CAA2DE348891A"
+ "37A"
+ "699F65E54D",
+ "0 0 4 "
+ "AC748D6C5AA652904A8763D64B7DFFFFA98152BE"
+ "12128D238BEBB481 "
+ "4B648F5A841E15CAA2DE348891A37A"
+ "699F65E54D"),
+ /*
+ * Invalid, excessively long SHA-384 digest.
+ */
+ TEXT_INVALID("0 0 4 AC748D6C5AA652904A8763D64B7DFFFFA98152"
+ "BE12128D238BEBB4814B648F5A841E15CAA2DE348891"
+ "A37A699F65E54D00"),
+ /*
+ * Valid, 1-octet digest for an unassigned digest type.
+ */
+ TEXT_VALID("0 0 5 00"),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL()
+ };
+ wire_ok_t wire_ok[] = {
+ /*
+ * Invalid, truncated key tag.
+ */
+ WIRE_INVALID(0x00),
+ /*
+ * Invalid, no algorithm.
+ */
+ WIRE_INVALID(0x00, 0x00),
+ /*
+ * Invalid, no digest type.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00),
+ /*
+ * Invalid, no digest.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00),
+ /*
+ * Valid, 1-octet digest for a reserved digest type.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Invalid, short SHA-1 digest.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x01, 0x00),
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x01, 0x4F, 0xDC, 0xE8, 0x30,
+ 0x16, 0xED, 0xD2, 0x90, 0x77, 0x62, 0x1F, 0xE5,
+ 0x68, 0xF8, 0xDA, 0xDD, 0xB5, 0x80, 0x9B),
+ /*
+ * Valid, 20-octet SHA-1 digest.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x01, 0x4F, 0xDC, 0xE8, 0x30, 0x16,
+ 0xED, 0xD2, 0x90, 0x77, 0x62, 0x1F, 0xE5, 0x68, 0xF8,
+ 0xDA, 0xDD, 0xB5, 0x80, 0x9B, 0x6A),
+ /*
+ * Invalid, excessively long SHA-1 digest.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x01, 0x4F, 0xDC, 0xE8, 0x30,
+ 0x16, 0xED, 0xD2, 0x90, 0x77, 0x62, 0x1F, 0xE5,
+ 0x68, 0xF8, 0xDA, 0xDD, 0xB5, 0x80, 0x9B, 0x6A,
+ 0x00),
+ /*
+ * Invalid, short SHA-256 digest.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x02, 0x00),
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x02, 0xD0, 0x01, 0xBD, 0x42,
+ 0x2F, 0xFD, 0xA9, 0xB7, 0x45, 0x42, 0x5B, 0x71,
+ 0xDC, 0x17, 0xD0, 0x07, 0xE6, 0x91, 0x86, 0x9B,
+ 0xD5, 0x9C, 0x5F, 0x23, 0x7D, 0x9B, 0xF8, 0x54,
+ 0x34, 0xC3, 0x13),
+ /*
+ * Valid, 32-octet SHA-256 digest.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x02, 0xD0, 0x01, 0xBD, 0x42, 0x2F,
+ 0xFD, 0xA9, 0xB7, 0x45, 0x42, 0x5B, 0x71, 0xDC, 0x17,
+ 0xD0, 0x07, 0xE6, 0x91, 0x86, 0x9B, 0xD5, 0x9C, 0x5F,
+ 0x23, 0x7D, 0x9B, 0xF8, 0x54, 0x34, 0xC3, 0x13,
+ 0x3F),
+ /*
+ * Invalid, excessively long SHA-256 digest.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x02, 0xD0, 0x01, 0xBD, 0x42,
+ 0x2F, 0xFD, 0xA9, 0xB7, 0x45, 0x42, 0x5B, 0x71,
+ 0xDC, 0x17, 0xD0, 0x07, 0xE6, 0x91, 0x86, 0x9B,
+ 0xD5, 0x9C, 0x5F, 0x23, 0x7D, 0x9B, 0xF8, 0x54,
+ 0x34, 0xC3, 0x13, 0x3F, 0x00),
+ /*
+ * Valid, GOST is no longer supported, hence no length checks.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x03, 0x00),
+ /*
+ * Invalid, short SHA-384 digest.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x04, 0x00),
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x04, 0xAC, 0x74, 0x8D, 0x6C,
+ 0x5A, 0xA6, 0x52, 0x90, 0x4A, 0x87, 0x63, 0xD6,
+ 0x4B, 0x7D, 0xFF, 0xFF, 0xA9, 0x81, 0x52, 0xBE,
+ 0x12, 0x12, 0x8D, 0x23, 0x8B, 0xEB, 0xB4, 0x81,
+ 0x4B, 0x64, 0x8F, 0x5A, 0x84, 0x1E, 0x15, 0xCA,
+ 0xA2, 0xDE, 0x34, 0x88, 0x91, 0xA3, 0x7A, 0x69,
+ 0x9F, 0x65, 0xE5),
+ /*
+ * Valid, 48-octet SHA-384 digest.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x04, 0xAC, 0x74, 0x8D, 0x6C, 0x5A,
+ 0xA6, 0x52, 0x90, 0x4A, 0x87, 0x63, 0xD6, 0x4B, 0x7D,
+ 0xFF, 0xFF, 0xA9, 0x81, 0x52, 0xBE, 0x12, 0x12, 0x8D,
+ 0x23, 0x8B, 0xEB, 0xB4, 0x81, 0x4B, 0x64, 0x8F, 0x5A,
+ 0x84, 0x1E, 0x15, 0xCA, 0xA2, 0xDE, 0x34, 0x88, 0x91,
+ 0xA3, 0x7A, 0x69, 0x9F, 0x65, 0xE5, 0x4D),
+ /*
+ * Invalid, excessively long SHA-384 digest.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x04, 0xAC, 0x74, 0x8D, 0x6C,
+ 0x5A, 0xA6, 0x52, 0x90, 0x4A, 0x87, 0x63, 0xD6,
+ 0x4B, 0x7D, 0xFF, 0xFF, 0xA9, 0x81, 0x52, 0xBE,
+ 0x12, 0x12, 0x8D, 0x23, 0x8B, 0xEB, 0xB4, 0x81,
+ 0x4B, 0x64, 0x8F, 0x5A, 0x84, 0x1E, 0x15, 0xCA,
+ 0xA2, 0xDE, 0x34, 0x88, 0x91, 0xA3, 0x7A, 0x69,
+ 0x9F, 0x65, 0xE5, 0x4D, 0x00),
+ WIRE_VALID(0x00, 0x00, 0x04, 0x00, 0x00),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_ds, sizeof(dns_rdata_ds_t));
+}
+
+/*
+ * EDNS Client Subnet tests.
+ *
+ * RFC 7871:
+ *
+ * 6. Option Format
+ *
+ * This protocol uses an EDNS0 [RFC6891] option to include client
+ * address information in DNS messages. The option is structured as
+ * follows:
+ *
+ * +0 (MSB) +1 (LSB)
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * 0: | OPTION-CODE |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * 2: | OPTION-LENGTH |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * 4: | FAMILY |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * 6: | SOURCE PREFIX-LENGTH | SCOPE PREFIX-LENGTH |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * 8: | ADDRESS... /
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * o (Defined in [RFC6891]) OPTION-CODE, 2 octets, for ECS is 8 (0x00
+ * 0x08).
+ *
+ * o (Defined in [RFC6891]) OPTION-LENGTH, 2 octets, contains the
+ * length of the payload (everything after OPTION-LENGTH) in octets.
+ *
+ * o FAMILY, 2 octets, indicates the family of the address contained in
+ * the option, using address family codes as assigned by IANA in
+ * Address Family Numbers [Address_Family_Numbers].
+ *
+ * The format of the address part depends on the value of FAMILY. This
+ * document only defines the format for FAMILY 1 (IPv4) and FAMILY 2
+ * (IPv6), which are as follows:
+ *
+ * o SOURCE PREFIX-LENGTH, an unsigned octet representing the leftmost
+ * number of significant bits of ADDRESS to be used for the lookup.
+ * In responses, it mirrors the same value as in the queries.
+ *
+ * o SCOPE PREFIX-LENGTH, an unsigned octet representing the leftmost
+ * number of significant bits of ADDRESS that the response covers.
+ * In queries, it MUST be set to 0.
+ *
+ * o ADDRESS, variable number of octets, contains either an IPv4 or
+ * IPv6 address, depending on FAMILY, which MUST be truncated to the
+ * number of bits indicated by the SOURCE PREFIX-LENGTH field,
+ * padding with 0 bits to pad to the end of the last octet needed.
+ *
+ * o A server receiving an ECS option that uses either too few or too
+ * many ADDRESS octets, or that has non-zero ADDRESS bits set beyond
+ * SOURCE PREFIX-LENGTH, SHOULD return FORMERR to reject the packet,
+ * as a signal to the software developer making the request to fix
+ * their implementation.
+ *
+ * All fields are in network byte order ("big-endian", per [RFC1700],
+ * Data Notation).
+ */
+ISC_RUN_TEST_IMPL(edns_client_subnet) {
+ wire_ok_t wire_ok[] = {
+ /*
+ * Option code with no content.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 0x00),
+ /*
+ * Option code family 0, source 0, scope 0.
+ */
+ WIRE_VALID(0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Option code family 1 (IPv4), source 0, scope 0.
+ */
+ WIRE_VALID(0x00, 0x08, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00),
+ /*
+ * Option code family 2 (IPv6) , source 0, scope 0.
+ */
+ WIRE_VALID(0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00),
+ /*
+ * Extra octet.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x00),
+ /*
+ * Source too long for IPv4.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 8, 0x00, 0x01, 33, 0x00, 0x00,
+ 0x00, 0x00, 0x00),
+ /*
+ * Source too long for IPv6.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 20, 0x00, 0x02, 129, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Scope too long for IPv4.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 8, 0x00, 0x01, 0x00, 33, 0x00,
+ 0x00, 0x00, 0x00),
+ /*
+ * Scope too long for IPv6.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 20, 0x00, 0x02, 0x00, 129, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * When family=0, source and scope should be 0.
+ */
+ WIRE_VALID(0x00, 0x08, 0x00, 4, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * When family=0, source and scope should be 0.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 5, 0x00, 0x00, 0x01, 0x00, 0x00),
+ /*
+ * When family=0, source and scope should be 0.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 5, 0x00, 0x00, 0x00, 0x01, 0x00),
+ /*
+ * Length too short for source IPv4.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 7, 0x00, 0x01, 32, 0x00, 0x00,
+ 0x00, 0x00),
+ /*
+ * Length too short for source IPv6.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 19, 0x00, 0x02, 128, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(NULL, wire_ok, NULL, true, dns_rdataclass_in,
+ dns_rdatatype_opt, sizeof(dns_rdata_opt_t));
+}
+
+/*
+ * http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt
+ *
+ * The RDATA portion of both the NIMLOC and EID records contains
+ * uninterpreted binary data. The representation in the text master file
+ * is an even number of hex characters (0 to 9, a to f), case is not
+ * significant. For readability, whitespace may be included in the value
+ * field and should be ignored when reading a master file.
+ */
+ISC_RUN_TEST_IMPL(eid) {
+ text_ok_t text_ok[] = { TEXT_VALID("AABBCC"),
+ TEXT_VALID_CHANGED("AA bb cc", "AABBCC"),
+ TEXT_INVALID("aab"),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL() };
+ wire_ok_t wire_ok[] = { WIRE_VALID(0x00), WIRE_VALID(0xAA, 0xBB, 0xCC),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL() };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_eid, sizeof(dns_rdata_in_eid_t));
+}
+
+/*
+ * test that an oversized HIP record will be rejected
+ */
+ISC_RUN_TEST_IMPL(hip) {
+ text_ok_t text_ok[] = {
+ /* RFC 8005 examples. */
+ TEXT_VALID_LOOP(0, "2 200100107B1A74DF365639CC39F1D578 "
+ "AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cI"
+ "vM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbW"
+ "Iy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+b"
+ "SRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWx"
+ "Z48AWkskmdHaVDP4BcelrTI3rMXdXF5D"),
+ TEXT_VALID_LOOP(1, "2 200100107B1A74DF365639CC39F1D578 "
+ "AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cI"
+ "vM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbW"
+ "Iy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+b"
+ "SRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWx"
+ "Z48AWkskmdHaVDP4BcelrTI3rMXdXF5D "
+ "rvs1.example.com."),
+ TEXT_VALID_LOOP(2, "2 200100107B1A74DF365639CC39F1D578 "
+ "AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cI"
+ "vM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbW"
+ "Iy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+b"
+ "SRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWx"
+ "Z48AWkskmdHaVDP4BcelrTI3rMXdXF5D "
+ "rvs1.example.com. rvs2.example.com."),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL()
+ };
+ unsigned char hipwire[DNS_RDATA_MAXLENGTH] = { 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x04, 0x41,
+ 0x42, 0x43, 0x44, 0x00 };
+ unsigned char buf[1024 * 1024];
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ size_t i;
+
+ /*
+ * Fill the rest of input buffer with compression pointers.
+ */
+ for (i = 12; i < sizeof(hipwire) - 2; i += 2) {
+ hipwire[i] = 0xc0;
+ hipwire[i + 1] = 0x06;
+ }
+
+ result = wire_to_rdata(hipwire, sizeof(hipwire), dns_rdataclass_in,
+ dns_rdatatype_hip, buf, sizeof(buf), &rdata);
+ assert_int_equal(result, DNS_R_FORMERR);
+ check_text_ok(text_ok, dns_rdataclass_in, dns_rdatatype_hip,
+ sizeof(dns_rdata_hip_t));
+}
+
+/*
+ * ISDN tests.
+ *
+ * RFC 1183:
+ *
+ * 3.2. The ISDN RR
+ *
+ * The ISDN RR is defined with mnemonic ISDN and type code 20 (decimal).
+ *
+ * An ISDN (Integrated Service Digital Network) number is simply a
+ * telephone number. The intent of the members of the CCITT is to
+ * upgrade all telephone and data network service to a common service.
+ *
+ * The numbering plan (E.163/E.164) is the same as the familiar
+ * international plan for POTS (an un-official acronym, meaning Plain
+ * Old Telephone Service). In E.166, CCITT says "An E.163/E.164
+ * telephony subscriber may become an ISDN subscriber without a number
+ * change."
+ *
+ * ISDN has the following format:
+ *
+ * <owner> <ttl> <class> ISDN <ISDN-address> <sa>
+ *
+ * The <ISDN-address> field is required; <sa> is optional.
+ *
+ * <ISDN-address> identifies the ISDN number of <owner> and DDI (Direct
+ * Dial In) if any, as defined by E.164 [8] and E.163 [7], the ISDN and
+ * PSTN (Public Switched Telephone Network) numbering plan. E.163
+ * defines the country codes, and E.164 the form of the addresses. Its
+ * format in master files is a <character-string> syntactically
+ * identical to that used in TXT and HINFO.
+ *
+ * <sa> specifies the subaddress (SA). The format of <sa> in master
+ * files is a <character-string> syntactically identical to that used in
+ * TXT and HINFO.
+ *
+ * The format of ISDN is class insensitive. ISDN RRs cause no
+ * additional section processing.
+ *
+ * The <ISDN-address> is a string of characters, normally decimal
+ * digits, beginning with the E.163 country code and ending with the DDI
+ * if any. Note that ISDN, in Q.931, permits any IA5 character in the
+ * general case.
+ *
+ * The <sa> is a string of hexadecimal digits. For digits 0-9, the
+ * concrete encoding in the Q.931 call setup information element is
+ * identical to BCD.
+ *
+ * For example:
+ *
+ * Relay.Prime.COM. IN ISDN 150862028003217
+ * sh.Prime.COM. IN ISDN 150862028003217 004
+ *
+ * (Note: "1" is the country code for the North American Integrated
+ * Numbering Area, i.e., the system of "area codes" familiar to people
+ * in those countries.)
+ *
+ * The RR data is the ASCII representation of the digits. It is encoded
+ * as one or two <character-string>s, i.e., count followed by
+ * characters.
+ */
+ISC_RUN_TEST_IMPL(isdn) {
+ wire_ok_t wire_ok[] = { /*
+ * "".
+ */
+ WIRE_VALID(0x00),
+ /*
+ * "\001".
+ */
+ WIRE_VALID(0x01, 0x01),
+ /*
+ * "\001" "".
+ */
+ WIRE_VALID(0x01, 0x01, 0x00),
+ /*
+ * "\001" "\001".
+ */
+ WIRE_VALID(0x01, 0x01, 0x01, 0x01),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(NULL, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_isdn, sizeof(dns_rdata_isdn_t));
+}
+
+/*
+ * KEY tests.
+ */
+ISC_RUN_TEST_IMPL(key) {
+ wire_ok_t wire_ok[] = { /*
+ * RDATA is comprised of:
+ *
+ * - 2 octets for Flags,
+ * - 1 octet for Protocol,
+ * - 1 octet for Algorithm,
+ * - variable number of octets for Public Key.
+ *
+ * RFC 2535 section 3.1.2 states that if bits
+ * 0-1 of Flags are both set, the RR stops after
+ * the algorithm octet and thus its length must
+ * be 4 octets. In any other case, though, the
+ * Public Key part must not be empty.
+ */
+ WIRE_INVALID(0x00),
+ WIRE_INVALID(0x00, 0x00),
+ WIRE_INVALID(0x00, 0x00, 0x00),
+ WIRE_VALID(0xc0, 0x00, 0x00, 0x00),
+ WIRE_INVALID(0xc0, 0x00, 0x00, 0x00, 0x00),
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00),
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00),
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(NULL, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_key, sizeof(dns_rdata_key_t));
+}
+
+/*
+ * LOC tests.
+ */
+ISC_RUN_TEST_IMPL(loc) {
+ text_ok_t text_ok[] = {
+ TEXT_VALID_CHANGED("0 N 0 E 0", "0 0 0.000 N 0 0 0.000 E 0.00m "
+ "1m 10000m 10m"),
+ TEXT_VALID_CHANGED("0 S 0 W 0", "0 0 0.000 N 0 0 0.000 E 0.00m "
+ "1m 10000m 10m"),
+ TEXT_VALID_CHANGED("0 0 N 0 0 E 0", "0 0 0.000 N 0 0 0.000 E "
+ "0.00m 1m 10000m 10m"),
+ TEXT_VALID_CHANGED("0 0 0 N 0 0 0 E 0",
+ "0 0 0.000 N 0 0 0.000 E 0.00m 1m 10000m "
+ "10m"),
+ TEXT_VALID_CHANGED("0 0 0 N 0 0 0 E 0",
+ "0 0 0.000 N 0 0 0.000 E 0.00m 1m 10000m "
+ "10m"),
+ TEXT_VALID_CHANGED("0 0 0. N 0 0 0. E 0",
+ "0 0 0.000 N 0 0 0.000 E 0.00m 1m 10000m "
+ "10m"),
+ TEXT_VALID_CHANGED("0 0 .0 N 0 0 .0 E 0",
+ "0 0 0.000 N 0 0 0.000 E 0.00m 1m 10000m "
+ "10m"),
+ TEXT_INVALID("0 North 0 East 0"),
+ TEXT_INVALID("0 South 0 West 0"),
+ TEXT_INVALID("0 0 . N 0 0 0. E 0"),
+ TEXT_INVALID("0 0 0. N 0 0 . E 0"),
+ TEXT_INVALID("0 0 0. N 0 0 0. E m"),
+ TEXT_INVALID("0 0 0. N 0 0 0. E 0 ."),
+ TEXT_INVALID("0 0 0. N 0 0 0. E 0 m"),
+ TEXT_INVALID("0 0 0. N 0 0 0. E 0 0 ."),
+ TEXT_INVALID("0 0 0. N 0 0 0. E 0 0 m"),
+ TEXT_INVALID("0 0 0. N 0 0 0. E 0 0 0 ."),
+ TEXT_INVALID("0 0 0. N 0 0 0. E 0 0 0 m"),
+ TEXT_VALID_CHANGED("90 N 180 E 0", "90 0 0.000 N 180 0 0.000 E "
+ "0.00m 1m 10000m 10m"),
+ TEXT_INVALID("90 1 N 180 E 0"),
+ TEXT_INVALID("90 0 1 N 180 E 0"),
+ TEXT_INVALID("90 N 180 1 E 0"),
+ TEXT_INVALID("90 N 180 0 1 E 0"),
+ TEXT_VALID_CHANGED("90 S 180 W 0", "90 0 0.000 S 180 0 0.000 W "
+ "0.00m 1m 10000m 10m"),
+ TEXT_INVALID("90 1 S 180 W 0"),
+ TEXT_INVALID("90 0 1 S 180 W 0"),
+ TEXT_INVALID("90 S 180 1 W 0"),
+ TEXT_INVALID("90 S 180 0 1 W 0"),
+ TEXT_INVALID("0 0 0.000 E 0 0 0.000 E -0.95m 1m 10000m 10m"),
+ TEXT_VALID("0 0 0.000 N 0 0 0.000 E -0.95m 1m 10000m 10m"),
+ TEXT_VALID("0 0 0.000 N 0 0 0.000 E -0.05m 1m 10000m 10m"),
+ TEXT_VALID("0 0 0.000 N 0 0 0.000 E -100000.00m 1m 10000m 10m"),
+ TEXT_VALID("0 0 0.000 N 0 0 0.000 E 42849672.95m 1m 10000m "
+ "10m"),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL()
+ };
+
+ check_rdata(text_ok, 0, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_loc, sizeof(dns_rdata_loc_t));
+}
+
+/*
+ * http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt
+ *
+ * The RDATA portion of both the NIMLOC and EID records contains
+ * uninterpreted binary data. The representation in the text master file
+ * is an even number of hex characters (0 to 9, a to f), case is not
+ * significant. For readability, whitespace may be included in the value
+ * field and should be ignored when reading a master file.
+ */
+ISC_RUN_TEST_IMPL(nimloc) {
+ text_ok_t text_ok[] = { TEXT_VALID("AABBCC"),
+ TEXT_VALID_CHANGED("AA bb cc", "AABBCC"),
+ TEXT_INVALID("aab"),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL() };
+ wire_ok_t wire_ok[] = { WIRE_VALID(0x00), WIRE_VALID(0xAA, 0xBB, 0xCC),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL() };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_nimloc, sizeof(dns_rdata_in_nimloc_t));
+}
+
+/*
+ * NSEC tests.
+ *
+ * RFC 4034:
+ *
+ * 4.1. NSEC RDATA Wire Format
+ *
+ * The RDATA of the NSEC RR is as shown below:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * / Next Domain Name /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * / Type Bit Maps /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 4.1.1. The Next Domain Name Field
+ *
+ * The Next Domain field contains the next owner name (in the canonical
+ * ordering of the zone) that has authoritative data or contains a
+ * delegation point NS RRset; see Section 6.1 for an explanation of
+ * canonical ordering. The value of the Next Domain Name field in the
+ * last NSEC record in the zone is the name of the zone apex (the owner
+ * name of the zone's SOA RR). This indicates that the owner name of
+ * the NSEC RR is the last name in the canonical ordering of the zone.
+ *
+ * A sender MUST NOT use DNS name compression on the Next Domain Name
+ * field when transmitting an NSEC RR.
+ *
+ * Owner names of RRsets for which the given zone is not authoritative
+ * (such as glue records) MUST NOT be listed in the Next Domain Name
+ * unless at least one authoritative RRset exists at the same owner
+ * name.
+ *
+ * 4.1.2. The Type Bit Maps Field
+ *
+ * The Type Bit Maps field identifies the RRset types that exist at the
+ * NSEC RR's owner name.
+ *
+ * The RR type space is split into 256 window blocks, each representing
+ * the low-order 8 bits of the 16-bit RR type space. Each block that
+ * has at least one active RR type is encoded using a single octet
+ * window number (from 0 to 255), a single octet bitmap length (from 1
+ * to 32) indicating the number of octets used for the window block's
+ * bitmap, and up to 32 octets (256 bits) of bitmap.
+ *
+ * Blocks are present in the NSEC RR RDATA in increasing numerical
+ * order.
+ *
+ * Type Bit Maps Field = ( Window Block # | Bitmap Length | Bitmap )+
+ *
+ * where "|" denotes concatenation.
+ *
+ * Each bitmap encodes the low-order 8 bits of RR types within the
+ * window block, in network bit order. The first bit is bit 0. For
+ * window block 0, bit 1 corresponds to RR type 1 (A), bit 2 corresponds
+ * to RR type 2 (NS), and so forth. For window block 1, bit 1
+ * corresponds to RR type 257, and bit 2 to RR type 258. If a bit is
+ * set, it indicates that an RRset of that type is present for the NSEC
+ * RR's owner name. If a bit is clear, it indicates that no RRset of
+ * that type is present for the NSEC RR's owner name.
+ *
+ * Bits representing pseudo-types MUST be clear, as they do not appear
+ * in zone data. If encountered, they MUST be ignored upon being read.
+ */
+ISC_RUN_TEST_IMPL(nsec) {
+ text_ok_t text_ok[] = { TEXT_INVALID(""), TEXT_INVALID("."),
+ TEXT_VALID(". RRSIG"), TEXT_SENTINEL() };
+ wire_ok_t wire_ok[] = { WIRE_INVALID(0x00), WIRE_INVALID(0x00, 0x00),
+ WIRE_INVALID(0x00, 0x00, 0x00),
+ WIRE_VALID(0x00, 0x00, 0x01, 0x02),
+ WIRE_SENTINEL() };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_nsec, sizeof(dns_rdata_nsec_t));
+}
+
+/*
+ * NSEC3 tests.
+ *
+ * RFC 5155.
+ */
+ISC_RUN_TEST_IMPL(nsec3) {
+ text_ok_t text_ok[] = { TEXT_INVALID(""),
+ TEXT_INVALID("."),
+ TEXT_INVALID(". RRSIG"),
+ TEXT_INVALID("1 0 10 76931F"),
+ TEXT_INVALID("1 0 10 76931F "
+ "IMQ912BREQP1POLAH3RMONG&"
+ "UED541AS"),
+ TEXT_INVALID("1 0 10 76931F "
+ "IMQ912BREQP1POLAH3RMONGAUED541AS "
+ "A RRSIG BADTYPE"),
+ TEXT_VALID("1 0 10 76931F "
+ "AJHVGTICN6K0VDA53GCHFMT219SRRQLM A "
+ "RRSIG"),
+ TEXT_VALID("1 0 10 76931F "
+ "AJHVGTICN6K0VDA53GCHFMT219SRRQLM"),
+ TEXT_VALID("1 0 10 - "
+ "AJHVGTICN6K0VDA53GCHFMT219SRRQLM"),
+ TEXT_SENTINEL() };
+
+ check_rdata(text_ok, NULL, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_nsec3, sizeof(dns_rdata_nsec3_t));
+}
+
+/* NXT RDATA manipulations */
+ISC_RUN_TEST_IMPL(nxt) {
+ compare_ok_t compare_ok[] = {
+ COMPARE("a. A SIG", "a. A SIG", 0),
+ /*
+ * Records that differ only in the case of the next
+ * name should be equal.
+ */
+ COMPARE("A. A SIG", "a. A SIG", 0),
+ /*
+ * Sorting on name field.
+ */
+ COMPARE("A. A SIG", "b. A SIG", -1),
+ COMPARE("b. A SIG", "A. A SIG", 1),
+ /* bit map differs */
+ COMPARE("b. A SIG", "b. A AAAA SIG", -1),
+ /* order of bit map does not matter */
+ COMPARE("b. A SIG AAAA", "b. A AAAA SIG", 0), COMPARE_SENTINEL()
+ };
+
+ check_rdata(NULL, NULL, compare_ok, false, dns_rdataclass_in,
+ dns_rdatatype_nxt, sizeof(dns_rdata_nxt_t));
+}
+
+ISC_RUN_TEST_IMPL(rkey) {
+ text_ok_t text_ok[] = { /*
+ * Valid, flags set to 0 and a key is present.
+ */
+ TEXT_VALID("0 0 0 aaaa"),
+ /*
+ * Invalid, non-zero flags.
+ */
+ TEXT_INVALID("1 0 0 aaaa"),
+ TEXT_INVALID("65535 0 0 aaaa"),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL()
+ };
+ wire_ok_t wire_ok[] = { /*
+ * Valid, flags set to 0 and a key is present.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Invalid, non-zero flags.
+ */
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x00),
+ WIRE_INVALID(0xff, 0xff, 0x00, 0x00, 0x00),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+ key_required(state, dns_rdatatype_rkey, sizeof(dns_rdata_rkey_t));
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_rkey, sizeof(dns_rdata_rkey_t));
+}
+
+/* SSHFP RDATA manipulations */
+ISC_RUN_TEST_IMPL(sshfp) {
+ text_ok_t text_ok[] = { TEXT_INVALID(""), /* too short */
+ TEXT_INVALID("0"), /* reserved, too short */
+ TEXT_VALID("0 0"), /* no finger print */
+ TEXT_VALID("0 0 AA"), /* reserved */
+ TEXT_INVALID("0 1 AA"), /* too short SHA 1
+ * digest */
+ TEXT_INVALID("0 2 AA"), /* too short SHA 256
+ * digest */
+ TEXT_VALID("0 3 AA"), /* unknown finger print
+ * type */
+ /* good length SHA 1 digest */
+ TEXT_VALID("1 1 "
+ "00112233445566778899AABBCCDDEEFF171"
+ "81920"),
+ /* good length SHA 256 digest */
+ TEXT_VALID("4 2 "
+ "A87F1B687AC0E57D2A081A2F282672334D9"
+ "0ED316D2B818CA9580EA3 84D92401"),
+ /*
+ * totext splits the fingerprint into chunks and
+ * emits uppercase hex.
+ */
+ TEXT_VALID_CHANGED("1 2 "
+ "00112233445566778899aabbccd"
+ "deeff "
+ "00112233445566778899AABBCCD"
+ "DEEFF",
+ "1 2 "
+ "00112233445566778899AABBCCD"
+ "DEEFF"
+ "00112233445566778899AABB "
+ "CCDDEEFF"),
+ TEXT_SENTINEL() };
+ wire_ok_t wire_ok[] = {
+ WIRE_INVALID(0x00), /* reserved too short */
+ WIRE_VALID(0x00, 0x00), /* reserved no finger print */
+ WIRE_VALID(0x00, 0x00, 0x00), /* reserved */
+
+ /* too short SHA 1 digests */
+ WIRE_INVALID(0x00, 0x01), WIRE_INVALID(0x00, 0x01, 0x00),
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD,
+ 0xEE, 0xFF, 0x17, 0x18, 0x19),
+ /* good length SHA 1 digest */
+ WIRE_VALID(0x00, 0x01, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ 0x17, 0x18, 0x19, 0x20),
+ /* too long SHA 1 digest */
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD,
+ 0xEE, 0xFF, 0x17, 0x18, 0x19, 0x20, 0x21),
+ /* too short SHA 256 digests */
+ WIRE_INVALID(0x00, 0x02), WIRE_INVALID(0x00, 0x02, 0x00),
+ WIRE_INVALID(0x00, 0x02, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD,
+ 0xEE, 0xFF, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22,
+ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
+ 0x31),
+ /* good length SHA 256 digest */
+ WIRE_VALID(0x00, 0x02, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x30, 0x31, 0x32),
+ /* too long SHA 256 digest */
+ WIRE_INVALID(0x00, 0x02, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD,
+ 0xEE, 0xFF, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22,
+ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
+ 0x31, 0x32, 0x33),
+ /* unknown digest, * no fingerprint */
+ WIRE_VALID(0x00, 0x03), WIRE_VALID(0x00, 0x03, 0x00), /* unknown
+ * digest
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_sshfp, sizeof(dns_rdata_sshfp_t));
+}
+
+/*
+ * WKS tests.
+ *
+ * RFC 1035:
+ *
+ * 3.4.2. WKS RDATA format
+ *
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ADDRESS |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | PROTOCOL | |
+ * +--+--+--+--+--+--+--+--+ |
+ * | |
+ * / <BIT MAP> /
+ * / /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *
+ * where:
+ *
+ * ADDRESS An 32 bit Internet address
+ *
+ * PROTOCOL An 8 bit IP protocol number
+ *
+ * <BIT MAP> A variable length bit map. The bit map must be a
+ * multiple of 8 bits long.
+ *
+ * The WKS record is used to describe the well known services supported by
+ * a particular protocol on a particular internet address. The PROTOCOL
+ * field specifies an IP protocol number, and the bit map has one bit per
+ * port of the specified protocol. The first bit corresponds to port 0,
+ * the second to port 1, etc. If the bit map does not include a bit for a
+ * protocol of interest, that bit is assumed zero. The appropriate values
+ * and mnemonics for ports and protocols are specified in [RFC-1010].
+ *
+ * For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port
+ * 25 (SMTP). If this bit is set, a SMTP server should be listening on TCP
+ * port 25; if zero, SMTP service is not supported on the specified
+ * address.
+ */
+ISC_RUN_TEST_IMPL(wks) {
+ text_ok_t text_ok[] = { /*
+ * Valid, IPv4 address in dotted-quad form.
+ */
+ TEXT_VALID("127.0.0.1 6"),
+ /*
+ * Invalid, IPv4 address not in dotted-quad
+ * form.
+ */
+ TEXT_INVALID("127.1 6"),
+ /*
+ * Sentinel.
+ */
+ TEXT_SENTINEL()
+ };
+ wire_ok_t wire_ok[] = { /*
+ * Too short.
+ */
+ WIRE_INVALID(0x00, 0x08, 0x00, 0x00),
+ /*
+ * Minimal TCP.
+ */
+ WIRE_VALID(0x00, 0x08, 0x00, 0x00, 6),
+ /*
+ * Minimal UDP.
+ */
+ WIRE_VALID(0x00, 0x08, 0x00, 0x00, 17),
+ /*
+ * Minimal other.
+ */
+ WIRE_VALID(0x00, 0x08, 0x00, 0x00, 1),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_wks, sizeof(dns_rdata_in_wks_t));
+}
+
+ISC_RUN_TEST_IMPL(https_svcb) {
+ /*
+ * Known keys: mandatory, apln, no-default-alpn, port,
+ * ipv4hint, port, ipv6hint, dohpath.
+ */
+ text_ok_t text_ok[] = {
+ /* unknown key invalid */
+ TEXT_INVALID("1 . unknown="),
+ /* no domain */
+ TEXT_INVALID("0"),
+ /* minimal record */
+ TEXT_VALID_LOOP(0, "0 ."),
+ /* Alias form requires SvcFieldValue to be empty */
+ TEXT_INVALID("0 . alpn=\"h2\""),
+ /* no "key" prefix */
+ TEXT_INVALID("2 svc.example.net. 0=\"2222\""),
+ /* no key value */
+ TEXT_INVALID("2 svc.example.net. key"),
+ /* no key value */
+ TEXT_INVALID("2 svc.example.net. key=\"2222\""),
+ /* zero pad invalid */
+ TEXT_INVALID("2 svc.example.net. key07=\"2222\""),
+ TEXT_VALID_LOOP(1, "2 svc.example.net. key8=\"2222\""),
+ TEXT_VALID_LOOPCHG(1, "2 svc.example.net. key8=2222",
+ "2 svc.example.net. key8=\"2222\""),
+ TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h2",
+ "2 svc.example.net. alpn=\"h2\""),
+ TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h3",
+ "2 svc.example.net. alpn=\"h3\""),
+ /* alpn has 2 sub field "h2" and "h3" */
+ TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h2,h3",
+ "2 svc.example.net. alpn=\"h2,h3\""),
+ /* apln has 2 sub fields "h1,h2" and "h3" (comma escaped) */
+ TEXT_VALID_LOOPCHG(1, "2 svc.example.net. alpn=h1\\\\,h2,h3",
+ "2 svc.example.net. alpn=\"h1\\\\,h2,h3\""),
+ TEXT_VALID_LOOP(1, "2 svc.example.net. port=50"),
+ /* no-default-alpn, alpn is required */
+ TEXT_INVALID("2 svc.example.net. no-default-alpn"),
+ /* no-default-alpn with alpn present */
+ TEXT_VALID_LOOPCHG(
+ 2, "2 svc.example.net. no-default-alpn alpn=h2",
+ "2 svc.example.net. alpn=\"h2\" no-default-alpn"),
+ /* empty hint */
+ TEXT_INVALID("2 svc.example.net. ipv4hint="),
+ TEXT_VALID_LOOP(1, "2 svc.example.net. "
+ "ipv4hint=10.50.0.1,10.50.0.2"),
+ /* empty hint */
+ TEXT_INVALID("2 svc.example.net. ipv6hint="),
+ TEXT_VALID_LOOP(1, "2 svc.example.net. ipv6hint=::1,2002::1"),
+ TEXT_VALID_LOOP(1, "2 svc.example.net. ech=abcdefghijkl"),
+ /* bad base64 */
+ TEXT_INVALID("2 svc.example.net. ech=abcdefghijklm"),
+ TEXT_VALID_LOOP(1, "2 svc.example.net. key8=\"2222\""),
+ /* Out of key order on input (alpn == key1). */
+ TEXT_VALID_LOOPCHG(2,
+ "2 svc.example.net. key8=\"2222\" alpn=h2",
+ "2 svc.example.net. alpn=\"h2\" "
+ "key8=\"2222\""),
+ TEXT_VALID_LOOP(1, "2 svc.example.net. key65535=\"2222\""),
+ TEXT_INVALID("2 svc.example.net. key65536=\"2222\""),
+ TEXT_VALID_LOOP(1, "2 svc.example.net. key10"),
+ TEXT_VALID_LOOPCHG(1, "2 svc.example.net. key11=",
+ "2 svc.example.net. key11"),
+ TEXT_VALID_LOOPCHG(1, "2 svc.example.net. key12=\"\"",
+ "2 svc.example.net. key12"),
+ /* empty alpn-id sub fields */
+ TEXT_INVALID("2 svc.example.net. alpn"),
+ TEXT_INVALID("2 svc.example.net. alpn="),
+ TEXT_INVALID("2 svc.example.net. alpn=,h1"),
+ TEXT_INVALID("2 svc.example.net. alpn=h1,"),
+ TEXT_INVALID("2 svc.example.net. alpn=h1,,h2"),
+ /* mandatory */
+ TEXT_VALID_LOOP(2, "2 svc.example.net. mandatory=alpn "
+ "alpn=\"h2\""),
+ TEXT_VALID_LOOP(3, "2 svc.example.net. mandatory=alpn,port "
+ "alpn=\"h2\" port=443"),
+ TEXT_VALID_LOOPCHG(3,
+ "2 svc.example.net. mandatory=port,alpn "
+ "alpn=\"h2\" port=443",
+ "2 svc.example.net. mandatory=alpn,port "
+ "alpn=\"h2\" port=443"),
+ TEXT_INVALID("2 svc.example.net. mandatory=mandatory"),
+ TEXT_INVALID("2 svc.example.net. mandatory=port"),
+ TEXT_INVALID("2 svc.example.net. mandatory=,port port=433"),
+ TEXT_INVALID("2 svc.example.net. mandatory=port, port=433"),
+ TEXT_INVALID("2 svc.example.net. "
+ "mandatory=alpn,,port alpn=h2 port=433"),
+ /* mandatory w/ unknown key values */
+ TEXT_VALID_LOOP(2, "2 svc.example.net. mandatory=key8 key8"),
+ TEXT_VALID_LOOP(3, "2 svc.example.net. mandatory=key8,key9 "
+ "key8 key9"),
+ TEXT_VALID_LOOPCHG(
+ 3, "2 svc.example.net. mandatory=key9,key8 key8 key9",
+ "2 svc.example.net. mandatory=key8,key9 key8 key9"),
+ TEXT_INVALID("2 svc.example.net. "
+ "mandatory=key8,key8"),
+ TEXT_INVALID("2 svc.example.net. mandatory=,key8"),
+ TEXT_INVALID("2 svc.example.net. mandatory=key8,"),
+ TEXT_INVALID("2 svc.example.net. "
+ "mandatory=key8,,key8"),
+ /* Invalid test vectors */
+ TEXT_INVALID("1 foo.example.com. ( key123=abc key123=def )"),
+ TEXT_INVALID("1 foo.example.com. mandatory"),
+ TEXT_INVALID("1 foo.example.com. alpn"),
+ TEXT_INVALID("1 foo.example.com. port"),
+ TEXT_INVALID("1 foo.example.com. ipv4hint"),
+ TEXT_INVALID("1 foo.example.com. ipv6hint"),
+ TEXT_INVALID("1 foo.example.com. no-default-alpn=abc"),
+ TEXT_INVALID("1 foo.example.com. mandatory=key123"),
+ TEXT_INVALID("1 foo.example.com. mandatory=mandatory"),
+ TEXT_INVALID("1 foo.example.com. ( mandatory=key123,key123 "
+ "key123=abc)"),
+ /* dohpath tests */
+ TEXT_VALID_LOOPCHG(1, "1 example.net. dohpath=/{?dns}",
+ "1 example.net. key7=\"/{?dns}\""),
+ TEXT_VALID_LOOPCHG(1, "1 example.net. dohpath=/some/path{?dns}",
+ "1 example.net. key7=\"/some/path{?dns}\""),
+ TEXT_INVALID("1 example.com. dohpath=no-slash"),
+ TEXT_INVALID("1 example.com. dohpath=/{?notdns}"),
+ TEXT_INVALID("1 example.com. dohpath=/notvariable"),
+ TEXT_SENTINEL()
+
+ };
+ wire_ok_t wire_ok[] = {
+ /*
+ * Too short
+ */
+ WIRE_INVALID(0x00, 0x00),
+ /*
+ * Minimal length record.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00),
+ /*
+ * Alias with non-empty SvcFieldValue (key7="").
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00),
+ /*
+ * Bad key7= length (longer than rdata).
+ */
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x01),
+ /*
+ * Port (0x03) too small (zero and one octets).
+ */
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00),
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00),
+ /* Valid port */
+ WIRE_VALID_LOOP(1, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x02,
+ 0x00, 0x00),
+ /*
+ * Port (0x03) too big (three octets).
+ */
+ WIRE_INVALID(0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
+ 0x00, 0x00),
+ /*
+ * Duplicate keys.
+ */
+ WIRE_INVALID(0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00),
+ /*
+ * Out of order keys.
+ */
+ WIRE_INVALID(0x01, 0x01, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00),
+ /*
+ * Empty of mandatory key list.
+ */
+ WIRE_INVALID(0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * "mandatory=mandatory" is invalid
+ */
+ WIRE_INVALID(0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00),
+ /*
+ * Out of order mandatory key list.
+ */
+ WIRE_INVALID(0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x80, 0x00, 0x71, 0x00, 0x71, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00),
+ /*
+ * Alpn(0x00 0x01) (length 0x00 0x09) "h1,h2" + "h3"
+ */
+ WIRE_VALID_LOOP(0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x09,
+ 5, 'h', '1', ',', 'h', '2', 2, 'h', '3'),
+ /*
+ * Alpn(0x00 0x01) (length 0x00 0x09) "h1\h2" + "h3"
+ */
+ WIRE_VALID_LOOP(0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x09,
+ 5, 'h', '1', '\\', 'h', '2', 2, 'h', '3'),
+ /*
+ * no-default-alpn (0x00 0x02) without alpn, alpn is required.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00),
+ /*
+ * Alpn(0x00 0x01) with zero length elements is invalid
+ */
+ WIRE_INVALID(0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00),
+ WIRE_SENTINEL()
+ };
+ /* Test vectors from RFCXXXX */
+ textvsunknown_t textvsunknown[] = {
+ /* AliasForm */
+ { "0 foo.example.com", "\\# 19 ( 00 00 03 66 6f 6f 07 65 78 61 "
+ "6d 70 6c 65 03 63 6f 6d 00)" },
+ /* ServiceForm */
+ { "1 .", "\\# 3 ( 00 01 00)" },
+ /* Port example */
+ { "16 foo.example.com port=53",
+ "\\# 25 ( 00 10 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f "
+ "6d 00 00 03 00 02 00 35 )" },
+ /* Unregistered keys with unquoted value. */
+ { "1 foo.example.com key667=hello",
+ "\\# 28 ( 00 01 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f "
+ "6d 00 02 9b 00 05 68 65 6c 6c 6f )" },
+ /*
+ * Quoted decimal-escaped character.
+ * 1 foo.example.com key667="hello\210qoo"
+ */
+ { "1 foo.example.com key667=\"hello\\210qoo\"",
+ "\\# 32 ( 00 01 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f "
+ "6d 00 02 9b 00 09 68 65 6c 6c 6f d2 71 6f 6f )" },
+ /*
+ * IPv6 hints example, quoted.
+ * 1 foo.example.com ipv6hint="2001:db8::1,2001:db8::53:1"
+ */
+ { "1 foo.example.com ipv6hint=\"2001:db8::1,2001:db8::53:1\"",
+ "\\# 55 ( 00 01 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 63 6f "
+ "6d 00 00 06 00 20 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 "
+ "00 01 20 01 0d b8 00 00 00 00 00 00 00 00 00 53 00 01 )" },
+ /* SvcParamValues and mandatory out of order. */
+ { "16 foo.example.org alpn=h2,h3-19 mandatory=ipv4hint,alpn "
+ "ipv4hint=192.0.2.1",
+ "\\# 48 ( 00 10 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 6f 72 "
+ "67 00 00 00 00 04 00 01 00 04 00 01 00 09 02 68 32 05 68 33 "
+ "2d 31 39 00 04 00 04 c0 00 02 01 )" },
+ /*
+ * Quoted ALPN with escaped comma and backslash.
+ * 16 foo.example.org alpn="f\\\\oo\\,bar,h2"
+ */
+ { "16 foo.example.org alpn=\"f\\\\\\\\oo\\\\,bar,h2\"",
+ "\\# 35 ( 00 10 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 6f 72 "
+ "67 00 00 01 00 0c 08 66 5c 6f 6f 2c 62 61 72 02 68 32 )" },
+ /*
+ * Unquoted ALPN with escaped comma and backslash.
+ * 16 foo.example.org alpn=f\\\092oo\092,bar,h2
+ */
+ { "16 foo.example.org alpn=f\\\\\\092oo\\092,bar,h2",
+ "\\# 35 ( 00 10 03 66 6f 6f 07 65 78 61 6d 70 6c 65 03 6f 72 "
+ "67 00 00 01 00 0c 08 66 5c 6f 6f 2c 62 61 72 02 68 32 )" },
+ { NULL, NULL }
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_svcb, sizeof(dns_rdata_in_svcb_t));
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_https, sizeof(dns_rdata_in_https_t));
+
+ check_textvsunknown(textvsunknown, dns_rdataclass_in,
+ dns_rdatatype_svcb);
+ check_textvsunknown(textvsunknown, dns_rdataclass_in,
+ dns_rdatatype_https);
+}
+
+/*
+ * ZONEMD tests.
+ *
+ * Excerpted from RFC 8976:
+ *
+ * The ZONEMD RDATA wire format is encoded as follows:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Serial |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Scheme |Hash Algorithm | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ * | Digest |
+ * / /
+ * / /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 2.2.1. The Serial Field
+ *
+ * The Serial field is a 32-bit unsigned integer in network byte order.
+ * It is the serial number from the zone's SOA record ([RFC1035],
+ * Section 3.3.13) for which the zone digest was generated.
+ *
+ * It is included here to clearly bind the ZONEMD RR to a particular
+ * version of the zone's content. Without the serial number, a stand-
+ * alone ZONEMD digest has no obvious association to any particular
+ * instance of a zone.
+ *
+ * 2.2.2. The Scheme Field
+ *
+ * The Scheme field is an 8-bit unsigned integer that identifies the
+ * methods by which data is collated and presented as input to the
+ * hashing function.
+ *
+ * Herein, SIMPLE, with Scheme value 1, is the only standardized Scheme
+ * defined for ZONEMD records and it MUST be supported by
+ * implementations. The "ZONEMD Schemes" registry is further described
+ * in Section 5.
+ *
+ * Scheme values 240-254 are allocated for Private Use.
+ *
+ * 2.2.3. The Hash Algorithm Field
+ *
+ * The Hash Algorithm field is an 8-bit unsigned integer that identifies
+ * the cryptographic hash algorithm used to construct the digest.
+ *
+ * Herein, SHA384 ([RFC6234]), with Hash Algorithm value 1, is the only
+ * standardized Hash Algorithm defined for ZONEMD records that MUST be
+ * supported by implementations. When SHA384 is used, the size of the
+ * Digest field is 48 octets. The result of the SHA384 digest algorithm
+ * MUST NOT be truncated, and the entire 48-octet digest is published in
+ * the ZONEMD record.
+ *
+ * SHA512 ([RFC6234]), with Hash Algorithm value 2, is also defined for
+ * ZONEMD records and SHOULD be supported by implementations. When
+ * SHA512 is used, the size of the Digest field is 64 octets. The
+ * result of the SHA512 digest algorithm MUST NOT be truncated, and the
+ * entire 64-octet digest is published in the ZONEMD record.
+ *
+ * Hash Algorithm values 240-254 are allocated for Private Use.
+ *
+ * The "ZONEMD Hash Algorithms" registry is further described in
+ * Section 5.
+ *
+ * 2.2.4. The Digest Field
+ *
+ * The Digest field is a variable-length sequence of octets containing
+ * the output of the hash algorithm. The length of the Digest field is
+ * determined by deducting the fixed size of the Serial, Scheme, and
+ * Hash Algorithm fields from the RDATA size in the ZONEMD RR header.
+ *
+ * The Digest field MUST NOT be shorter than 12 octets. Digests for the
+ * SHA384 and SHA512 hash algorithms specified herein are never
+ * truncated. Digests for future hash algorithms MAY be truncated but
+ * MUST NOT be truncated to a length that results in less than 96 bits
+ * (12 octets) of equivalent strength.
+ *
+ * Section 3 describes how to calculate the digest for a zone.
+ * Section 4 describes how to use the digest to verify the contents of a
+ * zone.
+ *
+ */
+
+ISC_RUN_TEST_IMPL(zonemd) {
+ text_ok_t text_ok[] = {
+ TEXT_INVALID(""),
+ /* No digest scheme or digest type*/
+ TEXT_INVALID("0"),
+ /* No digest type */
+ TEXT_INVALID("0 0"),
+ /* No digest */
+ TEXT_INVALID("0 0 0"),
+ /* No digest */
+ TEXT_INVALID("99999999 0 0"),
+ /* No digest */
+ TEXT_INVALID("2019020700 0 0"),
+ /* Digest too short */
+ TEXT_INVALID("2019020700 1 1 DEADBEEF"),
+ /* Digest too short */
+ TEXT_INVALID("2019020700 1 2 DEADBEEF"),
+ /* Digest too short */
+ TEXT_INVALID("2019020700 1 3 DEADBEEFDEADBEEFDEADBE"),
+ /* Digest type unknown */
+ TEXT_VALID("2019020700 1 3 DEADBEEFDEADBEEFDEADBEEF"),
+ /* Digest type max */
+ TEXT_VALID("2019020700 1 255 DEADBEEFDEADBEEFDEADBEEF"),
+ /* Digest type too big */
+ TEXT_INVALID("2019020700 0 256 DEADBEEFDEADBEEFDEADBEEF"),
+ /* Scheme max */
+ TEXT_VALID("2019020700 255 3 DEADBEEFDEADBEEFDEADBEEF"),
+ /* Scheme too big */
+ TEXT_INVALID("2019020700 256 3 DEADBEEFDEADBEEFDEADBEEF"),
+ /* SHA384 */
+ TEXT_VALID("2019020700 1 1 "
+ "7162D2BB75C047A53DE98767C9192BEB"
+ "14DB01E7E2267135DAF0230A 19BA4A31"
+ "6AF6BF64AA5C7BAE24B2992850300509"),
+ /* SHA512 */
+ TEXT_VALID("2019020700 1 2 "
+ "08CFA1115C7B948C4163A901270395EA"
+ "226A930CD2CBCF2FA9A5E6EB 85F37C8A"
+ "4E114D884E66F176EAB121CB02DB7D65"
+ "2E0CC4827E7A3204 F166B47E5613FD27"),
+ /* SHA384 too short and with private scheme */
+ TEXT_INVALID("2021042801 0 1 "
+ "7162D2BB75C047A53DE98767C9192BEB"
+ "6AF6BF64AA5C7BAE24B2992850300509"),
+ /* SHA512 too short and with private scheme */
+ TEXT_INVALID("2021042802 5 2 "
+ "A897B40072ECAE9E4CA3F1F227DE8F5E"
+ "480CDEBB16DFC64C1C349A7B5F6C71AB"
+ "E8A88B76EF0BA1604EC25752E946BF98"),
+ TEXT_SENTINEL()
+ };
+ wire_ok_t wire_ok[] = {
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00),
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00, 0x00),
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00),
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00),
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Short.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+ /*
+ * Short 11-octet digest.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00),
+ /*
+ * Minimal, 12-octet hash for an undefined digest type.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00),
+ /*
+ * SHA-384 is defined, so we insist there be a digest of
+ * the expected length.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00),
+ /*
+ * 48-octet digest, valid for SHA-384.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa,
+ 0xce),
+ /*
+ * 56-octet digest, too long for SHA-384.
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce),
+ /*
+ * 56-octet digest, too short for SHA-512
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad),
+ /*
+ * 64-octet digest, just right for SHA-512
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef),
+ /*
+ * 72-octet digest, too long for SHA-512
+ */
+ WIRE_INVALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad,
+ 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce),
+ /*
+ * 56-octet digest, valid for an undefined digest type.
+ */
+ WIRE_VALID(0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+ 0xef, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce,
+ 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce),
+ /*
+ * Sentinel.
+ */
+ WIRE_SENTINEL()
+ };
+
+ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_zonemd, sizeof(dns_rdata_zonemd_t));
+}
+
+ISC_RUN_TEST_IMPL(atcname) {
+ unsigned int i;
+
+#define UNR "# Unexpected result from dns_rdatatype_atcname for type %u\n"
+ for (i = 0; i < 0xffffU; i++) {
+ bool tf = dns_rdatatype_atcname((dns_rdatatype_t)i);
+ switch (i) {
+ case dns_rdatatype_nsec:
+ case dns_rdatatype_key:
+ case dns_rdatatype_rrsig:
+ if (!tf) {
+ print_message(UNR, i);
+ }
+ assert_true(tf);
+ break;
+ default:
+ if (tf) {
+ print_message(UNR, i);
+ }
+ assert_false(tf);
+ break;
+ }
+ }
+#undef UNR
+}
+
+ISC_RUN_TEST_IMPL(atparent) {
+ unsigned int i;
+
+#define UNR "# Unexpected result from dns_rdatatype_atparent for type %u\n"
+ for (i = 0; i < 0xffffU; i++) {
+ bool tf = dns_rdatatype_atparent((dns_rdatatype_t)i);
+ switch (i) {
+ case dns_rdatatype_ds:
+ if (!tf) {
+ print_message(UNR, i);
+ }
+ assert_true(tf);
+ break;
+ default:
+ if (tf) {
+ print_message(UNR, i);
+ }
+ assert_false(tf);
+ break;
+ }
+ }
+#undef UNR
+}
+
+ISC_RUN_TEST_IMPL(iszonecutauth) {
+ unsigned int i;
+#define UNR "# Unexpected result from dns_rdatatype_iszonecutauth for type %u\n"
+ for (i = 0; i < 0xffffU; i++) {
+ bool tf = dns_rdatatype_iszonecutauth((dns_rdatatype_t)i);
+ switch (i) {
+ case dns_rdatatype_ns:
+ case dns_rdatatype_ds:
+ case dns_rdatatype_nsec:
+ case dns_rdatatype_key:
+ case dns_rdatatype_rrsig:
+ if (!tf) {
+ print_message(UNR, i);
+ }
+ assert_true(tf);
+ break;
+ default:
+ if (tf) {
+ print_message(UNR, i);
+ }
+ assert_false(tf);
+ break;
+ }
+ }
+#undef UNR
+}
+
+ISC_TEST_LIST_START
+
+/* types */
+ISC_TEST_ENTRY(amtrelay)
+ISC_TEST_ENTRY(apl)
+ISC_TEST_ENTRY(atma)
+ISC_TEST_ENTRY(cdnskey)
+ISC_TEST_ENTRY(csync)
+ISC_TEST_ENTRY(dnskey)
+ISC_TEST_ENTRY(doa)
+ISC_TEST_ENTRY(ds)
+ISC_TEST_ENTRY(eid)
+ISC_TEST_ENTRY(hip)
+ISC_TEST_ENTRY(https_svcb)
+ISC_TEST_ENTRY(isdn)
+ISC_TEST_ENTRY(key)
+ISC_TEST_ENTRY(loc)
+ISC_TEST_ENTRY(nimloc)
+ISC_TEST_ENTRY(nsec)
+ISC_TEST_ENTRY(nsec3)
+ISC_TEST_ENTRY(nxt)
+ISC_TEST_ENTRY(rkey)
+ISC_TEST_ENTRY(sshfp)
+ISC_TEST_ENTRY(wks)
+ISC_TEST_ENTRY(zonemd)
+
+/* other tests */
+ISC_TEST_ENTRY(edns_client_subnet)
+ISC_TEST_ENTRY(atcname)
+ISC_TEST_ENTRY(atparent)
+ISC_TEST_ENTRY(iszonecutauth)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/rdataset_test.c b/tests/dns/rdataset_test.c
new file mode 100644
index 0000000..fc21b29
--- /dev/null
+++ b/tests/dns/rdataset_test.c
@@ -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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/util.h>
+
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+
+#include <tests/dns.h>
+
+/* test trimming of rdataset TTLs */
+ISC_RUN_TEST_IMPL(trimttl) {
+ dns_rdataset_t rdataset, sigrdataset;
+ dns_rdata_rrsig_t rrsig;
+ isc_stdtime_t ttltimenow, ttltimeexpire;
+
+ ttltimenow = 10000000;
+ ttltimeexpire = ttltimenow + 800;
+
+ UNUSED(state);
+
+ dns_rdataset_init(&rdataset);
+ dns_rdataset_init(&sigrdataset);
+
+ rdataset.ttl = 900;
+ sigrdataset.ttl = 1000;
+ rrsig.timeexpire = ttltimeexpire;
+ rrsig.originalttl = 1000;
+
+ dns_rdataset_trimttl(&rdataset, &sigrdataset, &rrsig, ttltimenow, true);
+ assert_int_equal(rdataset.ttl, 800);
+ assert_int_equal(sigrdataset.ttl, 800);
+
+ rdataset.ttl = 900;
+ sigrdataset.ttl = 1000;
+ rrsig.timeexpire = ttltimenow - 200;
+ rrsig.originalttl = 1000;
+
+ dns_rdataset_trimttl(&rdataset, &sigrdataset, &rrsig, ttltimenow, true);
+ assert_int_equal(rdataset.ttl, 120);
+ assert_int_equal(sigrdataset.ttl, 120);
+
+ rdataset.ttl = 900;
+ sigrdataset.ttl = 1000;
+ rrsig.timeexpire = ttltimenow - 200;
+ rrsig.originalttl = 1000;
+
+ dns_rdataset_trimttl(&rdataset, &sigrdataset, &rrsig, ttltimenow,
+ false);
+ assert_int_equal(rdataset.ttl, 0);
+ assert_int_equal(sigrdataset.ttl, 0);
+
+ sigrdataset.ttl = 900;
+ rdataset.ttl = 1000;
+ rrsig.timeexpire = ttltimeexpire;
+ rrsig.originalttl = 1000;
+
+ dns_rdataset_trimttl(&rdataset, &sigrdataset, &rrsig, ttltimenow, true);
+ assert_int_equal(rdataset.ttl, 800);
+ assert_int_equal(sigrdataset.ttl, 800);
+
+ sigrdataset.ttl = 900;
+ rdataset.ttl = 1000;
+ rrsig.timeexpire = ttltimenow - 200;
+ rrsig.originalttl = 1000;
+
+ dns_rdataset_trimttl(&rdataset, &sigrdataset, &rrsig, ttltimenow, true);
+ assert_int_equal(rdataset.ttl, 120);
+ assert_int_equal(sigrdataset.ttl, 120);
+
+ sigrdataset.ttl = 900;
+ rdataset.ttl = 1000;
+ rrsig.timeexpire = ttltimenow - 200;
+ rrsig.originalttl = 1000;
+
+ dns_rdataset_trimttl(&rdataset, &sigrdataset, &rrsig, ttltimenow,
+ false);
+ assert_int_equal(rdataset.ttl, 0);
+ assert_int_equal(sigrdataset.ttl, 0);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(trimttl)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/rdatasetstats_test.c b/tests/dns/rdatasetstats_test.c
new file mode 100644
index 0000000..7438034
--- /dev/null
+++ b/tests/dns/rdatasetstats_test.c
@@ -0,0 +1,265 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/print.h>
+#include <isc/util.h>
+
+#include <dns/stats.h>
+
+#include <tests/dns.h>
+
+static void
+set_typestats(dns_stats_t *stats, dns_rdatatype_t type) {
+ dns_rdatastatstype_t which;
+ unsigned int attributes;
+
+ attributes = 0;
+ which = DNS_RDATASTATSTYPE_VALUE(type, attributes);
+ dns_rdatasetstats_increment(stats, which);
+
+ attributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
+ which = DNS_RDATASTATSTYPE_VALUE(type, attributes);
+ dns_rdatasetstats_increment(stats, which);
+}
+
+static void
+set_nxdomainstats(dns_stats_t *stats) {
+ dns_rdatastatstype_t which;
+ unsigned int attributes;
+
+ attributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN;
+ which = DNS_RDATASTATSTYPE_VALUE(0, attributes);
+ dns_rdatasetstats_increment(stats, which);
+}
+
+static void
+mark_stale(dns_stats_t *stats, dns_rdatatype_t type, int from, int to) {
+ dns_rdatastatstype_t which;
+ unsigned int attributes;
+
+ attributes = from;
+ which = DNS_RDATASTATSTYPE_VALUE(type, attributes);
+ dns_rdatasetstats_decrement(stats, which);
+
+ attributes |= to;
+ which = DNS_RDATASTATSTYPE_VALUE(type, attributes);
+ dns_rdatasetstats_increment(stats, which);
+
+ attributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET | from;
+ which = DNS_RDATASTATSTYPE_VALUE(type, attributes);
+ dns_rdatasetstats_decrement(stats, which);
+
+ attributes |= to;
+ which = DNS_RDATASTATSTYPE_VALUE(type, attributes);
+ dns_rdatasetstats_increment(stats, which);
+}
+
+static void
+mark_nxdomain_stale(dns_stats_t *stats, int from, int to) {
+ dns_rdatastatstype_t which;
+ unsigned int attributes;
+
+ attributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN | from;
+ which = DNS_RDATASTATSTYPE_VALUE(0, attributes);
+ dns_rdatasetstats_decrement(stats, which);
+
+ attributes |= to;
+ which = DNS_RDATASTATSTYPE_VALUE(0, attributes);
+ dns_rdatasetstats_increment(stats, which);
+}
+
+#define ATTRIBUTE_SET(y) ((attributes & (y)) != 0)
+static void
+verify_active_counters(dns_rdatastatstype_t which, uint64_t value, void *arg) {
+ unsigned int attributes;
+#if debug
+ unsigned int type;
+#endif /* if debug */
+
+ UNUSED(which);
+ UNUSED(arg);
+
+ attributes = DNS_RDATASTATSTYPE_ATTR(which);
+#if debug
+ type = DNS_RDATASTATSTYPE_BASE(which);
+
+ fprintf(stderr, "%s%s%s%s%s/%u, %u\n",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) ? "O" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_NXRRSET) ? "!" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_ANCIENT) ? "~" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_STALE) ? "#" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) ? "X" : " ",
+ type, (unsigned)value);
+#endif /* if debug */
+ if ((attributes & DNS_RDATASTATSTYPE_ATTR_ANCIENT) == 0 &&
+ (attributes & DNS_RDATASTATSTYPE_ATTR_STALE) == 0)
+ {
+ assert_int_equal(value, 1);
+ } else {
+ assert_int_equal(value, 0);
+ }
+}
+
+static void
+verify_stale_counters(dns_rdatastatstype_t which, uint64_t value, void *arg) {
+ unsigned int attributes;
+#if debug
+ unsigned int type;
+#endif /* if debug */
+
+ UNUSED(which);
+ UNUSED(arg);
+
+ attributes = DNS_RDATASTATSTYPE_ATTR(which);
+#if debug
+ type = DNS_RDATASTATSTYPE_BASE(which);
+
+ fprintf(stderr, "%s%s%s%s%s/%u, %u\n",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) ? "O" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_NXRRSET) ? "!" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_ANCIENT) ? "~" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_STALE) ? "#" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) ? "X" : " ",
+ type, (unsigned)value);
+#endif /* if debug */
+ if ((attributes & DNS_RDATASTATSTYPE_ATTR_STALE) != 0) {
+ assert_int_equal(value, 1);
+ } else {
+ assert_int_equal(value, 0);
+ }
+}
+
+static void
+verify_ancient_counters(dns_rdatastatstype_t which, uint64_t value, void *arg) {
+ unsigned int attributes;
+#if debug
+ unsigned int type;
+#endif /* if debug */
+
+ UNUSED(which);
+ UNUSED(arg);
+
+ attributes = DNS_RDATASTATSTYPE_ATTR(which);
+#if debug
+ type = DNS_RDATASTATSTYPE_BASE(which);
+
+ fprintf(stderr, "%s%s%s%s%s/%u, %u\n",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) ? "O" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_NXRRSET) ? "!" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_ANCIENT) ? "~" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_STALE) ? "#" : " ",
+ ATTRIBUTE_SET(DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) ? "X" : " ",
+ type, (unsigned)value);
+#endif /* if debug */
+ if ((attributes & DNS_RDATASTATSTYPE_ATTR_ANCIENT) != 0) {
+ assert_int_equal(value, 1);
+ } else {
+ assert_int_equal(value, 0);
+ }
+}
+/*
+ * Individual unit tests
+ */
+
+/*
+ * Test that rdatasetstats counters are properly set when moving from
+ * active -> stale -> ancient.
+ */
+static void
+rdatasetstats(void **state, bool servestale) {
+ unsigned int i;
+ unsigned int from = 0;
+ dns_stats_t *stats = NULL;
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dns_rdatasetstats_create(mctx, &stats);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* First 255 types. */
+ for (i = 1; i <= 255; i++) {
+ set_typestats(stats, (dns_rdatatype_t)i);
+ }
+ /* Specials */
+ set_typestats(stats, (dns_rdatatype_t)1000);
+ set_nxdomainstats(stats);
+
+ /* Check that all active counters are set to appropriately. */
+ dns_rdatasetstats_dump(stats, verify_active_counters, NULL, 1);
+
+ if (servestale) {
+ /* Mark stale */
+ for (i = 1; i <= 255; i++) {
+ mark_stale(stats, (dns_rdatatype_t)i, 0,
+ DNS_RDATASTATSTYPE_ATTR_STALE);
+ }
+ mark_stale(stats, (dns_rdatatype_t)1000, 0,
+ DNS_RDATASTATSTYPE_ATTR_STALE);
+ mark_nxdomain_stale(stats, 0, DNS_RDATASTATSTYPE_ATTR_STALE);
+
+ /* Check that all counters are set to appropriately. */
+ dns_rdatasetstats_dump(stats, verify_stale_counters, NULL, 1);
+
+ /* Set correct staleness state */
+ from = DNS_RDATASTATSTYPE_ATTR_STALE;
+ }
+
+ /* Mark ancient */
+ for (i = 1; i <= 255; i++) {
+ mark_stale(stats, (dns_rdatatype_t)i, from,
+ DNS_RDATASTATSTYPE_ATTR_ANCIENT);
+ }
+ mark_stale(stats, (dns_rdatatype_t)1000, from,
+ DNS_RDATASTATSTYPE_ATTR_ANCIENT);
+ mark_nxdomain_stale(stats, from, DNS_RDATASTATSTYPE_ATTR_ANCIENT);
+
+ /*
+ * Check that all counters are set to appropriately.
+ */
+ dns_rdatasetstats_dump(stats, verify_ancient_counters, NULL, 1);
+
+ dns_stats_detach(&stats);
+}
+
+/*
+ * Test that rdatasetstats counters are properly set when moving from
+ * active -> stale -> ancient.
+ */
+ISC_RUN_TEST_IMPL(active_stale_ancient) { rdatasetstats(state, true); }
+
+/*
+ * Test that rdatasetstats counters are properly set when moving from
+ * active -> ancient.
+ */
+ISC_RUN_TEST_IMPL(active_ancient) { rdatasetstats(state, false); }
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(active_stale_ancient)
+ISC_TEST_ENTRY(active_ancient)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/resolver_test.c b/tests/dns/resolver_test.c
new file mode 100644
index 0000000..4967ffc
--- /dev/null
+++ b/tests/dns/resolver_test.c
@@ -0,0 +1,198 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/app.h>
+#include <isc/buffer.h>
+#include <isc/net.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/dispatch.h>
+#include <dns/name.h>
+#include <dns/resolver.h>
+#include <dns/view.h>
+
+#include <tests/dns.h>
+
+static dns_dispatchmgr_t *dispatchmgr = NULL;
+static dns_dispatch_t *dispatch = NULL;
+static dns_view_t *view = NULL;
+
+static int
+_setup(void **state) {
+ isc_result_t result;
+ isc_sockaddr_t local;
+
+ setup_managers(state);
+
+ result = dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_test_makeview("view", true, &view);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_sockaddr_any(&local);
+ result = dns_dispatch_createudp(dispatchmgr, &local, &dispatch);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ return (0);
+}
+
+static int
+_teardown(void **state) {
+ dns_dispatch_detach(&dispatch);
+ dns_view_detach(&view);
+ dns_dispatchmgr_detach(&dispatchmgr);
+
+ teardown_managers(state);
+
+ return (0);
+}
+
+static void
+mkres(dns_resolver_t **resolverp) {
+ isc_result_t result;
+
+ result = dns_resolver_create(view, taskmgr, 1, 1, netmgr, timermgr, 0,
+ dispatchmgr, dispatch, NULL, resolverp);
+ assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+static void
+destroy_resolver(dns_resolver_t **resolverp) {
+ dns_resolver_shutdown(*resolverp);
+ dns_resolver_detach(resolverp);
+}
+
+/* dns_resolver_create */
+ISC_RUN_TEST_IMPL(dns_resolver_create) {
+ dns_resolver_t *resolver = NULL;
+
+ UNUSED(state);
+
+ mkres(&resolver);
+ destroy_resolver(&resolver);
+}
+
+/* dns_resolver_gettimeout */
+ISC_RUN_TEST_IMPL(dns_resolver_gettimeout) {
+ dns_resolver_t *resolver = NULL;
+ unsigned int timeout;
+
+ UNUSED(state);
+
+ mkres(&resolver);
+
+ timeout = dns_resolver_gettimeout(resolver);
+ assert_true(timeout > 0);
+
+ destroy_resolver(&resolver);
+}
+
+/* dns_resolver_settimeout */
+ISC_RUN_TEST_IMPL(dns_resolver_settimeout) {
+ dns_resolver_t *resolver = NULL;
+ unsigned int default_timeout, timeout;
+
+ UNUSED(state);
+
+ mkres(&resolver);
+
+ default_timeout = dns_resolver_gettimeout(resolver);
+ dns_resolver_settimeout(resolver, default_timeout + 1);
+ timeout = dns_resolver_gettimeout(resolver);
+ assert_true(timeout == default_timeout + 1);
+
+ destroy_resolver(&resolver);
+}
+
+/* dns_resolver_settimeout */
+ISC_RUN_TEST_IMPL(dns_resolver_settimeout_default) {
+ dns_resolver_t *resolver = NULL;
+ unsigned int default_timeout, timeout;
+
+ UNUSED(state);
+
+ mkres(&resolver);
+
+ default_timeout = dns_resolver_gettimeout(resolver);
+ dns_resolver_settimeout(resolver, default_timeout + 100);
+
+ timeout = dns_resolver_gettimeout(resolver);
+ assert_int_equal(timeout, default_timeout + 100);
+
+ dns_resolver_settimeout(resolver, 0);
+ timeout = dns_resolver_gettimeout(resolver);
+ assert_int_equal(timeout, default_timeout);
+
+ destroy_resolver(&resolver);
+}
+
+/* dns_resolver_settimeout below minimum */
+ISC_RUN_TEST_IMPL(dns_resolver_settimeout_belowmin) {
+ dns_resolver_t *resolver = NULL;
+ unsigned int default_timeout, timeout;
+
+ UNUSED(state);
+
+ mkres(&resolver);
+
+ default_timeout = dns_resolver_gettimeout(resolver);
+ dns_resolver_settimeout(resolver, 9000);
+
+ timeout = dns_resolver_gettimeout(resolver);
+ assert_int_equal(timeout, default_timeout);
+
+ destroy_resolver(&resolver);
+}
+
+/* dns_resolver_settimeout over maximum */
+ISC_RUN_TEST_IMPL(dns_resolver_settimeout_overmax) {
+ dns_resolver_t *resolver = NULL;
+ unsigned int timeout;
+
+ UNUSED(state);
+
+ mkres(&resolver);
+
+ dns_resolver_settimeout(resolver, 4000000);
+ timeout = dns_resolver_gettimeout(resolver);
+ assert_in_range(timeout, 0, 3999999);
+ destroy_resolver(&resolver);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(dns_resolver_create, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dns_resolver_gettimeout, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dns_resolver_settimeout, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dns_resolver_settimeout_default, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dns_resolver_settimeout_belowmin, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dns_resolver_settimeout_overmax, _setup, _teardown)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/rsa_test.c b/tests/dns/rsa_test.c
new file mode 100644
index 0000000..d5b7a7f
--- /dev/null
+++ b/tests/dns/rsa_test.c
@@ -0,0 +1,233 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * As a workaround, include an OpenSSL header file before including cmocka.h,
+ * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a
+ * redefined malloc in cmocka.h.
+ */
+#include <openssl/err.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/print.h>
+#include <isc/util.h>
+
+#include "dst_internal.h"
+
+#include <tests/dns.h>
+
+static int
+setup_test(void **state) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dst_lib_init(mctx, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ UNUSED(state);
+
+ dst_lib_destroy();
+
+ return (0);
+}
+
+static unsigned char d[10] = { 0xa, 0x10, 0xbb, 0, 0xfe,
+ 0x15, 0x1, 0x88, 0xcc, 0x7d };
+
+static unsigned char sigsha1[256] = {
+ 0x45, 0x55, 0xd6, 0xf8, 0x05, 0xd2, 0x2e, 0x79, 0x14, 0x2b, 0x1b, 0xd1,
+ 0x4b, 0xb7, 0xcd, 0xc0, 0xa2, 0xf3, 0x85, 0x32, 0x1f, 0xa3, 0xfd, 0x1f,
+ 0x30, 0xe0, 0xde, 0xb2, 0x6f, 0x3c, 0x8e, 0x2b, 0x82, 0x92, 0xcd, 0x1c,
+ 0x1b, 0xdf, 0xe6, 0xd5, 0x4d, 0x93, 0xe6, 0xaa, 0x40, 0x28, 0x1b, 0x7b,
+ 0x2e, 0x40, 0x4d, 0xb5, 0x4d, 0x43, 0xe8, 0xfc, 0x93, 0x86, 0x68, 0xe3,
+ 0xbf, 0x73, 0x9a, 0x1e, 0x6b, 0x5d, 0x52, 0xb8, 0x98, 0x1c, 0x94, 0xe1,
+ 0x85, 0x8b, 0xee, 0xb1, 0x4f, 0x22, 0x71, 0xcb, 0xfd, 0xb2, 0xa8, 0x88,
+ 0x64, 0xb4, 0xb1, 0x4a, 0xa1, 0x7a, 0xce, 0x52, 0x83, 0xd8, 0xf2, 0x9e,
+ 0x67, 0x4c, 0xc3, 0x37, 0x74, 0xfe, 0xe0, 0x25, 0x2a, 0xfd, 0xa3, 0x09,
+ 0xff, 0x8a, 0x92, 0x0d, 0xa9, 0xb3, 0x90, 0x23, 0xbe, 0x6a, 0x2c, 0x9e,
+ 0x5c, 0x6d, 0xb4, 0xa7, 0xd7, 0x97, 0xdd, 0xc6, 0xb8, 0xae, 0xd4, 0x88,
+ 0x64, 0x63, 0x1e, 0x85, 0x20, 0x09, 0xea, 0xc4, 0x0b, 0xca, 0xbf, 0x83,
+ 0x5c, 0x89, 0xae, 0x64, 0x15, 0x76, 0x06, 0x51, 0xb6, 0xa1, 0x99, 0xb2,
+ 0x3c, 0x50, 0x99, 0x86, 0x7d, 0xc7, 0xca, 0x4e, 0x1d, 0x2c, 0x17, 0xbb,
+ 0x6c, 0x7a, 0xc9, 0x3f, 0x5e, 0x28, 0x57, 0x2c, 0xda, 0x01, 0x1d, 0xe8,
+ 0x01, 0xf8, 0xf6, 0x37, 0xe1, 0x34, 0x56, 0xae, 0x6e, 0xb1, 0xd4, 0xa2,
+ 0xc4, 0x02, 0xc1, 0xca, 0x96, 0xb0, 0x06, 0x72, 0x2a, 0x27, 0xaa, 0xc8,
+ 0xd5, 0x50, 0x81, 0x49, 0x46, 0x33, 0xf8, 0xf7, 0x6b, 0xf4, 0x9c, 0x30,
+ 0x90, 0x50, 0xf6, 0x16, 0x76, 0x9d, 0xc6, 0x73, 0xb5, 0xbc, 0x8a, 0xb6,
+ 0x1d, 0x98, 0xcb, 0xce, 0x36, 0x6f, 0x60, 0xec, 0x96, 0x49, 0x08, 0x85,
+ 0x5b, 0xc1, 0x8e, 0xb0, 0xea, 0x9e, 0x1f, 0xd6, 0x27, 0x7f, 0xb6, 0xe0,
+ 0x04, 0x12, 0xd2, 0x81
+};
+
+static unsigned char sigsha256[256] = {
+ 0x83, 0x53, 0x15, 0xfc, 0xca, 0xdb, 0xf6, 0x0d, 0x53, 0x24, 0x5b, 0x5a,
+ 0x8e, 0xd0, 0xbe, 0x5e, 0xbc, 0xe8, 0x9e, 0x92, 0x3c, 0xfa, 0x93, 0x03,
+ 0xce, 0x2f, 0xc7, 0x6d, 0xd0, 0xbb, 0x9d, 0x06, 0x83, 0xc6, 0xd3, 0xc0,
+ 0xc1, 0x57, 0x9c, 0x82, 0x17, 0x7f, 0xb5, 0xf8, 0x31, 0x18, 0xda, 0x46,
+ 0x05, 0x2c, 0xf8, 0xea, 0xaa, 0xcd, 0x99, 0x18, 0xff, 0x23, 0x5e, 0xef,
+ 0xf0, 0x87, 0x47, 0x6e, 0x91, 0xfd, 0x19, 0x0b, 0x39, 0x19, 0x6a, 0xc8,
+ 0xdf, 0x71, 0x66, 0x8e, 0xa9, 0xa0, 0x79, 0x5c, 0x2c, 0x52, 0x00, 0x61,
+ 0x17, 0x86, 0x66, 0x03, 0x52, 0xad, 0xec, 0x06, 0x53, 0xd9, 0x6d, 0xe3,
+ 0xe3, 0xea, 0x28, 0x15, 0xb3, 0x75, 0xf4, 0x61, 0x7d, 0xed, 0x69, 0x2c,
+ 0x24, 0xf3, 0x21, 0xb1, 0x8a, 0xea, 0x60, 0xa2, 0x9e, 0x6a, 0xa6, 0x53,
+ 0x12, 0xf6, 0x5c, 0xef, 0xd7, 0x49, 0x4a, 0x02, 0xe7, 0xf8, 0x64, 0x89,
+ 0x13, 0xac, 0xd5, 0x1e, 0x58, 0xff, 0xa1, 0x63, 0xdd, 0xa0, 0x1f, 0x44,
+ 0x99, 0x6a, 0x59, 0x7f, 0x35, 0xbd, 0xf1, 0xf3, 0x7a, 0x28, 0x44, 0xe3,
+ 0x4c, 0x68, 0xb1, 0xb3, 0x97, 0x3c, 0x46, 0xe3, 0xc2, 0x12, 0x9e, 0x68,
+ 0x0b, 0xa6, 0x6c, 0x8f, 0x58, 0x48, 0x44, 0xa4, 0xf7, 0xa7, 0xc2, 0x91,
+ 0x8f, 0xbf, 0x00, 0xd0, 0x01, 0x35, 0xd4, 0x86, 0x6e, 0x1f, 0xea, 0x42,
+ 0x60, 0xb1, 0x84, 0x27, 0xf4, 0x99, 0x36, 0x06, 0x98, 0x12, 0x83, 0x32,
+ 0x9f, 0xcd, 0x50, 0x5a, 0x5e, 0xb8, 0x8e, 0xfe, 0x8d, 0x8d, 0x33, 0x2d,
+ 0x45, 0xe1, 0xc9, 0xdf, 0x2a, 0xd8, 0x38, 0x1d, 0x95, 0xd4, 0x42, 0xee,
+ 0x93, 0x5b, 0x0f, 0x1e, 0x07, 0x06, 0x3a, 0x92, 0xf1, 0x59, 0x1d, 0x6e,
+ 0x1c, 0x31, 0xf3, 0xce, 0xa9, 0x1f, 0xad, 0x4d, 0x76, 0x4d, 0x24, 0x98,
+ 0xe2, 0x0e, 0x8c, 0x35
+};
+
+static unsigned char sigsha512[512] = {
+ 0x4e, 0x2f, 0x63, 0x42, 0xc5, 0xf3, 0x05, 0x4a, 0xa6, 0x3a, 0x93, 0xa0,
+ 0xd9, 0x33, 0xa0, 0xd1, 0x46, 0x33, 0x42, 0xe8, 0x74, 0xeb, 0x3b, 0x10,
+ 0x82, 0xd7, 0xcf, 0x39, 0x23, 0xb3, 0xe9, 0x23, 0x53, 0x87, 0x8c, 0xee,
+ 0x78, 0xcb, 0xb3, 0xd9, 0xd2, 0x6d, 0x1a, 0x7c, 0x01, 0x4f, 0xed, 0x8d,
+ 0xf2, 0x72, 0xe4, 0x6a, 0x00, 0x8a, 0x60, 0xa6, 0xd5, 0x9c, 0x43, 0x6c,
+ 0xef, 0x38, 0x0c, 0x74, 0x82, 0x5d, 0x22, 0xaa, 0x87, 0x81, 0x90, 0x9c,
+ 0x64, 0x07, 0x9b, 0x13, 0x51, 0xe0, 0xa5, 0xc2, 0x83, 0x78, 0x2b, 0x9b,
+ 0xb3, 0x8a, 0x9d, 0x36, 0x33, 0xbd, 0x0d, 0x53, 0x84, 0xae, 0xe8, 0x13,
+ 0x36, 0xf6, 0xdf, 0x96, 0xe9, 0xda, 0xc3, 0xd7, 0xa9, 0x2f, 0xf3, 0x5e,
+ 0x5f, 0x1f, 0x7f, 0x38, 0x7e, 0x8d, 0xbe, 0x90, 0x5e, 0x13, 0xb2, 0x20,
+ 0xbb, 0x9d, 0xfe, 0xe1, 0x52, 0xce, 0xe6, 0x80, 0xa7, 0x95, 0x24, 0x59,
+ 0xe3, 0xac, 0x24, 0xc4, 0xfa, 0x1c, 0x44, 0x34, 0x29, 0x8d, 0xb1, 0xd0,
+ 0xd9, 0x4c, 0xff, 0xc4, 0xdb, 0xca, 0xc4, 0x3f, 0x38, 0xf9, 0xe4, 0xaf,
+ 0x75, 0x0a, 0x67, 0x4d, 0xa0, 0x2b, 0xb0, 0x83, 0xce, 0x53, 0xc4, 0xb9,
+ 0x2e, 0x61, 0xb6, 0x64, 0xe5, 0xb5, 0xe5, 0xac, 0x9d, 0x51, 0xec, 0x58,
+ 0x42, 0x90, 0x78, 0xf6, 0x46, 0x96, 0xef, 0xb6, 0x97, 0xb7, 0x54, 0x28,
+ 0x1a, 0x4c, 0x29, 0xf4, 0x7a, 0x33, 0xc6, 0x07, 0xfd, 0xec, 0x97, 0x36,
+ 0x1d, 0x42, 0x88, 0x94, 0x27, 0xc2, 0xa3, 0xe1, 0xd4, 0x87, 0xa1, 0x8a,
+ 0x2b, 0xff, 0x47, 0x60, 0xfe, 0x1f, 0xaf, 0xc2, 0xeb, 0x17, 0xdd, 0x56,
+ 0xc5, 0x94, 0x5c, 0xcb, 0x23, 0xe5, 0x49, 0x4d, 0x99, 0x06, 0x02, 0x5a,
+ 0xfc, 0xfc, 0xdc, 0xee, 0x49, 0xbc, 0x47, 0x60, 0xff, 0x6a, 0x63, 0x8b,
+ 0xe1, 0x2e, 0xa3, 0xa7
+};
+
+/* RSA verify */
+ISC_RUN_TEST_IMPL(isc_rsa_verify) {
+ isc_result_t ret;
+ dns_fixedname_t fname;
+ isc_buffer_t buf;
+ dns_name_t *name;
+ dst_key_t *key = NULL;
+ dst_context_t *ctx = NULL;
+ isc_region_t r;
+
+ UNUSED(state);
+
+ name = dns_fixedname_initname(&fname);
+ isc_buffer_constinit(&buf, "rsa.", 4);
+ isc_buffer_add(&buf, 4);
+ ret = dns_name_fromtext(name, &buf, NULL, 0, NULL);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ ret = dst_key_fromfile(name, 29238, DST_ALG_RSASHA256, DST_TYPE_PUBLIC,
+ TESTS_DIR, mctx, &key);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ /* RSASHA1 - May not be supported by the OS */
+ if (dst_algorithm_supported(DST_ALG_RSASHA1)) {
+ key->key_alg = DST_ALG_RSASHA1;
+
+ ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC,
+ false, 0, &ctx);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ r.base = d;
+ r.length = 10;
+ ret = dst_context_adddata(ctx, &r);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ r.base = sigsha1;
+ r.length = 256;
+ ret = dst_context_verify(ctx, &r);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ dst_context_destroy(&ctx);
+ }
+
+ /* RSASHA256 */
+
+ key->key_alg = DST_ALG_RSASHA256;
+
+ ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false, 0,
+ &ctx);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ r.base = d;
+ r.length = 10;
+ ret = dst_context_adddata(ctx, &r);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ r.base = sigsha256;
+ r.length = 256;
+ ret = dst_context_verify(ctx, &r);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ dst_context_destroy(&ctx);
+
+ /* RSASHA512 */
+
+ key->key_alg = DST_ALG_RSASHA512;
+
+ ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false, 0,
+ &ctx);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ r.base = d;
+ r.length = 10;
+ ret = dst_context_adddata(ctx, &r);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ r.base = sigsha512;
+ r.length = 256;
+ ret = dst_context_verify(ctx, &r);
+ assert_int_equal(ret, ISC_R_SUCCESS);
+
+ dst_context_destroy(&ctx);
+
+ dst_key_free(&key);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(isc_rsa_verify, setup_test, teardown_test)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/sigs_test.c b/tests/dns/sigs_test.c
new file mode 100644
index 0000000..881c900
--- /dev/null
+++ b/tests/dns/sigs_test.c
@@ -0,0 +1,446 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/list.h>
+#include <isc/region.h>
+#include <isc/result.h>
+#include <isc/stdtime.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/diff.h>
+#include <dns/dnssec.h>
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+#include <dns/types.h>
+#include <dns/zone.h>
+
+#include <dst/dst.h>
+
+#include "zone_p.h"
+
+#include <tests/dns.h>
+
+/*%
+ * Structure characterizing a single diff tuple in the dns_diff_t structure
+ * prepared by dns__zone_updatesigs().
+ */
+typedef struct {
+ dns_diffop_t op;
+ const char *owner;
+ dns_ttl_t ttl;
+ const char *type;
+} zonediff_t;
+
+#define ZONEDIFF_SENTINEL \
+ { \
+ 0, NULL, 0, NULL \
+ }
+
+/*%
+ * Structure defining a dns__zone_updatesigs() test.
+ */
+typedef struct {
+ const char *description; /* test description */
+ const zonechange_t *changes; /* array of "raw" zone changes */
+ const zonediff_t *zonediff; /* array of "processed" zone changes
+ * */
+} updatesigs_test_params_t;
+
+static int
+setup_test(void **state) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dst_lib_init(mctx, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ UNUSED(state);
+
+ dst_lib_destroy();
+
+ return (0);
+}
+
+/*%
+ * Check whether the 'found' tuple matches the 'expected' tuple. 'found' is
+ * the 'index'th tuple output by dns__zone_updatesigs() in test 'test'.
+ */
+static void
+compare_tuples(const zonediff_t *expected, dns_difftuple_t *found,
+ size_t index) {
+ char found_covers[DNS_RDATATYPE_FORMATSIZE] = {};
+ char found_type[DNS_RDATATYPE_FORMATSIZE] = {};
+ char found_name[DNS_NAME_FORMATSIZE];
+ isc_consttextregion_t typeregion;
+ dns_fixedname_t expected_fname;
+ dns_rdatatype_t expected_type;
+ dns_name_t *expected_name;
+ dns_rdata_rrsig_t rrsig;
+ isc_buffer_t typebuf;
+ isc_result_t result;
+
+ REQUIRE(expected != NULL);
+ REQUIRE(found != NULL);
+ REQUIRE(index > 0);
+
+ /*
+ * Check operation.
+ */
+ assert_int_equal(expected->op, found->op);
+
+ /*
+ * Check owner name.
+ */
+ expected_name = dns_fixedname_initname(&expected_fname);
+ result = dns_name_fromstring(expected_name, expected->owner, 0, mctx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_name_format(&found->name, found_name, sizeof(found_name));
+ assert_true(dns_name_equal(expected_name, &found->name));
+
+ /*
+ * Check TTL.
+ */
+ assert_int_equal(expected->ttl, found->ttl);
+
+ /*
+ * Parse expected RR type.
+ */
+ typeregion.base = expected->type;
+ typeregion.length = strlen(expected->type);
+ result = dns_rdatatype_fromtext(&expected_type,
+ (isc_textregion_t *)&typeregion);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Format found RR type for reporting purposes.
+ */
+ isc_buffer_init(&typebuf, found_type, sizeof(found_type));
+ result = dns_rdatatype_totext(found->rdata.type, &typebuf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Check RR type.
+ */
+ switch (expected->op) {
+ case DNS_DIFFOP_ADDRESIGN:
+ case DNS_DIFFOP_DELRESIGN:
+ /*
+ * Found tuple must be of type RRSIG.
+ */
+ assert_int_equal(found->rdata.type, dns_rdatatype_rrsig);
+ if (found->rdata.type != dns_rdatatype_rrsig) {
+ break;
+ }
+ /*
+ * The signature must cover an RRset of type 'expected->type'.
+ */
+ result = dns_rdata_tostruct(&found->rdata, &rrsig, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_buffer_init(&typebuf, found_covers, sizeof(found_covers));
+ result = dns_rdatatype_totext(rrsig.covered, &typebuf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(expected_type, rrsig.covered);
+ break;
+ default:
+ /*
+ * Found tuple must be of type 'expected->type'.
+ */
+ assert_int_equal(expected_type, found->rdata.type);
+ break;
+ }
+}
+
+/*%
+ * Perform a single dns__zone_updatesigs() test defined in 'test'. All other
+ * arguments are expected to remain constant between subsequent invocations of
+ * this function.
+ */
+static void
+updatesigs_test(const updatesigs_test_params_t *test, dns_zone_t *zone,
+ dns_db_t *db, dst_key_t *zone_keys[], unsigned int nkeys,
+ isc_stdtime_t now) {
+ size_t tuples_expected, tuples_found, index;
+ dns_dbversion_t *version = NULL;
+ dns_diff_t raw_diff, zone_diff;
+ const zonediff_t *expected;
+ dns_difftuple_t *found;
+ isc_result_t result;
+
+ dns__zonediff_t zonediff = {
+ .diff = &zone_diff,
+ .offline = false,
+ };
+
+ REQUIRE(test != NULL);
+ REQUIRE(test->description != NULL);
+ REQUIRE(test->changes != NULL);
+ REQUIRE(zone != NULL);
+ REQUIRE(db != NULL);
+ REQUIRE(zone_keys != NULL);
+
+ /*
+ * Create a new version of the zone's database.
+ */
+ result = dns_db_newversion(db, &version);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Create a diff representing the supplied changes.
+ */
+ result = dns_test_difffromchanges(&raw_diff, test->changes, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Apply the "raw" diff to the new version of the zone's database as
+ * this is what dns__zone_updatesigs() expects to happen before it is
+ * called.
+ */
+ dns_diff_apply(&raw_diff, db, version);
+
+ /*
+ * Initialize the structure dns__zone_updatesigs() will modify.
+ */
+ dns_diff_init(mctx, &zone_diff);
+
+ /*
+ * Check whether dns__zone_updatesigs() behaves as expected.
+ */
+ result = dns__zone_updatesigs(&raw_diff, db, version, zone_keys, nkeys,
+ zone, now - 3600, now + 3600, 0, now,
+ true, false, &zonediff);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(ISC_LIST_EMPTY(raw_diff.tuples));
+ assert_false(ISC_LIST_EMPTY(zone_diff.tuples));
+
+ /*
+ * Ensure that the number of tuples in the zone diff is as expected.
+ */
+
+ tuples_expected = 0;
+ for (expected = test->zonediff; expected->owner != NULL; expected++) {
+ tuples_expected++;
+ }
+
+ tuples_found = 0;
+ for (found = ISC_LIST_HEAD(zone_diff.tuples); found != NULL;
+ found = ISC_LIST_NEXT(found, link))
+ {
+ tuples_found++;
+ }
+
+ assert_int_equal(tuples_expected, tuples_found);
+
+ /*
+ * Ensure that every tuple in the zone diff matches expectations.
+ */
+ expected = test->zonediff;
+ index = 1;
+ for (found = ISC_LIST_HEAD(zone_diff.tuples); found != NULL;
+ found = ISC_LIST_NEXT(found, link))
+ {
+ compare_tuples(expected, found, index);
+ expected++;
+ index++;
+ }
+
+ /*
+ * Apply changes to zone database contents and clean up.
+ */
+ dns_db_closeversion(db, &version, true);
+ dns_diff_clear(&zone_diff);
+ dns_diff_clear(&raw_diff);
+}
+
+/* dns__zone_updatesigs() tests */
+ISC_RUN_TEST_IMPL(updatesigs_next) {
+ dst_key_t *zone_keys[DNS_MAXZONEKEYS];
+ dns_zone_t *zone = NULL;
+ dns_db_t *db = NULL;
+ isc_result_t result;
+ unsigned int nkeys;
+ isc_stdtime_t now;
+ size_t i;
+
+ UNUSED(state);
+
+ /*
+ * Prepare a zone along with its signing keys.
+ */
+
+ result = dns_test_makezone("example", &zone, NULL, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_test_loaddb(&db, dns_dbtype_zone, "example",
+ "testdata/master/master18.data");
+ assert_int_equal(result, DNS_R_SEENINCLUDE);
+
+ result = dns_zone_setkeydirectory(zone, TESTS_DIR "/testkeys");
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_stdtime_get(&now);
+ result = dns__zone_findkeys(zone, db, NULL, now, mctx, DNS_MAXZONEKEYS,
+ zone_keys, &nkeys);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(nkeys, 2);
+
+ /*
+ * Define the tests to be run. Note that changes to zone database
+ * contents introduced by each test are preserved between tests.
+ */
+
+ const zonechange_t changes_add[] = {
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo" },
+ { DNS_DIFFOP_ADD, "bar.example", 600, "TXT", "bar" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_add[] = {
+ { DNS_DIFFOP_ADDRESIGN, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADDRESIGN, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_ADD, "bar.example", 600, "TXT" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_add = {
+ .description = "add new RRsets",
+ .changes = changes_add,
+ .zonediff = zonediff_add,
+ };
+
+ const zonechange_t changes_append[] = {
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo1" },
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo2" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_append[] = {
+ { DNS_DIFFOP_DELRESIGN, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADDRESIGN, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_append = {
+ .description = "append multiple RRs to an existing RRset",
+ .changes = changes_append,
+ .zonediff = zonediff_append,
+ };
+
+ const zonechange_t changes_replace[] = {
+ { DNS_DIFFOP_DEL, "bar.example", 600, "TXT", "bar" },
+ { DNS_DIFFOP_ADD, "bar.example", 600, "TXT", "rab" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_replace[] = {
+ { DNS_DIFFOP_DELRESIGN, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_ADDRESIGN, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_DEL, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_ADD, "bar.example", 600, "TXT" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_replace = {
+ .description = "replace an existing RRset",
+ .changes = changes_replace,
+ .zonediff = zonediff_replace,
+ };
+
+ const zonechange_t changes_delete[] = {
+ { DNS_DIFFOP_DEL, "bar.example", 600, "TXT", "rab" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_delete[] = {
+ { DNS_DIFFOP_DELRESIGN, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_DEL, "bar.example", 600, "TXT" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_delete = {
+ .description = "delete an existing RRset",
+ .changes = changes_delete,
+ .zonediff = zonediff_delete,
+ };
+
+ const zonechange_t changes_mixed[] = {
+ { DNS_DIFFOP_ADD, "baz.example", 900, "TXT", "baz1" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "A", "127.0.0.1" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "TXT", "baz2" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "AAAA", "::1" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_mixed[] = {
+ { DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "TXT" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "TXT" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "TXT" },
+ { DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "A" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "A" },
+ { DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "AAAA" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "AAAA" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_mixed = {
+ .description = "add different RRsets with common owner name",
+ .changes = changes_mixed,
+ .zonediff = zonediff_mixed,
+ };
+
+ const updatesigs_test_params_t *tests[] = {
+ &test_add, &test_append, &test_replace,
+ &test_delete, &test_mixed,
+ };
+
+ /*
+ * Run tests.
+ */
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ updatesigs_test(tests[i], zone, db, zone_keys, nkeys, now);
+ }
+
+ /*
+ * Clean up.
+ */
+ for (i = 0; i < nkeys; i++) {
+ dst_key_free(&zone_keys[i]);
+ }
+ dns_db_detach(&db);
+ dns_zone_detach(&zone);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(updatesigs_next, setup_test, teardown_test)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/testdata/db/data.db b/tests/dns/testdata/db/data.db
new file mode 100644
index 0000000..67a4fba
--- /dev/null
+++ b/tests/dns/testdata/db/data.db
@@ -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.
+
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+a in ns ns.vix.com.
+a in ns ns2.vix.com.
+a in ns ns3.vix.com.
+b in a 1.2.3.4
diff --git a/tests/dns/testdata/dbiterator/zone1.data b/tests/dns/testdata/dbiterator/zone1.data
new file mode 100644
index 0000000..c380d39
--- /dev/null
+++ b/tests/dns/testdata/dbiterator/zone1.data
@@ -0,0 +1,30 @@
+; Copyright (C) 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/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 600
+@ in soa localhost. postmaster.localhost. (
+ 2011080901 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 600 ) ;minimum
+ in ns ns
+ in ns ns2
+ns in a 10.0.0.1
+ns2 in a 10.0.0.2
+
+a in txt "test"
+b in txt "test"
+c in txt "test"
+d.e.f in txt "test"
+e in txt "test"
+f.g.h in txt "test"
+f.g.i in txt "test"
+f.g.j in txt "test"
+k in txt "test"
diff --git a/tests/dns/testdata/dbiterator/zone2.data b/tests/dns/testdata/dbiterator/zone2.data
new file mode 100644
index 0000000..7265c27
--- /dev/null
+++ b/tests/dns/testdata/dbiterator/zone2.data
@@ -0,0 +1,319 @@
+; File written on Mon Aug 15 16:51:56 2011
+; dnssec_signzone version 9.7.3rc1
+test. 600 IN SOA localhost. postmaster.localhost. (
+ 2011080901 ; serial
+ 3600 ; refresh (1 hour)
+ 1800 ; retry (30 minutes)
+ 604800 ; expire (1 week)
+ 600 ; minimum (10 minutes)
+ )
+ 600 RRSIG SOA 7 1 600 20110914225156 (
+ 20110815225156 39833 test.
+ IoQPcpx+Y2btVBBdM2H/9ppRMjphB1thwrdh
+ midhKH+MXDAauUIENucugi3zLsc1o2ke8LnQ
+ v3lCLd/bb5MD1otuS8vOw1GWEFhXOUBZU6wS
+ QwEIcG4BiSlz7/GvOlRa2znkOmZ3c8bD/J3Y
+ XUWDI3BEDPgrZqfxEvoMyPEWjO8= )
+ 600 NS ns.test.
+ 600 NS ns2.test.
+ 600 RRSIG NS 7 1 600 20110914225156 (
+ 20110815225156 39833 test.
+ OgEimhmFIAqlH0hyQy3pTsveBHKyqs9WfO1S
+ uDPRj3DFgFEAjoY473T8GxG2C+jTVL/UMVcb
+ BTZ8wIAiUHhqKLcmr0q/1X+kNUs7tNi+6oMn
+ /jxaOuRL6c8Kf2gl2t4g6JTwQqLQhUHTfQP+
+ bEfKUr75VsVfxCQZIHlZ3/AlxZM= )
+ 600 DNSKEY 256 3 7 (
+ AwEAAc0FzrE7jUiaKIGZpIaFE8E989topAJN
+ dWIQUQ7BSKabmpBP2M+SXHwIiQ/yC25iqudO
+ IxjRcK7nHB1VoP84xU2oMj6eeSqQHf/bYaji
+ Y8IfR7lgrzoDWzq+0rtnKMJc/JM8SMkcoBAS
+ llvxarDJTZheZjlrCvhpRJC+FAkBsx81
+ ) ; key id = 39833
+ 600 DNSKEY 257 3 7 (
+ AwEAAc55LPDhBLqfDUpjYYbBt+N63CiZtKrD
+ UDGeFAerbw0MWIUi3PgMr7yGVrj8e5Qjp9UN
+ zBUax6NdhlYVtFA8CwMTXGBjxgyqUoWpce08
+ lswxfE70BpgUA6w5efs0/mYtX9/A76etCaSI
+ oNH2vfa47BCdCPDfC1uTgyeuNuDvhszHaSiD
+ 8OY7tLa/voecUlq38sdqi2raf2DvgOm7rdFa
+ reXOS/WIj7zd4XYrV1JGthxOMVlQ7zdv9rVd
+ UNUIF2d4hwCZJQr0ejhmvB3m/DuNmNOPYmnv
+ KTmLSE+IJ6baqYvKOVxwV+SaCnuJEjv+3Yrx
+ 8WQYD/iS9WBhC9FUit0dy+0=
+ ) ; key id = 57183
+ 600 RRSIG DNSKEY 7 1 600 20110914225156 (
+ 20110815225156 39833 test.
+ xPV+bSGUlbxA5MKBeeRbwUDh3Qc+dm77+OHQ
+ BHIr1L8/kRP5o5J7MqPA37kea6nhyltYf9xM
+ RsxyiaBGUUeLyWg/q6hTtkNgAHifOPAhiDz8
+ AJDSTdSsq9RVtjdobAD0jyzz9sWnB+TPSOmj
+ Nlyd7VtPVEuSYljgawwfBBO3Kho= )
+ 600 RRSIG DNSKEY 7 1 600 20110914225156 (
+ 20110815225156 57183 test.
+ S3jkC7AvyFc4ShfHt6AWgS4zpx9DzWHBK9gV
+ 2H23OJzy8H1At/CjKxWVHLJ/io+ygryVnt/I
+ 47Jyhh9i43TnXj8il475YsweGnXGZSorrcXA
+ 3IsD2lOuRYnp3yetxe2ZrMGNDqqImE6X4x1a
+ UJI0cbE2UMZfUt8Rm5USiGzwAEgFD1OXxvMD
+ UT3flyp+Ote9FConK8gewV4wlJuBFemWT7BZ
+ lUYnoqfuAeEn2+1pIBS0iA0LNFjNBaEgtcjo
+ QeweN32yKoApau47Dl/Klw7KFT8+PLZ0QPbt
+ XAkJU7q94Q5aucDuHCSCTCc+2vZxdEnXKvRY
+ rfLuG8r/V5Kn+1iYrQ== )
+ 0 NSEC3PARAM 1 0 10 -
+ 0 RRSIG NSEC3PARAM 7 1 0 20110914225156 (
+ 20110815225156 39833 test.
+ kghSSeP8AZiQ/zmxgxAyG0itoUMo5adG5pxD
+ p8T3ZmbxEUSyG5acxBFkmeY39wVU0Cda8tWc
+ HHrMbB5e2GN8z6xJ0A4rVyXfKSYJSz+iKWfk
+ 7sOFRjd8OLYE3di6PwIpk6ORUiRPMFLDQCH0
+ Q27hLsSoKyd50orKKI+ncjz7WzU= )
+a.test. 600 IN TXT "test"
+ 600 RRSIG TXT 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ UEVOlnL6CDRNCfk/Xge2oaGYCV1+ewwi5zJ0
+ CX4DdwiNEkItL4HgBe8xXfxgFC3qySdsSYPE
+ 1krdFyIkAclMCwHECd1UwZbGlMTEUGrE1KOB
+ 8vQY+OhIV9TAhqNwnjbu7s2ZdNUv3wiUPcfk
+ hCJ4rzP6yeV2inLwZulXnhxb6Pk= )
+b.test. 600 IN TXT "test"
+ 600 RRSIG TXT 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ HcyQlO9io6Rc5e4vVqlRmK5PacOaFQJmdERG
+ 5Aobpgm1FuCLC7F+IMZ0d1XvBWnsw9iDzV43
+ UKzTGqUSmDiSBzs4QzHlacGickIW8EOV4xyJ
+ +mcJ0FZh4YNbkt6CiX+8SF6IxfCMhRMjpSsK
+ rWqJMG3LXkI6W9stShzsYAFBOzQ= )
+e.test. 600 IN TXT "test"
+ 600 RRSIG TXT 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ jUn5FGRTL9OcFU7tvfkUnSwY8jA+8JynE0hi
+ ZJbYXDU5CiWGmR2B3yPHxUCewRqouyVCV8bc
+ xZsSuBxvcdYKryYDbjsmB83GlSEuxE9J7XZs
+ 8SxUP8PobLVqzXgEZS/XRU2G+R915ZDP9/iL
+ z9oYwc9TkeyXbp8J/ZsH88tG980= )
+c.test. 600 IN TXT "test"
+ 600 RRSIG TXT 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ cRxAj45oFDDCd8xQXxD1F0Qq8XeBWAj8EYS3
+ 7nFXAgAy8sTczFvYCNGj79o7BALJwM4vc/wx
+ 6rjsiO/sHgfTMEBDq6lH9Wql72uhwavI2SrL
+ /h/wBP5q4BXlQ4xp6cLhhdifOWhNTvLP+Fe5
+ U6yjvqneiKspze9SiFbcmRDiJds= )
+d.e.f.test. 600 IN TXT "test"
+ 600 RRSIG TXT 7 4 600 20110914225156 (
+ 20110815225156 39833 test.
+ ENjCzr/P9rJmj5OJLzYwWtHtBg2Uz+qJDucz
+ I97Pq9F819/c5sxNfT4hgICCw6ZfT4ffbzye
+ fFJ0JVrh2cYOzu68ozlgek/Uml1UW0pDQVdI
+ s4zEgp4XK9wXUxtWChSqp5YXMdeHegZFu32i
+ IMNTbJDudwYSwhr2FyG92ZRi8Y8= )
+f.g.h.test. 600 IN TXT "test"
+ 600 RRSIG TXT 7 4 600 20110914225156 (
+ 20110815225156 39833 test.
+ HT7iocFsfDjeX6j9RJdE3xfVGkIxhajFHgM/
+ T/mJj/al4HKV6Ajia8DhpdfDrgM2m7r+Pgcn
+ FSIstfebQsuFCnHX/gIalDND/grHKsetQnMP
+ Y7O4QLsRnTV53fdlqQ4eT+jBW6fzJdGySVN+
+ bg6kNJZS8DebjmlKtZz7tXjkP+4= )
+f.g.i.test. 600 IN TXT "test"
+ 600 RRSIG TXT 7 4 600 20110914225156 (
+ 20110815225156 39833 test.
+ kHJJeNSL1rz4QRYqOzhGMQl1yIdio7l8Lg8H
+ f0TsvFLa6BudVtwKUm+Kz2QiDn7/Lew8w0KX
+ vVHxX/Vwl3Ixk54YgMKLNogz2TEvnh/VGiS7
+ 8r0oSUrg0CFd+xDfxnLeRqX5NNfMuSJap5WH
+ Aw7IVeRjXDwJFYnytMEnTrhHHHg= )
+f.g.j.test. 600 IN TXT "test"
+ 600 RRSIG TXT 7 4 600 20110914225156 (
+ 20110815225156 39833 test.
+ lIEHEhDFhOWK8W/F2xWELU2p/X77S2KTivm9
+ sY4k3RPsLNHE7p+lF8p72Lcb79rtltnoVYtE
+ pTIiaUcmgGwfaI4cwfXbeuEgnuTiLg7Xrefx
+ 3GT86Q+8gfgbMXUmRA/eouWZhCOaYJN99gYz
+ urzDMiRLYmILHmLlnvo82SgXeuk= )
+k.test. 600 IN TXT "test"
+ 600 RRSIG TXT 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ wC3zgYWsuLga8Vu3QFu/Ci8SzRbA5bvjSmDj
+ NzcpjU5cvJBxtgzatCr02AaUC94bI0JzNrEB
+ nFyWCYw55lyy+bAHU1u05UcQmz0n5yxkvmHX
+ i8ZjMyQkAvNKodJHaFQqUKKIDuSHD2EziKqg
+ eNn55YRS11ihkODehUVNl7TnYeA= )
+ns.test. 600 IN A 10.0.0.1
+ 600 RRSIG A 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ VyK/WlQ6ikXdjF/arGzyAyYhOc8IYNBp4QLW
+ gtYjvbjIcV5+9JINWmUs61VjJ14nES1sI0xb
+ 9vQJuiPXTM1awUAnvOKLhaX6fbJaEiR1w6Cf
+ RT5QKBMxNBKVStqdabHcigY4DUuc1PQk1vCw
+ yMUJt3nHNVMZk+XAycNHzBeYjik= )
+ns2.test. 600 IN A 10.0.0.2
+ 600 RRSIG A 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ CX6UlZL+5NQJViKfbe/E3uIJk/wjUzoiHBhY
+ B6gS8nxZzlRPdTTXyMZoRa4etTZEbrRjnyXk
+ 1rP47faCUwbh//XqukN9f7FZ4Y39NpPS2XpX
+ 0Lx6M93Jz46lbzmseMFs2YmNMzzhN4uhRvl/
+ 8gPtYsn9KMXnAlFfa4XrE5LNVyY= )
+1F3JQ6EANHNHOCMUPQTVNM339VDTR51C.test. 600 IN NSEC3 1 0 10 - 7QKPELF33JOK9BVJ7CKE99AHG40B0SH7 A RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ w7aS12lxLNh+G1B/2kEq1BO6IzYvyC8n/MGV
+ 0jvFnapNXGZMPrPxGeO2wkw1JXepuXCv98be
+ M4SjQywaH+VP6ZMTIfjxRxtcCM+aLAFhiz0l
+ /MILEkjemmxjAfvV7emRVMwCGcoGI7qC3Xxq
+ q5g8EzJiYyTCOnI5LKRggn97wGg= )
+7QKPELF33JOK9BVJ7CKE99AHG40B0SH7.test. 600 IN NSEC3 1 0 10 - 94Q15K1V1VE5F87EI37T2B9A39EEC368 TXT RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ J4ObL3p4eN0jWh06M+rX2SSPANQoKfnosElB
+ KcKE7fLqEjKK7N6Yh6KUlbEP25tfeZ7W6GBJ
+ b7q6Nh0Ax8fYdc/6JVvmxcwWcx5Lw1TfITGB
+ ttFntJlbp1A8lwP3pn8Ksql1X2ogh78AsgTb
+ X5kmXVukC1oEzt98EAa/V/an8QA= )
+CS8M3UVG0UJDR6USBES4U9SNUGQI2RJE.test. 600 IN NSEC3 1 0 10 - ETEQB5V431INUIIE547FKSOF7O4DJ62J A RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ Vyd/2b0S15fACJ8TiPXKtScV9A/ZztVumZAm
+ o2S6jaVJKWik+8orDW+WiJ4/PEl26PK2m1uv
+ HD2beuUCHj9EnYkN/dzL3Bsc302qr9xqsh0q
+ VFS2moznoNG415ZV3vgYR7L9DAp43ZeFuw6I
+ 7sr21hLYLUeo31xBsJg7RlOL+4s= )
+ETEQB5V431INUIIE547FKSOF7O4DJ62J.test. 600 IN NSEC3 1 0 10 - F8G1MB0JUEU3FBI11CAVFIPGEA3POOIM
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ oOHs1eb3JYeOMOnzE2PS6NIXBNzSoTYPIxo/
+ P0d/ihsLKra3yNJNPTlu4kf+FZoNYAGtMK/D
+ 6dZWFvtdswDdi2C5WSgsanuHqXq5Lr3A1nCe
+ cQI5PO4RrLymB+MtYg15CNKcnc0WmJO8deSR
+ WzNOarC+Iz1Xj3FkKDS4FFr+02Q= )
+94Q15K1V1VE5F87EI37T2B9A39EEC368.test. 600 IN NSEC3 1 0 10 - CS8M3UVG0UJDR6USBES4U9SNUGQI2RJE
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ K0PvN7YtHQ63x/x2yXXa2S9GBGuTNJywDZ8M
+ wyMSwytCb9mn4hnKD5mJHaXGTw3YX7usbnEO
+ ce6hiJdN/VhMfbRMOvUpgyblOj4kXiYVZY1a
+ SyycfugK/Hu1j4az7lIhhnnx58GChA6mg8Vx
+ 3Uz6cNDDCSTBTl09NyeUUrKWsHQ= )
+FBH6B0LHT9PPQB1P98D228HA1H52L8PO.test. 600 IN NSEC3 1 0 10 - JGU2L7C3LKLHAKC5RHUOORTI2DCKK3KL
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ giXRE+4ZeIzDrhx1XkFSpIKGFd3UGzlrLZnO
+ Ur9nMUfwvU5A3fitEkdayo3ZDH7MQGpSotaH
+ ReiFXx3Z6Hm2NIN/RHYZQr9e0vbMYSjkANdu
+ HWBA1SrSq5SHyuy970mPd4jfTHiABCo6fJGB
+ ykGClZGou0WSaB+Ak19fMbeQ2Wo= )
+JGU2L7C3LKLHAKC5RHUOORTI2DCKK3KL.test. 600 IN NSEC3 1 0 10 - KFMJ88CKMKUQQJE59IKFBOLLLD4DF55H TXT RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ BHTDUgZdWNLgz3xHYMqvlWK/IJ0xrXESoREc
+ 6D3sO9bcLTMYPO9t80itOlipwp4AmaVOBXPt
+ cKSdgsUXDEtHqNSxtGbNr5xQ+Aqsep0GX71V
+ HkcIuiNdTUw83dkajCHMkmQCbEjp9mbdiTmS
+ haNW2EsscldfaS1aq5tYUhCT3l4= )
+L993U6VC0DUV5QJ8TRPD2IQLM8FJ7AT9.test. 600 IN NSEC3 1 0 10 - LSMRLLNBQGGK8J6V40KLM2LG5TE4FS0P
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ vE7K0Nrju4qLFDYkIyMY5bIMT0wu8MJdxL6u
+ 7WVA4HepccKQcUnvVoBAcrA9+MUeteyrad8Y
+ SJvQIt7sz5t7FViWSq5IMPVPujWtW5J30LhJ
+ mOLd1KmnFWoVthJ1oFNzBM80A60seKNnEw1M
+ lV6Y+v0gNYIQensUb9w6SVMTpxE= )
+F8G1MB0JUEU3FBI11CAVFIPGEA3POOIM.test. 600 IN NSEC3 1 0 10 - FA1T7MKUUV9SD4VDBJQ3GRFK1IDTCKL7
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ DkL9ONc0vpsKdG20ol8XPAaVfLb7kf1wnKbR
+ rQUB1trGSHm/Igo06of43zm9J+56htFJg1xD
+ I2de0sCUBQYyHVBBDiBAd1g+ZvcpUlLP0w8M
+ NxMviMiG/WQAdGXHwYfUimwMWD7gNGl1m05H
+ HwYmzGs+d1bClDNBrFhdfdL2+iA= )
+LSMRLLNBQGGK8J6V40KLM2LG5TE4FS0P.test. 600 IN NSEC3 1 0 10 - LUAN2Q3I2OCVSD41MP08HNA9JP22D38K
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ ZgiWuMqodQuhwuAF6CIiJTsdRahi+poOiZAM
+ WXNP0wXfdptcG2uhbdDwy+0crhe3tuybhwcb
+ CuiaQUh0XNPhgF+qmXpGobaqBhCEvCF4K9qY
+ OCIoMfsI1pIBVbMw0+YXVarFZ8+mfNU/+6n6
+ yy2+1nCg3k4XR2Dpv4CeDBfcAuM= )
+NAL1UIEBM38NKMN6RQOKE8T781IA7UKI.test. 600 IN NSEC3 1 0 10 - OUSGP0LO9FGAROHDULQVSTI3OLQIBB39 TXT RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ x8JiXPI+EXHz8ZO/VW0/+9wWsBNqeSMxXZIV
+ ibOnogSg7Wi7Yq1xftKC2+xEevNxSZnBibEy
+ Sgro5xKTf0n7pD9hHVBLoYmOOnbXY3QNQ2EQ
+ y3LdPT355WmwVddVOOxNpNRp2zQyqg7BhVA3
+ wxY7tyVQd4x1+95ATUQBnFditdE= )
+KFMJ88CKMKUQQJE59IKFBOLLLD4DF55H.test. 600 IN NSEC3 1 0 10 - L993U6VC0DUV5QJ8TRPD2IQLM8FJ7AT9 TXT RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ KQPaN2Ecebifbl4Bz5Yo0x2DgGmZiVhpSydm
+ oy/5NtMjt7G472JrKlqByap+VxW0bpzo3IER
+ 3P8Dsv7pfBD4/Cl5sFqwZL7wYy7RB4dQLVCi
+ Pepc/Mr3gR2XmL91fpGttMj5jGscnVQJCyFa
+ obzhsVaVImUQZFDPb0UQUHwIhOA= )
+LUAN2Q3I2OCVSD41MP08HNA9JP22D38K.test. 600 IN NSEC3 1 0 10 - NAL1UIEBM38NKMN6RQOKE8T781IA7UKI TXT RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ NJ+X3d0qh2+fbSnG0iQPxAeDIOzX5NTmY9fS
+ x7IO/DDcgUhPvl1YYdz5J999cec1zzOKp10J
+ YbsIAzg0w/Y4D4CBUw3IkcOrUFOODb6eJQGb
+ rVFRqmp3BUP4qOAWUZvx4oQ0KG4K/h/KJMbU
+ Vcdl7PF7G5O5hMyR9UWg4zal7Sk= )
+OUSGP0LO9FGAROHDULQVSTI3OLQIBB39.test. 600 IN NSEC3 1 0 10 - PQQ28M3U2MM08GGFV3JKR76G2H9IUJPC TXT RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ A/qxYrSE/smBGbST8j8eGPCrRnwvVa25kDha
+ IuA3nv0vzXhFvlruc9f0HRGwsq6A2pw3I5W+
+ xo2/JxsNyFOotdwaDDEBzqPkJmrzupxQS4Hm
+ rHSLnRnNw4QzvzNjAGWMYAoe3OeHC47wmAtI
+ qE91EHZTlPP28CUXOMo+7sCaOa8= )
+U0UVS2SUP89P2TM3PJO4TC1GPJ2O6519.test. 600 IN NSEC3 1 0 10 - VA2VG5BEMCKQP6MS5NHHGL18031BIA7M NS SOA RRSIG DNSKEY NSEC3PARAM
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ rahhkfiF+Rk6oqbWTdu9qcwhmj5hbDuIFdiJ
+ GmaG+cFSv5Mjp+txNVCvBK9Hq/VpW0ypen/3
+ JC0sVAugSX+HAKAgyaMKmgWCvoQZ6ZSJUh7o
+ LRPcT+oxVXQAqjovxpaV8k6sYo44tpljPdOD
+ UluWAP5SrmJKjzCxs27KGRx8MK4= )
+VA2VG5BEMCKQP6MS5NHHGL18031BIA7M.test. 600 IN NSEC3 1 0 10 - VAKOQ2TPD7S25NFBJT73J3C4OGU10RJ5 TXT RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ XcBeZ8lo9Qo8z56+1FdGDjh6ZHCfO+MQ/wnY
+ TEUo/aWLkPTyq39nLhe0qVBJxmDpM+KQFuG9
+ cjQT5fvrlrY+lv6dedB64EBMYy4kKbIv7N5+
+ r6+sfWlvtKsfXxysLSk2+jLEm5NuLFrOdNas
+ WLVsq741D3YcWt4kM1HCyk3DNF8= )
+FA1T7MKUUV9SD4VDBJQ3GRFK1IDTCKL7.test. 600 IN NSEC3 1 0 10 - FBH6B0LHT9PPQB1P98D228HA1H52L8PO TXT RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ jB/vLrvx4sQQD7J3ZacAAyhcFmIPh7LH3ljw
+ IAIaeLb10oX5q1/nQKYdfq976TMy5sWpBcmd
+ i91WLxd+T/gOSumyP8bC3g+SUoyZ9wxY6A6a
+ MMx1rn0QA9IKrxMqojs9M3urJ8QAeIS+KyAn
+ rbyyJuG+EVm0prqlPZtzUi28WCI= )
+PQQ28M3U2MM08GGFV3JKR76G2H9IUJPC.test. 600 IN NSEC3 1 0 10 - U0UVS2SUP89P2TM3PJO4TC1GPJ2O6519
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ asCOU9OkVWMvUU2IUpwMgdYf0faA04zPbaFf
+ qywYsv3NH01Lky6G3a0WUPAbBm7TAYx/ln8a
+ 559vlpp/gpXEl9CcLrjO6wy5i0ryp8gVHtKJ
+ rQlEc/uw4SY+S5t7FuZc2rNRdAbxVMYuwrvm
+ HBsKDPblre3e06ZZFEmnGFzCgmg= )
+VAKOQ2TPD7S25NFBJT73J3C4OGU10RJ5.test. 600 IN NSEC3 1 0 10 - VNCCJH8JPOLGLAGVMV3FKS09M7RRDU47 TXT RRSIG
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ Pt4tKB1p/jsyLYab9LSt5MF1KTRT18nRTOox
+ q0IACkXkKx7W5xv6nSYXIB+nQzNp1Y1hhoXn
+ 9IFi0liPnIAOp73w4vybhfIdTFiEmHPHT6O9
+ VIx5cSriqBI6Qda8GtfeIb96P8SojbUk5BDI
+ g18iYjviGhQYRgpU3tg1qd7pbcc= )
+VNCCJH8JPOLGLAGVMV3FKS09M7RRDU47.test. 600 IN NSEC3 1 0 10 - 1F3JQ6EANHNHOCMUPQTVNM339VDTR51C
+ 600 RRSIG NSEC3 7 2 600 20110914225156 (
+ 20110815225156 39833 test.
+ ZMZPHawhkuzSV7C7zkgghH/jpw9CQVR1JUXq
+ pAeY2iIIWwNhfuskJaLgtu/5SuKnJtrv6D4N
+ g+lfEkBReia5xO/SCcHv8/hXEPH8vZ4xe1C9
+ 6GVB6ip2hKw2g5HpyF7X18WgwZ0cqPWVg+Q+
+ xRLpXH+53391Wt5rG7qJswn5RLE= )
diff --git a/tests/dns/testdata/diff/zone1.data b/tests/dns/testdata/diff/zone1.data
new file mode 100644
index 0000000..8ddf669
--- /dev/null
+++ b/tests/dns/testdata/diff/zone1.data
@@ -0,0 +1,13 @@
+; Copyright (C) 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/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+@ 0 SOA . . 0 0 0 0 0
+@ 0 NS @
+@ 0 A 1.2.3.4
+remove 0 A 5.6.7.8
diff --git a/tests/dns/testdata/diff/zone2.data b/tests/dns/testdata/diff/zone2.data
new file mode 100644
index 0000000..363af42
--- /dev/null
+++ b/tests/dns/testdata/diff/zone2.data
@@ -0,0 +1,14 @@
+; Copyright (C) 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/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+@ 0 SOA . . 0 0 0 0 0
+@ 0 NS @
+@ 0 A 1.2.3.4
+remove 0 A 5.6.7.8
+added 0 A 5.6.7.8
diff --git a/tests/dns/testdata/diff/zone3.data b/tests/dns/testdata/diff/zone3.data
new file mode 100644
index 0000000..ae3a60e
--- /dev/null
+++ b/tests/dns/testdata/diff/zone3.data
@@ -0,0 +1,12 @@
+; Copyright (C) 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/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+@ 0 SOA . . 0 0 0 0 0
+@ 0 NS @
+@ 0 A 1.2.3.4
diff --git a/tests/dns/testdata/dnstap/dnstap.saved b/tests/dns/testdata/dnstap/dnstap.saved
new file mode 100644
index 0000000..c657f41
--- /dev/null
+++ b/tests/dns/testdata/dnstap/dnstap.saved
Binary files differ
diff --git a/tests/dns/testdata/dnstap/dnstap.text b/tests/dns/testdata/dnstap/dnstap.text
new file mode 100644
index 0000000..71977e4
--- /dev/null
+++ b/tests/dns/testdata/dnstap/dnstap.text
@@ -0,0 +1,96 @@
+03-Feb-2017 15:47:16.000 SQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 SQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 SQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 SQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 SQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 SQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 SQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 SQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 SR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 SR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 SR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 SR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 SR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 SR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 SR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 SR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 CQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 CQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 CQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 CQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 CQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 CQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 CQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 CQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 CR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 CR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 CR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 CR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 CR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 CR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 CR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 CR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 AQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 AQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 AQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 AQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 AQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 AQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 AQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 AQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 AR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 AR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 AR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 AR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 AR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 AR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 AR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 AR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 RQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 RQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 RQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 RQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 RQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 RQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 RQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 RQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 RR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 RR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 RR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 RR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 RR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 RR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 RR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 RR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 FQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 FQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 FQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 FQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 FQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 FQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 FQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 FQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 FR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 FR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 FR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 FR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 FR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 FR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 FR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 FR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 TQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 TQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 TQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 TQ 10.53.0.1:2112 -> 10.53.0.2:2112 UDP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 TQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 TQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 15:47:16.000 TQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 TQ 10.53.0.1:2112 -> 10.53.0.2:2112 TCP 40b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 TR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 TR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 TR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 TR 10.53.0.1:2112 <- 10.53.0.2:2112 UDP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 TR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 17:47:16.000 TR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 TR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
+03-Feb-2017 16:47:16.830 TR 10.53.0.1:2112 <- 10.53.0.2:2112 TCP 287b www.isc.org/IN/A
diff --git a/tests/dns/testdata/dnstap/query.auth b/tests/dns/testdata/dnstap/query.auth
new file mode 100644
index 0000000..a14f850
--- /dev/null
+++ b/tests/dns/testdata/dnstap/query.auth
@@ -0,0 +1,4 @@
+# authoritative query, www.isc.org/A
+8d 24 00 20 00 01 00 00 00 00 00 01 03 77 77 77
+03 69 73 63 03 6f 72 67 00 00 01 00 01 00 00 29
+10 00 00 00 00 00 00 00
diff --git a/tests/dns/testdata/dnstap/query.recursive b/tests/dns/testdata/dnstap/query.recursive
new file mode 100644
index 0000000..8ee705f
--- /dev/null
+++ b/tests/dns/testdata/dnstap/query.recursive
@@ -0,0 +1,4 @@
+# recursive query for www.isc.org/A
+bf 08 01 20 00 01 00 00 00 00 00 01 03 77 77 77
+03 69 73 63 03 6f 72 67 00 00 01 00 01 00 00 29
+10 00 00 00 00 00 00 00
diff --git a/tests/dns/testdata/dnstap/response.auth b/tests/dns/testdata/dnstap/response.auth
new file mode 100644
index 0000000..4d0ea81
--- /dev/null
+++ b/tests/dns/testdata/dnstap/response.auth
@@ -0,0 +1,19 @@
+# authoritative response, www.isc.org/A
+8d 24 84 00 00 01 00 01 00 04 00 07 03 77 77 77
+03 69 73 63 03 6f 72 67 00 00 01 00 01 c0 0c 00
+01 00 01 00 00 00 3c 00 04 95 14 40 45 c0 10 00
+02 00 01 00 00 1c 20 00 0d 03 61 6d 73 06 73 6e
+73 2d 70 62 c0 10 c0 10 00 02 00 01 00 00 1c 20
+00 07 04 73 66 62 61 c0 3d c0 10 00 02 00 01 00
+00 1c 20 00 19 02 6e 73 03 69 73 63 0b 61 66 69
+6c 69 61 73 2d 6e 73 74 04 69 6e 66 6f 00 c0 10
+00 02 00 01 00 00 1c 20 00 06 03 6f 72 64 c0 3d
+c0 39 00 01 00 01 00 00 1c 20 00 04 c7 06 01 1e
+c0 39 00 1c 00 01 00 00 1c 20 00 10 20 01 05 00
+00 60 00 00 00 00 00 00 00 00 00 30 c0 8a 00 01
+00 01 00 00 1c 20 00 04 c7 06 00 1e c0 8a 00 1c
+00 01 00 00 1c 20 00 10 20 01 05 00 00 71 00 00
+00 00 00 00 00 00 00 30 c0 52 00 01 00 01 00 00
+1c 20 00 04 95 14 40 03 c0 52 00 1c 00 01 00 00
+1c 20 00 10 20 01 04 f8 00 00 00 02 00 00 00 00
+00 00 00 19 00 00 29 10 00 00 00 00 00 00 00
diff --git a/tests/dns/testdata/dnstap/response.recursive b/tests/dns/testdata/dnstap/response.recursive
new file mode 100644
index 0000000..6e3a3cf
--- /dev/null
+++ b/tests/dns/testdata/dnstap/response.recursive
@@ -0,0 +1,19 @@
+# recursive response, www.isc.org/A
+bf 08 81 a0 00 01 00 01 00 04 00 07 03 77 77 77
+03 69 73 63 03 6f 72 67 00 00 01 00 01 c0 0c 00
+01 00 01 00 00 00 15 00 04 95 14 40 45 c0 10 00
+02 00 01 00 00 1b a6 00 0e 04 73 66 62 61 06 73
+6e 73 2d 70 62 c0 10 c0 10 00 02 00 01 00 00 1b
+a6 00 06 03 6f 72 64 c0 3e c0 10 00 02 00 01 00
+00 1b a6 00 19 02 6e 73 03 69 73 63 0b 61 66 69
+6c 69 61 73 2d 6e 73 74 04 69 6e 66 6f 00 c0 10
+00 02 00 01 00 00 1b a6 00 06 03 61 6d 73 c0 3e
+c0 8a 00 01 00 01 00 00 b1 d5 00 04 c7 06 01 1e
+c0 8a 00 1c 00 01 00 00 b1 d5 00 10 20 01 05 00
+00 60 00 00 00 00 00 00 00 00 00 30 c0 53 00 01
+00 01 00 00 b1 d5 00 04 c7 06 00 1e c0 53 00 1c
+00 01 00 00 b1 d5 00 10 20 01 05 00 00 71 00 00
+00 00 00 00 00 00 00 30 c0 39 00 01 00 01 00 00
+b1 d5 00 04 95 14 40 03 c0 39 00 1c 00 01 00 00
+b1 d5 00 10 20 01 04 f8 00 00 00 02 00 00 00 00
+00 00 00 19 00 00 29 10 00 00 00 00 00 00 00
diff --git a/tests/dns/testdata/dst/Ktest.+008+11349.key b/tests/dns/testdata/dst/Ktest.+008+11349.key
new file mode 100644
index 0000000..a1bd768
--- /dev/null
+++ b/tests/dns/testdata/dst/Ktest.+008+11349.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 11349, for test.
+; Created: 20181025090713 (Thu Oct 25 11:07:13 2018)
+; Publish: 20181025090713 (Thu Oct 25 11:07:13 2018)
+; Activate: 20181025090713 (Thu Oct 25 11:07:13 2018)
+test. IN DNSKEY 256 3 8 AwEAAdqPwPScyURzeCUzEadKNYgQW50LPDV/ir9nWIbiSn2yMkymxiby BQH+Hk1neE9qa9X4XaEnKf5YZx7o14rRikmOb2lomtOkI9ovh1K/SvLO Zd1E3e61F29g1eCq52mMY3xAdEcBNqEq+6mgEwGmwl83+mAh5anxXNHa 2rcfdG+L
diff --git a/tests/dns/testdata/dst/Ktest.+008+11349.private b/tests/dns/testdata/dst/Ktest.+008+11349.private
new file mode 100644
index 0000000..5dfef79
--- /dev/null
+++ b/tests/dns/testdata/dst/Ktest.+008+11349.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: 2o/A9JzJRHN4JTMRp0o1iBBbnQs8NX+Kv2dYhuJKfbIyTKbGJvIFAf4eTWd4T2pr1fhdoScp/lhnHujXitGKSY5vaWia06Qj2i+HUr9K8s5l3UTd7rUXb2DV4KrnaYxjfEB0RwE2oSr7qaATAabCXzf6YCHlqfFc0dratx90b4s=
+PublicExponent: AQAB
+PrivateExponent: a4qmX/YxlmvWpz8spYr/MhcSbQCVPKGoLKv2RFBeZODknRDGmW0mh6d5U47hBPqRWvRdZak2oX7wJqZdQGIAT25bC09rLNMctfxXKtzwSaXFjXZGHGv+bDHcqIltvIYmRbb0pK/LinFaLZqfpVe0WOfKuT9BT03BlwSZV8GKgZE=
+Prime1: 8oZLQoVpIqsiQw7bX5pTm/O0gEUnEzNOVEoLGsfIl68Lz/1CBm9ypTp8QOB0B9IpnH8vOS+NJM1az1d0RhqKow==
+Prime2: 5rSbE6duWIb90uICkAUJn4OztHX0fkd9GKNYdsHVReFBH2poXGojVGkW6i/IaYl4NEXXr5Z89dWtR+RNH2Z9+Q==
+Exponent1: 2IcuCmYyR9Gi9Vv+YIzYuRQMw7j5+hqEhJzW7UIRxdtzIG9s03INWZet9/5tmc35eM/Uyam6ynDN8vCRz0VDIQ==
+Exponent2: vKcdVKIKWrvwXXzRaaGk79rLnZsDFiwxQG96TIpOczkyfpUNx9xHDaRtx4zRTnPKZrxiFkRx5LkZXHt1EWNHSQ==
+Coefficient: pb9dFRZA2IRXDCGCM1ikp+QCs72wNn3hgURZLRLmtcBbQcYhP/dcp80SpInviwJPNRcKrfxninqygEARzfHtqQ==
+Created: 20181025090713
+Publish: 20181025090713
+Activate: 20181025090713
diff --git a/tests/dns/testdata/dst/Ktest.+013+49130.key b/tests/dns/testdata/dst/Ktest.+013+49130.key
new file mode 100644
index 0000000..e3ff931
--- /dev/null
+++ b/tests/dns/testdata/dst/Ktest.+013+49130.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 49130, for test.
+; Created: 20181025090718 (Thu Oct 25 11:07:18 2018)
+; Publish: 20181025090718 (Thu Oct 25 11:07:18 2018)
+; Activate: 20181025090718 (Thu Oct 25 11:07:18 2018)
+test. IN DNSKEY 256 3 13 uP04fwB/DuBBqdjPLseIoFT7vgtP8Lr/be1NhRBvibwQ+Hr+3GQhIKIK XbamgOUxXJ9JDjWFAT2KXw0V3sAN9w==
diff --git a/tests/dns/testdata/dst/Ktest.+013+49130.private b/tests/dns/testdata/dst/Ktest.+013+49130.private
new file mode 100644
index 0000000..754d9f9
--- /dev/null
+++ b/tests/dns/testdata/dst/Ktest.+013+49130.private
@@ -0,0 +1,6 @@
+Private-key-format: v1.3
+Algorithm: 13 (ECDSAP256SHA256)
+PrivateKey: feGDRABRCbcsCqssKK5B5518y95smrv/cJnz2pa/UVA=
+Created: 20181025090718
+Publish: 20181025090718
+Activate: 20181025090718
diff --git a/tests/dns/testdata/dst/test1.data b/tests/dns/testdata/dst/test1.data
new file mode 100644
index 0000000..cf84e9f
--- /dev/null
+++ b/tests/dns/testdata/dst/test1.data
@@ -0,0 +1,3077 @@
+Network Working Group P. Mockapetris
+Request for Comments: 1035 ISI
+ November 1987
+Obsoletes: RFCs 882, 883, 973
+
+ DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
+
+
+1. STATUS OF THIS MEMO
+
+This RFC describes the details of the domain system and protocol, and
+assumes that the reader is familiar with the concepts discussed in a
+companion RFC, "Domain Names - Concepts and Facilities" [RFC-1034].
+
+The domain system is a mixture of functions and data types which are an
+official protocol and functions and data types which are still
+experimental. Since the domain system is intentionally extensible, new
+data types and experimental behavior should always be expected in parts
+of the system beyond the official protocol. The official protocol parts
+include standard queries, responses and the Internet class RR data
+formats (e.g., host addresses). Since the previous RFC set, several
+definitions have changed, so some previous definitions are obsolete.
+
+Experimental or obsolete features are clearly marked in these RFCs, and
+such information should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical. Distribution of this memo is unlimited.
+
+ Table of Contents
+
+ 1. STATUS OF THIS MEMO 1
+ 2. INTRODUCTION 3
+ 2.1. Overview 3
+ 2.2. Common configurations 4
+ 2.3. Conventions 7
+ 2.3.1. Preferred name syntax 7
+ 2.3.2. Data Transmission Order 8
+ 2.3.3. Character Case 9
+ 2.3.4. Size limits 10
+ 3. DOMAIN NAME SPACE AND RR DEFINITIONS 10
+ 3.1. Name space definitions 10
+ 3.2. RR definitions 11
+ 3.2.1. Format 11
+ 3.2.2. TYPE values 12
+ 3.2.3. QTYPE values 12
+ 3.2.4. CLASS values 13
+
+
+
+Mockapetris [Page 1]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 3.2.5. QCLASS values 13
+ 3.3. Standard RRs 13
+ 3.3.1. CNAME RDATA format 14
+ 3.3.2. HINFO RDATA format 14
+ 3.3.3. MB RDATA format (EXPERIMENTAL) 14
+ 3.3.4. MD RDATA format (Obsolete) 15
+ 3.3.5. MF RDATA format (Obsolete) 15
+ 3.3.6. MG RDATA format (EXPERIMENTAL) 16
+ 3.3.7. MINFO RDATA format (EXPERIMENTAL) 16
+ 3.3.8. MR RDATA format (EXPERIMENTAL) 17
+ 3.3.9. MX RDATA format 17
+ 3.3.10. NULL RDATA format (EXPERIMENTAL) 17
+ 3.3.11. NS RDATA format 18
+ 3.3.12. PTR RDATA format 18
+ 3.3.13. SOA RDATA format 19
+ 3.3.14. TXT RDATA format 20
+ 3.4. ARPA Internet specific RRs 20
+ 3.4.1. A RDATA format 20
+ 3.4.2. WKS RDATA format 21
+ 3.5. IN-ADDR.ARPA domain 22
+ 3.6. Defining new types, classes, and special namespaces 24
+ 4. MESSAGES 25
+ 4.1. Format 25
+ 4.1.1. Header section format 26
+ 4.1.2. Question section format 28
+ 4.1.3. Resource record format 29
+ 4.1.4. Message compression 30
+ 4.2. Transport 32
+ 4.2.1. UDP usage 32
+ 4.2.2. TCP usage 32
+ 5. MASTER FILES 33
+ 5.1. Format 33
+ 5.2. Use of master files to define zones 35
+ 5.3. Master file example 36
+ 6. NAME SERVER IMPLEMENTATION 37
+ 6.1. Architecture 37
+ 6.1.1. Control 37
+ 6.1.2. Database 37
+ 6.1.3. Time 39
+ 6.2. Standard query processing 39
+ 6.3. Zone refresh and reload processing 39
+ 6.4. Inverse queries (Optional) 40
+ 6.4.1. The contents of inverse queries and responses 40
+ 6.4.2. Inverse query and response example 41
+ 6.4.3. Inverse query processing 42
+
+
+
+
+
+
+Mockapetris [Page 2]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 6.5. Completion queries and responses 42
+ 7. RESOLVER IMPLEMENTATION 43
+ 7.1. Transforming a user request into a query 43
+ 7.2. Sending the queries 44
+ 7.3. Processing responses 46
+ 7.4. Using the cache 47
+ 8. MAIL SUPPORT 47
+ 8.1. Mail exchange binding 48
+ 8.2. Mailbox binding (Experimental) 48
+ 9. REFERENCES and BIBLIOGRAPHY 50
+ Index 54
+
+2. INTRODUCTION
+
+2.1. Overview
+
+The goal of domain names is to provide a mechanism for naming resources
+in such a way that the names are usable in different hosts, networks,
+protocol families, internets, and administrative organizations.
+
+From the user's point of view, domain names are useful as arguments to a
+local agent, called a resolver, which retrieves information associated
+with the domain name. Thus a user might ask for the host address or
+mail information associated with a particular domain name. To enable
+the user to request a particular type of information, an appropriate
+query type is passed to the resolver with the domain name. To the user,
+the domain tree is a single information space; the resolver is
+responsible for hiding the distribution of data among name servers from
+the user.
+
+From the resolver's point of view, the database that makes up the domain
+space is distributed among various name servers. Different parts of the
+domain space are stored in different name servers, although a particular
+data item will be stored redundantly in two or more name servers. The
+resolver starts with knowledge of at least one name server. When the
+resolver processes a user query it asks a known name server for the
+information; in return, the resolver either receives the desired
+information or a referral to another name server. Using these
+referrals, resolvers learn the identities and contents of other name
+servers. Resolvers are responsible for dealing with the distribution of
+the domain space and dealing with the effects of name server failure by
+consulting redundant databases in other servers.
+
+Name servers manage two kinds of data. The first kind of data held in
+sets called zones; each zone is the complete database for a particular
+"pruned" subtree of the domain space. This data is called
+authoritative. A name server periodically checks to make sure that its
+zones are up to date, and if not, obtains a new copy of updated zones
+
+
+
+Mockapetris [Page 3]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+from master files stored locally or in another name server. The second
+kind of data is cached data which was acquired by a local resolver.
+This data may be incomplete, but improves the performance of the
+retrieval process when non-local data is repeatedly accessed. Cached
+data is eventually discarded by a timeout mechanism.
+
+This functional structure isolates the problems of user interface,
+failure recovery, and distribution in the resolvers and isolates the
+database update and refresh problems in the name servers.
+
+2.2. Common configurations
+
+A host can participate in the domain name system in a number of ways,
+depending on whether the host runs programs that retrieve information
+from the domain system, name servers that answer queries from other
+hosts, or various combinations of both functions. The simplest, and
+perhaps most typical, configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | cache | |
+ +----------+ |
+
+User programs interact with the domain name space through resolvers; the
+format of user queries and user responses is specific to the host and
+its operating system. User queries will typically be operating system
+calls, and the resolver and its cache will be part of the host operating
+system. Less capable hosts may choose to implement the resolver as a
+subroutine to be linked in with every program that needs its services.
+Resolvers answer user queries with information they acquire via queries
+to foreign name servers and the local cache.
+
+Note that the resolver may have to make several queries to several
+different foreign name servers to answer a particular user query, and
+hence the resolution of a user query may involve several network
+accesses and an arbitrary amount of time. The queries to foreign name
+servers and the corresponding responses have a standard format described
+
+
+
+Mockapetris [Page 4]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in this memo, and may be datagrams.
+
+Depending on its capabilities, a name server could be a stand alone
+program on a dedicated machine or a process or processes on a large
+timeshared host. A simple configuration might be:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+
+Here a primary name server acquires information about one or more zones
+by reading master files from its local file system, and answers queries
+about those zones that arrive from foreign resolvers.
+
+The DNS requires that all zones be redundantly supported by more than
+one name server. Designated secondary servers can acquire zones and
+check for updates from the primary server using the zone transfer
+protocol of the DNS. This configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+In this configuration, the name server periodically establishes a
+virtual circuit to a foreign name server to acquire a copy of a zone or
+to check that an existing copy has not changed. The messages sent for
+
+
+
+Mockapetris [Page 5]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+these maintenance activities follow the same form as queries and
+responses, but the message sequences are somewhat different.
+
+The information flow in a host that supports all aspects of the domain
+name system is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | Shared | |
+ | database | |
+ +----------+ |
+ A | |
+ +---------+ refreshes | | references |
+ / /| | V |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+The shared database holds domain space data for the local name server
+and resolver. The contents of the shared database will typically be a
+mixture of authoritative data maintained by the periodic refresh
+operations of the name server and cached data from previous resolver
+requests. The structure of the domain data and the necessity for
+synchronization between name servers and resolvers imply the general
+characteristics of this database, but the actual format is up to the
+local implementor.
+
+
+
+
+Mockapetris [Page 6]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Information flow can also be tailored so that a group of hosts act
+together to optimize activities. Sometimes this is done to offload less
+capable hosts so that they do not have to implement a full resolver.
+This can be appropriate for PCs or hosts which want to minimize the
+amount of new network code which is required. This scheme can also
+allow a group of hosts can share a small number of caches rather than
+maintaining a large number of separate caches, on the premise that the
+centralized caches will have a higher hit ratio. In either case,
+resolvers are replaced with stub resolvers which act as front ends to
+resolvers located in a recursive server in one or more name servers
+known to perform that service:
+
+ Local Hosts | Foreign
+ |
+ +---------+ |
+ | | responses |
+ | Stub |<--------------------+ |
+ | Resolver| | |
+ | |----------------+ | |
+ +---------+ recursive | | |
+ queries | | |
+ V | |
+ +---------+ recursive +----------+ | +--------+
+ | | queries | |queries | | |
+ | Stub |-------------->| Recursive|---------|->|Foreign |
+ | Resolver| | Server | | | Name |
+ | |<--------------| |<--------|--| Server |
+ +---------+ responses | |responses| | |
+ +----------+ | +--------+
+ | Central | |
+ | cache | |
+ +----------+ |
+
+In any case, note that domain components are always replicated for
+reliability whenever possible.
+
+2.3. Conventions
+
+The domain system has several conventions dealing with low-level, but
+fundamental, issues. While the implementor is free to violate these
+conventions WITHIN HIS OWN SYSTEM, he must observe these conventions in
+ALL behavior observed from other hosts.
+
+2.3.1. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+for constructing domain names. The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+
+
+
+Mockapetris [Page 7]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822. When creating a new host name,
+the old rules for HOSTS.TXT should be followed. This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case. That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names. They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen. There are also some
+restrictions on the length. Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA
+
+2.3.2. Data Transmission Order
+
+The order of transmission of the header and data described in this
+document is resolved to the octet level. Whenever a diagram shows a
+
+
+
+Mockapetris [Page 8]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+group of octets, the order of transmission of those octets is the normal
+order in which they are read in English. For example, in the following
+diagram, the octets are transmitted in the order they are numbered.
+
+ 0 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 1 | 2 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 3 | 4 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 5 | 6 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Whenever an octet represents a numeric quantity, the left most bit in
+the diagram is the high order or most significant bit. That is, the bit
+labeled 0 is the most significant bit. For example, the following
+diagram represents the value 170 (decimal).
+
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |1 0 1 0 1 0 1 0|
+ +-+-+-+-+-+-+-+-+
+
+Similarly, whenever a multi-octet field represents a numeric quantity
+the left most bit of the whole field is the most significant bit. When
+a multi-octet quantity is transmitted the most significant octet is
+transmitted first.
+
+2.3.3. Character Case
+
+For all parts of the DNS that are part of the official protocol, all
+comparisons between character strings (e.g., labels, domain names, etc.)
+are done in a case-insensitive manner. At present, this rule is in
+force throughout the domain system without exception. However, future
+additions beyond current usage may need to use the full binary octet
+capabilities in names, so attempts to store domain names in 7-bit ASCII
+or use of special bytes to terminate labels, etc., should be avoided.
+
+When data enters the domain system, its original case should be
+preserved whenever possible. In certain circumstances this cannot be
+done. For example, if two RRs are stored in a database, one at x.y and
+one at X.Y, they are actually stored at the same place in the database,
+and hence only one casing would be preserved. The basic rule is that
+case can be discarded only when data is used to define structure in a
+database, and two names are identical when compared in a case
+insensitive manner.
+
+
+
+
+Mockapetris [Page 9]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Loss of case sensitive data must be minimized. Thus while data for x.y
+and X.Y may both be stored under a single location x.y or X.Y, data for
+a.x and B.X would never be stored under A.x, A.X, b.x, or b.X. In
+general, this preserves the case of the first label of a domain name,
+but forces standardization of interior node labels.
+
+Systems administrators who enter data into the domain database should
+take care to represent the data they supply to the domain system in a
+case-consistent manner if their system is case-sensitive. The data
+distribution system in the domain system will ensure that consistent
+representations are preserved.
+
+2.3.4. Size limits
+
+Various objects and parameters in the DNS have size limits. They are
+listed below. Some could be easily changed, others are more
+fundamental.
+
+labels 63 octets or less
+
+names 255 octets or less
+
+TTL positive values of a signed 32 bit number.
+
+UDP messages 512 octets or less
+
+3. DOMAIN NAME SPACE AND RR DEFINITIONS
+
+3.1. Name space definitions
+
+Domain names in messages are expressed in terms of a sequence of labels.
+Each label is represented as a one octet length field followed by that
+number of octets. Since every domain name ends with the null label of
+the root, a domain name is terminated by a length byte of zero. The
+high order two bits of every length octet must be zero, and the
+remaining six bits of the length field limit the label to 63 octets or
+less.
+
+To simplify implementations, the total length of a domain name (i.e.,
+label octets and label length octets) is restricted to 255 octets or
+less.
+
+Although labels can contain any 8 bit values in octets that make up a
+label, it is strongly recommended that labels follow the preferred
+syntax described elsewhere in this memo, which is compatible with
+existing host naming conventions. Name servers and resolvers must
+compare labels in a case-insensitive manner (i.e., A=a), assuming ASCII
+with zero parity. Non-alphabetic codes must match exactly.
+
+
+
+Mockapetris [Page 10]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.2. RR definitions
+
+3.2.1. Format
+
+All RRs have the same top level format shown below:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+
+where:
+
+NAME an owner name, i.e., the name of the node to which this
+ resource record pertains.
+
+TYPE two octets containing one of the RR TYPE codes.
+
+CLASS two octets containing one of the RR CLASS codes.
+
+TTL a 32 bit signed integer that specifies the time interval
+ that the resource record may be cached before the source
+ of the information should again be consulted. Zero
+ values are interpreted to mean that the RR can only be
+ used for the transaction in progress, and should not be
+ cached. For example, SOA records are always distributed
+ with a zero TTL to prohibit caching. Zero values can
+ also be used for extremely volatile data.
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+
+
+Mockapetris [Page 11]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+
+3.2.2. TYPE values
+
+TYPE fields are used in resource records. Note that these types are a
+subset of QTYPEs.
+
+TYPE value and meaning
+
+A 1 a host address
+
+NS 2 an authoritative name server
+
+MD 3 a mail destination (Obsolete - use MX)
+
+MF 4 a mail forwarder (Obsolete - use MX)
+
+CNAME 5 the canonical name for an alias
+
+SOA 6 marks the start of a zone of authority
+
+MB 7 a mailbox domain name (EXPERIMENTAL)
+
+MG 8 a mail group member (EXPERIMENTAL)
+
+MR 9 a mail rename domain name (EXPERIMENTAL)
+
+NULL 10 a null RR (EXPERIMENTAL)
+
+WKS 11 a well known service description
+
+PTR 12 a domain name pointer
+
+HINFO 13 host information
+
+MINFO 14 mailbox or mail list information
+
+MX 15 mail exchange
+
+TXT 16 text strings
+
+3.2.3. QTYPE values
+
+QTYPE fields appear in the question part of a query. QTYPES are a
+superset of TYPEs, hence all TYPEs are valid QTYPEs. In addition, the
+following QTYPEs are defined:
+
+
+
+Mockapetris [Page 12]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+AXFR 252 A request for a transfer of an entire zone
+
+MAILB 253 A request for mailbox-related records (MB, MG or MR)
+
+MAILA 254 A request for mail agent RRs (Obsolete - see MX)
+
+* 255 A request for all records
+
+3.2.4. CLASS values
+
+CLASS fields appear in resource records. The following CLASS mnemonics
+and values are defined:
+
+IN 1 the Internet
+
+CS 2 the CSNET class (Obsolete - used only for examples in
+ some obsolete RFCs)
+
+CH 3 the CHAOS class
+
+HS 4 Hesiod [Dyer 87]
+
+3.2.5. QCLASS values
+
+QCLASS fields appear in the question section of a query. QCLASS values
+are a superset of CLASS values; every CLASS is a valid QCLASS. In
+addition to CLASS values, the following QCLASSes are defined:
+
+* 255 any class
+
+3.3. Standard RRs
+
+The following RR definitions are expected to occur, at least
+potentially, in all classes. In particular, NS, SOA, CNAME, and PTR
+will be used in all classes, and have the same format in all classes.
+Because their RDATA format is known, all domain names in the RDATA
+section of these RRs may be compressed.
+
+<domain-name> is a domain name represented as a series of labels, and
+terminated by a label with zero length. <character-string> is a single
+length octet followed by that number of characters. <character-string>
+is treated as binary information, and can be up to 256 characters in
+length (including the length octet).
+
+
+
+
+
+
+
+
+Mockapetris [Page 13]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.1. CNAME RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CNAME A <domain-name> which specifies the canonical or primary
+ name for the owner. The owner name is an alias.
+
+CNAME RRs cause no additional section processing, but name servers may
+choose to restart the query at the canonical name in certain cases. See
+the description of name server logic in [RFC-1034] for details.
+
+3.3.2. HINFO RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CPU /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / OS /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CPU A <character-string> which specifies the CPU type.
+
+OS A <character-string> which specifies the operating
+ system type.
+
+Standard values for CPU and OS can be found in [RFC-1010].
+
+HINFO records are used to acquire general information about a host. The
+main use is for protocols such as FTP that can use special procedures
+when talking between machines or operating systems of the same type.
+
+3.3.3. MB RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has the
+ specified mailbox.
+
+
+
+Mockapetris [Page 14]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MB records cause additional section processing which looks up an A type
+RRs corresponding to MADNAME.
+
+3.3.4. MD RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which should be able to deliver
+ mail for the domain.
+
+MD records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MD is obsolete. See the definition of MX and [RFC-974] for details of
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 0.
+
+3.3.5. MF RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which will accept mail for
+ forwarding to the domain.
+
+MF records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MF is obsolete. See the definition of MX and [RFC-974] for details ofw
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 10.
+
+
+
+
+
+
+
+Mockapetris [Page 15]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.6. MG RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MGMNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MGMNAME A <domain-name> which specifies a mailbox which is a
+ member of the mail group specified by the domain name.
+
+MG records cause no additional section processing.
+
+3.3.7. MINFO RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+RMAILBX A <domain-name> which specifies a mailbox which is
+ responsible for the mailing list or mailbox. If this
+ domain name names the root, the owner of the MINFO RR is
+ responsible for itself. Note that many existing mailing
+ lists use a mailbox X-request for the RMAILBX field of
+ mailing list X, e.g., Msgroup-request for Msgroup. This
+ field provides a more general mechanism.
+
+
+EMAILBX A <domain-name> which specifies a mailbox which is to
+ receive error messages related to the mailing list or
+ mailbox specified by the owner of the MINFO RR (similar
+ to the ERRORS-TO: field which has been proposed). If
+ this domain name names the root, errors should be
+ returned to the sender of the message.
+
+MINFO records cause no additional section processing. Although these
+records can be associated with a simple mailbox, they are usually used
+with a mailing list.
+
+
+
+
+
+
+
+
+Mockapetris [Page 16]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.8. MR RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NEWNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NEWNAME A <domain-name> which specifies a mailbox which is the
+ proper rename of the specified mailbox.
+
+MR records cause no additional section processing. The main use for MR
+is as a forwarding entry for a user who has moved to a different
+mailbox.
+
+3.3.9. MX RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PREFERENCE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EXCHANGE /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PREFERENCE A 16 bit integer which specifies the preference given to
+ this RR among others at the same owner. Lower values
+ are preferred.
+
+EXCHANGE A <domain-name> which specifies a host willing to act as
+ a mail exchange for the owner name.
+
+MX records cause type A additional section processing for the host
+specified by EXCHANGE. The use of MX RRs is explained in detail in
+[RFC-974].
+
+3.3.10. NULL RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / <anything> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+Anything at all may be in the RDATA field so long as it is 65535 octets
+or less.
+
+
+
+
+Mockapetris [Page 17]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+NULL records cause no additional section processing. NULL RRs are not
+allowed in master files. NULLs are used as placeholders in some
+experimental extensions of the DNS.
+
+3.3.11. NS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NSDNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NSDNAME A <domain-name> which specifies a host which should be
+ authoritative for the specified class and domain.
+
+NS records cause both the usual additional section processing to locate
+a type A record, and, when used in a referral, a special search of the
+zone in which they reside for glue information.
+
+The NS RR states that the named host should be expected to have a zone
+starting at owner name of the specified class. Note that the class may
+not indicate the protocol family which should be used to communicate
+with the host, although it is typically a strong hint. For example,
+hosts which are name servers for either Internet (IN) or Hesiod (HS)
+class information are normally queried using IN class protocols.
+
+3.3.12. PTR RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / PTRDNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PTRDNAME A <domain-name> which points to some location in the
+ domain name space.
+
+PTR records cause no additional section processing. These RRs are used
+in special domains to point to some other location in the domain space.
+These records are simple data, and don't imply any special processing
+similar to that performed by CNAME, which identifies aliases. See the
+description of the IN-ADDR.ARPA domain for an example.
+
+
+
+
+
+
+
+
+Mockapetris [Page 18]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.13. SOA RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | SERIAL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | REFRESH |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RETRY |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | EXPIRE |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | MINIMUM |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MNAME The <domain-name> of the name server that was the
+ original or primary source of data for this zone.
+
+RNAME A <domain-name> which specifies the mailbox of the
+ person responsible for this zone.
+
+SERIAL The unsigned 32 bit version number of the original copy
+ of the zone. Zone transfers preserve this value. This
+ value wraps and should be compared using sequence space
+ arithmetic.
+
+REFRESH A 32 bit time interval before the zone should be
+ refreshed.
+
+RETRY A 32 bit time interval that should elapse before a
+ failed refresh should be retried.
+
+EXPIRE A 32 bit time value that specifies the upper limit on
+ the time interval that can elapse before the zone is no
+ longer authoritative.
+
+
+
+
+
+Mockapetris [Page 19]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MINIMUM The unsigned 32 bit minimum TTL field that should be
+ exported with any RR from this zone.
+
+SOA records cause no additional section processing.
+
+All times are in units of seconds.
+
+Most of these fields are pertinent only for name server maintenance
+operations. However, MINIMUM is used in all query operations that
+retrieve RRs from a zone. Whenever a RR is sent in a response to a
+query, the TTL field is set to the maximum of the TTL field from the RR
+and the MINIMUM field in the appropriate SOA. Thus MINIMUM is a lower
+bound on the TTL field for all RRs in a zone. Note that this use of
+MINIMUM should occur when the RRs are copied into the response and not
+when the zone is loaded from a master file or via a zone transfer. The
+reason for this provison is to allow future dynamic update facilities to
+change the SOA RR with known semantics.
+
+
+3.3.14. TXT RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / TXT-DATA /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+TXT-DATA One or more <character-string>s.
+
+TXT RRs are used to hold descriptive text. The semantics of the text
+depends on the domain where it is found.
+
+3.4. Internet specific RRs
+
+3.4.1. A RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS A 32 bit Internet address.
+
+Hosts that have multiple Internet addresses will have multiple A
+records.
+
+
+
+
+
+Mockapetris [Page 20]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+A records cause no additional section processing. The RDATA section of
+an A line in a master file is an Internet address expressed as four
+decimal numbers separated by dots without any embedded spaces (e.g.,
+"10.2.0.52" or "192.0.5.6").
+
+3.4.2. WKS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PROTOCOL | |
+ +--+--+--+--+--+--+--+--+ |
+ | |
+ / <BIT MAP> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS An 32 bit Internet address
+
+PROTOCOL An 8 bit IP protocol number
+
+<BIT MAP> A variable length bit map. The bit map must be a
+ multiple of 8 bits long.
+
+The WKS record is used to describe the well known services supported by
+a particular protocol on a particular internet address. The PROTOCOL
+field specifies an IP protocol number, and the bit map has one bit per
+port of the specified protocol. The first bit corresponds to port 0,
+the second to port 1, etc. If the bit map does not include a bit for a
+protocol of interest, that bit is assumed zero. The appropriate values
+and mnemonics for ports and protocols are specified in [RFC-1010].
+
+For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port
+25 (SMTP). If this bit is set, a SMTP server should be listening on TCP
+port 25; if zero, SMTP service is not supported on the specified
+address.
+
+The purpose of WKS RRs is to provide availability information for
+servers for TCP and UDP. If a server supports both TCP and UDP, or has
+multiple Internet addresses, then multiple WKS RRs are used.
+
+WKS RRs cause no additional section processing.
+
+In master files, both ports and protocols are expressed using mnemonics
+or decimal numbers.
+
+
+
+
+Mockapetris [Page 21]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.5. IN-ADDR.ARPA domain
+
+The Internet uses a special domain to support gateway location and
+Internet address to host mapping. Other classes may employ a similar
+strategy in other domains. The intent of this domain is to provide a
+guaranteed method to perform host address to host name mapping, and to
+facilitate queries to locate all gateways on a particular network in the
+Internet.
+
+Note that both of these services are similar to functions that could be
+performed by inverse queries; the difference is that this part of the
+domain name space is structured according to address, and hence can
+guarantee that the appropriate data can be located without an exhaustive
+search of the domain space.
+
+The domain begins at IN-ADDR.ARPA and has a substructure which follows
+the Internet addressing structure.
+
+Domain names in the IN-ADDR.ARPA domain are defined to have up to four
+labels in addition to the IN-ADDR.ARPA suffix. Each label represents
+one octet of an Internet address, and is expressed as a character string
+for a decimal value in the range 0-255 (with leading zeros omitted
+except in the case of a zero octet which is represented by a single
+zero).
+
+Host addresses are represented by domain names that have all four labels
+specified. Thus data for Internet address 10.2.0.52 is located at
+domain name 52.0.2.10.IN-ADDR.ARPA. The reversal, though awkward to
+read, allows zones to be delegated which are exactly one network of
+address space. For example, 10.IN-ADDR.ARPA can be a zone containing
+data for the ARPANET, while 26.IN-ADDR.ARPA can be a separate zone for
+MILNET. Address nodes are used to hold pointers to primary host names
+in the normal domain space.
+
+Network numbers correspond to some non-terminal nodes at various depths
+in the IN-ADDR.ARPA domain, since Internet network numbers are either 1,
+2, or 3 octets. Network nodes are used to hold pointers to the primary
+host names of gateways attached to that network. Since a gateway is, by
+definition, on more than one network, it will typically have two or more
+network nodes which point at it. Gateways will also have host level
+pointers at their fully qualified addresses.
+
+Both the gateway pointers at network nodes and the normal host pointers
+at full address nodes use the PTR RR to point back to the primary domain
+names of the corresponding hosts.
+
+For example, the IN-ADDR.ARPA domain will contain information about the
+ISI gateway between net 10 and 26, an MIT gateway from net 10 to MIT's
+
+
+
+Mockapetris [Page 22]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+net 18, and hosts A.ISI.EDU and MULTICS.MIT.EDU. Assuming that ISI
+gateway has addresses 10.2.0.22 and 26.0.0.103, and a name MILNET-
+GW.ISI.EDU, and the MIT gateway has addresses 10.0.0.77 and 18.10.0.4
+and a name GW.LCS.MIT.EDU, the domain database would contain:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 22.0.2.10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 103.0.0.26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 77.0.0.10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 4.0.10.18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 103.0.3.26.IN-ADDR.ARPA. PTR A.ISI.EDU.
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Thus a program which wanted to locate gateways on net 10 would originate
+a query of the form QTYPE=PTR, QCLASS=IN, QNAME=10.IN-ADDR.ARPA. It
+would receive two RRs in response:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+
+The program could then originate QTYPE=A, QCLASS=IN queries for MILNET-
+GW.ISI.EDU. and GW.LCS.MIT.EDU. to discover the Internet addresses of
+these gateways.
+
+A resolver which wanted to find the host name corresponding to Internet
+host address 10.0.0.6 would pursue a query of the form QTYPE=PTR,
+QCLASS=IN, QNAME=6.0.0.10.IN-ADDR.ARPA, and would receive:
+
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Several cautions apply to the use of these services:
+ - Since the IN-ADDR.ARPA special domain and the normal domain
+ for a particular host or gateway will be in different zones,
+ the possibility exists that that the data may be inconsistent.
+
+ - Gateways will often have two names in separate domains, only
+ one of which can be primary.
+
+ - Systems that use the domain database to initialize their
+ routing tables must start with enough gateway information to
+ guarantee that they can access the appropriate name server.
+
+ - The gateway data only reflects the existence of a gateway in a
+ manner equivalent to the current HOSTS.TXT file. It doesn't
+ replace the dynamic availability information from GGP or EGP.
+
+
+
+Mockapetris [Page 23]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.6. Defining new types, classes, and special namespaces
+
+The previously defined types and classes are the ones in use as of the
+date of this memo. New definitions should be expected. This section
+makes some recommendations to designers considering additions to the
+existing facilities. The mailing list NAMEDROPPERS@SRI-NIC.ARPA is the
+forum where general discussion of design issues takes place.
+
+In general, a new type is appropriate when new information is to be
+added to the database about an existing object, or we need new data
+formats for some totally new object. Designers should attempt to define
+types and their RDATA formats that are generally applicable to all
+classes, and which avoid duplication of information. New classes are
+appropriate when the DNS is to be used for a new protocol, etc which
+requires new class-specific data formats, or when a copy of the existing
+name space is desired, but a separate management domain is necessary.
+
+New types and classes need mnemonics for master files; the format of the
+master files requires that the mnemonics for type and class be disjoint.
+
+TYPE and CLASS values must be a proper subset of QTYPEs and QCLASSes
+respectively.
+
+The present system uses multiple RRs to represent multiple values of a
+type rather than storing multiple values in the RDATA section of a
+single RR. This is less efficient for most applications, but does keep
+RRs shorter. The multiple RRs assumption is incorporated in some
+experimental work on dynamic update methods.
+
+The present system attempts to minimize the duplication of data in the
+database in order to insure consistency. Thus, in order to find the
+address of the host for a mail exchange, you map the mail domain name to
+a host name, then the host name to addresses, rather than a direct
+mapping to host address. This approach is preferred because it avoids
+the opportunity for inconsistency.
+
+In defining a new type of data, multiple RR types should not be used to
+create an ordering between entries or express different formats for
+equivalent bindings, instead this information should be carried in the
+body of the RR and a single type used. This policy avoids problems with
+caching multiple types and defining QTYPEs to match multiple types.
+
+For example, the original form of mail exchange binding used two RR
+types one to represent a "closer" exchange (MD) and one to represent a
+"less close" exchange (MF). The difficulty is that the presence of one
+RR type in a cache doesn't convey any information about the other
+because the query which acquired the cached information might have used
+a QTYPE of MF, MD, or MAILA (which matched both). The redesigned
+
+
+
+Mockapetris [Page 24]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+service used a single type (MX) with a "preference" value in the RDATA
+section which can order different RRs. However, if any MX RRs are found
+in the cache, then all should be there.
+
+4. MESSAGES
+
+4.1. Format
+
+All communications inside of the domain protocol are carried in a single
+format called a message. The top level format of message is divided
+into 5 sections (some of which are empty in certain cases) shown below:
+
+ +---------------------+
+ | Header |
+ +---------------------+
+ | Question | the question for the name server
+ +---------------------+
+ | Answer | RRs answering the question
+ +---------------------+
+ | Authority | RRs pointing toward an authority
+ +---------------------+
+ | Additional | RRs holding additional information
+ +---------------------+
+
+The header section is always present. The header includes fields that
+specify which of the remaining sections are present, and also specify
+whether the message is a query or a response, a standard query or some
+other opcode, etc.
+
+The names of the sections after the header are derived from their use in
+standard queries. The question section contains fields that describe a
+question to a name server. These fields are a query type (QTYPE), a
+query class (QCLASS), and a query domain name (QNAME). The last three
+sections have the same format: a possibly empty list of concatenated
+resource records (RRs). The answer section contains RRs that answer the
+question; the authority section contains RRs that point toward an
+authoritative name server; the additional records section contains RRs
+which relate to the query, but are not strictly answers for the
+question.
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 25]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+4.1.1. Header section format
+
+The header contains the following fields:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ID |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QDCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ANCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | NSCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ARCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ID A 16 bit identifier assigned by the program that
+ generates any kind of query. This identifier is copied
+ the corresponding reply and can be used by the requester
+ to match up replies to outstanding queries.
+
+QR A one bit field that specifies whether this message is a
+ query (0), or a response (1).
+
+OPCODE A four bit field that specifies kind of query in this
+ message. This value is set by the originator of a query
+ and copied into the response. The values are:
+
+ 0 a standard query (QUERY)
+
+ 1 an inverse query (IQUERY)
+
+ 2 a server status request (STATUS)
+
+ 3-15 reserved for future use
+
+AA Authoritative Answer - this bit is valid in responses,
+ and specifies that the responding name server is an
+ authority for the domain name in question section.
+
+ Note that the contents of the answer section may have
+ multiple owner names because of aliases. The AA bit
+
+
+
+Mockapetris [Page 26]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ corresponds to the name which matches the query name, or
+ the first owner name in the answer section.
+
+TC TrunCation - specifies that this message was truncated
+ due to length greater than that permitted on the
+ transmission channel.
+
+RD Recursion Desired - this bit may be set in a query and
+ is copied into the response. If RD is set, it directs
+ the name server to pursue the query recursively.
+ Recursive query support is optional.
+
+RA Recursion Available - this be is set or cleared in a
+ response, and denotes whether recursive query support is
+ available in the name server.
+
+Z Reserved for future use. Must be zero in all queries
+ and responses.
+
+RCODE Response code - this 4 bit field is set as part of
+ responses. The values have the following
+ interpretation:
+
+ 0 No error condition
+
+ 1 Format error - The name server was
+ unable to interpret the query.
+
+ 2 Server failure - The name server was
+ unable to process this query due to a
+ problem with the name server.
+
+ 3 Name Error - Meaningful only for
+ responses from an authoritative name
+ server, this code signifies that the
+ domain name referenced in the query does
+ not exist.
+
+ 4 Not Implemented - The name server does
+ not support the requested kind of query.
+
+ 5 Refused - The name server refuses to
+ perform the specified operation for
+ policy reasons. For example, a name
+ server may not wish to provide the
+ information to the particular requester,
+ or a name server may not wish to perform
+ a particular operation (e.g., zone
+
+
+
+Mockapetris [Page 27]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ transfer) for particular data.
+
+ 6-15 Reserved for future use.
+
+QDCOUNT an unsigned 16 bit integer specifying the number of
+ entries in the question section.
+
+ANCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the answer section.
+
+NSCOUNT an unsigned 16 bit integer specifying the number of name
+ server resource records in the authority records
+ section.
+
+ARCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the additional records section.
+
+4.1.2. Question section format
+
+The question section is used to carry the "question" in most queries,
+i.e., the parameters that define what is being asked. The section
+contains QDCOUNT (usually 1) entries, each of the following format:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / QNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QTYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QCLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+QNAME a domain name represented as a sequence of labels, where
+ each label consists of a length octet followed by that
+ number of octets. The domain name terminates with the
+ zero length octet for the null label of the root. Note
+ that this field may be an odd number of octets; no
+ padding is used.
+
+QTYPE a two octet code which specifies the type of the query.
+ The values for this field include all codes valid for a
+ TYPE field, together with some more general codes which
+ can match more than one type of RR.
+
+
+
+Mockapetris [Page 28]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+QCLASS a two octet code that specifies the class of the query.
+ For example, the QCLASS field is IN for the Internet.
+
+4.1.3. Resource record format
+
+The answer, authority, and additional sections all share the same
+format: a variable number of resource records, where the number of
+records is specified in the corresponding count field in the header.
+Each resource record has the following format:
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NAME a domain name to which this resource record pertains.
+
+TYPE two octets containing one of the RR type codes. This
+ field specifies the meaning of the data in the RDATA
+ field.
+
+CLASS two octets which specify the class of the data in the
+ RDATA field.
+
+TTL a 32 bit unsigned integer that specifies the time
+ interval (in seconds) that the resource record may be
+ cached before it should be discarded. Zero values are
+ interpreted to mean that the RR can only be used for the
+ transaction in progress, and should not be cached.
+
+
+
+
+
+Mockapetris [Page 29]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+ For example, the if the TYPE is A and the CLASS is IN,
+ the RDATA field is a 4 octet ARPA Internet address.
+
+4.1.4. Message compression
+
+In order to reduce the size of messages, the domain system utilizes a
+compression scheme which eliminates the repetition of domain names in a
+message. In this scheme, an entire domain name or a list of labels at
+the end of a domain name is replaced with a pointer to a prior occurrence
+of the same name.
+
+The pointer takes the form of a two octet sequence:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | 1 1| OFFSET |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The first two bits are ones. This allows a pointer to be distinguished
+from a label, since the label must begin with two zero bits because
+labels are restricted to 63 octets or less. (The 10 and 01 combinations
+are reserved for future use.) The OFFSET field specifies an offset from
+the start of the message (i.e., the first octet of the ID field in the
+domain header). A zero offset specifies the first byte of the ID field,
+etc.
+
+The compression scheme allows a domain name in a message to be
+represented as either:
+
+ - a sequence of labels ending in a zero octet
+
+ - a pointer
+
+ - a sequence of labels ending with a pointer
+
+Pointers can only be used for occurrences of a domain name where the
+format is not class specific. If this were not the case, a name server
+or resolver would be required to know the format of all RRs it handled.
+As yet, there are no such cases, but they may occur in future RDATA
+formats.
+
+If a domain name is contained in a part of the message subject to a
+length field (such as the RDATA section of an RR), and compression is
+
+
+
+Mockapetris [Page 30]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+used, the length of the compressed name is used in the length
+calculation, rather than the length of the expanded name.
+
+Programs are free to avoid using pointers in messages they generate,
+although this will reduce datagram capacity, and may cause truncation.
+However all programs are required to understand arriving messages that
+contain pointers.
+
+For example, a datagram might need to use the domain names F.ISI.ARPA,
+FOO.F.ISI.ARPA, ARPA, and the root. Ignoring the other fields of the
+message, these domain names might be represented as:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 20 | 1 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 22 | 3 | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 24 | S | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 26 | 4 | A |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 28 | R | P |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 30 | A | 0 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 40 | 3 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 42 | O | O |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 44 | 1 1| 20 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 64 | 1 1| 26 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 92 | 0 | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The domain name for F.ISI.ARPA is shown at offset 20. The domain name
+FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to
+concatenate a label for FOO to the previously defined F.ISI.ARPA. The
+domain name ARPA is defined at offset 64 using a pointer to the ARPA
+component of the name F.ISI.ARPA at 20; note that this pointer relies on
+ARPA being the last label in the string at 20. The root domain name is
+
+
+
+Mockapetris [Page 31]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+defined by a single octet of zeros at 92; the root domain name has no
+labels.
+
+4.2. Transport
+
+The DNS assumes that messages will be transmitted as datagrams or in a
+byte stream carried by a virtual circuit. While virtual circuits can be
+used for any DNS activity, datagrams are preferred for queries due to
+their lower overhead and better performance. Zone refresh activities
+must use virtual circuits because of the need for reliable transfer.
+
+The Internet supports name server access using TCP [RFC-793] on server
+port 53 (decimal) as well as datagram access using UDP [RFC-768] on UDP
+port 53 (decimal).
+
+4.2.1. UDP usage
+
+Messages sent using UDP user server port 53 (decimal).
+
+Messages carried by UDP are restricted to 512 bytes (not counting the IP
+or UDP headers). Longer messages are truncated and the TC bit is set in
+the header.
+
+UDP is not acceptable for zone transfers, but is the recommended method
+for standard queries in the Internet. Queries sent using UDP may be
+lost, and hence a retransmission strategy is required. Queries or their
+responses may be reordered by the network, or by processing in name
+servers, so resolvers should not depend on them being returned in order.
+
+The optimal UDP retransmission policy will vary with performance of the
+Internet and the needs of the client, but the following are recommended:
+
+ - The client should try other servers and server addresses
+ before repeating a query to a specific address of a server.
+
+ - The retransmission interval should be based on prior
+ statistics if possible. Too aggressive retransmission can
+ easily slow responses for the community at large. Depending
+ on how well connected the client is to its expected servers,
+ the minimum retransmission interval should be 2-5 seconds.
+
+More suggestions on server selection and retransmission policy can be
+found in the resolver section of this memo.
+
+4.2.2. TCP usage
+
+Messages sent over TCP connections use server port 53 (decimal). The
+message is prefixed with a two byte length field which gives the message
+
+
+
+Mockapetris [Page 32]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+length, excluding the two byte length field. This length field allows
+the low-level processing to assemble a complete message before beginning
+to parse it.
+
+Several connection management policies are recommended:
+
+ - The server should not block other activities waiting for TCP
+ data.
+
+ - The server should support multiple connections.
+
+ - The server should assume that the client will initiate
+ connection closing, and should delay closing its end of the
+ connection until all outstanding client requests have been
+ satisfied.
+
+ - If the server needs to close a dormant connection to reclaim
+ resources, it should wait until the connection has been idle
+ for a period on the order of two minutes. In particular, the
+ server should allow the SOA and AXFR request sequence (which
+ begins a refresh operation) to be made on a single connection.
+ Since the server would be unable to answer queries anyway, a
+ unilateral close or reset may be used instead of a graceful
+ close.
+
+5. MASTER FILES
+
+Master files are text files that contain RRs in text form. Since the
+contents of a zone can be expressed in the form of a list of RRs a
+master file is most often used to define a zone, though it can be used
+to list a cache's contents. Hence, this section first discusses the
+format of RRs in a master file, and then the special considerations when
+a master file is used to create a zone in some name server.
+
+5.1. Format
+
+The format of these files is a sequence of entries. Entries are
+predominantly line-oriented, though parentheses can be used to continue
+a list of items across a line boundary, and text literals can contain
+CRLF within the text. Any combination of tabs and spaces act as a
+delimiter between the separate items that make up an entry. The end of
+any line in the master file can end with a comment. The comment starts
+with a ";" (semicolon).
+
+The following entries are defined:
+
+ <blank>[<comment>]
+
+
+
+
+Mockapetris [Page 33]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ $ORIGIN <domain-name> [<comment>]
+
+ $INCLUDE <file-name> [<domain-name>] [<comment>]
+
+ <domain-name><rr> [<comment>]
+
+ <blank><rr> [<comment>]
+
+Blank lines, with or without comments, are allowed anywhere in the file.
+
+Two control entries are defined: $ORIGIN and $INCLUDE. $ORIGIN is
+followed by a domain name, and resets the current origin for relative
+domain names to the stated name. $INCLUDE inserts the named file into
+the current file, and may optionally specify a domain name that sets the
+relative domain name origin for the included file. $INCLUDE may also
+have a comment. Note that a $INCLUDE entry never changes the relative
+origin of the parent file, regardless of changes to the relative origin
+made within the included file.
+
+The last two forms represent RRs. If an entry for an RR begins with a
+blank, then the RR is assumed to be owned by the last stated owner. If
+an RR entry begins with a <domain-name>, then the owner name is reset.
+
+<rr> contents take one of the following forms:
+
+ [<TTL>] [<class>] <type> <RDATA>
+
+ [<class>] [<TTL>] <type> <RDATA>
+
+The RR begins with optional TTL and class fields, followed by a type and
+RDATA field appropriate to the type and class. Class and type use the
+standard mnemonics, TTL is a decimal integer. Omitted class and TTL
+values are default to the last explicitly stated values. Since type and
+class mnemonics are disjoint, the parse is unique. (Note that this
+order is different from the order used in examples and the order used in
+the actual RRs; the given order allows easier parsing and defaulting.)
+
+<domain-name>s make up a large share of the data in the master file.
+The labels in the domain name are expressed as character strings and
+separated by dots. Quoting conventions allow arbitrary characters to be
+stored in domain names. Domain names that end in a dot are called
+absolute, and are taken as complete. Domain names which do not end in a
+dot are called relative; the actual domain name is the concatenation of
+the relative part with an origin specified in a $ORIGIN, $INCLUDE, or as
+an argument to the master file loading routine. A relative name is an
+error when no origin is available.
+
+
+
+
+
+Mockapetris [Page 34]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+<character-string> is expressed in one or two ways: as a contiguous set
+of characters without interior spaces, or as a string beginning with a "
+and ending with a ". Inside a " delimited string any character can
+occur, except for a " itself, which must be quoted using \ (back slash).
+
+Because these files are text files several special encodings are
+necessary to allow arbitrary data to be loaded. In particular:
+
+ of the root.
+
+@ A free standing @ is used to denote the current origin.
+
+\X where X is any character other than a digit (0-9), is
+ used to quote that character so that its special meaning
+ does not apply. For example, "\." can be used to place
+ a dot character in a label.
+
+\DDD where each D is a digit is the octet corresponding to
+ the decimal number described by DDD. The resulting
+ octet is assumed to be text and is not checked for
+ special meaning.
+
+( ) Parentheses are used to group data that crosses a line
+ boundary. In effect, line terminations are not
+ recognized within parentheses.
+
+; Semicolon is used to start a comment; the remainder of
+ the line is ignored.
+
+5.2. Use of master files to define zones
+
+When a master file is used to load a zone, the operation should be
+suppressed if any errors are encountered in the master file. The
+rationale for this is that a single error can have widespread
+consequences. For example, suppose that the RRs defining a delegation
+have syntax errors; then the server will return authoritative name
+errors for all names in the subzone (except in the case where the
+subzone is also present on the server).
+
+Several other validity checks that should be performed in addition to
+insuring that the file is syntactically correct:
+
+ 1. All RRs in the file should have the same class.
+
+ 2. Exactly one SOA RR should be present at the top of the zone.
+
+ 3. If delegations are present and glue information is required,
+ it should be present.
+
+
+
+Mockapetris [Page 35]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 4. Information present outside of the authoritative nodes in the
+ zone should be glue information, rather than the result of an
+ origin or similar error.
+
+5.3. Master file example
+
+The following is an example file which might be used to define the
+ISI.EDU zone.and is loaded with an origin of ISI.EDU:
+
+@ IN SOA VENERA Action\.domains (
+ 20 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 3600000; EXPIRE
+ 60) ; MINIMUM
+
+ NS A.ISI.EDU.
+ NS VENERA
+ NS VAXA
+ MX 10 VENERA
+ MX 20 VAXA
+
+A A 26.3.0.103
+
+VENERA A 10.1.0.52
+ A 128.9.0.32
+
+VAXA A 10.2.0.27
+ A 128.9.0.33
+
+
+$INCLUDE <SUBSYS>ISI-MAILBOXES.TXT
+
+Where the file <SUBSYS>ISI-MAILBOXES.TXT is:
+
+ MOE MB A.ISI.EDU.
+ LARRY MB A.ISI.EDU.
+ CURLEY MB A.ISI.EDU.
+ STOOGES MG MOE
+ MG LARRY
+ MG CURLEY
+
+Note the use of the \ character in the SOA RR to specify the responsible
+person mailbox "Action.domains@E.ISI.EDU".
+
+
+
+
+
+
+
+Mockapetris [Page 36]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+6. NAME SERVER IMPLEMENTATION
+
+6.1. Architecture
+
+The optimal structure for the name server will depend on the host
+operating system and whether the name server is integrated with resolver
+operations, either by supporting recursive service, or by sharing its
+database with a resolver. This section discusses implementation
+considerations for a name server which shares a database with a
+resolver, but most of these concerns are present in any name server.
+
+6.1.1. Control
+
+A name server must employ multiple concurrent activities, whether they
+are implemented as separate tasks in the host's OS or multiplexing
+inside a single name server program. It is simply not acceptable for a
+name server to block the service of UDP requests while it waits for TCP
+data for refreshing or query activities. Similarly, a name server
+should not attempt to provide recursive service without processing such
+requests in parallel, though it may choose to serialize requests from a
+single client, or to regard identical requests from the same client as
+duplicates. A name server should not substantially delay requests while
+it reloads a zone from master files or while it incorporates a newly
+refreshed zone into its database.
+
+6.1.2. Database
+
+While name server implementations are free to use any internal data
+structures they choose, the suggested structure consists of three major
+parts:
+
+ - A "catalog" data structure which lists the zones available to
+ this server, and a "pointer" to the zone data structure. The
+ main purpose of this structure is to find the nearest ancestor
+ zone, if any, for arriving standard queries.
+
+ - Separate data structures for each of the zones held by the
+ name server.
+
+ - A data structure for cached data. (or perhaps separate caches
+ for different classes)
+
+All of these data structures can be implemented an identical tree
+structure format, with different data chained off the nodes in different
+parts: in the catalog the data is pointers to zones, while in the zone
+and cache data structures, the data will be RRs. In designing the tree
+framework the designer should recognize that query processing will need
+to traverse the tree using case-insensitive label comparisons; and that
+
+
+
+Mockapetris [Page 37]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in real data, a few nodes have a very high branching factor (100-1000 or
+more), but the vast majority have a very low branching factor (0-1).
+
+One way to solve the case problem is to store the labels for each node
+in two pieces: a standardized-case representation of the label where all
+ASCII characters are in a single case, together with a bit mask that
+denotes which characters are actually of a different case. The
+branching factor diversity can be handled using a simple linked list for
+a node until the branching factor exceeds some threshold, and
+transitioning to a hash structure after the threshold is exceeded. In
+any case, hash structures used to store tree sections must insure that
+hash functions and procedures preserve the casing conventions of the
+DNS.
+
+The use of separate structures for the different parts of the database
+is motivated by several factors:
+
+ - The catalog structure can be an almost static structure that
+ need change only when the system administrator changes the
+ zones supported by the server. This structure can also be
+ used to store parameters used to control refreshing
+ activities.
+
+ - The individual data structures for zones allow a zone to be
+ replaced simply by changing a pointer in the catalog. Zone
+ refresh operations can build a new structure and, when
+ complete, splice it into the database via a simple pointer
+ replacement. It is very important that when a zone is
+ refreshed, queries should not use old and new data
+ simultaneously.
+
+ - With the proper search procedures, authoritative data in zones
+ will always "hide", and hence take precedence over, cached
+ data.
+
+ - Errors in zone definitions that cause overlapping zones, etc.,
+ may cause erroneous responses to queries, but problem
+ determination is simplified, and the contents of one "bad"
+ zone can't corrupt another.
+
+ - Since the cache is most frequently updated, it is most
+ vulnerable to corruption during system restarts. It can also
+ become full of expired RR data. In either case, it can easily
+ be discarded without disturbing zone data.
+
+A major aspect of database design is selecting a structure which allows
+the name server to deal with crashes of the name server's host. State
+information which a name server should save across system crashes
+
+
+
+Mockapetris [Page 38]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+includes the catalog structure (including the state of refreshing for
+each zone) and the zone data itself.
+
+6.1.3. Time
+
+Both the TTL data for RRs and the timing data for refreshing activities
+depends on 32 bit timers in units of seconds. Inside the database,
+refresh timers and TTLs for cached data conceptually "count down", while
+data in the zone stays with constant TTLs.
+
+A recommended implementation strategy is to store time in two ways: as
+a relative increment and as an absolute time. One way to do this is to
+use positive 32 bit numbers for one type and negative numbers for the
+other. The RRs in zones use relative times; the refresh timers and
+cache data use absolute times. Absolute numbers are taken with respect
+to some known origin and converted to relative values when placed in the
+response to a query. When an absolute TTL is negative after conversion
+to relative, then the data is expired and should be ignored.
+
+6.2. Standard query processing
+
+The major algorithm for standard query processing is presented in
+[RFC-1034].
+
+When processing queries with QCLASS=*, or some other QCLASS which
+matches multiple classes, the response should never be authoritative
+unless the server can guarantee that the response covers all classes.
+
+When composing a response, RRs which are to be inserted in the
+additional section, but duplicate RRs in the answer or authority
+sections, may be omitted from the additional section.
+
+When a response is so long that truncation is required, the truncation
+should start at the end of the response and work forward in the
+datagram. Thus if there is any data for the authority section, the
+answer section is guaranteed to be unique.
+
+The MINIMUM value in the SOA should be used to set a floor on the TTL of
+data distributed from a zone. This floor function should be done when
+the data is copied into a response. This will allow future dynamic
+update protocols to change the SOA MINIMUM field without ambiguous
+semantics.
+
+6.3. Zone refresh and reload processing
+
+In spite of a server's best efforts, it may be unable to load zone data
+from a master file due to syntax errors, etc., or be unable to refresh a
+zone within the its expiration parameter. In this case, the name server
+
+
+
+Mockapetris [Page 39]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+should answer queries as if it were not supposed to possess the zone.
+
+If a master is sending a zone out via AXFR, and a new version is created
+during the transfer, the master should continue to send the old version
+if possible. In any case, it should never send part of one version and
+part of another. If completion is not possible, the master should reset
+the connection on which the zone transfer is taking place.
+
+6.4. Inverse queries (Optional)
+
+Inverse queries are an optional part of the DNS. Name servers are not
+required to support any form of inverse queries. If a name server
+receives an inverse query that it does not support, it returns an error
+response with the "Not Implemented" error set in the header. While
+inverse query support is optional, all name servers must be at least
+able to return the error response.
+
+6.4.1. The contents of inverse queries and responses Inverse
+queries reverse the mappings performed by standard query operations;
+while a standard query maps a domain name to a resource, an inverse
+query maps a resource to a domain name. For example, a standard query
+might bind a domain name to a host address; the corresponding inverse
+query binds the host address to a domain name.
+
+Inverse queries take the form of a single RR in the answer section of
+the message, with an empty question section. The owner name of the
+query RR and its TTL are not significant. The response carries
+questions in the question section which identify all names possessing
+the query RR WHICH THE NAME SERVER KNOWS. Since no name server knows
+about all of the domain name space, the response can never be assumed to
+be complete. Thus inverse queries are primarily useful for database
+management and debugging activities. Inverse queries are NOT an
+acceptable method of mapping host addresses to host names; use the IN-
+ADDR.ARPA domain instead.
+
+Where possible, name servers should provide case-insensitive comparisons
+for inverse queries. Thus an inverse query asking for an MX RR of
+"Venera.isi.edu" should get the same response as a query for
+"VENERA.ISI.EDU"; an inverse query for HINFO RR "IBM-PC UNIX" should
+produce the same result as an inverse query for "IBM-pc unix". However,
+this cannot be guaranteed because name servers may possess RRs that
+contain character strings but the name server does not know that the
+data is character.
+
+When a name server processes an inverse query, it either returns:
+
+ 1. zero, one, or multiple domain names for the specified
+ resource as QNAMEs in the question section
+
+
+
+Mockapetris [Page 40]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 2. an error code indicating that the name server doesn't support
+ inverse mapping of the specified resource type.
+
+When the response to an inverse query contains one or more QNAMEs, the
+owner name and TTL of the RR in the answer section which defines the
+inverse query is modified to exactly match an RR found at the first
+QNAME.
+
+RRs returned in the inverse queries cannot be cached using the same
+mechanism as is used for the replies to standard queries. One reason
+for this is that a name might have multiple RRs of the same type, and
+only one would appear. For example, an inverse query for a single
+address of a multiply homed host might create the impression that only
+one address existed.
+
+6.4.2. Inverse query and response example The overall structure
+of an inverse query for retrieving the domain name that corresponds to
+Internet address 10.1.0.52 is shown below:
+
+ +-----------------------------------------+
+ Header | OPCODE=IQUERY, ID=997 |
+ +-----------------------------------------+
+ Question | <empty> |
+ +-----------------------------------------+
+ Answer | <anyname> A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+This query asks for a question whose answer is the Internet style
+address 10.1.0.52. Since the owner name is not known, any domain name
+can be used as a placeholder (and is ignored). A single octet of zero,
+signifying the root, is usually used because it minimizes the length of
+the message. The TTL of the RR is not significant. The response to
+this query might be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 41]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ +-----------------------------------------+
+ Header | OPCODE=RESPONSE, ID=997 |
+ +-----------------------------------------+
+ Question |QTYPE=A, QCLASS=IN, QNAME=VENERA.ISI.EDU |
+ +-----------------------------------------+
+ Answer | VENERA.ISI.EDU A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+Note that the QTYPE in a response to an inverse query is the same as the
+TYPE field in the answer section of the inverse query. Responses to
+inverse queries may contain multiple questions when the inverse is not
+unique. If the question section in the response is not empty, then the
+RR in the answer section is modified to correspond to be an exact copy
+of an RR at the first QNAME.
+
+6.4.3. Inverse query processing
+
+Name servers that support inverse queries can support these operations
+through exhaustive searches of their databases, but this becomes
+impractical as the size of the database increases. An alternative
+approach is to invert the database according to the search key.
+
+For name servers that support multiple zones and a large amount of data,
+the recommended approach is separate inversions for each zone. When a
+particular zone is changed during a refresh, only its inversions need to
+be redone.
+
+Support for transfer of this type of inversion may be included in future
+versions of the domain system, but is not supported in this version.
+
+6.5. Completion queries and responses
+
+The optional completion services described in RFC-882 and RFC-883 have
+been deleted. Redesigned services may become available in the future.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 42]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7. RESOLVER IMPLEMENTATION
+
+The top levels of the recommended resolver algorithm are discussed in
+[RFC-1034]. This section discusses implementation details assuming the
+database structure suggested in the name server implementation section
+of this memo.
+
+7.1. Transforming a user request into a query
+
+The first step a resolver takes is to transform the client's request,
+stated in a format suitable to the local OS, into a search specification
+for RRs at a specific name which match a specific QTYPE and QCLASS.
+Where possible, the QTYPE and QCLASS should correspond to a single type
+and a single class, because this makes the use of cached data much
+simpler. The reason for this is that the presence of data of one type
+in a cache doesn't confirm the existence or non-existence of data of
+other types, hence the only way to be sure is to consult an
+authoritative source. If QCLASS=* is used, then authoritative answers
+won't be available.
+
+Since a resolver must be able to multiplex multiple requests if it is to
+perform its function efficiently, each pending request is usually
+represented in some block of state information. This state block will
+typically contain:
+
+ - A timestamp indicating the time the request began.
+ The timestamp is used to decide whether RRs in the database
+ can be used or are out of date. This timestamp uses the
+ absolute time format previously discussed for RR storage in
+ zones and caches. Note that when an RRs TTL indicates a
+ relative time, the RR must be timely, since it is part of a
+ zone. When the RR has an absolute time, it is part of a
+ cache, and the TTL of the RR is compared against the timestamp
+ for the start of the request.
+
+ Note that using the timestamp is superior to using a current
+ time, since it allows RRs with TTLs of zero to be entered in
+ the cache in the usual manner, but still used by the current
+ request, even after intervals of many seconds due to system
+ load, query retransmission timeouts, etc.
+
+ - Some sort of parameters to limit the amount of work which will
+ be performed for this request.
+
+ The amount of work which a resolver will do in response to a
+ client request must be limited to guard against errors in the
+ database, such as circular CNAME references, and operational
+ problems, such as network partition which prevents the
+
+
+
+Mockapetris [Page 43]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ resolver from accessing the name servers it needs. While
+ local limits on the number of times a resolver will retransmit
+ a particular query to a particular name server address are
+ essential, the resolver should have a global per-request
+ counter to limit work on a single request. The counter should
+ be set to some initial value and decremented whenever the
+ resolver performs any action (retransmission timeout,
+ retransmission, etc.) If the counter passes zero, the request
+ is terminated with a temporary error.
+
+ Note that if the resolver structure allows one request to
+ start others in parallel, such as when the need to access a
+ name server for one request causes a parallel resolve for the
+ name server's addresses, the spawned request should be started
+ with a lower counter. This prevents circular references in
+ the database from starting a chain reaction of resolver
+ activity.
+
+ - The SLIST data structure discussed in [RFC-1034].
+
+ This structure keeps track of the state of a request if it
+ must wait for answers from foreign name servers.
+
+7.2. Sending the queries
+
+As described in [RFC-1034], the basic task of the resolver is to
+formulate a query which will answer the client's request and direct that
+query to name servers which can provide the information. The resolver
+will usually only have very strong hints about which servers to ask, in
+the form of NS RRs, and may have to revise the query, in response to
+CNAMEs, or revise the set of name servers the resolver is asking, in
+response to delegation responses which point the resolver to name
+servers closer to the desired information. In addition to the
+information requested by the client, the resolver may have to call upon
+its own services to determine the address of name servers it wishes to
+contact.
+
+In any case, the model used in this memo assumes that the resolver is
+multiplexing attention between multiple requests, some from the client,
+and some internally generated. Each request is represented by some
+state information, and the desired behavior is that the resolver
+transmit queries to name servers in a way that maximizes the probability
+that the request is answered, minimizes the time that the request takes,
+and avoids excessive transmissions. The key algorithm uses the state
+information of the request to select the next name server address to
+query, and also computes a timeout which will cause the next action
+should a response not arrive. The next action will usually be a
+transmission to some other server, but may be a temporary error to the
+
+
+
+Mockapetris [Page 44]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+client.
+
+The resolver always starts with a list of server names to query (SLIST).
+This list will be all NS RRs which correspond to the nearest ancestor
+zone that the resolver knows about. To avoid startup problems, the
+resolver should have a set of default servers which it will ask should
+it have no current NS RRs which are appropriate. The resolver then adds
+to SLIST all of the known addresses for the name servers, and may start
+parallel requests to acquire the addresses of the servers when the
+resolver has the name, but no addresses, for the name servers.
+
+To complete initialization of SLIST, the resolver attaches whatever
+history information it has to the each address in SLIST. This will
+usually consist of some sort of weighted averages for the response time
+of the address, and the batting average of the address (i.e., how often
+the address responded at all to the request). Note that this
+information should be kept on a per address basis, rather than on a per
+name server basis, because the response time and batting average of a
+particular server may vary considerably from address to address. Note
+also that this information is actually specific to a resolver address /
+server address pair, so a resolver with multiple addresses may wish to
+keep separate histories for each of its addresses. Part of this step
+must deal with addresses which have no such history; in this case an
+expected round trip time of 5-10 seconds should be the worst case, with
+lower estimates for the same local network, etc.
+
+Note that whenever a delegation is followed, the resolver algorithm
+reinitializes SLIST.
+
+The information establishes a partial ranking of the available name
+server addresses. Each time an address is chosen and the state should
+be altered to prevent its selection again until all other addresses have
+been tried. The timeout for each transmission should be 50-100% greater
+than the average predicted value to allow for variance in response.
+
+Some fine points:
+
+ - The resolver may encounter a situation where no addresses are
+ available for any of the name servers named in SLIST, and
+ where the servers in the list are precisely those which would
+ normally be used to look up their own addresses. This
+ situation typically occurs when the glue address RRs have a
+ smaller TTL than the NS RRs marking delegation, or when the
+ resolver caches the result of a NS search. The resolver
+ should detect this condition and restart the search at the
+ next ancestor zone, or alternatively at the root.
+
+
+
+
+
+Mockapetris [Page 45]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ - If a resolver gets a server error or other bizarre response
+ from a name server, it should remove it from SLIST, and may
+ wish to schedule an immediate transmission to the next
+ candidate server address.
+
+7.3. Processing responses
+
+The first step in processing arriving response datagrams is to parse the
+response. This procedure should include:
+
+ - Check the header for reasonableness. Discard datagrams which
+ are queries when responses are expected.
+
+ - Parse the sections of the message, and insure that all RRs are
+ correctly formatted.
+
+ - As an optional step, check the TTLs of arriving data looking
+ for RRs with excessively long TTLs. If a RR has an
+ excessively long TTL, say greater than 1 week, either discard
+ the whole response, or limit all TTLs in the response to 1
+ week.
+
+The next step is to match the response to a current resolver request.
+The recommended strategy is to do a preliminary matching using the ID
+field in the domain header, and then to verify that the question section
+corresponds to the information currently desired. This requires that
+the transmission algorithm devote several bits of the domain ID field to
+a request identifier of some sort. This step has several fine points:
+
+ - Some name servers send their responses from different
+ addresses than the one used to receive the query. That is, a
+ resolver cannot rely that a response will come from the same
+ address which it sent the corresponding query to. This name
+ server bug is typically encountered in UNIX systems.
+
+ - If the resolver retransmits a particular request to a name
+ server it should be able to use a response from any of the
+ transmissions. However, if it is using the response to sample
+ the round trip time to access the name server, it must be able
+ to determine which transmission matches the response (and keep
+ transmission times for each outgoing message), or only
+ calculate round trip times based on initial transmissions.
+
+ - A name server will occasionally not have a current copy of a
+ zone which it should have according to some NS RRs. The
+ resolver should simply remove the name server from the current
+ SLIST, and continue.
+
+
+
+
+Mockapetris [Page 46]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7.4. Using the cache
+
+In general, we expect a resolver to cache all data which it receives in
+responses since it may be useful in answering future client requests.
+However, there are several types of data which should not be cached:
+
+ - When several RRs of the same type are available for a
+ particular owner name, the resolver should either cache them
+ all or none at all. When a response is truncated, and a
+ resolver doesn't know whether it has a complete set, it should
+ not cache a possibly partial set of RRs.
+
+ - Cached data should never be used in preference to
+ authoritative data, so if caching would cause this to happen
+ the data should not be cached.
+
+ - The results of an inverse query should not be cached.
+
+ - The results of standard queries where the QNAME contains "*"
+ labels if the data might be used to construct wildcards. The
+ reason is that the cache does not necessarily contain existing
+ RRs or zone boundary information which is necessary to
+ restrict the application of the wildcard RRs.
+
+ - RR data in responses of dubious reliability. When a resolver
+ receives unsolicited responses or RR data other than that
+ requested, it should discard it without caching it. The basic
+ implication is that all sanity checks on a packet should be
+ performed before any of it is cached.
+
+In a similar vein, when a resolver has a set of RRs for some name in a
+response, and wants to cache the RRs, it should check its cache for
+already existing RRs. Depending on the circumstances, either the data
+in the response or the cache is preferred, but the two should never be
+combined. If the data in the response is from authoritative data in the
+answer section, it is always preferred.
+
+8. MAIL SUPPORT
+
+The domain system defines a standard for mapping mailboxes into domain
+names, and two methods for using the mailbox information to derive mail
+routing information. The first method is called mail exchange binding
+and the other method is mailbox binding. The mailbox encoding standard
+and mail exchange binding are part of the DNS official protocol, and are
+the recommended method for mail routing in the Internet. Mailbox
+binding is an experimental feature which is still under development and
+subject to change.
+
+
+
+
+Mockapetris [Page 47]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+The mailbox encoding standard assumes a mailbox name of the form
+"<local-part>@<mail-domain>". While the syntax allowed in each of these
+sections varies substantially between the various mail internets, the
+preferred syntax for the ARPA Internet is given in [RFC-822].
+
+The DNS encodes the <local-part> as a single label, and encodes the
+<mail-domain> as a domain name. The single label from the <local-part>
+is prefaced to the domain name from <mail-domain> to form the domain
+name corresponding to the mailbox. Thus the mailbox HOSTMASTER@SRI-
+NIC.ARPA is mapped into the domain name HOSTMASTER.SRI-NIC.ARPA. If the
+<local-part> contains dots or other special characters, its
+representation in a master file will require the use of backslash
+quoting to ensure that the domain name is properly encoded. For
+example, the mailbox Action.domains@ISI.EDU would be represented as
+Action\.domains.ISI.EDU.
+
+8.1. Mail exchange binding
+
+Mail exchange binding uses the <mail-domain> part of a mailbox
+specification to determine where mail should be sent. The <local-part>
+is not even consulted. [RFC-974] specifies this method in detail, and
+should be consulted before attempting to use mail exchange support.
+
+One of the advantages of this method is that it decouples mail
+destination naming from the hosts used to support mail service, at the
+cost of another layer of indirection in the lookup function. However,
+the addition layer should eliminate the need for complicated "%", "!",
+etc encodings in <local-part>.
+
+The essence of the method is that the <mail-domain> is used as a domain
+name to locate type MX RRs which list hosts willing to accept mail for
+<mail-domain>, together with preference values which rank the hosts
+according to an order specified by the administrators for <mail-domain>.
+
+In this memo, the <mail-domain> ISI.EDU is used in examples, together
+with the hosts VENERA.ISI.EDU and VAXA.ISI.EDU as mail exchanges for
+ISI.EDU. If a mailer had a message for Mockapetris@ISI.EDU, it would
+route it by looking up MX RRs for ISI.EDU. The MX RRs at ISI.EDU name
+VENERA.ISI.EDU and VAXA.ISI.EDU, and type A queries can find the host
+addresses.
+
+8.2. Mailbox binding (Experimental)
+
+In mailbox binding, the mailer uses the entire mail destination
+specification to construct a domain name. The encoded domain name for
+the mailbox is used as the QNAME field in a QTYPE=MAILB query.
+
+Several outcomes are possible for this query:
+
+
+
+Mockapetris [Page 48]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 1. The query can return a name error indicating that the mailbox
+ does not exist as a domain name.
+
+ In the long term, this would indicate that the specified
+ mailbox doesn't exist. However, until the use of mailbox
+ binding is universal, this error condition should be
+ interpreted to mean that the organization identified by the
+ global part does not support mailbox binding. The
+ appropriate procedure is to revert to exchange binding at
+ this point.
+
+ 2. The query can return a Mail Rename (MR) RR.
+
+ The MR RR carries new mailbox specification in its RDATA
+ field. The mailer should replace the old mailbox with the
+ new one and retry the operation.
+
+ 3. The query can return a MB RR.
+
+ The MB RR carries a domain name for a host in its RDATA
+ field. The mailer should deliver the message to that host
+ via whatever protocol is applicable, e.g., b,SMTP.
+
+ 4. The query can return one or more Mail Group (MG) RRs.
+
+ This condition means that the mailbox was actually a mailing
+ list or mail group, rather than a single mailbox. Each MG RR
+ has a RDATA field that identifies a mailbox that is a member
+ of the group. The mailer should deliver a copy of the
+ message to each member.
+
+ 5. The query can return a MB RR as well as one or more MG RRs.
+
+ This condition means the the mailbox was actually a mailing
+ list. The mailer can either deliver the message to the host
+ specified by the MB RR, which will in turn do the delivery to
+ all members, or the mailer can use the MG RRs to do the
+ expansion itself.
+
+In any of these cases, the response may include a Mail Information
+(MINFO) RR. This RR is usually associated with a mail group, but is
+legal with a MB. The MINFO RR identifies two mailboxes. One of these
+identifies a responsible person for the original mailbox name. This
+mailbox should be used for requests to be added to a mail group, etc.
+The second mailbox name in the MINFO RR identifies a mailbox that should
+receive error messages for mail failures. This is particularly
+appropriate for mailing lists when errors in member names should be
+reported to a person other than the one who sends a message to the list.
+
+
+
+Mockapetris [Page 49]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+New fields may be added to this RR in the future.
+
+
+9. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87] S. Dyer, F. Hsu, "Hesiod", Project Athena
+ Technical Plan - Name Service, April 1987, version 1.9.
+
+ Describes the fundamentals of the Hesiod name service.
+
+[IEN-116] J. Postel, "Internet Name Server", IEN-116,
+ USC/Information Sciences Institute, August 1979.
+
+ A name service obsoleted by the Domain Name System, but
+ still in use.
+
+[Quarterman 86] J. Quarterman, and J. Hoskins, "Notable Computer Networks",
+ Communications of the ACM, October 1986, volume 29, number
+ 10.
+
+[RFC-742] K. Harrenstien, "NAME/FINGER", RFC-742, Network
+ Information Center, SRI International, December 1977.
+
+[RFC-768] J. Postel, "User Datagram Protocol", RFC-768,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-793] J. Postel, "Transmission Control Protocol", RFC-793,
+ USC/Information Sciences Institute, September 1981.
+
+[RFC-799] D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+ September 1981.
+
+ Suggests introduction of a hierarchy in place of a flat
+ name space for the Internet.
+
+[RFC-805] J. Postel, "Computer Mail Meeting Notes", RFC-805,
+ USC/Information Sciences Institute, February 1982.
+
+[RFC-810] E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+ Internet Host Table Specification", RFC-810, Network
+ Information Center, SRI International, March 1982.
+
+ Obsolete. See RFC-952.
+
+[RFC-811] K. Harrenstien, V. White, and E. Feinler, "Hostnames
+ Server", RFC-811, Network Information Center, SRI
+ International, March 1982.
+
+
+
+
+Mockapetris [Page 50]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Obsolete. See RFC-953.
+
+[RFC-812] K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+ Network Information Center, SRI International, March
+ 1982.
+
+[RFC-819] Z. Su, and J. Postel, "The Domain Naming Convention for
+ Internet User Applications", RFC-819, Network
+ Information Center, SRI International, August 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-821] J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-830] Z. Su, "A Distributed System for Internet Name Service",
+ RFC-830, Network Information Center, SRI International,
+ October 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-882] P. Mockapetris, "Domain names - Concepts and
+ Facilities," RFC-882, USC/Information Sciences
+ Institute, November 1983.
+
+ Superseded by this memo.
+
+[RFC-883] P. Mockapetris, "Domain names - Implementation and
+ Specification," RFC-883, USC/Information Sciences
+ Institute, November 1983.
+
+ Superseded by this memo.
+
+[RFC-920] J. Postel and J. Reynolds, "Domain Requirements",
+ RFC-920, USC/Information Sciences Institute,
+ October 1984.
+
+ Explains the naming scheme for top level domains.
+
+[RFC-952] K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+ Table Specification", RFC-952, SRI, October 1985.
+
+ Specifies the format of HOSTS.TXT, the host/address
+ table replaced by the DNS.
+
+
+
+
+
+Mockapetris [Page 51]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+[RFC-953] K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+ RFC-953, SRI, October 1985.
+
+ This RFC contains the official specification of the
+ hostname server protocol, which is obsoleted by the DNS.
+ This TCP based protocol accesses information stored in
+ the RFC-952 format, and is used to obtain copies of the
+ host table.
+
+[RFC-973] P. Mockapetris, "Domain System Changes and
+ Observations", RFC-973, USC/Information Sciences
+ Institute, January 1986.
+
+ Describes changes to RFC-882 and RFC-883 and reasons for
+ them.
+
+[RFC-974] C. Partridge, "Mail routing and the domain system",
+ RFC-974, CSNET CIC BBN Labs, January 1986.
+
+ Describes the transition from HOSTS.TXT based mail
+ addressing to the more powerful MX system used with the
+ domain system.
+
+[RFC-1001] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Concepts and Methods",
+ RFC-1001, March 1987.
+
+ This RFC and RFC-1002 are a preliminary design for
+ NETBIOS on top of TCP/IP which proposes to base NetBIOS
+ name service on top of the DNS.
+
+[RFC-1002] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Detailed
+ Specifications", RFC-1002, March 1987.
+
+[RFC-1010] J. Reynolds, and J. Postel, "Assigned Numbers", RFC-1010,
+ USC/Information Sciences Institute, May 1987.
+
+ Contains socket numbers and mnemonics for host names,
+ operating systems, etc.
+
+[RFC-1031] W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+ November 1987.
+
+ Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032] M. Stahl, "Establishing a Domain - Guidelines for
+ Administrators", RFC-1032, November 1987.
+
+
+
+Mockapetris [Page 52]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Describes the registration policies used by the NIC to
+ administer the top level domains and delegate subzones.
+
+[RFC-1033] M. Lottor, "Domain Administrators Operations Guide",
+ RFC-1033, November 1987.
+
+ A cookbook for domain administrators.
+
+[Solomon 82] M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+ Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+ Describes a name service for CSNET which is independent
+ from the DNS and DNS use in the CSNET.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 53]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Index
+
+ * 13
+
+ ; 33, 35
+
+ <character-string> 35
+ <domain-name> 34
+
+ @ 35
+
+ \ 35
+
+ A 12
+
+ Byte order 8
+
+ CH 13
+ Character case 9
+ CLASS 11
+ CNAME 12
+ Completion 42
+ CS 13
+
+ Hesiod 13
+ HINFO 12
+ HS 13
+
+ IN 13
+ IN-ADDR.ARPA domain 22
+ Inverse queries 40
+
+ Mailbox names 47
+ MB 12
+ MD 12
+ MF 12
+ MG 12
+ MINFO 12
+ MINIMUM 20
+ MR 12
+ MX 12
+
+ NS 12
+ NULL 12
+
+ Port numbers 32
+ Primary server 5
+ PTR 12, 18
+
+
+
+Mockapetris [Page 54]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ QCLASS 13
+ QTYPE 12
+
+ RDATA 12
+ RDLENGTH 11
+
+ Secondary server 5
+ SOA 12
+ Stub resolvers 7
+
+ TCP 32
+ TXT 12
+ TYPE 11
+
+ UDP 32
+
+ WKS 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 55]
+
diff --git a/tests/dns/testdata/dst/test1.ecdsa256sig b/tests/dns/testdata/dst/test1.ecdsa256sig
new file mode 100644
index 0000000..dcae9d1
--- /dev/null
+++ b/tests/dns/testdata/dst/test1.ecdsa256sig
@@ -0,0 +1 @@
+72E0998732EECAE2BEA12A278DFDEE14DB09A43C1E646A08BB0A6EEB90C5B75F9B359BEC1580313BFA8012C1DC15D34D1B227C71AD23161E2757AEB162AE3D99
diff --git a/tests/dns/testdata/dst/test1.rsasha256sig b/tests/dns/testdata/dst/test1.rsasha256sig
new file mode 100644
index 0000000..36e0b09
--- /dev/null
+++ b/tests/dns/testdata/dst/test1.rsasha256sig
@@ -0,0 +1 @@
+C5CC8AB9FB5C0B4F03650456C993A868EB674ACBF2A867E023DC00F17D240CEDCADB8714981B7B48CF6CF86722632610FF312063B5E6D20EF441B89F02BC6813A35F9C6F045D017DB75C8724DBAA0C55A0D4EA850339944C75890B4DD0382AFA3E30E1CAA7B190C1B1FB17B5DD2279C0DF1049911E64198B3376070A34F38F4B
diff --git a/tests/dns/testdata/dst/test2.data b/tests/dns/testdata/dst/test2.data
new file mode 100644
index 0000000..a323bb3
--- /dev/null
+++ b/tests/dns/testdata/dst/test2.data
@@ -0,0 +1,3077 @@
+Network Working Group P. Mockapetris
+Request for Comments: 1035 ISI
+ November 1987
+Obsoletes: RFCs 882, 883, 973
+
+ DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
+
+
+1. STATUS OF THIS MEMO
+
+This RFC describes the details of the domain system and protocol, and
+assumes that the reader is familiar with the concepts discussed in a
+companion RFC, "Domain Names - Concepts and Facilities" [RFC-4301].
+
+The domain system is a mixture of functions and data types which are an
+official protocol and functions and data types which are still
+experimental. Since the domain system is intentionally extensible, new
+data types and experimental behavior should always be expected in parts
+of the system beyond the official protocol. The official protocol parts
+include standard queries, responses and the Internet class RR data
+formats (e.g., host addresses). Since the previous RFC set, several
+definitions have changed, so some previous definitions are obsolete.
+
+Experimental or obsolete features are clearly marked in these RFCs, and
+such information should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical. Distribution of this memo is unlimited.
+
+ Table of Contents
+
+ 1. STATUS OF THIS MEMO 1
+ 2. INTRODUCTION 3
+ 2.1. Overview 3
+ 2.2. Common configurations 4
+ 2.3. Conventions 7
+ 2.3.1. Preferred name syntax 7
+ 2.3.2. Data Transmission Order 8
+ 2.3.3. Character Case 9
+ 2.3.4. Size limits 10
+ 3. DOMAIN NAME SPACE AND RR DEFINITIONS 10
+ 3.1. Name space definitions 10
+ 3.2. RR definitions 11
+ 3.2.1. Format 11
+ 3.2.2. TYPE values 12
+ 3.2.3. QTYPE values 12
+ 3.2.4. CLASS values 13
+
+
+
+Mockapetris [Page 1]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 3.2.5. QCLASS values 13
+ 3.3. Standard RRs 13
+ 3.3.1. CNAME RDATA format 14
+ 3.3.2. HINFO RDATA format 14
+ 3.3.3. MB RDATA format (EXPERIMENTAL) 14
+ 3.3.4. MD RDATA format (Obsolete) 15
+ 3.3.5. MF RDATA format (Obsolete) 15
+ 3.3.6. MG RDATA format (EXPERIMENTAL) 16
+ 3.3.7. MINFO RDATA format (EXPERIMENTAL) 16
+ 3.3.8. MR RDATA format (EXPERIMENTAL) 17
+ 3.3.9. MX RDATA format 17
+ 3.3.10. NULL RDATA format (EXPERIMENTAL) 17
+ 3.3.11. NS RDATA format 18
+ 3.3.12. PTR RDATA format 18
+ 3.3.13. SOA RDATA format 19
+ 3.3.14. TXT RDATA format 20
+ 3.4. ARPA Internet specific RRs 20
+ 3.4.1. A RDATA format 20
+ 3.4.2. WKS RDATA format 21
+ 3.5. IN-ADDR.ARPA domain 22
+ 3.6. Defining new types, classes, and special namespaces 24
+ 4. MESSAGES 25
+ 4.1. Format 25
+ 4.1.1. Header section format 26
+ 4.1.2. Question section format 28
+ 4.1.3. Resource record format 29
+ 4.1.4. Message compression 30
+ 4.2. Transport 32
+ 4.2.1. UDP usage 32
+ 4.2.2. TCP usage 32
+ 5. MASTER FILES 33
+ 5.1. Format 33
+ 5.2. Use of master files to define zones 35
+ 5.3. Master file example 36
+ 6. NAME SERVER IMPLEMENTATION 37
+ 6.1. Architecture 37
+ 6.1.1. Control 37
+ 6.1.2. Database 37
+ 6.1.3. Time 39
+ 6.2. Standard query processing 39
+ 6.3. Zone refresh and reload processing 39
+ 6.4. Inverse queries (Optional) 40
+ 6.4.1. The contents of inverse queries and responses 40
+ 6.4.2. Inverse query and response example 41
+ 6.4.3. Inverse query processing 42
+
+
+
+
+
+
+Mockapetris [Page 2]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 6.5. Completion queries and responses 42
+ 7. RESOLVER IMPLEMENTATION 43
+ 7.1. Transforming a user request into a query 43
+ 7.2. Sending the queries 44
+ 7.3. Processing responses 46
+ 7.4. Using the cache 47
+ 8. MAIL SUPPORT 47
+ 8.1. Mail exchange binding 48
+ 8.2. Mailbox binding (Experimental) 48
+ 9. REFERENCES and BIBLIOGRAPHY 50
+ Index 54
+
+2. INTRODUCTION
+
+2.1. Overview
+
+The goal of domain names is to provide a mechanism for naming resources
+in such a way that the names are usable in different hosts, networks,
+protocol families, internets, and administrative organizations.
+
+From the user's point of view, domain names are useful as arguments to a
+local agent, called a resolver, which retrieves information associated
+with the domain name. Thus a user might ask for the host address or
+mail information associated with a particular domain name. To enable
+the user to request a particular type of information, an appropriate
+query type is passed to the resolver with the domain name. To the user,
+the domain tree is a single information space; the resolver is
+responsible for hiding the distribution of data among name servers from
+the user.
+
+From the resolver's point of view, the database that makes up the domain
+space is distributed among various name servers. Different parts of the
+domain space are stored in different name servers, although a particular
+data item will be stored redundantly in two or more name servers. The
+resolver starts with knowledge of at least one name server. When the
+resolver processes a user query it asks a known name server for the
+information; in return, the resolver either receives the desired
+information or a referral to another name server. Using these
+referrals, resolvers learn the identities and contents of other name
+servers. Resolvers are responsible for dealing with the distribution of
+the domain space and dealing with the effects of name server failure by
+consulting redundant databases in other servers.
+
+Name servers manage two kinds of data. The first kind of data held in
+sets called zones; each zone is the complete database for a particular
+"pruned" subtree of the domain space. This data is called
+authoritative. A name server periodically checks to make sure that its
+zones are up to date, and if not, obtains a new copy of updated zones
+
+
+
+Mockapetris [Page 3]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+from master files stored locally or in another name server. The second
+kind of data is cached data which was acquired by a local resolver.
+This data may be incomplete, but improves the performance of the
+retrieval process when non-local data is repeatedly accessed. Cached
+data is eventually discarded by a timeout mechanism.
+
+This functional structure isolates the problems of user interface,
+failure recovery, and distribution in the resolvers and isolates the
+database update and refresh problems in the name servers.
+
+2.2. Common configurations
+
+A host can participate in the domain name system in a number of ways,
+depending on whether the host runs programs that retrieve information
+from the domain system, name servers that answer queries from other
+hosts, or various combinations of both functions. The simplest, and
+perhaps most typical, configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | cache | |
+ +----------+ |
+
+User programs interact with the domain name space through resolvers; the
+format of user queries and user responses is specific to the host and
+its operating system. User queries will typically be operating system
+calls, and the resolver and its cache will be part of the host operating
+system. Less capable hosts may choose to implement the resolver as a
+subroutine to be linked in with every program that needs its services.
+Resolvers answer user queries with information they acquire via queries
+to foreign name servers and the local cache.
+
+Note that the resolver may have to make several queries to several
+different foreign name servers to answer a particular user query, and
+hence the resolution of a user query may involve several network
+accesses and an arbitrary amount of time. The queries to foreign name
+servers and the corresponding responses have a standard format described
+
+
+
+Mockapetris [Page 4]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in this memo, and may be datagrams.
+
+Depending on its capabilities, a name server could be a stand alone
+program on a dedicated machine or a process or processes on a large
+timeshared host. A simple configuration might be:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+
+Here a primary name server acquires information about one or more zones
+by reading master files from its local file system, and answers queries
+about those zones that arrive from foreign resolvers.
+
+The DNS requires that all zones be redundantly supported by more than
+one name server. Designated secondary servers can acquire zones and
+check for updates from the primary server using the zone transfer
+protocol of the DNS. This configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+In this configuration, the name server periodically establishes a
+virtual circuit to a foreign name server to acquire a copy of a zone or
+to check that an existing copy has not changed. The messages sent for
+
+
+
+Mockapetris [Page 5]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+these maintenance activities follow the same form as queries and
+responses, but the message sequences are somewhat different.
+
+The information flow in a host that supports all aspects of the domain
+name system is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | Shared | |
+ | database | |
+ +----------+ |
+ A | |
+ +---------+ refreshes | | references |
+ / /| | V |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+The shared database holds domain space data for the local name server
+and resolver. The contents of the shared database will typically be a
+mixture of authoritative data maintained by the periodic refresh
+operations of the name server and cached data from previous resolver
+requests. The structure of the domain data and the necessity for
+synchronization between name servers and resolvers imply the general
+characteristics of this database, but the actual format is up to the
+local implementor.
+
+
+
+
+Mockapetris [Page 6]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Information flow can also be tailored so that a group of hosts act
+together to optimize activities. Sometimes this is done to offload less
+capable hosts so that they do not have to implement a full resolver.
+This can be appropriate for PCs or hosts which want to minimize the
+amount of new network code which is required. This scheme can also
+allow a group of hosts can share a small number of caches rather than
+maintaining a large number of separate caches, on the premise that the
+centralized caches will have a higher hit ratio. In either case,
+resolvers are replaced with stub resolvers which act as front ends to
+resolvers located in a recursive server in one or more name servers
+known to perform that service:
+
+ Local Hosts | Foreign
+ |
+ +---------+ |
+ | | responses |
+ | Stub |<--------------------+ |
+ | Resolver| | |
+ | |----------------+ | |
+ +---------+ recursive | | |
+ queries | | |
+ V | |
+ +---------+ recursive +----------+ | +--------+
+ | | queries | |queries | | |
+ | Stub |-------------->| Recursive|---------|->|Foreign |
+ | Resolver| | Server | | | Name |
+ | |<--------------| |<--------|--| Server |
+ +---------+ responses | |responses| | |
+ +----------+ | +--------+
+ | Central | |
+ | cache | |
+ +----------+ |
+
+In any case, note that domain components are always replicated for
+reliability whenever possible.
+
+2.3. Conventions
+
+The domain system has several conventions dealing with low-level, but
+fundamental, issues. While the implementor is free to violate these
+conventions WITHIN HIS OWN SYSTEM, he must observe these conventions in
+ALL behavior observed from other hosts.
+
+2.3.1. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+for constructing domain names. The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+
+
+
+Mockapetris [Page 7]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822. When creating a new host name,
+the old rules for HOSTS.TXT should be followed. This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case. That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names. They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen. There are also some
+restrictions on the length. Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA
+
+2.3.2. Data Transmission Order
+
+The order of transmission of the header and data described in this
+document is resolved to the octet level. Whenever a diagram shows a
+
+
+
+Mockapetris [Page 8]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+group of octets, the order of transmission of those octets is the normal
+order in which they are read in English. For example, in the following
+diagram, the octets are transmitted in the order they are numbered.
+
+ 0 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 1 | 2 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 3 | 4 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 5 | 6 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Whenever an octet represents a numeric quantity, the left most bit in
+the diagram is the high order or most significant bit. That is, the bit
+labeled 0 is the most significant bit. For example, the following
+diagram represents the value 170 (decimal).
+
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |1 0 1 0 1 0 1 0|
+ +-+-+-+-+-+-+-+-+
+
+Similarly, whenever a multi-octet field represents a numeric quantity
+the left most bit of the whole field is the most significant bit. When
+a multi-octet quantity is transmitted the most significant octet is
+transmitted first.
+
+2.3.3. Character Case
+
+For all parts of the DNS that are part of the official protocol, all
+comparisons between character strings (e.g., labels, domain names, etc.)
+are done in a case-insensitive manner. At present, this rule is in
+force throughout the domain system without exception. However, future
+additions beyond current usage may need to use the full binary octet
+capabilities in names, so attempts to store domain names in 7-bit ASCII
+or use of special bytes to terminate labels, etc., should be avoided.
+
+When data enters the domain system, its original case should be
+preserved whenever possible. In certain circumstances this cannot be
+done. For example, if two RRs are stored in a database, one at x.y and
+one at X.Y, they are actually stored at the same place in the database,
+and hence only one casing would be preserved. The basic rule is that
+case can be discarded only when data is used to define structure in a
+database, and two names are identical when compared in a case
+insensitive manner.
+
+
+
+
+Mockapetris [Page 9]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Loss of case sensitive data must be minimized. Thus while data for x.y
+and X.Y may both be stored under a single location x.y or X.Y, data for
+a.x and B.X would never be stored under A.x, A.X, b.x, or b.X. In
+general, this preserves the case of the first label of a domain name,
+but forces standardization of interior node labels.
+
+Systems administrators who enter data into the domain database should
+take care to represent the data they supply to the domain system in a
+case-consistent manner if their system is case-sensitive. The data
+distribution system in the domain system will ensure that consistent
+representations are preserved.
+
+2.3.4. Size limits
+
+Various objects and parameters in the DNS have size limits. They are
+listed below. Some could be easily changed, others are more
+fundamental.
+
+labels 63 octets or less
+
+names 255 octets or less
+
+TTL positive values of a signed 32 bit number.
+
+UDP messages 512 octets or less
+
+3. DOMAIN NAME SPACE AND RR DEFINITIONS
+
+3.1. Name space definitions
+
+Domain names in messages are expressed in terms of a sequence of labels.
+Each label is represented as a one octet length field followed by that
+number of octets. Since every domain name ends with the null label of
+the root, a domain name is terminated by a length byte of zero. The
+high order two bits of every length octet must be zero, and the
+remaining six bits of the length field limit the label to 63 octets or
+less.
+
+To simplify implementations, the total length of a domain name (i.e.,
+label octets and label length octets) is restricted to 255 octets or
+less.
+
+Although labels can contain any 8 bit values in octets that make up a
+label, it is strongly recommended that labels follow the preferred
+syntax described elsewhere in this memo, which is compatible with
+existing host naming conventions. Name servers and resolvers must
+compare labels in a case-insensitive manner (i.e., A=a), assuming ASCII
+with zero parity. Non-alphabetic codes must match exactly.
+
+
+
+Mockapetris [Page 10]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.2. RR definitions
+
+3.2.1. Format
+
+All RRs have the same top level format shown below:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+
+where:
+
+NAME an owner name, i.e., the name of the node to which this
+ resource record pertains.
+
+TYPE two octets containing one of the RR TYPE codes.
+
+CLASS two octets containing one of the RR CLASS codes.
+
+TTL a 32 bit signed integer that specifies the time interval
+ that the resource record may be cached before the source
+ of the information should again be consulted. Zero
+ values are interpreted to mean that the RR can only be
+ used for the transaction in progress, and should not be
+ cached. For example, SOA records are always distributed
+ with a zero TTL to prohibit caching. Zero values can
+ also be used for extremely volatile data.
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+
+
+Mockapetris [Page 11]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+
+3.2.2. TYPE values
+
+TYPE fields are used in resource records. Note that these types are a
+subset of QTYPEs.
+
+TYPE value and meaning
+
+A 1 a host address
+
+NS 2 an authoritative name server
+
+MD 3 a mail destination (Obsolete - use MX)
+
+MF 4 a mail forwarder (Obsolete - use MX)
+
+CNAME 5 the canonical name for an alias
+
+SOA 6 marks the start of a zone of authority
+
+MB 7 a mailbox domain name (EXPERIMENTAL)
+
+MG 8 a mail group member (EXPERIMENTAL)
+
+MR 9 a mail rename domain name (EXPERIMENTAL)
+
+NULL 10 a null RR (EXPERIMENTAL)
+
+WKS 11 a well known service description
+
+PTR 12 a domain name pointer
+
+HINFO 13 host information
+
+MINFO 14 mailbox or mail list information
+
+MX 15 mail exchange
+
+TXT 16 text strings
+
+3.2.3. QTYPE values
+
+QTYPE fields appear in the question part of a query. QTYPES are a
+superset of TYPEs, hence all TYPEs are valid QTYPEs. In addition, the
+following QTYPEs are defined:
+
+
+
+Mockapetris [Page 12]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+AXFR 252 A request for a transfer of an entire zone
+
+MAILB 253 A request for mailbox-related records (MB, MG or MR)
+
+MAILA 254 A request for mail agent RRs (Obsolete - see MX)
+
+* 255 A request for all records
+
+3.2.4. CLASS values
+
+CLASS fields appear in resource records. The following CLASS mnemonics
+and values are defined:
+
+IN 1 the Internet
+
+CS 2 the CSNET class (Obsolete - used only for examples in
+ some obsolete RFCs)
+
+CH 3 the CHAOS class
+
+HS 4 Hesiod [Dyer 87]
+
+3.2.5. QCLASS values
+
+QCLASS fields appear in the question section of a query. QCLASS values
+are a superset of CLASS values; every CLASS is a valid QCLASS. In
+addition to CLASS values, the following QCLASSes are defined:
+
+* 255 any class
+
+3.3. Standard RRs
+
+The following RR definitions are expected to occur, at least
+potentially, in all classes. In particular, NS, SOA, CNAME, and PTR
+will be used in all classes, and have the same format in all classes.
+Because their RDATA format is known, all domain names in the RDATA
+section of these RRs may be compressed.
+
+<domain-name> is a domain name represented as a series of labels, and
+terminated by a label with zero length. <character-string> is a single
+length octet followed by that number of characters. <character-string>
+is treated as binary information, and can be up to 256 characters in
+length (including the length octet).
+
+
+
+
+
+
+
+
+Mockapetris [Page 13]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.1. CNAME RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CNAME A <domain-name> which specifies the canonical or primary
+ name for the owner. The owner name is an alias.
+
+CNAME RRs cause no additional section processing, but name servers may
+choose to restart the query at the canonical name in certain cases. See
+the description of name server logic in [RFC-1034] for details.
+
+3.3.2. HINFO RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CPU /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / OS /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CPU A <character-string> which specifies the CPU type.
+
+OS A <character-string> which specifies the operating
+ system type.
+
+Standard values for CPU and OS can be found in [RFC-1010].
+
+HINFO records are used to acquire general information about a host. The
+main use is for protocols such as FTP that can use special procedures
+when talking between machines or operating systems of the same type.
+
+3.3.3. MB RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has the
+ specified mailbox.
+
+
+
+Mockapetris [Page 14]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MB records cause additional section processing which looks up an A type
+RRs corresponding to MADNAME.
+
+3.3.4. MD RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which should be able to deliver
+ mail for the domain.
+
+MD records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MD is obsolete. See the definition of MX and [RFC-974] for details of
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 0.
+
+3.3.5. MF RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which will accept mail for
+ forwarding to the domain.
+
+MF records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MF is obsolete. See the definition of MX and [RFC-974] for details ofw
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 10.
+
+
+
+
+
+
+
+Mockapetris [Page 15]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.6. MG RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MGMNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MGMNAME A <domain-name> which specifies a mailbox which is a
+ member of the mail group specified by the domain name.
+
+MG records cause no additional section processing.
+
+3.3.7. MINFO RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+RMAILBX A <domain-name> which specifies a mailbox which is
+ responsible for the mailing list or mailbox. If this
+ domain name names the root, the owner of the MINFO RR is
+ responsible for itself. Note that many existing mailing
+ lists use a mailbox X-request for the RMAILBX field of
+ mailing list X, e.g., Msgroup-request for Msgroup. This
+ field provides a more general mechanism.
+
+
+EMAILBX A <domain-name> which specifies a mailbox which is to
+ receive error messages related to the mailing list or
+ mailbox specified by the owner of the MINFO RR (similar
+ to the ERRORS-TO: field which has been proposed). If
+ this domain name names the root, errors should be
+ returned to the sender of the message.
+
+MINFO records cause no additional section processing. Although these
+records can be associated with a simple mailbox, they are usually used
+with a mailing list.
+
+
+
+
+
+
+
+
+Mockapetris [Page 16]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.8. MR RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NEWNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NEWNAME A <domain-name> which specifies a mailbox which is the
+ proper rename of the specified mailbox.
+
+MR records cause no additional section processing. The main use for MR
+is as a forwarding entry for a user who has moved to a different
+mailbox.
+
+3.3.9. MX RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PREFERENCE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EXCHANGE /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PREFERENCE A 16 bit integer which specifies the preference given to
+ this RR among others at the same owner. Lower values
+ are preferred.
+
+EXCHANGE A <domain-name> which specifies a host willing to act as
+ a mail exchange for the owner name.
+
+MX records cause type A additional section processing for the host
+specified by EXCHANGE. The use of MX RRs is explained in detail in
+[RFC-974].
+
+3.3.10. NULL RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / <anything> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+Anything at all may be in the RDATA field so long as it is 65535 octets
+or less.
+
+
+
+
+Mockapetris [Page 17]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+NULL records cause no additional section processing. NULL RRs are not
+allowed in master files. NULLs are used as placeholders in some
+experimental extensions of the DNS.
+
+3.3.11. NS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NSDNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NSDNAME A <domain-name> which specifies a host which should be
+ authoritative for the specified class and domain.
+
+NS records cause both the usual additional section processing to locate
+a type A record, and, when used in a referral, a special search of the
+zone in which they reside for glue information.
+
+The NS RR states that the named host should be expected to have a zone
+starting at owner name of the specified class. Note that the class may
+not indicate the protocol family which should be used to communicate
+with the host, although it is typically a strong hint. For example,
+hosts which are name servers for either Internet (IN) or Hesiod (HS)
+class information are normally queried using IN class protocols.
+
+3.3.12. PTR RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / PTRDNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PTRDNAME A <domain-name> which points to some location in the
+ domain name space.
+
+PTR records cause no additional section processing. These RRs are used
+in special domains to point to some other location in the domain space.
+These records are simple data, and don't imply any special processing
+similar to that performed by CNAME, which identifies aliases. See the
+description of the IN-ADDR.ARPA domain for an example.
+
+
+
+
+
+
+
+
+Mockapetris [Page 18]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.13. SOA RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | SERIAL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | REFRESH |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RETRY |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | EXPIRE |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | MINIMUM |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MNAME The <domain-name> of the name server that was the
+ original or primary source of data for this zone.
+
+RNAME A <domain-name> which specifies the mailbox of the
+ person responsible for this zone.
+
+SERIAL The unsigned 32 bit version number of the original copy
+ of the zone. Zone transfers preserve this value. This
+ value wraps and should be compared using sequence space
+ arithmetic.
+
+REFRESH A 32 bit time interval before the zone should be
+ refreshed.
+
+RETRY A 32 bit time interval that should elapse before a
+ failed refresh should be retried.
+
+EXPIRE A 32 bit time value that specifies the upper limit on
+ the time interval that can elapse before the zone is no
+ longer authoritative.
+
+
+
+
+
+Mockapetris [Page 19]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MINIMUM The unsigned 32 bit minimum TTL field that should be
+ exported with any RR from this zone.
+
+SOA records cause no additional section processing.
+
+All times are in units of seconds.
+
+Most of these fields are pertinent only for name server maintenance
+operations. However, MINIMUM is used in all query operations that
+retrieve RRs from a zone. Whenever a RR is sent in a response to a
+query, the TTL field is set to the maximum of the TTL field from the RR
+and the MINIMUM field in the appropriate SOA. Thus MINIMUM is a lower
+bound on the TTL field for all RRs in a zone. Note that this use of
+MINIMUM should occur when the RRs are copied into the response and not
+when the zone is loaded from a master file or via a zone transfer. The
+reason for this provison is to allow future dynamic update facilities to
+change the SOA RR with known semantics.
+
+
+3.3.14. TXT RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / TXT-DATA /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+TXT-DATA One or more <character-string>s.
+
+TXT RRs are used to hold descriptive text. The semantics of the text
+depends on the domain where it is found.
+
+3.4. Internet specific RRs
+
+3.4.1. A RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS A 32 bit Internet address.
+
+Hosts that have multiple Internet addresses will have multiple A
+records.
+
+
+
+
+
+Mockapetris [Page 20]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+A records cause no additional section processing. The RDATA section of
+an A line in a master file is an Internet address expressed as four
+decimal numbers separated by dots without any embedded spaces (e.g.,
+"10.2.0.52" or "192.0.5.6").
+
+3.4.2. WKS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PROTOCOL | |
+ +--+--+--+--+--+--+--+--+ |
+ | |
+ / <BIT MAP> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS An 32 bit Internet address
+
+PROTOCOL An 8 bit IP protocol number
+
+<BIT MAP> A variable length bit map. The bit map must be a
+ multiple of 8 bits long.
+
+The WKS record is used to describe the well known services supported by
+a particular protocol on a particular internet address. The PROTOCOL
+field specifies an IP protocol number, and the bit map has one bit per
+port of the specified protocol. The first bit corresponds to port 0,
+the second to port 1, etc. If the bit map does not include a bit for a
+protocol of interest, that bit is assumed zero. The appropriate values
+and mnemonics for ports and protocols are specified in [RFC-1010].
+
+For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port
+25 (SMTP). If this bit is set, a SMTP server should be listening on TCP
+port 25; if zero, SMTP service is not supported on the specified
+address.
+
+The purpose of WKS RRs is to provide availability information for
+servers for TCP and UDP. If a server supports both TCP and UDP, or has
+multiple Internet addresses, then multiple WKS RRs are used.
+
+WKS RRs cause no additional section processing.
+
+In master files, both ports and protocols are expressed using mnemonics
+or decimal numbers.
+
+
+
+
+Mockapetris [Page 21]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.5. IN-ADDR.ARPA domain
+
+The Internet uses a special domain to support gateway location and
+Internet address to host mapping. Other classes may employ a similar
+strategy in other domains. The intent of this domain is to provide a
+guaranteed method to perform host address to host name mapping, and to
+facilitate queries to locate all gateways on a particular network in the
+Internet.
+
+Note that both of these services are similar to functions that could be
+performed by inverse queries; the difference is that this part of the
+domain name space is structured according to address, and hence can
+guarantee that the appropriate data can be located without an exhaustive
+search of the domain space.
+
+The domain begins at IN-ADDR.ARPA and has a substructure which follows
+the Internet addressing structure.
+
+Domain names in the IN-ADDR.ARPA domain are defined to have up to four
+labels in addition to the IN-ADDR.ARPA suffix. Each label represents
+one octet of an Internet address, and is expressed as a character string
+for a decimal value in the range 0-255 (with leading zeros omitted
+except in the case of a zero octet which is represented by a single
+zero).
+
+Host addresses are represented by domain names that have all four labels
+specified. Thus data for Internet address 10.2.0.52 is located at
+domain name 52.0.2.10.IN-ADDR.ARPA. The reversal, though awkward to
+read, allows zones to be delegated which are exactly one network of
+address space. For example, 10.IN-ADDR.ARPA can be a zone containing
+data for the ARPANET, while 26.IN-ADDR.ARPA can be a separate zone for
+MILNET. Address nodes are used to hold pointers to primary host names
+in the normal domain space.
+
+Network numbers correspond to some non-terminal nodes at various depths
+in the IN-ADDR.ARPA domain, since Internet network numbers are either 1,
+2, or 3 octets. Network nodes are used to hold pointers to the primary
+host names of gateways attached to that network. Since a gateway is, by
+definition, on more than one network, it will typically have two or more
+network nodes which point at it. Gateways will also have host level
+pointers at their fully qualified addresses.
+
+Both the gateway pointers at network nodes and the normal host pointers
+at full address nodes use the PTR RR to point back to the primary domain
+names of the corresponding hosts.
+
+For example, the IN-ADDR.ARPA domain will contain information about the
+ISI gateway between net 10 and 26, an MIT gateway from net 10 to MIT's
+
+
+
+Mockapetris [Page 22]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+net 18, and hosts A.ISI.EDU and MULTICS.MIT.EDU. Assuming that ISI
+gateway has addresses 10.2.0.22 and 26.0.0.103, and a name MILNET-
+GW.ISI.EDU, and the MIT gateway has addresses 10.0.0.77 and 18.10.0.4
+and a name GW.LCS.MIT.EDU, the domain database would contain:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 22.0.2.10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 103.0.0.26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 77.0.0.10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 4.0.10.18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 103.0.3.26.IN-ADDR.ARPA. PTR A.ISI.EDU.
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Thus a program which wanted to locate gateways on net 10 would originate
+a query of the form QTYPE=PTR, QCLASS=IN, QNAME=10.IN-ADDR.ARPA. It
+would receive two RRs in response:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+
+The program could then originate QTYPE=A, QCLASS=IN queries for MILNET-
+GW.ISI.EDU. and GW.LCS.MIT.EDU. to discover the Internet addresses of
+these gateways.
+
+A resolver which wanted to find the host name corresponding to Internet
+host address 10.0.0.6 would pursue a query of the form QTYPE=PTR,
+QCLASS=IN, QNAME=6.0.0.10.IN-ADDR.ARPA, and would receive:
+
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Several cautions apply to the use of these services:
+ - Since the IN-ADDR.ARPA special domain and the normal domain
+ for a particular host or gateway will be in different zones,
+ the possibility exists that that the data may be inconsistent.
+
+ - Gateways will often have two names in separate domains, only
+ one of which can be primary.
+
+ - Systems that use the domain database to initialize their
+ routing tables must start with enough gateway information to
+ guarantee that they can access the appropriate name server.
+
+ - The gateway data only reflects the existence of a gateway in a
+ manner equivalent to the current HOSTS.TXT file. It doesn't
+ replace the dynamic availability information from GGP or EGP.
+
+
+
+Mockapetris [Page 23]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.6. Defining new types, classes, and special namespaces
+
+The previously defined types and classes are the ones in use as of the
+date of this memo. New definitions should be expected. This section
+makes some recommendations to designers considering additions to the
+existing facilities. The mailing list NAMEDROPPERS@SRI-NIC.ARPA is the
+forum where general discussion of design issues takes place.
+
+In general, a new type is appropriate when new information is to be
+added to the database about an existing object, or we need new data
+formats for some totally new object. Designers should attempt to define
+types and their RDATA formats that are generally applicable to all
+classes, and which avoid duplication of information. New classes are
+appropriate when the DNS is to be used for a new protocol, etc which
+requires new class-specific data formats, or when a copy of the existing
+name space is desired, but a separate management domain is necessary.
+
+New types and classes need mnemonics for master files; the format of the
+master files requires that the mnemonics for type and class be disjoint.
+
+TYPE and CLASS values must be a proper subset of QTYPEs and QCLASSes
+respectively.
+
+The present system uses multiple RRs to represent multiple values of a
+type rather than storing multiple values in the RDATA section of a
+single RR. This is less efficient for most applications, but does keep
+RRs shorter. The multiple RRs assumption is incorporated in some
+experimental work on dynamic update methods.
+
+The present system attempts to minimize the duplication of data in the
+database in order to insure consistency. Thus, in order to find the
+address of the host for a mail exchange, you map the mail domain name to
+a host name, then the host name to addresses, rather than a direct
+mapping to host address. This approach is preferred because it avoids
+the opportunity for inconsistency.
+
+In defining a new type of data, multiple RR types should not be used to
+create an ordering between entries or express different formats for
+equivalent bindings, instead this information should be carried in the
+body of the RR and a single type used. This policy avoids problems with
+caching multiple types and defining QTYPEs to match multiple types.
+
+For example, the original form of mail exchange binding used two RR
+types one to represent a "closer" exchange (MD) and one to represent a
+"less close" exchange (MF). The difficulty is that the presence of one
+RR type in a cache doesn't convey any information about the other
+because the query which acquired the cached information might have used
+a QTYPE of MF, MD, or MAILA (which matched both). The redesigned
+
+
+
+Mockapetris [Page 24]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+service used a single type (MX) with a "preference" value in the RDATA
+section which can order different RRs. However, if any MX RRs are found
+in the cache, then all should be there.
+
+4. MESSAGES
+
+4.1. Format
+
+All communications inside of the domain protocol are carried in a single
+format called a message. The top level format of message is divided
+into 5 sections (some of which are empty in certain cases) shown below:
+
+ +---------------------+
+ | Header |
+ +---------------------+
+ | Question | the question for the name server
+ +---------------------+
+ | Answer | RRs answering the question
+ +---------------------+
+ | Authority | RRs pointing toward an authority
+ +---------------------+
+ | Additional | RRs holding additional information
+ +---------------------+
+
+The header section is always present. The header includes fields that
+specify which of the remaining sections are present, and also specify
+whether the message is a query or a response, a standard query or some
+other opcode, etc.
+
+The names of the sections after the header are derived from their use in
+standard queries. The question section contains fields that describe a
+question to a name server. These fields are a query type (QTYPE), a
+query class (QCLASS), and a query domain name (QNAME). The last three
+sections have the same format: a possibly empty list of concatenated
+resource records (RRs). The answer section contains RRs that answer the
+question; the authority section contains RRs that point toward an
+authoritative name server; the additional records section contains RRs
+which relate to the query, but are not strictly answers for the
+question.
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 25]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+4.1.1. Header section format
+
+The header contains the following fields:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ID |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QDCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ANCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | NSCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ARCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ID A 16 bit identifier assigned by the program that
+ generates any kind of query. This identifier is copied
+ the corresponding reply and can be used by the requester
+ to match up replies to outstanding queries.
+
+QR A one bit field that specifies whether this message is a
+ query (0), or a response (1).
+
+OPCODE A four bit field that specifies kind of query in this
+ message. This value is set by the originator of a query
+ and copied into the response. The values are:
+
+ 0 a standard query (QUERY)
+
+ 1 an inverse query (IQUERY)
+
+ 2 a server status request (STATUS)
+
+ 3-15 reserved for future use
+
+AA Authoritative Answer - this bit is valid in responses,
+ and specifies that the responding name server is an
+ authority for the domain name in question section.
+
+ Note that the contents of the answer section may have
+ multiple owner names because of aliases. The AA bit
+
+
+
+Mockapetris [Page 26]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ corresponds to the name which matches the query name, or
+ the first owner name in the answer section.
+
+TC TrunCation - specifies that this message was truncated
+ due to length greater than that permitted on the
+ transmission channel.
+
+RD Recursion Desired - this bit may be set in a query and
+ is copied into the response. If RD is set, it directs
+ the name server to pursue the query recursively.
+ Recursive query support is optional.
+
+RA Recursion Available - this be is set or cleared in a
+ response, and denotes whether recursive query support is
+ available in the name server.
+
+Z Reserved for future use. Must be zero in all queries
+ and responses.
+
+RCODE Response code - this 4 bit field is set as part of
+ responses. The values have the following
+ interpretation:
+
+ 0 No error condition
+
+ 1 Format error - The name server was
+ unable to interpret the query.
+
+ 2 Server failure - The name server was
+ unable to process this query due to a
+ problem with the name server.
+
+ 3 Name Error - Meaningful only for
+ responses from an authoritative name
+ server, this code signifies that the
+ domain name referenced in the query does
+ not exist.
+
+ 4 Not Implemented - The name server does
+ not support the requested kind of query.
+
+ 5 Refused - The name server refuses to
+ perform the specified operation for
+ policy reasons. For example, a name
+ server may not wish to provide the
+ information to the particular requester,
+ or a name server may not wish to perform
+ a particular operation (e.g., zone
+
+
+
+Mockapetris [Page 27]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ transfer) for particular data.
+
+ 6-15 Reserved for future use.
+
+QDCOUNT an unsigned 16 bit integer specifying the number of
+ entries in the question section.
+
+ANCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the answer section.
+
+NSCOUNT an unsigned 16 bit integer specifying the number of name
+ server resource records in the authority records
+ section.
+
+ARCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the additional records section.
+
+4.1.2. Question section format
+
+The question section is used to carry the "question" in most queries,
+i.e., the parameters that define what is being asked. The section
+contains QDCOUNT (usually 1) entries, each of the following format:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / QNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QTYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QCLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+QNAME a domain name represented as a sequence of labels, where
+ each label consists of a length octet followed by that
+ number of octets. The domain name terminates with the
+ zero length octet for the null label of the root. Note
+ that this field may be an odd number of octets; no
+ padding is used.
+
+QTYPE a two octet code which specifies the type of the query.
+ The values for this field include all codes valid for a
+ TYPE field, together with some more general codes which
+ can match more than one type of RR.
+
+
+
+Mockapetris [Page 28]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+QCLASS a two octet code that specifies the class of the query.
+ For example, the QCLASS field is IN for the Internet.
+
+4.1.3. Resource record format
+
+The answer, authority, and additional sections all share the same
+format: a variable number of resource records, where the number of
+records is specified in the corresponding count field in the header.
+Each resource record has the following format:
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NAME a domain name to which this resource record pertains.
+
+TYPE two octets containing one of the RR type codes. This
+ field specifies the meaning of the data in the RDATA
+ field.
+
+CLASS two octets which specify the class of the data in the
+ RDATA field.
+
+TTL a 32 bit unsigned integer that specifies the time
+ interval (in seconds) that the resource record may be
+ cached before it should be discarded. Zero values are
+ interpreted to mean that the RR can only be used for the
+ transaction in progress, and should not be cached.
+
+
+
+
+
+Mockapetris [Page 29]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+ For example, the if the TYPE is A and the CLASS is IN,
+ the RDATA field is a 4 octet ARPA Internet address.
+
+4.1.4. Message compression
+
+In order to reduce the size of messages, the domain system utilizes a
+compression scheme which eliminates the repetition of domain names in a
+message. In this scheme, an entire domain name or a list of labels at
+the end of a domain name is replaced with a pointer to a prior occurrence
+of the same name.
+
+The pointer takes the form of a two octet sequence:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | 1 1| OFFSET |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The first two bits are ones. This allows a pointer to be distinguished
+from a label, since the label must begin with two zero bits because
+labels are restricted to 63 octets or less. (The 10 and 01 combinations
+are reserved for future use.) The OFFSET field specifies an offset from
+the start of the message (i.e., the first octet of the ID field in the
+domain header). A zero offset specifies the first byte of the ID field,
+etc.
+
+The compression scheme allows a domain name in a message to be
+represented as either:
+
+ - a sequence of labels ending in a zero octet
+
+ - a pointer
+
+ - a sequence of labels ending with a pointer
+
+Pointers can only be used for occurrences of a domain name where the
+format is not class specific. If this were not the case, a name server
+or resolver would be required to know the format of all RRs it handled.
+As yet, there are no such cases, but they may occur in future RDATA
+formats.
+
+If a domain name is contained in a part of the message subject to a
+length field (such as the RDATA section of an RR), and compression is
+
+
+
+Mockapetris [Page 30]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+used, the length of the compressed name is used in the length
+calculation, rather than the length of the expanded name.
+
+Programs are free to avoid using pointers in messages they generate,
+although this will reduce datagram capacity, and may cause truncation.
+However all programs are required to understand arriving messages that
+contain pointers.
+
+For example, a datagram might need to use the domain names F.ISI.ARPA,
+FOO.F.ISI.ARPA, ARPA, and the root. Ignoring the other fields of the
+message, these domain names might be represented as:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 20 | 1 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 22 | 3 | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 24 | S | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 26 | 4 | A |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 28 | R | P |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 30 | A | 0 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 40 | 3 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 42 | O | O |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 44 | 1 1| 20 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 64 | 1 1| 26 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 92 | 0 | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The domain name for F.ISI.ARPA is shown at offset 20. The domain name
+FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to
+concatenate a label for FOO to the previously defined F.ISI.ARPA. The
+domain name ARPA is defined at offset 64 using a pointer to the ARPA
+component of the name F.ISI.ARPA at 20; note that this pointer relies on
+ARPA being the last label in the string at 20. The root domain name is
+
+
+
+Mockapetris [Page 31]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+defined by a single octet of zeros at 92; the root domain name has no
+labels.
+
+4.2. Transport
+
+The DNS assumes that messages will be transmitted as datagrams or in a
+byte stream carried by a virtual circuit. While virtual circuits can be
+used for any DNS activity, datagrams are preferred for queries due to
+their lower overhead and better performance. Zone refresh activities
+must use virtual circuits because of the need for reliable transfer.
+
+The Internet supports name server access using TCP [RFC-793] on server
+port 53 (decimal) as well as datagram access using UDP [RFC-768] on UDP
+port 53 (decimal).
+
+4.2.1. UDP usage
+
+Messages sent using UDP user server port 53 (decimal).
+
+Messages carried by UDP are restricted to 512 bytes (not counting the IP
+or UDP headers). Longer messages are truncated and the TC bit is set in
+the header.
+
+UDP is not acceptable for zone transfers, but is the recommended method
+for standard queries in the Internet. Queries sent using UDP may be
+lost, and hence a retransmission strategy is required. Queries or their
+responses may be reordered by the network, or by processing in name
+servers, so resolvers should not depend on them being returned in order.
+
+The optimal UDP retransmission policy will vary with performance of the
+Internet and the needs of the client, but the following are recommended:
+
+ - The client should try other servers and server addresses
+ before repeating a query to a specific address of a server.
+
+ - The retransmission interval should be based on prior
+ statistics if possible. Too aggressive retransmission can
+ easily slow responses for the community at large. Depending
+ on how well connected the client is to its expected servers,
+ the minimum retransmission interval should be 2-5 seconds.
+
+More suggestions on server selection and retransmission policy can be
+found in the resolver section of this memo.
+
+4.2.2. TCP usage
+
+Messages sent over TCP connections use server port 53 (decimal). The
+message is prefixed with a two byte length field which gives the message
+
+
+
+Mockapetris [Page 32]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+length, excluding the two byte length field. This length field allows
+the low-level processing to assemble a complete message before beginning
+to parse it.
+
+Several connection management policies are recommended:
+
+ - The server should not block other activities waiting for TCP
+ data.
+
+ - The server should support multiple connections.
+
+ - The server should assume that the client will initiate
+ connection closing, and should delay closing its end of the
+ connection until all outstanding client requests have been
+ satisfied.
+
+ - If the server needs to close a dormant connection to reclaim
+ resources, it should wait until the connection has been idle
+ for a period on the order of two minutes. In particular, the
+ server should allow the SOA and AXFR request sequence (which
+ begins a refresh operation) to be made on a single connection.
+ Since the server would be unable to answer queries anyway, a
+ unilateral close or reset may be used instead of a graceful
+ close.
+
+5. MASTER FILES
+
+Master files are text files that contain RRs in text form. Since the
+contents of a zone can be expressed in the form of a list of RRs a
+master file is most often used to define a zone, though it can be used
+to list a cache's contents. Hence, this section first discusses the
+format of RRs in a master file, and then the special considerations when
+a master file is used to create a zone in some name server.
+
+5.1. Format
+
+The format of these files is a sequence of entries. Entries are
+predominantly line-oriented, though parentheses can be used to continue
+a list of items across a line boundary, and text literals can contain
+CRLF within the text. Any combination of tabs and spaces act as a
+delimiter between the separate items that make up an entry. The end of
+any line in the master file can end with a comment. The comment starts
+with a ";" (semicolon).
+
+The following entries are defined:
+
+ <blank>[<comment>]
+
+
+
+
+Mockapetris [Page 33]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ $ORIGIN <domain-name> [<comment>]
+
+ $INCLUDE <file-name> [<domain-name>] [<comment>]
+
+ <domain-name><rr> [<comment>]
+
+ <blank><rr> [<comment>]
+
+Blank lines, with or without comments, are allowed anywhere in the file.
+
+Two control entries are defined: $ORIGIN and $INCLUDE. $ORIGIN is
+followed by a domain name, and resets the current origin for relative
+domain names to the stated name. $INCLUDE inserts the named file into
+the current file, and may optionally specify a domain name that sets the
+relative domain name origin for the included file. $INCLUDE may also
+have a comment. Note that a $INCLUDE entry never changes the relative
+origin of the parent file, regardless of changes to the relative origin
+made within the included file.
+
+The last two forms represent RRs. If an entry for an RR begins with a
+blank, then the RR is assumed to be owned by the last stated owner. If
+an RR entry begins with a <domain-name>, then the owner name is reset.
+
+<rr> contents take one of the following forms:
+
+ [<TTL>] [<class>] <type> <RDATA>
+
+ [<class>] [<TTL>] <type> <RDATA>
+
+The RR begins with optional TTL and class fields, followed by a type and
+RDATA field appropriate to the type and class. Class and type use the
+standard mnemonics, TTL is a decimal integer. Omitted class and TTL
+values are default to the last explicitly stated values. Since type and
+class mnemonics are disjoint, the parse is unique. (Note that this
+order is different from the order used in examples and the order used in
+the actual RRs; the given order allows easier parsing and defaulting.)
+
+<domain-name>s make up a large share of the data in the master file.
+The labels in the domain name are expressed as character strings and
+separated by dots. Quoting conventions allow arbitrary characters to be
+stored in domain names. Domain names that end in a dot are called
+absolute, and are taken as complete. Domain names which do not end in a
+dot are called relative; the actual domain name is the concatenation of
+the relative part with an origin specified in a $ORIGIN, $INCLUDE, or as
+an argument to the master file loading routine. A relative name is an
+error when no origin is available.
+
+
+
+
+
+Mockapetris [Page 34]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+<character-string> is expressed in one or two ways: as a contiguous set
+of characters without interior spaces, or as a string beginning with a "
+and ending with a ". Inside a " delimited string any character can
+occur, except for a " itself, which must be quoted using \ (back slash).
+
+Because these files are text files several special encodings are
+necessary to allow arbitrary data to be loaded. In particular:
+
+ of the root.
+
+@ A free standing @ is used to denote the current origin.
+
+\X where X is any character other than a digit (0-9), is
+ used to quote that character so that its special meaning
+ does not apply. For example, "\." can be used to place
+ a dot character in a label.
+
+\DDD where each D is a digit is the octet corresponding to
+ the decimal number described by DDD. The resulting
+ octet is assumed to be text and is not checked for
+ special meaning.
+
+( ) Parentheses are used to group data that crosses a line
+ boundary. In effect, line terminations are not
+ recognized within parentheses.
+
+; Semicolon is used to start a comment; the remainder of
+ the line is ignored.
+
+5.2. Use of master files to define zones
+
+When a master file is used to load a zone, the operation should be
+suppressed if any errors are encountered in the master file. The
+rationale for this is that a single error can have widespread
+consequences. For example, suppose that the RRs defining a delegation
+have syntax errors; then the server will return authoritative name
+errors for all names in the subzone (except in the case where the
+subzone is also present on the server).
+
+Several other validity checks that should be performed in addition to
+insuring that the file is syntactically correct:
+
+ 1. All RRs in the file should have the same class.
+
+ 2. Exactly one SOA RR should be present at the top of the zone.
+
+ 3. If delegations are present and glue information is required,
+ it should be present.
+
+
+
+Mockapetris [Page 35]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 4. Information present outside of the authoritative nodes in the
+ zone should be glue information, rather than the result of an
+ origin or similar error.
+
+5.3. Master file example
+
+The following is an example file which might be used to define the
+ISI.EDU zone.and is loaded with an origin of ISI.EDU:
+
+@ IN SOA VENERA Action\.domains (
+ 20 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 3600000; EXPIRE
+ 60) ; MINIMUM
+
+ NS A.ISI.EDU.
+ NS VENERA
+ NS VAXA
+ MX 10 VENERA
+ MX 20 VAXA
+
+A A 26.3.0.103
+
+VENERA A 10.1.0.52
+ A 128.9.0.32
+
+VAXA A 10.2.0.27
+ A 128.9.0.33
+
+
+$INCLUDE <SUBSYS>ISI-MAILBOXES.TXT
+
+Where the file <SUBSYS>ISI-MAILBOXES.TXT is:
+
+ MOE MB A.ISI.EDU.
+ LARRY MB A.ISI.EDU.
+ CURLEY MB A.ISI.EDU.
+ STOOGES MG MOE
+ MG LARRY
+ MG CURLEY
+
+Note the use of the \ character in the SOA RR to specify the responsible
+person mailbox "Action.domains@E.ISI.EDU".
+
+
+
+
+
+
+
+Mockapetris [Page 36]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+6. NAME SERVER IMPLEMENTATION
+
+6.1. Architecture
+
+The optimal structure for the name server will depend on the host
+operating system and whether the name server is integrated with resolver
+operations, either by supporting recursive service, or by sharing its
+database with a resolver. This section discusses implementation
+considerations for a name server which shares a database with a
+resolver, but most of these concerns are present in any name server.
+
+6.1.1. Control
+
+A name server must employ multiple concurrent activities, whether they
+are implemented as separate tasks in the host's OS or multiplexing
+inside a single name server program. It is simply not acceptable for a
+name server to block the service of UDP requests while it waits for TCP
+data for refreshing or query activities. Similarly, a name server
+should not attempt to provide recursive service without processing such
+requests in parallel, though it may choose to serialize requests from a
+single client, or to regard identical requests from the same client as
+duplicates. A name server should not substantially delay requests while
+it reloads a zone from master files or while it incorporates a newly
+refreshed zone into its database.
+
+6.1.2. Database
+
+While name server implementations are free to use any internal data
+structures they choose, the suggested structure consists of three major
+parts:
+
+ - A "catalog" data structure which lists the zones available to
+ this server, and a "pointer" to the zone data structure. The
+ main purpose of this structure is to find the nearest ancestor
+ zone, if any, for arriving standard queries.
+
+ - Separate data structures for each of the zones held by the
+ name server.
+
+ - A data structure for cached data. (or perhaps separate caches
+ for different classes)
+
+All of these data structures can be implemented an identical tree
+structure format, with different data chained off the nodes in different
+parts: in the catalog the data is pointers to zones, while in the zone
+and cache data structures, the data will be RRs. In designing the tree
+framework the designer should recognize that query processing will need
+to traverse the tree using case-insensitive label comparisons; and that
+
+
+
+Mockapetris [Page 37]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in real data, a few nodes have a very high branching factor (100-1000 or
+more), but the vast majority have a very low branching factor (0-1).
+
+One way to solve the case problem is to store the labels for each node
+in two pieces: a standardized-case representation of the label where all
+ASCII characters are in a single case, together with a bit mask that
+denotes which characters are actually of a different case. The
+branching factor diversity can be handled using a simple linked list for
+a node until the branching factor exceeds some threshold, and
+transitioning to a hash structure after the threshold is exceeded. In
+any case, hash structures used to store tree sections must insure that
+hash functions and procedures preserve the casing conventions of the
+DNS.
+
+The use of separate structures for the different parts of the database
+is motivated by several factors:
+
+ - The catalog structure can be an almost static structure that
+ need change only when the system administrator changes the
+ zones supported by the server. This structure can also be
+ used to store parameters used to control refreshing
+ activities.
+
+ - The individual data structures for zones allow a zone to be
+ replaced simply by changing a pointer in the catalog. Zone
+ refresh operations can build a new structure and, when
+ complete, splice it into the database via a simple pointer
+ replacement. It is very important that when a zone is
+ refreshed, queries should not use old and new data
+ simultaneously.
+
+ - With the proper search procedures, authoritative data in zones
+ will always "hide", and hence take precedence over, cached
+ data.
+
+ - Errors in zone definitions that cause overlapping zones, etc.,
+ may cause erroneous responses to queries, but problem
+ determination is simplified, and the contents of one "bad"
+ zone can't corrupt another.
+
+ - Since the cache is most frequently updated, it is most
+ vulnerable to corruption during system restarts. It can also
+ become full of expired RR data. In either case, it can easily
+ be discarded without disturbing zone data.
+
+A major aspect of database design is selecting a structure which allows
+the name server to deal with crashes of the name server's host. State
+information which a name server should save across system crashes
+
+
+
+Mockapetris [Page 38]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+includes the catalog structure (including the state of refreshing for
+each zone) and the zone data itself.
+
+6.1.3. Time
+
+Both the TTL data for RRs and the timing data for refreshing activities
+depends on 32 bit timers in units of seconds. Inside the database,
+refresh timers and TTLs for cached data conceptually "count down", while
+data in the zone stays with constant TTLs.
+
+A recommended implementation strategy is to store time in two ways: as
+a relative increment and as an absolute time. One way to do this is to
+use positive 32 bit numbers for one type and negative numbers for the
+other. The RRs in zones use relative times; the refresh timers and
+cache data use absolute times. Absolute numbers are taken with respect
+to some known origin and converted to relative values when placed in the
+response to a query. When an absolute TTL is negative after conversion
+to relative, then the data is expired and should be ignored.
+
+6.2. Standard query processing
+
+The major algorithm for standard query processing is presented in
+[RFC-1034].
+
+When processing queries with QCLASS=*, or some other QCLASS which
+matches multiple classes, the response should never be authoritative
+unless the server can guarantee that the response covers all classes.
+
+When composing a response, RRs which are to be inserted in the
+additional section, but duplicate RRs in the answer or authority
+sections, may be omitted from the additional section.
+
+When a response is so long that truncation is required, the truncation
+should start at the end of the response and work forward in the
+datagram. Thus if there is any data for the authority section, the
+answer section is guaranteed to be unique.
+
+The MINIMUM value in the SOA should be used to set a floor on the TTL of
+data distributed from a zone. This floor function should be done when
+the data is copied into a response. This will allow future dynamic
+update protocols to change the SOA MINIMUM field without ambiguous
+semantics.
+
+6.3. Zone refresh and reload processing
+
+In spite of a server's best efforts, it may be unable to load zone data
+from a master file due to syntax errors, etc., or be unable to refresh a
+zone within the its expiration parameter. In this case, the name server
+
+
+
+Mockapetris [Page 39]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+should answer queries as if it were not supposed to possess the zone.
+
+If a master is sending a zone out via AXFR, and a new version is created
+during the transfer, the master should continue to send the old version
+if possible. In any case, it should never send part of one version and
+part of another. If completion is not possible, the master should reset
+the connection on which the zone transfer is taking place.
+
+6.4. Inverse queries (Optional)
+
+Inverse queries are an optional part of the DNS. Name servers are not
+required to support any form of inverse queries. If a name server
+receives an inverse query that it does not support, it returns an error
+response with the "Not Implemented" error set in the header. While
+inverse query support is optional, all name servers must be at least
+able to return the error response.
+
+6.4.1. The contents of inverse queries and responses Inverse
+queries reverse the mappings performed by standard query operations;
+while a standard query maps a domain name to a resource, an inverse
+query maps a resource to a domain name. For example, a standard query
+might bind a domain name to a host address; the corresponding inverse
+query binds the host address to a domain name.
+
+Inverse queries take the form of a single RR in the answer section of
+the message, with an empty question section. The owner name of the
+query RR and its TTL are not significant. The response carries
+questions in the question section which identify all names possessing
+the query RR WHICH THE NAME SERVER KNOWS. Since no name server knows
+about all of the domain name space, the response can never be assumed to
+be complete. Thus inverse queries are primarily useful for database
+management and debugging activities. Inverse queries are NOT an
+acceptable method of mapping host addresses to host names; use the IN-
+ADDR.ARPA domain instead.
+
+Where possible, name servers should provide case-insensitive comparisons
+for inverse queries. Thus an inverse query asking for an MX RR of
+"Venera.isi.edu" should get the same response as a query for
+"VENERA.ISI.EDU"; an inverse query for HINFO RR "IBM-PC UNIX" should
+produce the same result as an inverse query for "IBM-pc unix". However,
+this cannot be guaranteed because name servers may possess RRs that
+contain character strings but the name server does not know that the
+data is character.
+
+When a name server processes an inverse query, it either returns:
+
+ 1. zero, one, or multiple domain names for the specified
+ resource as QNAMEs in the question section
+
+
+
+Mockapetris [Page 40]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 2. an error code indicating that the name server doesn't support
+ inverse mapping of the specified resource type.
+
+When the response to an inverse query contains one or more QNAMEs, the
+owner name and TTL of the RR in the answer section which defines the
+inverse query is modified to exactly match an RR found at the first
+QNAME.
+
+RRs returned in the inverse queries cannot be cached using the same
+mechanism as is used for the replies to standard queries. One reason
+for this is that a name might have multiple RRs of the same type, and
+only one would appear. For example, an inverse query for a single
+address of a multiply homed host might create the impression that only
+one address existed.
+
+6.4.2. Inverse query and response example The overall structure
+of an inverse query for retrieving the domain name that corresponds to
+Internet address 10.1.0.52 is shown below:
+
+ +-----------------------------------------+
+ Header | OPCODE=IQUERY, ID=997 |
+ +-----------------------------------------+
+ Question | <empty> |
+ +-----------------------------------------+
+ Answer | <anyname> A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+This query asks for a question whose answer is the Internet style
+address 10.1.0.52. Since the owner name is not known, any domain name
+can be used as a placeholder (and is ignored). A single octet of zero,
+signifying the root, is usually used because it minimizes the length of
+the message. The TTL of the RR is not significant. The response to
+this query might be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 41]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ +-----------------------------------------+
+ Header | OPCODE=RESPONSE, ID=997 |
+ +-----------------------------------------+
+ Question |QTYPE=A, QCLASS=IN, QNAME=VENERA.ISI.EDU |
+ +-----------------------------------------+
+ Answer | VENERA.ISI.EDU A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+Note that the QTYPE in a response to an inverse query is the same as the
+TYPE field in the answer section of the inverse query. Responses to
+inverse queries may contain multiple questions when the inverse is not
+unique. If the question section in the response is not empty, then the
+RR in the answer section is modified to correspond to be an exact copy
+of an RR at the first QNAME.
+
+6.4.3. Inverse query processing
+
+Name servers that support inverse queries can support these operations
+through exhaustive searches of their databases, but this becomes
+impractical as the size of the database increases. An alternative
+approach is to invert the database according to the search key.
+
+For name servers that support multiple zones and a large amount of data,
+the recommended approach is separate inversions for each zone. When a
+particular zone is changed during a refresh, only its inversions need to
+be redone.
+
+Support for transfer of this type of inversion may be included in future
+versions of the domain system, but is not supported in this version.
+
+6.5. Completion queries and responses
+
+The optional completion services described in RFC-882 and RFC-883 have
+been deleted. Redesigned services may become available in the future.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 42]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7. RESOLVER IMPLEMENTATION
+
+The top levels of the recommended resolver algorithm are discussed in
+[RFC-1034]. This section discusses implementation details assuming the
+database structure suggested in the name server implementation section
+of this memo.
+
+7.1. Transforming a user request into a query
+
+The first step a resolver takes is to transform the client's request,
+stated in a format suitable to the local OS, into a search specification
+for RRs at a specific name which match a specific QTYPE and QCLASS.
+Where possible, the QTYPE and QCLASS should correspond to a single type
+and a single class, because this makes the use of cached data much
+simpler. The reason for this is that the presence of data of one type
+in a cache doesn't confirm the existence or non-existence of data of
+other types, hence the only way to be sure is to consult an
+authoritative source. If QCLASS=* is used, then authoritative answers
+won't be available.
+
+Since a resolver must be able to multiplex multiple requests if it is to
+perform its function efficiently, each pending request is usually
+represented in some block of state information. This state block will
+typically contain:
+
+ - A timestamp indicating the time the request began.
+ The timestamp is used to decide whether RRs in the database
+ can be used or are out of date. This timestamp uses the
+ absolute time format previously discussed for RR storage in
+ zones and caches. Note that when an RRs TTL indicates a
+ relative time, the RR must be timely, since it is part of a
+ zone. When the RR has an absolute time, it is part of a
+ cache, and the TTL of the RR is compared against the timestamp
+ for the start of the request.
+
+ Note that using the timestamp is superior to using a current
+ time, since it allows RRs with TTLs of zero to be entered in
+ the cache in the usual manner, but still used by the current
+ request, even after intervals of many seconds due to system
+ load, query retransmission timeouts, etc.
+
+ - Some sort of parameters to limit the amount of work which will
+ be performed for this request.
+
+ The amount of work which a resolver will do in response to a
+ client request must be limited to guard against errors in the
+ database, such as circular CNAME references, and operational
+ problems, such as network partition which prevents the
+
+
+
+Mockapetris [Page 43]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ resolver from accessing the name servers it needs. While
+ local limits on the number of times a resolver will retransmit
+ a particular query to a particular name server address are
+ essential, the resolver should have a global per-request
+ counter to limit work on a single request. The counter should
+ be set to some initial value and decremented whenever the
+ resolver performs any action (retransmission timeout,
+ retransmission, etc.) If the counter passes zero, the request
+ is terminated with a temporary error.
+
+ Note that if the resolver structure allows one request to
+ start others in parallel, such as when the need to access a
+ name server for one request causes a parallel resolve for the
+ name server's addresses, the spawned request should be started
+ with a lower counter. This prevents circular references in
+ the database from starting a chain reaction of resolver
+ activity.
+
+ - The SLIST data structure discussed in [RFC-1034].
+
+ This structure keeps track of the state of a request if it
+ must wait for answers from foreign name servers.
+
+7.2. Sending the queries
+
+As described in [RFC-1034], the basic task of the resolver is to
+formulate a query which will answer the client's request and direct that
+query to name servers which can provide the information. The resolver
+will usually only have very strong hints about which servers to ask, in
+the form of NS RRs, and may have to revise the query, in response to
+CNAMEs, or revise the set of name servers the resolver is asking, in
+response to delegation responses which point the resolver to name
+servers closer to the desired information. In addition to the
+information requested by the client, the resolver may have to call upon
+its own services to determine the address of name servers it wishes to
+contact.
+
+In any case, the model used in this memo assumes that the resolver is
+multiplexing attention between multiple requests, some from the client,
+and some internally generated. Each request is represented by some
+state information, and the desired behavior is that the resolver
+transmit queries to name servers in a way that maximizes the probability
+that the request is answered, minimizes the time that the request takes,
+and avoids excessive transmissions. The key algorithm uses the state
+information of the request to select the next name server address to
+query, and also computes a timeout which will cause the next action
+should a response not arrive. The next action will usually be a
+transmission to some other server, but may be a temporary error to the
+
+
+
+Mockapetris [Page 44]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+client.
+
+The resolver always starts with a list of server names to query (SLIST).
+This list will be all NS RRs which correspond to the nearest ancestor
+zone that the resolver knows about. To avoid startup problems, the
+resolver should have a set of default servers which it will ask should
+it have no current NS RRs which are appropriate. The resolver then adds
+to SLIST all of the known addresses for the name servers, and may start
+parallel requests to acquire the addresses of the servers when the
+resolver has the name, but no addresses, for the name servers.
+
+To complete initialization of SLIST, the resolver attaches whatever
+history information it has to the each address in SLIST. This will
+usually consist of some sort of weighted averages for the response time
+of the address, and the batting average of the address (i.e., how often
+the address responded at all to the request). Note that this
+information should be kept on a per address basis, rather than on a per
+name server basis, because the response time and batting average of a
+particular server may vary considerably from address to address. Note
+also that this information is actually specific to a resolver address /
+server address pair, so a resolver with multiple addresses may wish to
+keep separate histories for each of its addresses. Part of this step
+must deal with addresses which have no such history; in this case an
+expected round trip time of 5-10 seconds should be the worst case, with
+lower estimates for the same local network, etc.
+
+Note that whenever a delegation is followed, the resolver algorithm
+reinitializes SLIST.
+
+The information establishes a partial ranking of the available name
+server addresses. Each time an address is chosen and the state should
+be altered to prevent its selection again until all other addresses have
+been tried. The timeout for each transmission should be 50-100% greater
+than the average predicted value to allow for variance in response.
+
+Some fine points:
+
+ - The resolver may encounter a situation where no addresses are
+ available for any of the name servers named in SLIST, and
+ where the servers in the list are precisely those which would
+ normally be used to look up their own addresses. This
+ situation typically occurs when the glue address RRs have a
+ smaller TTL than the NS RRs marking delegation, or when the
+ resolver caches the result of a NS search. The resolver
+ should detect this condition and restart the search at the
+ next ancestor zone, or alternatively at the root.
+
+
+
+
+
+Mockapetris [Page 45]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ - If a resolver gets a server error or other bizarre response
+ from a name server, it should remove it from SLIST, and may
+ wish to schedule an immediate transmission to the next
+ candidate server address.
+
+7.3. Processing responses
+
+The first step in processing arriving response datagrams is to parse the
+response. This procedure should include:
+
+ - Check the header for reasonableness. Discard datagrams which
+ are queries when responses are expected.
+
+ - Parse the sections of the message, and insure that all RRs are
+ correctly formatted.
+
+ - As an optional step, check the TTLs of arriving data looking
+ for RRs with excessively long TTLs. If a RR has an
+ excessively long TTL, say greater than 1 week, either discard
+ the whole response, or limit all TTLs in the response to 1
+ week.
+
+The next step is to match the response to a current resolver request.
+The recommended strategy is to do a preliminary matching using the ID
+field in the domain header, and then to verify that the question section
+corresponds to the information currently desired. This requires that
+the transmission algorithm devote several bits of the domain ID field to
+a request identifier of some sort. This step has several fine points:
+
+ - Some name servers send their responses from different
+ addresses than the one used to receive the query. That is, a
+ resolver cannot rely that a response will come from the same
+ address which it sent the corresponding query to. This name
+ server bug is typically encountered in UNIX systems.
+
+ - If the resolver retransmits a particular request to a name
+ server it should be able to use a response from any of the
+ transmissions. However, if it is using the response to sample
+ the round trip time to access the name server, it must be able
+ to determine which transmission matches the response (and keep
+ transmission times for each outgoing message), or only
+ calculate round trip times based on initial transmissions.
+
+ - A name server will occasionally not have a current copy of a
+ zone which it should have according to some NS RRs. The
+ resolver should simply remove the name server from the current
+ SLIST, and continue.
+
+
+
+
+Mockapetris [Page 46]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7.4. Using the cache
+
+In general, we expect a resolver to cache all data which it receives in
+responses since it may be useful in answering future client requests.
+However, there are several types of data which should not be cached:
+
+ - When several RRs of the same type are available for a
+ particular owner name, the resolver should either cache them
+ all or none at all. When a response is truncated, and a
+ resolver doesn't know whether it has a complete set, it should
+ not cache a possibly partial set of RRs.
+
+ - Cached data should never be used in preference to
+ authoritative data, so if caching would cause this to happen
+ the data should not be cached.
+
+ - The results of an inverse query should not be cached.
+
+ - The results of standard queries where the QNAME contains "*"
+ labels if the data might be used to construct wildcards. The
+ reason is that the cache does not necessarily contain existing
+ RRs or zone boundary information which is necessary to
+ restrict the application of the wildcard RRs.
+
+ - RR data in responses of dubious reliability. When a resolver
+ receives unsolicited responses or RR data other than that
+ requested, it should discard it without caching it. The basic
+ implication is that all sanity checks on a packet should be
+ performed before any of it is cached.
+
+In a similar vein, when a resolver has a set of RRs for some name in a
+response, and wants to cache the RRs, it should check its cache for
+already existing RRs. Depending on the circumstances, either the data
+in the response or the cache is preferred, but the two should never be
+combined. If the data in the response is from authoritative data in the
+answer section, it is always preferred.
+
+8. MAIL SUPPORT
+
+The domain system defines a standard for mapping mailboxes into domain
+names, and two methods for using the mailbox information to derive mail
+routing information. The first method is called mail exchange binding
+and the other method is mailbox binding. The mailbox encoding standard
+and mail exchange binding are part of the DNS official protocol, and are
+the recommended method for mail routing in the Internet. Mailbox
+binding is an experimental feature which is still under development and
+subject to change.
+
+
+
+
+Mockapetris [Page 47]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+The mailbox encoding standard assumes a mailbox name of the form
+"<local-part>@<mail-domain>". While the syntax allowed in each of these
+sections varies substantially between the various mail internets, the
+preferred syntax for the ARPA Internet is given in [RFC-822].
+
+The DNS encodes the <local-part> as a single label, and encodes the
+<mail-domain> as a domain name. The single label from the <local-part>
+is prefaced to the domain name from <mail-domain> to form the domain
+name corresponding to the mailbox. Thus the mailbox HOSTMASTER@SRI-
+NIC.ARPA is mapped into the domain name HOSTMASTER.SRI-NIC.ARPA. If the
+<local-part> contains dots or other special characters, its
+representation in a master file will require the use of backslash
+quoting to ensure that the domain name is properly encoded. For
+example, the mailbox Action.domains@ISI.EDU would be represented as
+Action\.domains.ISI.EDU.
+
+8.1. Mail exchange binding
+
+Mail exchange binding uses the <mail-domain> part of a mailbox
+specification to determine where mail should be sent. The <local-part>
+is not even consulted. [RFC-974] specifies this method in detail, and
+should be consulted before attempting to use mail exchange support.
+
+One of the advantages of this method is that it decouples mail
+destination naming from the hosts used to support mail service, at the
+cost of another layer of indirection in the lookup function. However,
+the addition layer should eliminate the need for complicated "%", "!",
+etc encodings in <local-part>.
+
+The essence of the method is that the <mail-domain> is used as a domain
+name to locate type MX RRs which list hosts willing to accept mail for
+<mail-domain>, together with preference values which rank the hosts
+according to an order specified by the administrators for <mail-domain>.
+
+In this memo, the <mail-domain> ISI.EDU is used in examples, together
+with the hosts VENERA.ISI.EDU and VAXA.ISI.EDU as mail exchanges for
+ISI.EDU. If a mailer had a message for Mockapetris@ISI.EDU, it would
+route it by looking up MX RRs for ISI.EDU. The MX RRs at ISI.EDU name
+VENERA.ISI.EDU and VAXA.ISI.EDU, and type A queries can find the host
+addresses.
+
+8.2. Mailbox binding (Experimental)
+
+In mailbox binding, the mailer uses the entire mail destination
+specification to construct a domain name. The encoded domain name for
+the mailbox is used as the QNAME field in a QTYPE=MAILB query.
+
+Several outcomes are possible for this query:
+
+
+
+Mockapetris [Page 48]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 1. The query can return a name error indicating that the mailbox
+ does not exist as a domain name.
+
+ In the long term, this would indicate that the specified
+ mailbox doesn't exist. However, until the use of mailbox
+ binding is universal, this error condition should be
+ interpreted to mean that the organization identified by the
+ global part does not support mailbox binding. The
+ appropriate procedure is to revert to exchange binding at
+ this point.
+
+ 2. The query can return a Mail Rename (MR) RR.
+
+ The MR RR carries new mailbox specification in its RDATA
+ field. The mailer should replace the old mailbox with the
+ new one and retry the operation.
+
+ 3. The query can return a MB RR.
+
+ The MB RR carries a domain name for a host in its RDATA
+ field. The mailer should deliver the message to that host
+ via whatever protocol is applicable, e.g., b,SMTP.
+
+ 4. The query can return one or more Mail Group (MG) RRs.
+
+ This condition means that the mailbox was actually a mailing
+ list or mail group, rather than a single mailbox. Each MG RR
+ has a RDATA field that identifies a mailbox that is a member
+ of the group. The mailer should deliver a copy of the
+ message to each member.
+
+ 5. The query can return a MB RR as well as one or more MG RRs.
+
+ This condition means the the mailbox was actually a mailing
+ list. The mailer can either deliver the message to the host
+ specified by the MB RR, which will in turn do the delivery to
+ all members, or the mailer can use the MG RRs to do the
+ expansion itself.
+
+In any of these cases, the response may include a Mail Information
+(MINFO) RR. This RR is usually associated with a mail group, but is
+legal with a MB. The MINFO RR identifies two mailboxes. One of these
+identifies a responsible person for the original mailbox name. This
+mailbox should be used for requests to be added to a mail group, etc.
+The second mailbox name in the MINFO RR identifies a mailbox that should
+receive error messages for mail failures. This is particularly
+appropriate for mailing lists when errors in member names should be
+reported to a person other than the one who sends a message to the list.
+
+
+
+Mockapetris [Page 49]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+New fields may be added to this RR in the future.
+
+
+9. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87] S. Dyer, F. Hsu, "Hesiod", Project Athena
+ Technical Plan - Name Service, April 1987, version 1.9.
+
+ Describes the fundamentals of the Hesiod name service.
+
+[IEN-116] J. Postel, "Internet Name Server", IEN-116,
+ USC/Information Sciences Institute, August 1979.
+
+ A name service obsoleted by the Domain Name System, but
+ still in use.
+
+[Quarterman 86] J. Quarterman, and J. Hoskins, "Notable Computer Networks",
+ Communications of the ACM, October 1986, volume 29, number
+ 10.
+
+[RFC-742] K. Harrenstien, "NAME/FINGER", RFC-742, Network
+ Information Center, SRI International, December 1977.
+
+[RFC-768] J. Postel, "User Datagram Protocol", RFC-768,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-793] J. Postel, "Transmission Control Protocol", RFC-793,
+ USC/Information Sciences Institute, September 1981.
+
+[RFC-799] D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+ September 1981.
+
+ Suggests introduction of a hierarchy in place of a flat
+ name space for the Internet.
+
+[RFC-805] J. Postel, "Computer Mail Meeting Notes", RFC-805,
+ USC/Information Sciences Institute, February 1982.
+
+[RFC-810] E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+ Internet Host Table Specification", RFC-810, Network
+ Information Center, SRI International, March 1982.
+
+ Obsolete. See RFC-952.
+
+[RFC-811] K. Harrenstien, V. White, and E. Feinler, "Hostnames
+ Server", RFC-811, Network Information Center, SRI
+ International, March 1982.
+
+
+
+
+Mockapetris [Page 50]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Obsolete. See RFC-953.
+
+[RFC-812] K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+ Network Information Center, SRI International, March
+ 1982.
+
+[RFC-819] Z. Su, and J. Postel, "The Domain Naming Convention for
+ Internet User Applications", RFC-819, Network
+ Information Center, SRI International, August 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-821] J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-830] Z. Su, "A Distributed System for Internet Name Service",
+ RFC-830, Network Information Center, SRI International,
+ October 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-882] P. Mockapetris, "Domain names - Concepts and
+ Facilities," RFC-882, USC/Information Sciences
+ Institute, November 1983.
+
+ Superseded by this memo.
+
+[RFC-883] P. Mockapetris, "Domain names - Implementation and
+ Specification," RFC-883, USC/Information Sciences
+ Institute, November 1983.
+
+ Superseded by this memo.
+
+[RFC-920] J. Postel and J. Reynolds, "Domain Requirements",
+ RFC-920, USC/Information Sciences Institute,
+ October 1984.
+
+ Explains the naming scheme for top level domains.
+
+[RFC-952] K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+ Table Specification", RFC-952, SRI, October 1985.
+
+ Specifies the format of HOSTS.TXT, the host/address
+ table replaced by the DNS.
+
+
+
+
+
+Mockapetris [Page 51]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+[RFC-953] K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+ RFC-953, SRI, October 1985.
+
+ This RFC contains the official specification of the
+ hostname server protocol, which is obsoleted by the DNS.
+ This TCP based protocol accesses information stored in
+ the RFC-952 format, and is used to obtain copies of the
+ host table.
+
+[RFC-973] P. Mockapetris, "Domain System Changes and
+ Observations", RFC-973, USC/Information Sciences
+ Institute, January 1986.
+
+ Describes changes to RFC-882 and RFC-883 and reasons for
+ them.
+
+[RFC-974] C. Partridge, "Mail routing and the domain system",
+ RFC-974, CSNET CIC BBN Labs, January 1986.
+
+ Describes the transition from HOSTS.TXT based mail
+ addressing to the more powerful MX system used with the
+ domain system.
+
+[RFC-1001] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Concepts and Methods",
+ RFC-1001, March 1987.
+
+ This RFC and RFC-1002 are a preliminary design for
+ NETBIOS on top of TCP/IP which proposes to base NetBIOS
+ name service on top of the DNS.
+
+[RFC-1002] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Detailed
+ Specifications", RFC-1002, March 1987.
+
+[RFC-1010] J. Reynolds, and J. Postel, "Assigned Numbers", RFC-1010,
+ USC/Information Sciences Institute, May 1987.
+
+ Contains socket numbers and mnemonics for host names,
+ operating systems, etc.
+
+[RFC-1031] W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+ November 1987.
+
+ Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032] M. Stahl, "Establishing a Domain - Guidelines for
+ Administrators", RFC-1032, November 1987.
+
+
+
+Mockapetris [Page 52]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Describes the registration policies used by the NIC to
+ administer the top level domains and delegate subzones.
+
+[RFC-1033] M. Lottor, "Domain Administrators Operations Guide",
+ RFC-1033, November 1987.
+
+ A cookbook for domain administrators.
+
+[Solomon 82] M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+ Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+ Describes a name service for CSNET which is independent
+ from the DNS and DNS use in the CSNET.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 53]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Index
+
+ * 13
+
+ ; 33, 35
+
+ <character-string> 35
+ <domain-name> 34
+
+ @ 35
+
+ \ 35
+
+ A 12
+
+ Byte order 8
+
+ CH 13
+ Character case 9
+ CLASS 11
+ CNAME 12
+ Completion 42
+ CS 13
+
+ Hesiod 13
+ HINFO 12
+ HS 13
+
+ IN 13
+ IN-ADDR.ARPA domain 22
+ Inverse queries 40
+
+ Mailbox names 47
+ MB 12
+ MD 12
+ MF 12
+ MG 12
+ MINFO 12
+ MINIMUM 20
+ MR 12
+ MX 12
+
+ NS 12
+ NULL 12
+
+ Port numbers 32
+ Primary server 5
+ PTR 12, 18
+
+
+
+Mockapetris [Page 54]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ QCLASS 13
+ QTYPE 12
+
+ RDATA 12
+ RDLENGTH 11
+
+ Secondary server 5
+ SOA 12
+ Stub resolvers 7
+
+ TCP 32
+ TXT 12
+ TYPE 11
+
+ UDP 32
+
+ WKS 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 55]
+
diff --git a/tests/dns/testdata/dstrandom/random.data b/tests/dns/testdata/dstrandom/random.data
new file mode 100644
index 0000000..354add0
--- /dev/null
+++ b/tests/dns/testdata/dstrandom/random.data
Binary files differ
diff --git a/tests/dns/testdata/master/master1.data b/tests/dns/testdata/master/master1.data
new file mode 100644
index 0000000..030bc68
--- /dev/null
+++ b/tests/dns/testdata/master/master1.data
@@ -0,0 +1,11 @@
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+ in ns ns.vix.com.
+ in ns ns2.vix.com.
+ in ns ns3.vix.com.
+b in a 1.2.3.4
diff --git a/tests/dns/testdata/master/master10.data b/tests/dns/testdata/master/master10.data
new file mode 100644
index 0000000..9ee052f
--- /dev/null
+++ b/tests/dns/testdata/master/master10.data
@@ -0,0 +1,7 @@
+;
+; the following black line contains spaces
+
+;
+@ 300 IN A 10.0.0.1
+ ;
+;
diff --git a/tests/dns/testdata/master/master11.data b/tests/dns/testdata/master/master11.data
new file mode 100644
index 0000000..0aaec25
--- /dev/null
+++ b/tests/dns/testdata/master/master11.data
@@ -0,0 +1,6 @@
+;
+; The following serial number contains a leading 0 and a 9 so the
+; we can catch cases where it is incorrectly treated as a octal
+; number.
+;
+@ 300 IN SOA ns hostmaster 00090000 1200 3600 604800 300
diff --git a/tests/dns/testdata/master/master12.data.in b/tests/dns/testdata/master/master12.data.in
new file mode 100644
index 0000000..3634388
--- /dev/null
+++ b/tests/dns/testdata/master/master12.data.in
@@ -0,0 +1 @@
+00000002000000004ed7306600000051000100060000000003e80000000100060474657374000035096c6f63616c686f7374000a706f73746d6173746572096c6f63616c686f73740076cb8ab100000e100000070800093a8000000e1000000046000100020000000003e8000000030006047465737400000c026e730376697803636f6d00000d036e73320376697803636f6d00000d036e73330376697803636f6d0000000022000100010000000003e80000000100080162047465737400000401020304
diff --git a/tests/dns/testdata/master/master13.data.in b/tests/dns/testdata/master/master13.data.in
new file mode 100644
index 0000000..d1c262f
--- /dev/null
+++ b/tests/dns/testdata/master/master13.data.in
@@ -0,0 +1 @@
+00000002000000014ed7337f00000000000000000000000000000051000100060000000003e80000000100060474657374000035096c6f63616c686f7374000a706f73746d6173746572096c6f63616c686f73740076cb8ab100000e100000070800093a8000000e1000000046000100020000000003e8000000030006047465737400000c026e730376697803636f6d00000d036e73320376697803636f6d00000d036e73330376697803636f6d0000000022000100010000000003e80000000100080162047465737400000401020304
diff --git a/tests/dns/testdata/master/master14.data.in b/tests/dns/testdata/master/master14.data.in
new file mode 100644
index 0000000..149a25f
--- /dev/null
+++ b/tests/dns/testdata/master/master14.data.in
@@ -0,0 +1 @@
+00000002000000014ed7337f0000000277df41e50000000000000051000100060000000003e80000000100060474657374000035096c6f63616c686f7374000a706f73746d6173746572096c6f63616c686f73740076cb8ab100000e100000070800093a8000000e1000000046000100020000000003e8000000030006047465737400000c026e730376697803636f6d00000d036e73320376697803636f6d00000d036e73330376697803636f6d0000000022000100010000000003e80000000100080162047465737400000401020304
diff --git a/tests/dns/testdata/master/master15.data b/tests/dns/testdata/master/master15.data
new file mode 100644
index 0000000..cf413ce
--- /dev/null
+++ b/tests/dns/testdata/master/master15.data
@@ -0,0 +1,1609 @@
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+ in ns ns.vix.com.
+ in ns ns2.vix.com.
+ in ns ns3.vix.com.
+b in a 1.2.3.4
+c in txt ( TOOBIGTOOBIGTOOBIGTOOBIGTOOBIGTOOBI
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890 )
diff --git a/tests/dns/testdata/master/master16.data b/tests/dns/testdata/master/master16.data
new file mode 100644
index 0000000..e969bd3
--- /dev/null
+++ b/tests/dns/testdata/master/master16.data
@@ -0,0 +1,1609 @@
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+ in ns ns.vix.com.
+ in ns ns2.vix.com.
+ in ns ns3.vix.com.
+b in a 1.2.3.4
+c in txt ( MAXSIZSEMAXSIZSEMAXSIZSEMAXSIZSMAX
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890 )
diff --git a/tests/dns/testdata/master/master17.data b/tests/dns/testdata/master/master17.data
new file mode 100644
index 0000000..4b2b63d
--- /dev/null
+++ b/tests/dns/testdata/master/master17.data
@@ -0,0 +1,14 @@
+$ORIGIN test.
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+ in ns ns.test.
+ in ns ns2.test.
+ in ns ns3.test.
+b in a 1.2.3.4
+$ORIGIN sub.test.
+ in a 4.3.2.1
diff --git a/tests/dns/testdata/master/master18.data.in b/tests/dns/testdata/master/master18.data.in
new file mode 100644
index 0000000..73c17ff
--- /dev/null
+++ b/tests/dns/testdata/master/master18.data.in
@@ -0,0 +1,10 @@
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+
+$INCLUDE "@TOP_SRCDIR@/testkeys/Kexample.+008+20386.key";
+$INCLUDE "@TOP_SRCDIR@/testkeys/Kexample.+008+37464.key";
diff --git a/tests/dns/testdata/master/master2.data b/tests/dns/testdata/master/master2.data
new file mode 100644
index 0000000..b8ca38d
--- /dev/null
+++ b/tests/dns/testdata/master/master2.data
@@ -0,0 +1,11 @@
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+a in ns
+a in ns ns2vix.com.
+a in ns ns3vix.com.
+b in a 1.2.3.4
diff --git a/tests/dns/testdata/master/master3.data b/tests/dns/testdata/master/master3.data
new file mode 100644
index 0000000..7283af6
--- /dev/null
+++ b/tests/dns/testdata/master/master3.data
@@ -0,0 +1,11 @@
+$TTL 1000
+ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+ in ns ns.vix.com
+ in ns ns2vix.com.
+a in ns ns3vix.com.
+b in a 1.2.3.4
diff --git a/tests/dns/testdata/master/master4.data b/tests/dns/testdata/master/master4.data
new file mode 100644
index 0000000..3a694ea
--- /dev/null
+++ b/tests/dns/testdata/master/master4.data
@@ -0,0 +1,11 @@
+
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+a in ns ns.vix.com.
+a in ns ns2vix.com.
+a in ns ns3vix.com.
+b in a 1.2.3.4
diff --git a/tests/dns/testdata/master/master5.data b/tests/dns/testdata/master/master5.data
new file mode 100644
index 0000000..95234bd
--- /dev/null
+++ b/tests/dns/testdata/master/master5.data
@@ -0,0 +1,11 @@
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+a any ns ns.vix.com.
+a in ns ns2vix.com.
+a in ns ns3vix.com.
+b in a 1.2.3.4
diff --git a/tests/dns/testdata/master/master6.data b/tests/dns/testdata/master/master6.data
new file mode 100644
index 0000000..a9a37bb
--- /dev/null
+++ b/tests/dns/testdata/master/master6.data
@@ -0,0 +1,33 @@
+
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+
+secure1 3600 IN DNSKEY (
+ FLAG2|FLAG4|FLAG5|NTYP3|FLAG8|FLAG9|FLAG10|FLAG11|SIG15
+ 3 3
+ ArT0a8FtOZWEONG2YQVl9+RA34op30JPz4NPEroCxm2yImT2
+ 2OYggnPIzrgayyepgKU1PfTTypnJDTwrSrtISyEsj7tjM7/n
+ 03DP8VWSn0aLwpUuc7Sx9vtM1Wi+YeiA4Bv2Oz1VB9de4qql
+ sIq+KLn8J4wz95bGnJ0mHUB7oTDJ3Hl1zeaCMdX69Kr46yAY
+ AvGJJdGGDYxYgxzx2zNdzypkYSkxpdsNqUt38tabSfdvCn12
+ pnmSWjlVJsjHhsaYnrPhouN5acOXMNbxNVbGU5LZ8Es6EYbV
+ /7YMt8VUkA8/8UCszBBT7XAJ3OFjiMO8mvxrZZFzvwJlPBQ1
+ oFq/TNZlSe+N )
+
+secure2 3600 in DNSKEY (
+ flag2|flag4|flag5|ntyp3|flag8|flag9|flag10|flag11|sig15
+ 3 3
+ ArT0a8FtOZWEONG2YQVl9+RA34op30JPz4NPEroCxm2yImT2
+ 2OYggnPIzrgayyepgKU1PfTTypnJDTwrSrtISyEsj7tjM7/n
+ 03DP8VWSn0aLwpUuc7Sx9vtM1Wi+YeiA4Bv2Oz1VB9de4qql
+ sIq+KLn8J4wz95bGnJ0mHUB7oTDJ3Hl1zeaCMdX69Kr46yAY
+ AvGJJdGGDYxYgxzx2zNdzypkYSkxpdsNqUt38tabSfdvCn12
+ pnmSWjlVJsjHhsaYnrPhouN5acOXMNbxNVbGU5LZ8Es6EYbV
+ /7YMt8VUkA8/8UCszBBT7XAJ3OFjiMO8mvxrZZFzvwJlPBQ1
+ oFq/TNZlSe+N )
+
diff --git a/tests/dns/testdata/master/master7.data b/tests/dns/testdata/master/master7.data
new file mode 100644
index 0000000..2638b5d
--- /dev/null
+++ b/tests/dns/testdata/master/master7.data
@@ -0,0 +1,17 @@
+
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+
+secure1 3600 IN DNSKEY (
+ NOKEY|FLAG2|FLAG4|FLAG5|NTYP3|FLAG8|FLAG9|FLAG10|FLAG11|SIG15
+ 3 3 )
+
+secure2 3600 in DNSKEY (
+ nokey|flag2|flag4|flag5|ntyp3|flag8|flag9|flag10|flag11|sig15
+ 3 3 )
+
diff --git a/tests/dns/testdata/master/master8.data b/tests/dns/testdata/master/master8.data
new file mode 100644
index 0000000..d16b6f3
--- /dev/null
+++ b/tests/dns/testdata/master/master8.data
@@ -0,0 +1,4 @@
+;
+; master6.data contains a good zone file
+;
+$include testdata/master/master6.data
diff --git a/tests/dns/testdata/master/master9.data b/tests/dns/testdata/master/master9.data
new file mode 100644
index 0000000..b22688b
--- /dev/null
+++ b/tests/dns/testdata/master/master9.data
@@ -0,0 +1,4 @@
+;
+; master5.data is bad
+;
+$include testdata/master/master5.data
diff --git a/tests/dns/testdata/nsec3/1024.db b/tests/dns/testdata/nsec3/1024.db
new file mode 100644
index 0000000..2576328
--- /dev/null
+++ b/tests/dns/testdata/nsec3/1024.db
@@ -0,0 +1,16 @@
+; 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 0
+test. SOA . . 0 0 0 0 0
+test. NS .
+; 1024 bit key.
+test. IN DNSKEY 256 3 5 AwEAAd5oKx06HRE6NRrTDz49lljdRmxgp/4YB/cyMkpwUMkaLhDNCfTq hql84ab2LRbtUWLHFXGWENvxPGQzVHeleXu+3ThNfFOwIaySedxHmLGT lTtBRDhPc8iSb+2IYDemmA+ut8kwHhCVz/tDMbD/dgAswdOtmXCpQyJk Q1HqY3Xj
diff --git a/tests/dns/testdata/nsec3/2048.db b/tests/dns/testdata/nsec3/2048.db
new file mode 100644
index 0000000..26dd980
--- /dev/null
+++ b/tests/dns/testdata/nsec3/2048.db
@@ -0,0 +1,16 @@
+; 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 0
+test. SOA . . 0 0 0 0 0
+test. NS .
+; 2048 bits
+test. IN DNSKEY 256 3 5 AwEAAcfQX59iZr9gK+XzhTZQ5KWrfCLA0iYHTqheEIhC2dXS8gUSppQS g9SmzH2129u/LSSb7gqJSoLLAsn36iinqCqUXl2BT6xzwznbSP3mn0hn N6DegsykcYhHycKH6ifjZiMN+SGGeNsi5rhoW5Cj9ptw3C3yQnrFNDbS GZCT97z5lpQU3ZcvP4RDNk7dhri7Bh3SJeaCFoqx00NgFvlBR48hosSG bGUbUKzNf58GBTkW4Us2jIWsreZx8LLLev232Hy7NU9L19k+hVq7pJOf Uvtrn5fmGSutWOzsR+8EacOnh0lwssCKjutk5MSmfdFC5P7CTZkdq58L 8he13HGmr00=
diff --git a/tests/dns/testdata/nsec3/4096.db b/tests/dns/testdata/nsec3/4096.db
new file mode 100644
index 0000000..d628c33
--- /dev/null
+++ b/tests/dns/testdata/nsec3/4096.db
@@ -0,0 +1,16 @@
+; 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 0
+test. SOA . . 0 0 0 0 0
+test. NS .
+; 4096 bits
+test. IN DNSKEY 256 3 5 AwEAAbYlqbKxXoq9mzkqdsAaSZ3XywBVAb2sCTgrQBCExyGEYNpWw3LN +imCrLQi7jHKQW6GZIqKNgQaiFEwr3zK8nPWbwNwyKU9a2hhINv/gim1 5iA87Vu7DiiJrQ0O79ospvsGsKknBQ41zaaQMp3Q/W1S6WNe4uyh4C/f R0qmxT+8MyXEqCpTGb+e+YT6BuqpNQPuYYYvUJ1/HJltzY/lY2b9RZ+Q ZJ23Zje79YIRM0kJapqj11fDUDeynhDL1DUikYCwRfQiO/blChhOHjIa uTK1qqRY3fqanLGOufpLTr7GRpL7RxeRIMJfDzmcjFLmCsMA1AJ56Bxq jiXr3ODgn9D30vAB74Lr7lqLQSWyrSlJjoZLLhmPrEP/nnuCxEhOhDRA XJpJWpcQ4Hdu+yb5K/qldnsGLLI1Hr0GmhLTDHsxDb6BxM7/8rv8QeQY GKSGshBqD2lO1xUVT8inbi8uXI1iyN68vHX6xoFT5wsjls70PxSZPO5i F40vn6BWNsHtKWOCDqMKYx8hYwiv0zETVwxBaj58vylFwYGU+g1wIQmF Pgi2HKv4KaxgikUvdFISre5rxVoG5VrmmXWiNJcLTbwZ+tE1xujCNU1c V31CaIB5hdSnkEvQADr5V64RTxWAKuSLNMU+XUqTkaJHasSm3OPJOteo SPj2uoesuxNFYps3
diff --git a/tests/dns/testdata/nsec3/min-1024.db b/tests/dns/testdata/nsec3/min-1024.db
new file mode 100644
index 0000000..360c282
--- /dev/null
+++ b/tests/dns/testdata/nsec3/min-1024.db
@@ -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.
+
+$TTL 0
+test. SOA . . 0 0 0 0 0
+test. NS .
+; 1024 bit key.
+test. IN DNSKEY 256 3 5 AwEAAd5oKx06HRE6NRrTDz49lljdRmxgp/4YB/cyMkpwUMkaLhDNCfTq hql84ab2LRbtUWLHFXGWENvxPGQzVHeleXu+3ThNfFOwIaySedxHmLGT lTtBRDhPc8iSb+2IYDemmA+ut8kwHhCVz/tDMbD/dgAswdOtmXCpQyJk Q1HqY3Xj
+; 2048 bits
+test. IN DNSKEY 256 3 5 AwEAAcfQX59iZr9gK+XzhTZQ5KWrfCLA0iYHTqheEIhC2dXS8gUSppQS g9SmzH2129u/LSSb7gqJSoLLAsn36iinqCqUXl2BT6xzwznbSP3mn0hn N6DegsykcYhHycKH6ifjZiMN+SGGeNsi5rhoW5Cj9ptw3C3yQnrFNDbS GZCT97z5lpQU3ZcvP4RDNk7dhri7Bh3SJeaCFoqx00NgFvlBR48hosSG bGUbUKzNf58GBTkW4Us2jIWsreZx8LLLev232Hy7NU9L19k+hVq7pJOf Uvtrn5fmGSutWOzsR+8EacOnh0lwssCKjutk5MSmfdFC5P7CTZkdq58L 8he13HGmr00=
+; 4096 bits
+test. IN DNSKEY 256 3 5 AwEAAbYlqbKxXoq9mzkqdsAaSZ3XywBVAb2sCTgrQBCExyGEYNpWw3LN +imCrLQi7jHKQW6GZIqKNgQaiFEwr3zK8nPWbwNwyKU9a2hhINv/gim1 5iA87Vu7DiiJrQ0O79ospvsGsKknBQ41zaaQMp3Q/W1S6WNe4uyh4C/f R0qmxT+8MyXEqCpTGb+e+YT6BuqpNQPuYYYvUJ1/HJltzY/lY2b9RZ+Q ZJ23Zje79YIRM0kJapqj11fDUDeynhDL1DUikYCwRfQiO/blChhOHjIa uTK1qqRY3fqanLGOufpLTr7GRpL7RxeRIMJfDzmcjFLmCsMA1AJ56Bxq jiXr3ODgn9D30vAB74Lr7lqLQSWyrSlJjoZLLhmPrEP/nnuCxEhOhDRA XJpJWpcQ4Hdu+yb5K/qldnsGLLI1Hr0GmhLTDHsxDb6BxM7/8rv8QeQY GKSGshBqD2lO1xUVT8inbi8uXI1iyN68vHX6xoFT5wsjls70PxSZPO5i F40vn6BWNsHtKWOCDqMKYx8hYwiv0zETVwxBaj58vylFwYGU+g1wIQmF Pgi2HKv4KaxgikUvdFISre5rxVoG5VrmmXWiNJcLTbwZ+tE1xujCNU1c V31CaIB5hdSnkEvQADr5V64RTxWAKuSLNMU+XUqTkaJHasSm3OPJOteo SPj2uoesuxNFYps3
diff --git a/tests/dns/testdata/nsec3/min-2048.db b/tests/dns/testdata/nsec3/min-2048.db
new file mode 100644
index 0000000..606264e
--- /dev/null
+++ b/tests/dns/testdata/nsec3/min-2048.db
@@ -0,0 +1,18 @@
+; 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 0
+test. SOA . . 0 0 0 0 0
+test. NS .
+; 2048 bits
+test. IN DNSKEY 256 3 5 AwEAAcfQX59iZr9gK+XzhTZQ5KWrfCLA0iYHTqheEIhC2dXS8gUSppQS g9SmzH2129u/LSSb7gqJSoLLAsn36iinqCqUXl2BT6xzwznbSP3mn0hn N6DegsykcYhHycKH6ifjZiMN+SGGeNsi5rhoW5Cj9ptw3C3yQnrFNDbS GZCT97z5lpQU3ZcvP4RDNk7dhri7Bh3SJeaCFoqx00NgFvlBR48hosSG bGUbUKzNf58GBTkW4Us2jIWsreZx8LLLev232Hy7NU9L19k+hVq7pJOf Uvtrn5fmGSutWOzsR+8EacOnh0lwssCKjutk5MSmfdFC5P7CTZkdq58L 8he13HGmr00=
+; 4096 bits
+test. IN DNSKEY 256 3 5 AwEAAbYlqbKxXoq9mzkqdsAaSZ3XywBVAb2sCTgrQBCExyGEYNpWw3LN +imCrLQi7jHKQW6GZIqKNgQaiFEwr3zK8nPWbwNwyKU9a2hhINv/gim1 5iA87Vu7DiiJrQ0O79ospvsGsKknBQ41zaaQMp3Q/W1S6WNe4uyh4C/f R0qmxT+8MyXEqCpTGb+e+YT6BuqpNQPuYYYvUJ1/HJltzY/lY2b9RZ+Q ZJ23Zje79YIRM0kJapqj11fDUDeynhDL1DUikYCwRfQiO/blChhOHjIa uTK1qqRY3fqanLGOufpLTr7GRpL7RxeRIMJfDzmcjFLmCsMA1AJ56Bxq jiXr3ODgn9D30vAB74Lr7lqLQSWyrSlJjoZLLhmPrEP/nnuCxEhOhDRA XJpJWpcQ4Hdu+yb5K/qldnsGLLI1Hr0GmhLTDHsxDb6BxM7/8rv8QeQY GKSGshBqD2lO1xUVT8inbi8uXI1iyN68vHX6xoFT5wsjls70PxSZPO5i F40vn6BWNsHtKWOCDqMKYx8hYwiv0zETVwxBaj58vylFwYGU+g1wIQmF Pgi2HKv4KaxgikUvdFISre5rxVoG5VrmmXWiNJcLTbwZ+tE1xujCNU1c V31CaIB5hdSnkEvQADr5V64RTxWAKuSLNMU+XUqTkaJHasSm3OPJOteo SPj2uoesuxNFYps3
diff --git a/tests/dns/testdata/nsec3param/nsec3.db.signed b/tests/dns/testdata/nsec3param/nsec3.db.signed
new file mode 100644
index 0000000..aeced0e
--- /dev/null
+++ b/tests/dns/testdata/nsec3param/nsec3.db.signed
@@ -0,0 +1,73 @@
+; File written on Mon Nov 16 16:04:21 2020
+; dnssec_signzone version 9.16.8
+nsec3. 1000 IN SOA nsec3. postmaster.nsec3. (
+ 1993050801 ; serial
+ 3600 ; refresh (1 hour)
+ 1800 ; retry (30 minutes)
+ 604800 ; expire (1 week)
+ 3600 ; minimum (1 hour)
+ )
+ 1000 RRSIG SOA 13 1 1000 (
+ 20201216140421 20201116140421 40382 nsec3.
+ qh61ZPgQaNLAoIQvAoTLbR3sLBY7XATaMGSS
+ fYOssQWvgAzpAzhalmF/cSXmQ/RZQOyIdpVg
+ v3rgyTxA2vGNnA== )
+ 1000 NS ns1.nsec3.
+ 1000 NS ns2.nsec3.
+ 1000 RRSIG NS 13 1 1000 (
+ 20201216140421 20201116140421 40382 nsec3.
+ 4Le+e5Lu/taEvrvrmBn/z+QP4zhzUqwO6v70
+ WYrzCggUls8+fUd2unBHDPWag1oSKfNpGGWA
+ crihrs4RhMPfZA== )
+ 1000 DNSKEY 257 3 13 (
+ VKkttSi/v3lAyzUYnykwdwowXfDOQ7wdN9BT
+ +eb8fVfgRApvuun9hjUBlv7ogriU/GAb60B8
+ juj9bXZADT+OGg==
+ ) ; KSK; alg = ECDSAP256SHA256 ; key id = 40382
+ 1000 RRSIG DNSKEY 13 1 1000 (
+ 20201216140421 20201116140421 40382 nsec3.
+ ZnBqGgWvHwjjQBSIRPXe2fx6+MsQp1QQdzJ0
+ QaEyaOmud5JPatUXaV9eFRcPNCsi+2HZSZVp
+ vsAGUCge7w6u9A== )
+ 0 NSEC3PARAM 1 0 5 FEDCBA98
+ 0 RRSIG NSEC3PARAM 13 1 0 (
+ 20201216140421 20201116140421 40382 nsec3.
+ WPTD+5vr54YtvGqCUJHPvGdF7Wd4piZYltcs
+ cztBRfdM7FRJ/zvrDS72rt6zm0TYSXzawqt/
+ MiwOkYKv2vxfUg== )
+ns2.nsec3. 1000 IN A 1.2.3.5
+ 1000 RRSIG A 13 2 1000 (
+ 20201216140421 20201116140421 40382 nsec3.
+ l9Mc2Y5JFmllSxJj3GUdH6RtEsYfhjJU39sa
+ vAVa4zxv6S9vU+vLvTA05aQ+DPLvKTX+WNH7
+ dDa+Yy5ffBs68g== )
+QVCH33BSJ0Q2C74FEDFDBCFQHO255NEB.nsec3. 3600 IN NSEC3 1 0 5 FEDCBA98 (
+ STH5N5QDVC5DGEN5VGUC7JGALSM3R8AP
+ A RRSIG )
+ 3600 RRSIG NSEC3 13 2 3600 (
+ 20201216140421 20201116140421 40382 nsec3.
+ F/wKQtv+RlBHG1WCz0CkHlTSoUiRx0z+qBI1
+ GTHoXSjgG1NSHqTI4C32AasZSMp+uuF2R8KW
+ 9z4gOLucl0Xmfg== )
+STH5N5QDVC5DGEN5VGUC7JGALSM3R8AP.nsec3. 3600 IN NSEC3 1 0 5 FEDCBA98 (
+ A084TNR6VJ2ND5K1U0AI4HO4EPVKBG4U
+ NS SOA RRSIG DNSKEY NSEC3PARAM )
+ 3600 RRSIG NSEC3 13 2 3600 (
+ 20201216140421 20201116140421 40382 nsec3.
+ 9TgGFGY3vwkxMFlXy3oKMgHPqvcPozKDHZzc
+ Ny6eJn3TXNX5bLhiT5rw5+CCtyOEQmn3pf0X
+ njK7jZBAcBV+5Q== )
+A084TNR6VJ2ND5K1U0AI4HO4EPVKBG4U.nsec3. 3600 IN NSEC3 1 0 5 FEDCBA98 (
+ QVCH33BSJ0Q2C74FEDFDBCFQHO255NEB
+ A RRSIG )
+ 3600 RRSIG NSEC3 13 2 3600 (
+ 20201216140421 20201116140421 40382 nsec3.
+ auf+5lrkMESIfdFK8bf4yg1a+NLGWzgUmohS
+ ydcKaJz0XcnULegatWdfE75jmZoDeqKNpwdL
+ 5lQ77GF4cEh1OQ== )
+ns1.nsec3. 1000 IN A 1.2.3.4
+ 1000 RRSIG A 13 2 1000 (
+ 20201216140421 20201116140421 40382 nsec3.
+ yAmr1EE8qe+Jl+wQXOdj/uSjMFUmns0D1lx6
+ zAVe9BaQwvF3wR7ZUk/u9G0RrUBchmEj0+yq
+ KEsw32Tru4Romg== )
diff --git a/tests/dns/testdata/zt/zone1.db b/tests/dns/testdata/zt/zone1.db
new file mode 100644
index 0000000..85e7951
--- /dev/null
+++ b/tests/dns/testdata/zt/zone1.db
@@ -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.
+
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+ in ns ns.vix.com.
+ in ns ns2.vix.com.
+ in ns ns3.vix.com.
+a in a 1.2.3.4
diff --git a/tests/dns/testkeys/Kexample.+008+20386.key b/tests/dns/testkeys/Kexample.+008+20386.key
new file mode 100644
index 0000000..3404dca
--- /dev/null
+++ b/tests/dns/testkeys/Kexample.+008+20386.key
@@ -0,0 +1,5 @@
+; This is a key-signing key, keyid 20386, for example.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example. IN DNSKEY 257 3 8 AwEAAZd7/hBRvMooz0sepkD/2r3Bp021f8lGzDj6sZEVbg1hcqZTzURc eGkS541wyOqjvJv2KBi5qLLE2HthmexmOBycjTQ7EiKd1P9bE8RgF8Et j73X/CHLiX6YL7cb93TXWiUvbRh4E6D2URgOmxMdMOXTuCvjvDaGVCOt Jc77UUosuBeurZzP8g8t/zccAUTzu2cdRyI5/ZxOBfJaDtc9TlRdWsaN Af+nT0C14ccH7QVlKjjaYV4lXueruDW3yTTzu9bQ1ikgegsCLi/tcD/1 dWTOI9whV06szs+ouhuJkZuhIjrGDtOHCpjPjIxOOrIZceU1YSY30kAR QNVzshJqyx8=
diff --git a/tests/dns/testkeys/Kexample.+008+20386.private b/tests/dns/testkeys/Kexample.+008+20386.private
new file mode 100644
index 0000000..d8cff93
--- /dev/null
+++ b/tests/dns/testkeys/Kexample.+008+20386.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: l3v+EFG8yijPSx6mQP/avcGnTbV/yUbMOPqxkRVuDWFyplPNRFx4aRLnjXDI6qO8m/YoGLmossTYe2GZ7GY4HJyNNDsSIp3U/1sTxGAXwS2Pvdf8IcuJfpgvtxv3dNdaJS9tGHgToPZRGA6bEx0w5dO4K+O8NoZUI60lzvtRSiy4F66tnM/yDy3/NxwBRPO7Zx1HIjn9nE4F8loO1z1OVF1axo0B/6dPQLXhxwftBWUqONphXiVe56u4NbfJNPO71tDWKSB6CwIuL+1wP/V1ZM4j3CFXTqzOz6i6G4mRm6EiOsYO04cKmM+MjE46shlx5TVhJjfSQBFA1XOyEmrLHw==
+PublicExponent: AQAB
+PrivateExponent: aSkynrGfldfuz/9e+xCjEcg2FMRDCb+UVpnyWv29gJx9sunKPgLTtF3jUVVSpVE1xi+EdmWsry3n+v8uk+YCXhpwDCpV1KItE3huqIzs8LZoaypdZjieIrwTo9JOX1aAxf++hJYXSk60zTaWgRZqs6He4Nkf99oY3wt8i8v8CrkfQy76K/qK9xUVv5GHrEZzCGLfLv77eqDab/J84ANxc0kUtQvgt2/JTHofXmcA6/YDh5PWB8KRw1PjQTck61/xIgfI6ky/yIF1riCQCYXwTv7jcmMV/QvQ+dfN+HZ2CSGp7xcH2Yxe9OhAY823ZkmkOQ2YZPjIj6dEoRMmSiaagQ==
+Prime1: x2GMnpRPwvUhM+yPRa7nh5Jjl4mbofeOtVrxe1hEVy8l2UGFh+FDZCbyoLRNUTYDji00NHpGtmcAyoY9pLdOn7ci4zqGVnNJcIY75Ie4p6J7pPfDh9d+AGtJ5NpNhr1sjD0bFncJC2FGY9vj4eC0CkatMu/Qovrd2FwZ8VpDsAk=
+Prime2: woB8MYsEfSYGD0hZGtmgK6UQ+Oo9smxdPmahLYXnLSAdqtqZbZX+ABk/kFduT+XwlHOXmp3HMmUtQTRZBaQyBrsFWfWjOGevByEsT9aLQSZOEgnqy4xrc9XNwDs4/WkrEgw/TOVnZYdaCyLxsFl4bpTX8Fj3yVqg/tJvuUMWG+c=
+Exponent1: iQO7a9rF+VcVSyZ8yslIaL0r3Z5+Kk8CbhSiMD5XMIbA/sztI5SlCDVPtSpSm8V/qfvcjVeeMokUXRjlUcV6rX1f50F3wf8V79L/Y6v1NJYPXC273CU1fLo+HJv8fOS9rJ3teIGy4HQnuEYLE1WkxA8PxRpSiT3WqHGajmaWb2k=
+Exponent2: elMWSI5Wz2KXkwr8Rz+xVWGl7/ZZwRoX9oPTQG8jeiTlo6uBrQMVUPiQGnZyQTuq96JPKYWrXs11DbofdsXSVJtQfUhYU8QZtxEs7jVPNTUjCoNEMKnqdlpz4T8d03pOBTbApNruEVNz1OcwO6m5bUqdGGLLy838zOaKL2i6wec=
+Coefficient: q2mejAmT3A4H2C0rT1hm8XQFuISHjAAEyM9t09Q8tEeQ0lHi4gMVA3bXoAn9U21eBkFQDwvyB0vqlVSGgRqHovOKx9uXAU9eoDxGcJsFlGsM0aUsUjGVXv5kVmaw8a5PHBbvYAbgAZUmKqrVF0PWD3o+/DbzP9PCmlJcqxoAulU=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/testkeys/Kexample.+008+37464.key b/tests/dns/testkeys/Kexample.+008+37464.key
new file mode 100644
index 0000000..3dd0619
--- /dev/null
+++ b/tests/dns/testkeys/Kexample.+008+37464.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 37464, for example.
+; Created: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000)
+; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000)
+example. IN DNSKEY 256 3 8 AwEAAbxHOF8G0xw9ekCodhL8KivuZ3o0jmGlycLiXBjBN8c5R5fjLjUh D0gy3IDbDC+kLaPhHGF/MwrSEjrgSowxZ8nrxDzsq5ZdpeUsYaNrbQEY /mqf35T/9/Ulm4v06x58v/NTugWd05Xq04aAyfm7EViyGFzmVOVfPnll h9xQtvWEWoRWPseFw+dY5/nc/+xB/IsQMihoH2rO+cek/lsP3R9DsHCG RbQ/ks/+rrp6/O+QJZyZrzsONl7mlMDXNy3Pz9J4qMW2W6Mz702LN324 7/9UsetDGGbuZfrCLMpKWXzdsJm36DOk4aMooS9111plfXaXQgQNcL5G 021utpTau+8=
diff --git a/tests/dns/testkeys/Kexample.+008+37464.private b/tests/dns/testkeys/Kexample.+008+37464.private
new file mode 100644
index 0000000..ecc2ad0
--- /dev/null
+++ b/tests/dns/testkeys/Kexample.+008+37464.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 8 (RSASHA256)
+Modulus: vEc4XwbTHD16QKh2EvwqK+5nejSOYaXJwuJcGME3xzlHl+MuNSEPSDLcgNsML6Qto+EcYX8zCtISOuBKjDFnyevEPOyrll2l5Sxho2ttARj+ap/flP/39SWbi/TrHny/81O6BZ3TlerThoDJ+bsRWLIYXOZU5V8+eWWH3FC29YRahFY+x4XD51jn+dz/7EH8ixAyKGgfas75x6T+Ww/dH0OwcIZFtD+Sz/6uunr875AlnJmvOw42XuaUwNc3Lc/P0nioxbZbozPvTYs3fbjv/1Sx60MYZu5l+sIsykpZfN2wmbfoM6ThoyihL3XXWmV9dpdCBA1wvkbTbW62lNq77w==
+PublicExponent: AQAB
+PrivateExponent: AhR3VvVoV6OGOjiiNUt728hidEMoX4PJWtHNWqinyRek5tSnqgaXeKC3NuU0mUIjDvBps9oH4lK3yNa5fBr/nodwP4wNyTd3obR/z6JcLersxJjHi4nYX2ju8vjdsBSIulNudqlrsPhLJe0+Tff3FRfClSQmQ/JtakHo4lIx8zxiOJY8aWFeHGdWJDkAf6NStt3eVYyOyAwISfv3muaGPZKShiIOfLyTvqFqzwYFgdTWmvFqTdwgjIMc5XAwqw73WP2BPCN+fdCiMtrw0fCrhWzw/gfMJBHdOPH0diUZysAJhM0vdVKQzEi/g3YOo00fahZiPzaxNtZnLNj2mA54YQ==
+Prime1: 5YpfVjEtL1owW9gSFbIMx65POr+fiktxirgy1bc5fSsVqUgG6zhbaN/VpWcNZG0Zg5xd6S7C8V3djGlnJN8wZIyjIh7+Z3WWjqbOD9oY7rC1fR+W0OvbCmZiEzOpRJ5qoMOh1MzkkanhMy0/ICpaa8eQ9zEb80oTIQpFgoLn7K0=
+Prime2: 0fs3ncL5/2qzq2dmPXLYcOfc1EGSuESO0VpREP8EpTkyPKeVw5LaF9TgZRqPWlRf2T0LPoZ766xLAn090u0pLQ5fWM96NMas7kS+rxtRssat6MiQo3YfoU3ysk3xuPzrMBHyn/N42CjSG+bJEToHR7V16KsCT6dBIPkI3tj/Yos=
+Exponent1: Bdsp44ENrg+W/EDe9T69pLqFuvH4mAaktu1MHre198OJoe/8fTPK4ToUsUuXw+Akrn7mxnQy9QV4CYUG5KHtEiOkZdJ0mx8c4DbROwZNbImFl9OefWYHCJTkG6lNwDpqbf+PuWYgzraO0EdvPNrXw7grsqLGG8bgBg/FBjdgw2E=
+Exponent2: uV1pxW0fwGhzX3aR/ODrTRCCEyYn3V84LHvsYHKfqTOKs5zFSrbSrIMR7G676ePeESogSPvzXSLlvLbO4urVlJ7BcOcHXJuegWBSbMZTItzdHUgg1wwp8/2Zp+nC36j1/aN6adVG8ptmj5b2HKz7TERWaCS+j454oiD1wbQSDu0=
+Coefficient: JO6RxBIaoEd/Z4ITcsYT8TslP1KmIuAqdhMt3FSpqeogUDut7f3FZIEyNi4wsrSK5peIQSVmO2pQLupS+eRIPHXZ1vh5kcFAsgd7XBb7Fvsg26/WSjhB4wjx+wgWzVomK0519pfdtH854fePWPkdDKtLNL2zh0APne3GjwrbNEM=
+Created: 20000101000000
+Publish: 20000101000000
+Activate: 20000101000000
diff --git a/tests/dns/time_test.c b/tests/dns/time_test.c
new file mode 100644
index 0000000..f6e1948
--- /dev/null
+++ b/tests/dns/time_test.c
@@ -0,0 +1,169 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/util.h>
+
+#include <dns/time.h>
+
+#include <tests/dns.h>
+
+#define TEST_ORIGIN "test"
+
+/* value = 0xfffffffff <-> 19691231235959 */
+ISC_RUN_TEST_IMPL(epoch_minus_one) {
+ const char *test_text = "19691231235959";
+ const uint32_t test_time = 0xffffffff;
+ isc_result_t result;
+ isc_buffer_t target;
+ uint32_t when;
+ char buf[128];
+
+ UNUSED(state);
+
+ memset(buf, 0, sizeof(buf));
+ isc_buffer_init(&target, buf, sizeof(buf));
+ result = dns_time32_totext(test_time, &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, test_text);
+ result = dns_time32_fromtext(test_text, &when);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(when, test_time);
+}
+
+/* value = 0x000000000 <-> 19700101000000*/
+ISC_RUN_TEST_IMPL(epoch) {
+ const char *test_text = "19700101000000";
+ const uint32_t test_time = 0x00000000;
+ isc_result_t result;
+ isc_buffer_t target;
+ uint32_t when;
+ char buf[128];
+
+ UNUSED(state);
+
+ memset(buf, 0, sizeof(buf));
+ isc_buffer_init(&target, buf, sizeof(buf));
+ result = dns_time32_totext(test_time, &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, test_text);
+ result = dns_time32_fromtext(test_text, &when);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(when, test_time);
+}
+
+/* value = 0x7fffffff <-> 20380119031407 */
+ISC_RUN_TEST_IMPL(half_maxint) {
+ const char *test_text = "20380119031407";
+ const uint32_t test_time = 0x7fffffff;
+ isc_result_t result;
+ isc_buffer_t target;
+ uint32_t when;
+ char buf[128];
+
+ UNUSED(state);
+
+ memset(buf, 0, sizeof(buf));
+ isc_buffer_init(&target, buf, sizeof(buf));
+ result = dns_time32_totext(test_time, &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, test_text);
+ result = dns_time32_fromtext(test_text, &when);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(when, test_time);
+}
+
+/* value = 0x80000000 <-> 20380119031408 */
+ISC_RUN_TEST_IMPL(half_plus_one) {
+ const char *test_text = "20380119031408";
+ const uint32_t test_time = 0x80000000;
+ isc_result_t result;
+ isc_buffer_t target;
+ uint32_t when;
+ char buf[128];
+
+ UNUSED(state);
+
+ memset(buf, 0, sizeof(buf));
+ isc_buffer_init(&target, buf, sizeof(buf));
+ result = dns_time32_totext(test_time, &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, test_text);
+ result = dns_time32_fromtext(test_text, &when);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(when, test_time);
+}
+
+/* value = 0xef68f5d0 <-> 19610307130000 */
+ISC_RUN_TEST_IMPL(fifty_before) {
+ isc_result_t result;
+ const char *test_text = "19610307130000";
+ const uint32_t test_time = 0xef68f5d0;
+ isc_buffer_t target;
+ uint32_t when;
+ char buf[128];
+
+ UNUSED(state);
+
+ memset(buf, 0, sizeof(buf));
+ isc_buffer_init(&target, buf, sizeof(buf));
+ result = dns_time32_totext(test_time, &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, test_text);
+ result = dns_time32_fromtext(test_text, &when);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(when, test_time);
+}
+
+/* value = 0x4d74d6d0 <-> 20110307130000 */
+ISC_RUN_TEST_IMPL(some_ago) {
+ const char *test_text = "20110307130000";
+ const uint32_t test_time = 0x4d74d6d0;
+ isc_result_t result;
+ isc_buffer_t target;
+ uint32_t when;
+ char buf[128];
+
+ UNUSED(state);
+
+ memset(buf, 0, sizeof(buf));
+ isc_buffer_init(&target, buf, sizeof(buf));
+ result = dns_time32_totext(test_time, &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, test_text);
+ result = dns_time32_fromtext(test_text, &when);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(when, test_time);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(epoch_minus_one)
+ISC_TEST_ENTRY(epoch)
+ISC_TEST_ENTRY(half_maxint)
+ISC_TEST_ENTRY(half_plus_one)
+ISC_TEST_ENTRY(fifty_before)
+ISC_TEST_ENTRY(some_ago)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/tsig_test.c b/tests/dns/tsig_test.c
new file mode 100644
index 0000000..2cc26c7
--- /dev/null
+++ b/tests/dns/tsig_test.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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/util.h>
+
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/tsig.h>
+
+#include "tsig_p.h"
+
+#include <tests/dns.h>
+
+#define TEST_ORIGIN "test"
+
+static int debug = 0;
+
+static int
+setup_test(void **state) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dst_lib_init(mctx, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ UNUSED(state);
+
+ dst_lib_destroy();
+
+ return (0);
+}
+
+static isc_result_t
+add_mac(dst_context_t *tsigctx, isc_buffer_t *buf) {
+ dns_rdata_any_tsig_t tsig;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_buffer_t databuf;
+ isc_region_t r;
+ isc_result_t result;
+ unsigned char tsigbuf[1024];
+
+ isc_buffer_usedregion(buf, &r);
+ dns_rdata_fromregion(&rdata, dns_rdataclass_any, dns_rdatatype_tsig,
+ &r);
+ isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf));
+ CHECK(dns_rdata_tostruct(&rdata, &tsig, NULL));
+ isc_buffer_putuint16(&databuf, tsig.siglen);
+ isc_buffer_putmem(&databuf, tsig.signature, tsig.siglen);
+ isc_buffer_usedregion(&databuf, &r);
+ result = dst_context_adddata(tsigctx, &r);
+ dns_rdata_freestruct(&tsig);
+cleanup:
+ return (result);
+}
+
+static isc_result_t
+add_tsig(dst_context_t *tsigctx, dns_tsigkey_t *key, isc_buffer_t *target) {
+ dns_compress_t cctx;
+ dns_rdata_any_tsig_t tsig;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdatalist_t rdatalist;
+ dns_rdataset_t rdataset;
+ isc_buffer_t *dynbuf = NULL;
+ isc_buffer_t databuf;
+ isc_buffer_t sigbuf;
+ isc_region_t r;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_stdtime_t now;
+ unsigned char tsigbuf[1024];
+ unsigned int count;
+ unsigned int sigsize = 0;
+ bool invalidate_ctx = false;
+
+ memset(&tsig, 0, sizeof(tsig));
+
+ CHECK(dns_compress_init(&cctx, -1, mctx));
+ invalidate_ctx = true;
+
+ tsig.common.rdclass = dns_rdataclass_any;
+ tsig.common.rdtype = dns_rdatatype_tsig;
+ ISC_LINK_INIT(&tsig.common, link);
+ dns_name_init(&tsig.algorithm, NULL);
+ dns_name_clone(key->algorithm, &tsig.algorithm);
+
+ isc_stdtime_get(&now);
+ tsig.timesigned = now;
+ tsig.fudge = DNS_TSIG_FUDGE;
+ tsig.originalid = 50;
+ tsig.error = dns_rcode_noerror;
+ tsig.otherlen = 0;
+ tsig.other = NULL;
+
+ isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf));
+ isc_buffer_putuint48(&databuf, tsig.timesigned);
+ isc_buffer_putuint16(&databuf, tsig.fudge);
+ isc_buffer_usedregion(&databuf, &r);
+ CHECK(dst_context_adddata(tsigctx, &r));
+
+ CHECK(dst_key_sigsize(key->key, &sigsize));
+ tsig.signature = isc_mem_get(mctx, sigsize);
+ isc_buffer_init(&sigbuf, tsig.signature, sigsize);
+ CHECK(dst_context_sign(tsigctx, &sigbuf));
+ tsig.siglen = isc_buffer_usedlength(&sigbuf);
+ assert_int_equal(sigsize, tsig.siglen);
+
+ isc_buffer_allocate(mctx, &dynbuf, 512);
+ CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_any,
+ dns_rdatatype_tsig, &tsig, dynbuf));
+ dns_rdatalist_init(&rdatalist);
+ rdatalist.rdclass = dns_rdataclass_any;
+ rdatalist.type = dns_rdatatype_tsig;
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+ dns_rdataset_init(&rdataset);
+ CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
+ CHECK(dns_rdataset_towire(&rdataset, &key->name, &cctx, target, 0,
+ &count));
+
+ /*
+ * Fixup additional record count.
+ */
+ ((unsigned char *)target->base)[11]++;
+ if (((unsigned char *)target->base)[11] == 0) {
+ ((unsigned char *)target->base)[10]++;
+ }
+cleanup:
+ if (tsig.signature != NULL) {
+ isc_mem_put(mctx, tsig.signature, sigsize);
+ }
+ if (dynbuf != NULL) {
+ isc_buffer_free(&dynbuf);
+ }
+ if (invalidate_ctx) {
+ dns_compress_invalidate(&cctx);
+ }
+
+ return (result);
+}
+
+static void
+printmessage(dns_message_t *msg) {
+ isc_buffer_t b;
+ char *buf = NULL;
+ int len = 1024;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ if (!debug) {
+ return;
+ }
+
+ do {
+ buf = isc_mem_get(mctx, len);
+
+ isc_buffer_init(&b, buf, len);
+ result = dns_message_totext(msg, &dns_master_style_debug, 0,
+ &b);
+ if (result == ISC_R_NOSPACE) {
+ isc_mem_put(mctx, buf, len);
+ len *= 2;
+ } else if (result == ISC_R_SUCCESS) {
+ printf("%.*s\n", (int)isc_buffer_usedlength(&b), buf);
+ }
+ } while (result == ISC_R_NOSPACE);
+
+ if (buf != NULL) {
+ isc_mem_put(mctx, buf, len);
+ }
+}
+
+static void
+render(isc_buffer_t *buf, unsigned flags, dns_tsigkey_t *key,
+ isc_buffer_t **tsigin, isc_buffer_t **tsigout, dst_context_t *tsigctx) {
+ dns_message_t *msg = NULL;
+ dns_compress_t cctx;
+ isc_result_t result;
+
+ dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &msg);
+ assert_non_null(msg);
+
+ msg->id = 50;
+ msg->rcode = dns_rcode_noerror;
+ msg->flags = flags;
+
+ /*
+ * XXXMPA: this hack needs to be replaced with use of
+ * dns_message_reply() at some point.
+ */
+ if ((flags & DNS_MESSAGEFLAG_QR) != 0) {
+ msg->verified_sig = 1;
+ }
+
+ if (tsigin == tsigout) {
+ msg->tcp_continuation = 1;
+ }
+
+ if (tsigctx == NULL) {
+ result = dns_message_settsigkey(msg, key);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_message_setquerytsig(msg, *tsigin);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ result = dns_compress_init(&cctx, -1, mctx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_message_renderbegin(msg, &cctx, buf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_message_renderend(msg);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ if (tsigctx != NULL) {
+ isc_region_t r;
+
+ isc_buffer_usedregion(buf, &r);
+ result = dst_context_adddata(tsigctx, &r);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ } else {
+ if (tsigin == tsigout && *tsigin != NULL) {
+ isc_buffer_free(tsigin);
+ }
+
+ result = dns_message_getquerytsig(msg, mctx, tsigout);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ dns_compress_invalidate(&cctx);
+ dns_message_detach(&msg);
+}
+
+/*
+ * Test tsig tcp-continuation validation:
+ * Check that a simulated three message TCP sequence where the first
+ * and last messages contain TSIGs but the intermediate message doesn't
+ * correctly verifies.
+ */
+ISC_RUN_TEST_IMPL(tsig_tcp) {
+ const dns_name_t *tsigowner = NULL;
+ dns_fixedname_t fkeyname;
+ dns_message_t *msg = NULL;
+ dns_name_t *keyname;
+ dns_tsig_keyring_t *ring = NULL;
+ dns_tsigkey_t *key = NULL;
+ isc_buffer_t *buf = NULL;
+ isc_buffer_t *querytsig = NULL;
+ isc_buffer_t *tsigin = NULL;
+ isc_buffer_t *tsigout = NULL;
+ isc_result_t result;
+ unsigned char secret[16] = { 0 };
+ dst_context_t *tsigctx = NULL;
+ dst_context_t *outctx = NULL;
+
+ UNUSED(state);
+
+ /* isc_log_setdebuglevel(lctx, 99); */
+
+ keyname = dns_fixedname_initname(&fkeyname);
+ result = dns_name_fromstring(keyname, "test", 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_tsigkeyring_create(mctx, &ring);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_tsigkey_create(keyname, dns_tsig_hmacsha256_name, secret,
+ sizeof(secret), false, NULL, 0, 0, mctx,
+ ring, &key);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(key);
+
+ /*
+ * Create request.
+ */
+ isc_buffer_allocate(mctx, &buf, 65535);
+ render(buf, 0, key, &tsigout, &querytsig, NULL);
+ isc_buffer_free(&buf);
+
+ /*
+ * Create response message 1.
+ */
+ isc_buffer_allocate(mctx, &buf, 65535);
+ render(buf, DNS_MESSAGEFLAG_QR, key, &querytsig, &tsigout, NULL);
+ assert_non_null(tsigout);
+
+ /*
+ * Process response message 1.
+ */
+ dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
+ assert_non_null(msg);
+
+ result = dns_message_settsigkey(msg, key);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_message_parse(msg, buf, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ printmessage(msg);
+
+ result = dns_message_setquerytsig(msg, querytsig);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_tsig_verify(buf, msg, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(msg->verified_sig, 1);
+ assert_int_equal(msg->tsigstatus, dns_rcode_noerror);
+
+ /*
+ * Check that we have a TSIG in the first message.
+ */
+ assert_non_null(dns_message_gettsig(msg, &tsigowner));
+
+ result = dns_message_getquerytsig(msg, mctx, &tsigin);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ tsigctx = msg->tsigctx;
+ msg->tsigctx = NULL;
+ isc_buffer_free(&buf);
+ dns_message_detach(&msg);
+
+ result = dst_context_create(key->key, mctx, DNS_LOGCATEGORY_DNSSEC,
+ false, 0, &outctx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(outctx);
+
+ /*
+ * Start digesting.
+ */
+ result = add_mac(outctx, tsigout);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Create response message 2.
+ */
+ isc_buffer_allocate(mctx, &buf, 65535);
+
+ assert_int_equal(result, ISC_R_SUCCESS);
+ render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx);
+
+ /*
+ * Process response message 2.
+ */
+ dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
+ assert_non_null(msg);
+
+ msg->tcp_continuation = 1;
+ msg->tsigctx = tsigctx;
+ tsigctx = NULL;
+
+ result = dns_message_settsigkey(msg, key);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_message_parse(msg, buf, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ printmessage(msg);
+
+ result = dns_message_setquerytsig(msg, tsigin);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_tsig_verify(buf, msg, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(msg->verified_sig, 0);
+ assert_int_equal(msg->tsigstatus, dns_rcode_noerror);
+
+ /*
+ * Check that we don't have a TSIG in the second message.
+ */
+ tsigowner = NULL;
+ assert_true(dns_message_gettsig(msg, &tsigowner) == NULL);
+
+ tsigctx = msg->tsigctx;
+ msg->tsigctx = NULL;
+ isc_buffer_free(&buf);
+ dns_message_detach(&msg);
+
+ /*
+ * Create response message 3.
+ */
+ isc_buffer_allocate(mctx, &buf, 65535);
+ render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx);
+
+ result = add_tsig(outctx, key, buf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Process response message 3.
+ */
+ dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
+ assert_non_null(msg);
+
+ msg->tcp_continuation = 1;
+ msg->tsigctx = tsigctx;
+ tsigctx = NULL;
+
+ result = dns_message_settsigkey(msg, key);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_message_parse(msg, buf, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ printmessage(msg);
+
+ /*
+ * Check that we had a TSIG in the third message.
+ */
+ assert_non_null(dns_message_gettsig(msg, &tsigowner));
+
+ result = dns_message_setquerytsig(msg, tsigin);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_tsig_verify(buf, msg, NULL, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(msg->verified_sig, 1);
+ assert_int_equal(msg->tsigstatus, dns_rcode_noerror);
+
+ if (tsigin != NULL) {
+ isc_buffer_free(&tsigin);
+ }
+
+ result = dns_message_getquerytsig(msg, mctx, &tsigin);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_free(&buf);
+ dns_message_detach(&msg);
+
+ if (outctx != NULL) {
+ dst_context_destroy(&outctx);
+ }
+ if (querytsig != NULL) {
+ isc_buffer_free(&querytsig);
+ }
+ if (tsigin != NULL) {
+ isc_buffer_free(&tsigin);
+ }
+ if (tsigout != NULL) {
+ isc_buffer_free(&tsigout);
+ }
+ dns_tsigkey_detach(&key);
+ if (ring != NULL) {
+ dns_tsigkeyring_detach(&ring);
+ }
+}
+
+/* Tests the dns__tsig_algvalid function */
+ISC_RUN_TEST_IMPL(algvalid) {
+ UNUSED(state);
+
+ assert_true(dns__tsig_algvalid(DST_ALG_HMACMD5));
+
+ assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA1));
+ assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA224));
+ assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA256));
+ assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA384));
+ assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA512));
+
+ assert_false(dns__tsig_algvalid(DST_ALG_GSSAPI));
+}
+
+/* Tests the dns__tsig_algfromname function */
+ISC_RUN_TEST_IMPL(algfromname) {
+ UNUSED(state);
+
+ assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACMD5_NAME),
+ DST_ALG_HMACMD5);
+ assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA1_NAME),
+ DST_ALG_HMACSHA1);
+ assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA224_NAME),
+ DST_ALG_HMACSHA224);
+ assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA256_NAME),
+ DST_ALG_HMACSHA256);
+ assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA384_NAME),
+ DST_ALG_HMACSHA384);
+ assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA512_NAME),
+ DST_ALG_HMACSHA512);
+
+ assert_int_equal(dns__tsig_algfromname(DNS_TSIG_GSSAPI_NAME),
+ DST_ALG_GSSAPI);
+ assert_int_equal(dns__tsig_algfromname(DNS_TSIG_GSSAPIMS_NAME),
+ DST_ALG_GSSAPI);
+
+ assert_int_equal(dns__tsig_algfromname(dns_rootname), 0);
+}
+
+/* Tests the dns__tsig_algnamefromname function */
+
+/*
+ * Helper function to create a dns_name_t from a string and see if
+ * the dns__tsig_algnamefromname function can correctly match it against the
+ * static table of known algorithms.
+ */
+static void
+test_name(const char *name_string, const dns_name_t *expected) {
+ dns_name_t name;
+ dns_name_init(&name, NULL);
+ assert_int_equal(dns_name_fromstring(&name, name_string, 0, mctx),
+ ISC_R_SUCCESS);
+ assert_ptr_equal(dns__tsig_algnamefromname(&name), expected);
+ dns_name_free(&name, mctx);
+}
+
+ISC_RUN_TEST_IMPL(algnamefromname) {
+ UNUSED(state);
+
+ /* test the standard algorithms */
+ test_name("hmac-md5.sig-alg.reg.int", DNS_TSIG_HMACMD5_NAME);
+ test_name("hmac-sha1", DNS_TSIG_HMACSHA1_NAME);
+ test_name("hmac-sha224", DNS_TSIG_HMACSHA224_NAME);
+ test_name("hmac-sha256", DNS_TSIG_HMACSHA256_NAME);
+ test_name("hmac-sha384", DNS_TSIG_HMACSHA384_NAME);
+ test_name("hmac-sha512", DNS_TSIG_HMACSHA512_NAME);
+
+ test_name("gss-tsig", DNS_TSIG_GSSAPI_NAME);
+ test_name("gss.microsoft.com", DNS_TSIG_GSSAPIMS_NAME);
+
+ /* try another name that isn't a standard algorithm name */
+ assert_null(dns__tsig_algnamefromname(dns_rootname));
+}
+
+/* Tests the dns__tsig_algallocated function */
+ISC_RUN_TEST_IMPL(algallocated) {
+ UNUSED(state);
+
+ /* test the standard algorithms */
+ assert_false(dns__tsig_algallocated(DNS_TSIG_HMACMD5_NAME));
+ assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA1_NAME));
+ assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA224_NAME));
+ assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA256_NAME));
+ assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA384_NAME));
+ assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME));
+
+ assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME));
+ assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME));
+
+ /* try another name that isn't a standard algorithm name */
+ assert_true(dns__tsig_algallocated(dns_rootname));
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(tsig_tcp, setup_test, teardown_test)
+ISC_TEST_ENTRY(algvalid)
+ISC_TEST_ENTRY(algfromname)
+ISC_TEST_ENTRY_CUSTOM(algnamefromname, setup_test, teardown_test)
+ISC_TEST_ENTRY(algallocated)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/update_test.c b/tests/dns/update_test.c
new file mode 100644
index 0000000..afeaa5c
--- /dev/null
+++ b/tests/dns/update_test.c
@@ -0,0 +1,309 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/serial.h>
+#include <isc/stdtime.h>
+#include <isc/util.h>
+
+#include <dns/update.h>
+#define KEEP_BEFORE
+
+/*
+ * Fix the linking order problem for overridden isc_stdtime_get() by making
+ * everything local. This also allows static functions from update.c to be
+ * tested.
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#undef CHECK
+#include "update.c"
+#pragma GCC diagnostic pop
+
+#undef CHECK
+#include <tests/dns.h>
+
+static int
+setup_test(void **state) {
+ UNUSED(state);
+
+ setenv("TZ", "", 1);
+
+ return (0);
+}
+
+static uint32_t mystdtime;
+
+static void
+set_mystdtime(int year, int month, int day) {
+ struct tm tm;
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ mystdtime = timegm(&tm);
+}
+
+void
+isc_stdtime_get(isc_stdtime_t *now) {
+ *now = mystdtime;
+}
+
+/* simple increment by 1 */
+ISC_RUN_TEST_IMPL(increment) {
+ uint32_t old = 50;
+ uint32_t serial;
+
+ UNUSED(state);
+
+ serial = dns_update_soaserial(old, dns_updatemethod_increment, NULL);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, 51);
+}
+
+/* increment past zero, 0xfffffffff -> 1 */
+ISC_RUN_TEST_IMPL(increment_past_zero) {
+ uint32_t old = 0xffffffffu;
+ uint32_t serial;
+
+ UNUSED(state);
+
+ serial = dns_update_soaserial(old, dns_updatemethod_increment, NULL);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, 1u);
+}
+
+/* past to unixtime */
+ISC_RUN_TEST_IMPL(past_to_unix) {
+ uint32_t old;
+ uint32_t serial;
+
+ UNUSED(state);
+
+ set_mystdtime(2011, 6, 22);
+ old = mystdtime - 1;
+
+ serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, mystdtime);
+}
+
+/* now to unixtime */
+ISC_RUN_TEST_IMPL(now_to_unix) {
+ uint32_t old;
+ uint32_t serial;
+
+ UNUSED(state);
+
+ set_mystdtime(2011, 6, 22);
+ old = mystdtime;
+
+ serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, old + 1);
+}
+
+/* future to unixtime */
+ISC_RUN_TEST_IMPL(future_to_unix) {
+ uint32_t old;
+ uint32_t serial;
+
+ UNUSED(state);
+
+ set_mystdtime(2011, 6, 22);
+ old = mystdtime + 1;
+
+ serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, old + 1);
+}
+
+/* undefined plus 1 to unixtime */
+ISC_RUN_TEST_IMPL(undefined_plus1_to_unix) {
+ uint32_t old;
+ uint32_t serial;
+
+ UNUSED(state);
+
+ set_mystdtime(2011, 6, 22);
+ old = mystdtime ^ 0x80000000u;
+ old += 1;
+
+ serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, mystdtime);
+}
+
+/* undefined minus 1 to unixtime */
+ISC_RUN_TEST_IMPL(undefined_minus1_to_unix) {
+ uint32_t old;
+ uint32_t serial;
+
+ UNUSED(state);
+
+ set_mystdtime(2011, 6, 22);
+ old = mystdtime ^ 0x80000000u;
+ old -= 1;
+
+ serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, old + 1);
+}
+
+/* undefined to unixtime */
+ISC_RUN_TEST_IMPL(undefined_to_unix) {
+ uint32_t old;
+ uint32_t serial;
+
+ UNUSED(state);
+
+ set_mystdtime(2011, 6, 22);
+ old = mystdtime ^ 0x80000000u;
+
+ serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, old + 1);
+}
+
+/* handle unixtime being zero */
+ISC_RUN_TEST_IMPL(unixtime_zero) {
+ uint32_t old;
+ uint32_t serial;
+
+ UNUSED(state);
+
+ mystdtime = 0;
+ old = 0xfffffff0;
+
+ serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, old + 1);
+}
+
+/* past to date */
+ISC_RUN_TEST_IMPL(past_to_date) {
+ uint32_t old, serial;
+ dns_updatemethod_t used = dns_updatemethod_none;
+
+ UNUSED(state);
+
+ set_mystdtime(2014, 3, 31);
+ old = dns_update_soaserial(0, dns_updatemethod_date, NULL);
+ set_mystdtime(2014, 4, 1);
+
+ serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, 2014040100);
+ assert_int_equal(dns_updatemethod_date, used);
+}
+
+/* now to date */
+ISC_RUN_TEST_IMPL(now_to_date) {
+ uint32_t old;
+ uint32_t serial;
+ dns_updatemethod_t used = dns_updatemethod_none;
+
+ UNUSED(state);
+
+ set_mystdtime(2014, 4, 1);
+ old = dns_update_soaserial(0, dns_updatemethod_date, NULL);
+
+ serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, 2014040101);
+ assert_int_equal(dns_updatemethod_date, used);
+
+ old = 2014040198;
+ serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, 2014040199);
+ assert_int_equal(dns_updatemethod_date, used);
+
+ /*
+ * Stealing from "tomorrow".
+ */
+ old = 2014040199;
+ serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, 2014040200);
+ assert_int_equal(dns_updatemethod_increment, used);
+}
+
+/* future to date */
+ISC_RUN_TEST_IMPL(future_to_date) {
+ uint32_t old;
+ uint32_t serial;
+ dns_updatemethod_t used = dns_updatemethod_none;
+
+ UNUSED(state);
+
+ set_mystdtime(2014, 4, 1);
+ old = dns_update_soaserial(0, dns_updatemethod_date, NULL);
+ set_mystdtime(2014, 3, 31);
+
+ serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, 2014040101);
+ assert_int_equal(dns_updatemethod_increment, used);
+
+ old = serial;
+ serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
+ assert_true(isc_serial_lt(old, serial));
+ assert_int_not_equal(serial, 0);
+ assert_int_equal(serial, 2014040102);
+ assert_int_equal(dns_updatemethod_increment, used);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(increment, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(increment_past_zero, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(past_to_unix, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(now_to_unix, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(future_to_unix, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(undefined_to_unix, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(undefined_plus1_to_unix, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(undefined_minus1_to_unix, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(unixtime_zero, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(past_to_date, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(now_to_date, setup_test, NULL)
+ISC_TEST_ENTRY_CUSTOM(future_to_date, setup_test, NULL)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/zonemgr_test.c b/tests/dns/zonemgr_test.c
new file mode 100644
index 0000000..0cbbca4
--- /dev/null
+++ b/tests/dns/zonemgr_test.c
@@ -0,0 +1,224 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/name.h>
+#include <dns/view.h>
+#include <dns/zone.h>
+
+#include <tests/dns.h>
+
+/* create zone manager */
+ISC_RUN_TEST_IMPL(dns_zonemgr_create) {
+ dns_zonemgr_t *myzonemgr = NULL;
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dns_zonemgr_create(mctx, taskmgr, timermgr, netmgr,
+ &myzonemgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_zonemgr_shutdown(myzonemgr);
+ dns_zonemgr_detach(&myzonemgr);
+ assert_null(myzonemgr);
+}
+
+/* manage and release a zone */
+ISC_RUN_TEST_IMPL(dns_zonemgr_managezone) {
+ dns_zonemgr_t *myzonemgr = NULL;
+ dns_zone_t *zone = NULL;
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dns_zonemgr_create(mctx, taskmgr, timermgr, netmgr,
+ &myzonemgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_test_makezone("foo", &zone, NULL, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* This should not succeed until the dns_zonemgr_setsize() is run */
+ result = dns_zonemgr_managezone(myzonemgr, zone);
+ assert_int_equal(result, ISC_R_FAILURE);
+
+ assert_int_equal(dns_zonemgr_getcount(myzonemgr, DNS_ZONESTATE_ANY), 0);
+
+ result = dns_zonemgr_setsize(myzonemgr, 1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Now it should succeed */
+ result = dns_zonemgr_managezone(myzonemgr, zone);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_int_equal(dns_zonemgr_getcount(myzonemgr, DNS_ZONESTATE_ANY), 1);
+
+ dns_zonemgr_releasezone(myzonemgr, zone);
+ dns_zone_detach(&zone);
+
+ assert_int_equal(dns_zonemgr_getcount(myzonemgr, DNS_ZONESTATE_ANY), 0);
+
+ dns_zonemgr_shutdown(myzonemgr);
+ dns_zonemgr_detach(&myzonemgr);
+ assert_null(myzonemgr);
+}
+
+/* create and release a zone */
+ISC_RUN_TEST_IMPL(dns_zonemgr_createzone) {
+ dns_zonemgr_t *myzonemgr = NULL;
+ dns_zone_t *zone = NULL;
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = dns_zonemgr_create(mctx, taskmgr, timermgr, netmgr,
+ &myzonemgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* This should not succeed until the dns_zonemgr_setsize() is run */
+ result = dns_zonemgr_createzone(myzonemgr, &zone);
+ assert_int_equal(result, ISC_R_FAILURE);
+
+ result = dns_zonemgr_setsize(myzonemgr, 1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* Now it should succeed */
+ result = dns_zonemgr_createzone(myzonemgr, &zone);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(zone);
+
+ result = dns_zonemgr_managezone(myzonemgr, zone);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_zone_detach(&zone);
+
+ dns_zonemgr_shutdown(myzonemgr);
+ dns_zonemgr_detach(&myzonemgr);
+ assert_null(myzonemgr);
+}
+
+/* manage and release a zone */
+ISC_RUN_TEST_IMPL(dns_zonemgr_unreachable) {
+ dns_zonemgr_t *myzonemgr = NULL;
+ dns_zone_t *zone = NULL;
+ isc_sockaddr_t addr1, addr2;
+ struct in_addr in;
+ isc_result_t result;
+ isc_time_t now;
+
+ UNUSED(state);
+
+ TIME_NOW(&now);
+
+ result = dns_zonemgr_create(mctx, taskmgr, timermgr, netmgr,
+ &myzonemgr);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_test_makezone("foo", &zone, NULL, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_zonemgr_setsize(myzonemgr, 1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_zonemgr_managezone(myzonemgr, zone);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ in.s_addr = inet_addr("10.53.0.1");
+ isc_sockaddr_fromin(&addr1, &in, 2112);
+ in.s_addr = inet_addr("10.53.0.2");
+ isc_sockaddr_fromin(&addr2, &in, 5150);
+ assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
+ /*
+ * We require multiple unreachableadd calls to mark a server as
+ * unreachable.
+ */
+ dns_zonemgr_unreachableadd(myzonemgr, &addr1, &addr2, &now);
+ assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
+ dns_zonemgr_unreachableadd(myzonemgr, &addr1, &addr2, &now);
+ assert_true(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
+
+ in.s_addr = inet_addr("10.53.0.3");
+ isc_sockaddr_fromin(&addr2, &in, 5150);
+ assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
+ /*
+ * We require multiple unreachableadd calls to mark a server as
+ * unreachable.
+ */
+ dns_zonemgr_unreachableadd(myzonemgr, &addr1, &addr2, &now);
+ dns_zonemgr_unreachableadd(myzonemgr, &addr1, &addr2, &now);
+ assert_true(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
+
+ dns_zonemgr_unreachabledel(myzonemgr, &addr1, &addr2);
+ assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
+
+ in.s_addr = inet_addr("10.53.0.2");
+ isc_sockaddr_fromin(&addr2, &in, 5150);
+ assert_true(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
+ dns_zonemgr_unreachabledel(myzonemgr, &addr1, &addr2);
+ assert_false(dns_zonemgr_unreachable(myzonemgr, &addr1, &addr2, &now));
+
+ dns_zonemgr_releasezone(myzonemgr, zone);
+ dns_zone_detach(&zone);
+ dns_zonemgr_shutdown(myzonemgr);
+ dns_zonemgr_detach(&myzonemgr);
+ assert_null(myzonemgr);
+}
+
+/*
+ * XXX:
+ * dns_zonemgr API calls that are not yet part of this unit test:
+ *
+ * - dns_zonemgr_attach
+ * - dns_zonemgr_forcemaint
+ * - dns_zonemgr_resumexfrs
+ * - dns_zonemgr_shutdown
+ * - dns_zonemgr_setsize
+ * - dns_zonemgr_settransfersin
+ * - dns_zonemgr_getttransfersin
+ * - dns_zonemgr_settransfersperns
+ * - dns_zonemgr_getttransfersperns
+ * - dns_zonemgr_setiolimit
+ * - dns_zonemgr_getiolimit
+ * - dns_zonemgr_dbdestroyed
+ * - dns_zonemgr_setserialqueryrate
+ * - dns_zonemgr_getserialqueryrate
+ */
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(dns_zonemgr_create, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(dns_zonemgr_managezone, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(dns_zonemgr_createzone, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(dns_zonemgr_unreachable, setup_managers,
+ teardown_managers)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/dns/zt_test.c b/tests/dns/zt_test.c
new file mode 100644
index 0000000..c38e601
--- /dev/null
+++ b/tests/dns/zt_test.c
@@ -0,0 +1,352 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/app.h>
+#include <isc/atomic.h>
+#include <isc/buffer.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/name.h>
+#include <dns/view.h>
+#include <dns/zone.h>
+#include <dns/zt.h>
+
+#include <tests/dns.h>
+
+static int
+_setup(void **state) {
+ isc_app_start();
+ setup_managers(state);
+
+ return (0);
+}
+
+static int
+_teardown(void **state) {
+ teardown_managers(state);
+ isc_app_finish();
+
+ return (0);
+}
+
+struct args {
+ void *arg1;
+ void *arg2;
+ bool arg3;
+};
+
+static isc_result_t
+count_zone(dns_zone_t *zone, void *uap) {
+ int *nzones = (int *)uap;
+
+ UNUSED(zone);
+
+ *nzones += 1;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+load_done(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
+ /* We treat zt as a pointer to a boolean for testing purposes */
+ atomic_bool *done = (atomic_bool *)zt;
+
+ UNUSED(zone);
+ UNUSED(task);
+
+ atomic_store(done, true);
+ isc_app_shutdown();
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+all_done(void *arg) {
+ atomic_bool *done = (atomic_bool *)arg;
+
+ atomic_store(done, true);
+ isc_app_shutdown();
+ return (ISC_R_SUCCESS);
+}
+
+static void
+start_zt_asyncload(isc_task_t *task, isc_event_t *event) {
+ struct args *args = (struct args *)(event->ev_arg);
+
+ UNUSED(task);
+
+ dns_zt_asyncload(args->arg1, false, all_done, args->arg2);
+
+ isc_event_free(&event);
+}
+
+static void
+start_zone_asyncload(isc_task_t *task, isc_event_t *event) {
+ struct args *args = (struct args *)(event->ev_arg);
+
+ UNUSED(task);
+
+ dns_zone_asyncload(args->arg1, args->arg3, load_done, args->arg2);
+ isc_event_free(&event);
+}
+
+/* apply a function to a zone table */
+ISC_RUN_TEST_IMPL(dns_zt_apply) {
+ isc_result_t result;
+ dns_zone_t *zone = NULL;
+ dns_view_t *view = NULL;
+ int nzones = 0;
+
+ UNUSED(state);
+
+ result = dns_test_makezone("foo", &zone, NULL, true);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ view = dns_zone_getview(zone);
+ assert_non_null(view->zonetable);
+
+ assert_int_equal(nzones, 0);
+ result = dns_zt_apply(view->zonetable, isc_rwlocktype_read, false, NULL,
+ count_zone, &nzones);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(nzones, 1);
+
+ /* These steps are necessary so the zone can be detached properly */
+ result = dns_test_setupzonemgr();
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_test_releasezone(zone);
+ dns_test_closezonemgr();
+
+ /* The view was left attached in dns_test_makezone() */
+ dns_view_detach(&view);
+ dns_zone_detach(&zone);
+}
+
+/* asynchronous zone load */
+ISC_RUN_TEST_IMPL(dns_zt_asyncload_zone) {
+ isc_result_t result;
+ int n;
+ dns_zone_t *zone = NULL;
+ dns_view_t *view = NULL;
+ dns_db_t *db = NULL;
+ FILE *zonefile, *origfile;
+ char buf[4096];
+ atomic_bool done;
+ int i = 0;
+ struct args args;
+
+ UNUSED(state);
+
+ atomic_init(&done, false);
+
+ result = dns_test_makezone("foo", &zone, NULL, true);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_test_setupzonemgr();
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ view = dns_zone_getview(zone);
+ assert_non_null(view->zonetable);
+
+ assert_false(dns__zone_loadpending(zone));
+ assert_false(atomic_load(&done));
+ zonefile = fopen("./zone.data", "wb");
+ assert_non_null(zonefile);
+ origfile = fopen(TESTS_DIR "/testdata/zt/zone1.db", "r+b");
+ assert_non_null(origfile);
+ n = fread(buf, 1, 4096, origfile);
+ fclose(origfile);
+ fwrite(buf, 1, n, zonefile);
+ fflush(zonefile);
+
+ dns_zone_setfile(zone, "./zone.data", dns_masterformat_text,
+ &dns_master_style_default);
+
+ args.arg1 = zone;
+ args.arg2 = &done;
+ args.arg3 = false;
+ isc_app_onrun(mctx, maintask, start_zone_asyncload, &args);
+
+ isc_app_run();
+ while (dns__zone_loadpending(zone) && i++ < 5000) {
+ dns_test_nap(1000);
+ }
+ assert_true(atomic_load(&done));
+ /* The zone should now be loaded; test it */
+ result = dns_zone_getdb(zone, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_db_detach(&db);
+ /*
+ * Add something to zone file, reload zone with newonly - it should
+ * not be reloaded.
+ */
+ fprintf(zonefile, "\nb in b 1.2.3.4\n");
+ fflush(zonefile);
+ fclose(zonefile);
+
+ args.arg1 = zone;
+ args.arg2 = &done;
+ args.arg3 = true;
+ isc_app_onrun(mctx, maintask, start_zone_asyncload, &args);
+
+ isc_app_run();
+
+ while (dns__zone_loadpending(zone) && i++ < 5000) {
+ dns_test_nap(1000);
+ }
+ assert_true(atomic_load(&done));
+ /* The zone should now be loaded; test it */
+ result = dns_zone_getdb(zone, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_db_detach(&db);
+
+ /* Now reload it without newonly - it should be reloaded */
+ args.arg1 = zone;
+ args.arg2 = &done;
+ args.arg3 = false;
+ isc_app_onrun(mctx, maintask, start_zone_asyncload, &args);
+
+ isc_app_run();
+
+ while (dns__zone_loadpending(zone) && i++ < 5000) {
+ dns_test_nap(1000);
+ }
+ assert_true(atomic_load(&done));
+ /* The zone should now be loaded; test it */
+ result = dns_zone_getdb(zone, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_non_null(db);
+ if (db != NULL) {
+ dns_db_detach(&db);
+ }
+
+ dns_test_releasezone(zone);
+ dns_test_closezonemgr();
+
+ dns_zone_detach(&zone);
+ dns_view_detach(&view);
+}
+
+/* asynchronous zone table load */
+ISC_RUN_TEST_IMPL(dns_zt_asyncload_zt) {
+ isc_result_t result;
+ dns_zone_t *zone1 = NULL, *zone2 = NULL, *zone3 = NULL;
+ dns_view_t *view;
+ dns_zt_t *zt = NULL;
+ dns_db_t *db = NULL;
+ atomic_bool done;
+ int i = 0;
+ struct args args;
+
+ UNUSED(state);
+
+ atomic_init(&done, false);
+
+ result = dns_test_makezone("foo", &zone1, NULL, true);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_zone_setfile(zone1, TESTS_DIR "/testdata/zt/zone1.db",
+ dns_masterformat_text, &dns_master_style_default);
+ view = dns_zone_getview(zone1);
+
+ result = dns_test_makezone("bar", &zone2, view, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_zone_setfile(zone2, TESTS_DIR "/testdata/zt/zone1.db",
+ dns_masterformat_text, &dns_master_style_default);
+
+ /* This one will fail to load */
+ result = dns_test_makezone("fake", &zone3, view, false);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_zone_setfile(zone3, TESTS_DIR "/testdata/zt/nonexistent.db",
+ dns_masterformat_text, &dns_master_style_default);
+
+ zt = view->zonetable;
+ assert_non_null(zt);
+
+ result = dns_test_setupzonemgr();
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone3);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_false(dns__zone_loadpending(zone1));
+ assert_false(dns__zone_loadpending(zone2));
+ assert_false(atomic_load(&done));
+
+ args.arg1 = zt;
+ args.arg2 = &done;
+ isc_app_onrun(mctx, maintask, start_zt_asyncload, &args);
+
+ isc_app_run();
+ while (!atomic_load(&done) && i++ < 5000) {
+ dns_test_nap(1000);
+ }
+ assert_true(atomic_load(&done));
+
+ /* Both zones should now be loaded; test them */
+ result = dns_zone_getdb(zone1, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(db);
+ if (db != NULL) {
+ dns_db_detach(&db);
+ }
+
+ result = dns_zone_getdb(zone2, &db);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(db);
+ if (db != NULL) {
+ dns_db_detach(&db);
+ }
+
+ dns_test_releasezone(zone3);
+ dns_test_releasezone(zone2);
+ dns_test_releasezone(zone1);
+ dns_test_closezonemgr();
+
+ dns_zone_detach(&zone1);
+ dns_zone_detach(&zone2);
+ dns_zone_detach(&zone3);
+ dns_view_detach(&view);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(dns_zt_apply, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dns_zt_asyncload_zone, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(dns_zt_asyncload_zt, _setup, _teardown)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/include/tests/dns.h b/tests/include/tests/dns.h
new file mode 100644
index 0000000..64a265b
--- /dev/null
+++ b/tests/include/tests/dns.h
@@ -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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/cache.h>
+#include <dns/diff.h>
+#include <dns/zone.h>
+
+#include <tests/isc.h>
+
+extern dns_zonemgr_t *zonemgr;
+
+typedef struct {
+ dns_diffop_t op;
+ const char *owner;
+ dns_ttl_t ttl;
+ const char *type;
+ const char *rdata;
+} zonechange_t;
+
+#define ZONECHANGE_SENTINEL \
+ { \
+ 0, NULL, 0, NULL, NULL \
+ }
+
+isc_result_t
+dns_test_makeview(const char *name, bool with_cache, dns_view_t **viewp);
+
+/*%
+ * Create a zone with origin 'name', return a pointer to the zone object in
+ * 'zonep'.
+ *
+ * If 'view' is set, the returned zone will be assigned to the passed view.
+ * 'createview' must be set to false when 'view' is non-NULL.
+ *
+ * If 'view' is not set and 'createview' is true, a new view is also created
+ * and the returned zone is assigned to it. This imposes two requirements on
+ * the caller: 1) the returned zone has to be subsequently assigned to a zone
+ * manager, otherwise its cleanup will fail, 2) the created view has to be
+ * cleaned up by the caller.
+ *
+ * If 'view' is not set and 'createview' is false, the returned zone will not
+ * be assigned to any view.
+ */
+isc_result_t
+dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
+ bool createview);
+
+isc_result_t
+dns_test_setupzonemgr(void);
+
+isc_result_t
+dns_test_managezone(dns_zone_t *zone);
+
+void
+dns_test_releasezone(dns_zone_t *zone);
+
+void
+dns_test_closezonemgr(void);
+
+void
+dns_test_nap(uint32_t usec);
+
+isc_result_t
+dns_test_loaddb(dns_db_t **db, dns_dbtype_t dbtype, const char *origin,
+ const char *testfile);
+
+isc_result_t
+dns_test_getdata(const char *file, unsigned char *buf, size_t bufsiz,
+ size_t *sizep);
+
+char *
+dns_test_tohex(const unsigned char *data, size_t len, char *buf, size_t buflen);
+
+/*%
+ * Try parsing text form RDATA in "src" (of class "rdclass" and type "rdtype")
+ * into a structure representing that RDATA at "rdata", storing the
+ * uncompressed wire form of that RDATA at "dst", which is "dstlen" bytes long.
+ * Set 'warnings' to true to print logged warnings from dns_rdata_fromtext().
+ */
+isc_result_t
+dns_test_rdatafromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t rdtype, unsigned char *dst,
+ size_t dstlen, const char *src, bool warnings);
+
+void
+dns_test_namefromstring(const char *namestr, dns_fixedname_t *fname);
+
+/*%
+ * Given a pointer to an uninitialized dns_diff_t structure in 'diff', make it
+ * contain diff tuples representing zone database changes listed in 'changes'.
+ * Set 'warnings' to true to print logged warnings from dns_rdata_fromtext().
+ */
+isc_result_t
+dns_test_difffromchanges(dns_diff_t *diff, const zonechange_t *changes,
+ bool warnings);
diff --git a/tests/include/tests/isc.h b/tests/include/tests/isc.h
new file mode 100644
index 0000000..6131c20
--- /dev/null
+++ b/tests/include/tests/isc.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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <uv.h>
+
+#include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/netmgr.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include "netmgr_p.h"
+#include "task_p.h"
+#include "timer_p.h"
+
+#define CHECK(r) \
+ do { \
+ result = (r); \
+ if (result != ISC_R_SUCCESS) \
+ goto cleanup; \
+ } while (0)
+
+extern isc_mem_t *mctx;
+extern isc_nm_t *netmgr;
+extern isc_taskmgr_t *taskmgr;
+extern isc_timermgr_t *timermgr;
+extern unsigned int workers;
+extern isc_task_t *maintask;
+
+#define isc_test_nap(ms) uv_sleep(ms)
+
+int
+setup_managers(void **state);
+int
+teardown_managers(void **state);
+
+#ifndef TESTS_DIR
+#define TESTS_DIR "./"
+#endif
+
+/* clang-format off */
+/* Copied from cmocka */
+#define ISC_TEST_ENTRY(name) \
+ { #name, run_test_##name, NULL, NULL, NULL },
+#define ISC_TEST_ENTRY_SETUP(name) \
+ { #name, run_test_##name, setup_test_##name, NULL, NULL },
+#define ISC_TEST_ENTRY_TEARDOWN(name) \
+ { #name, run_test_##name, NULL, teardown_test_##name, NULL },
+#define ISC_TEST_ENTRY_SETUP_TEARDOWN(name) \
+ { #name, run_test_##name, setup_test_##name, teardown_test_##name, NULL },
+#define ISC_TEST_ENTRY_CUSTOM(name, setup, teardown) \
+ { #name, run_test_##name, setup, teardown, NULL },
+/* clang-format on */
+
+#define ISC_SETUP_TEST_DECLARE(name) \
+ int setup_test_##name(void **state __attribute__((unused)));
+
+#define ISC_RUN_TEST_DECLARE(name) \
+ void run_test_##name(void **state __attribute__((unused)));
+
+#define ISC_TEARDOWN_TEST_DECLARE(name) \
+ int teardown_test_##name(void **state __attribute__((unused)))
+
+#define ISC_SETUP_TEST_IMPL(name) \
+ int setup_test_##name(void **state __attribute__((unused))); \
+ int setup_test_##name(void **state __attribute__((unused)))
+
+#define ISC_RUN_TEST_IMPL(name) \
+ void run_test_##name(void **state __attribute__((unused))); \
+ void run_test_##name(void **state __attribute__((unused)))
+
+#define ISC_TEARDOWN_TEST_IMPL(name) \
+ int teardown_test_##name(void **state __attribute__((unused))); \
+ int teardown_test_##name(void **state __attribute__((unused)))
+
+#define ISC_TEST_LIST_START const struct CMUnitTest tests[] = {
+#define ISC_TEST_LIST_END \
+ } \
+ ;
+
+#define ISC_TEST_MAIN ISC_TEST_MAIN_CUSTOM(NULL, NULL)
+
+#define ISC_TEST_MAIN_CUSTOM(setup, teardown) \
+ int main(void) { \
+ int r; \
+ \
+ signal(SIGPIPE, SIG_IGN); \
+ \
+ isc_mem_debugging |= ISC_MEM_DEBUGRECORD; \
+ isc_mem_create(&mctx); \
+ \
+ r = cmocka_run_group_tests(tests, setup, teardown); \
+ \
+ isc_mem_destroy(&mctx); \
+ \
+ return (r); \
+ }
diff --git a/tests/include/tests/ns.h b/tests/include/tests/ns.h
new file mode 100644
index 0000000..175cb90
--- /dev/null
+++ b/tests/include/tests/ns.h
@@ -0,0 +1,132 @@
+/*
+ * 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
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/zone.h>
+
+#include <ns/client.h>
+#include <ns/hooks.h>
+#include <ns/interfacemgr.h>
+
+#include <tests/dns.h>
+
+typedef struct ns_test_id {
+ const char *description;
+ int lineno;
+} ns_test_id_t;
+
+#define NS_TEST_ID(desc) \
+ { \
+ .description = desc, .lineno = __LINE__ \
+ }
+
+#define CHECK(r) \
+ do { \
+ result = (r); \
+ if (result != ISC_R_SUCCESS) \
+ goto cleanup; \
+ } while (0)
+
+extern dns_dispatchmgr_t *dispatchmgr;
+extern ns_clientmgr_t *clientmgr;
+extern ns_interfacemgr_t *interfacemgr;
+extern ns_server_t *sctx;
+
+#ifdef NETMGR_TRACE
+#define FLARG \
+ , const char *file __attribute__((unused)), \
+ unsigned int line __attribute__((unused)), \
+ const char *func __attribute__((unused))
+#else
+#define FLARG
+#endif
+
+int
+setup_server(void **state);
+int
+teardown_server(void **state);
+
+/*%
+ * Load data for zone "zonename" from file "filename" and start serving it to
+ * clients matching "view". Only one zone loaded using this function can be
+ * served at any given time.
+ */
+isc_result_t
+ns_test_serve_zone(const char *zonename, const char *filename,
+ dns_view_t *view);
+
+/*%
+ * Release the zone loaded by ns_test_serve_zone().
+ */
+void
+ns_test_cleanup_zone(void);
+
+isc_result_t
+ns_test_loaddb(dns_db_t **db, dns_dbtype_t dbtype, const char *origin,
+ const char *testfile);
+
+isc_result_t
+ns_test_getdata(const char *file, unsigned char *buf, size_t bufsiz,
+ size_t *sizep);
+
+isc_result_t
+ns_test_getclient(ns_interface_t *ifp0, bool tcp, ns_client_t **clientp);
+
+/*%
+ * Structure containing parameters for ns_test_qctx_create().
+ */
+typedef struct ns_test_qctx_create_params {
+ const char *qname;
+ dns_rdatatype_t qtype;
+ unsigned int qflags;
+ bool with_cache;
+} ns_test_qctx_create_params_t;
+
+/*%
+ * Prepare a query context identical with one that would be prepared if a query
+ * with given QNAME, QTYPE and flags was received from a client. Recursion is
+ * assumed to be allowed for this client. If "with_cache" is set to true,
+ * a cache database will be created and associated with the view matching the
+ * incoming query.
+ */
+isc_result_t
+ns_test_qctx_create(const ns_test_qctx_create_params_t *params,
+ query_ctx_t **qctxp);
+
+/*%
+ * Destroy a query context created by ns_test_qctx_create().
+ */
+void
+ns_test_qctx_destroy(query_ctx_t **qctxp);
+
+/*%
+ * A hook callback interrupting execution at given hook's insertion point.
+ */
+ns_hookresult_t
+ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp);
diff --git a/tests/irs/Makefile.am b/tests/irs/Makefile.am
new file mode 100644
index 0000000..8e6e52f
--- /dev/null
+++ b/tests/irs/Makefile.am
@@ -0,0 +1,16 @@
+include $(top_srcdir)/Makefile.top
+
+AM_CPPFLAGS += \
+ $(LIBISC_CFLAGS) \
+ $(LIBIRS_CFLAGS)
+
+LDADD += \
+ $(LIBISC_LIBS) \
+ $(LIBIRS_LIBS)
+
+check_PROGRAMS = \
+ resconf_test
+
+EXTRA_DIST = testdata
+
+include $(top_srcdir)/Makefile.tests
diff --git a/tests/irs/Makefile.in b/tests/irs/Makefile.in
new file mode 100644
index 0000000..e5500c1
--- /dev/null
+++ b/tests/irs/Makefile.in
@@ -0,0 +1,1152 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HOST_MACOS_TRUE@am__append_1 = \
+@HOST_MACOS_TRUE@ -Wl,-flat_namespace
+
+check_PROGRAMS = resconf_test$(EXEEXT)
+subdir = tests/irs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4/ax_jemalloc.m4 \
+ $(top_srcdir)/m4/ax_lib_lmdb.m4 \
+ $(top_srcdir)/m4/ax_perl_module.m4 \
+ $(top_srcdir)/m4/ax_posix_shell.m4 \
+ $(top_srcdir)/m4/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_python_module.m4 \
+ $(top_srcdir)/m4/ax_restore_flags.m4 \
+ $(top_srcdir)/m4/ax_save_flags.m4 $(top_srcdir)/m4/ax_tls.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+resconf_test_SOURCES = resconf_test.c
+resconf_test_OBJECTS = resconf_test.$(OBJEXT)
+resconf_test_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+resconf_test_DEPENDENCIES = $(LIBISC_LIBS) $(LIBIRS_LIBS) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/resconf_test.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = resconf_test.c
+DIST_SOURCES = resconf_test.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = test-recursive unit-recursive \
+ doc-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/Makefile.tests \
+ $(top_srcdir)/Makefile.top $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CMOCKA_CFLAGS = @CMOCKA_CFLAGS@
+CMOCKA_LIBS = @CMOCKA_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURL = @CURL@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEVELOPER_MODE = @DEVELOPER_MODE@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FSTRM_CAPTURE = @FSTRM_CAPTURE@
+FUZZ_LDFLAGS = @FUZZ_LDFLAGS@
+FUZZ_LOG_COMPILER = @FUZZ_LOG_COMPILER@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@
+JEMALLOC_LIBS = @JEMALLOC_LIBS@
+JSON_C_CFLAGS = @JSON_C_CFLAGS@
+JSON_C_LIBS = @JSON_C_LIBS@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_CONFIG = @KRB5_CONFIG@
+KRB5_LIBS = @KRB5_LIBS@
+LATEXMK = @LATEXMK@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBNGHTTP2_CFLAGS = @LIBNGHTTP2_CFLAGS@
+LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUV_CFLAGS = @LIBUV_CFLAGS@
+LIBUV_LIBS = @LIBUV_LIBS@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIPO = @LIPO@
+LMDB_CFLAGS = @LMDB_CFLAGS@
+LMDB_LIBS = @LMDB_LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAXMINDDB_CFLAGS = @MAXMINDDB_CFLAGS@
+MAXMINDDB_LIBS = @MAXMINDDB_LIBS@
+MAXMINDDB_PREFIX = @MAXMINDDB_PREFIX@
+MKDIR_P = @MKDIR_P@
+NC = @NC@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTEST = @PYTEST@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+READLINE_CFLAGS = @READLINE_CFLAGS@
+READLINE_LIBS = @READLINE_LIBS@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINX_BUILD = @SPHINX_BUILD@
+STD_CFLAGS = @STD_CFLAGS@
+STD_CPPFLAGS = @STD_CPPFLAGS@
+STD_LDFLAGS = @STD_LDFLAGS@
+STRIP = @STRIP@
+TEST_CFLAGS = @TEST_CFLAGS@
+VERSION = @VERSION@
+XELATEX = @XELATEX@
+XSLTPROC = @XSLTPROC@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
+AM_CFLAGS = $(STD_CFLAGS) -I$(top_srcdir)/tests/include $(TEST_CFLAGS)
+AM_CPPFLAGS = $(STD_CPPFLAGS) -include $(top_builddir)/config.h \
+ -I$(srcdir)/include $(LIBISC_CFLAGS) $(LIBIRS_CFLAGS) \
+ $(CMOCKA_CFLAGS) -DNAMED_PLUGINDIR=\"$(pkglibdir)\" \
+ -DTESTS_DIR=\"$(abs_srcdir)\"
+AM_LDFLAGS = $(STD_LDFLAGS) $(am__append_1)
+LDADD = $(LIBISC_LIBS) $(LIBIRS_LIBS) \
+ $(top_builddir)/tests/libtest/libtest.la $(CMOCKA_LIBS)
+LIBISC_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib/isc/include \
+ -I$(top_builddir)/lib/isc/include
+
+LIBISC_LIBS = $(top_builddir)/lib/isc/libisc.la
+LIBDNS_CFLAGS = \
+ -I$(top_srcdir)/lib/dns/include \
+ -I$(top_builddir)/lib/dns/include
+
+LIBDNS_LIBS = \
+ $(top_builddir)/lib/dns/libdns.la
+
+LIBNS_CFLAGS = \
+ -I$(top_srcdir)/lib/ns/include
+
+LIBNS_LIBS = \
+ $(top_builddir)/lib/ns/libns.la
+
+LIBIRS_CFLAGS = \
+ -I$(top_srcdir)/lib/irs/include
+
+LIBIRS_LIBS = \
+ $(top_builddir)/lib/irs/libirs.la
+
+LIBISCCFG_CFLAGS = \
+ -I$(top_srcdir)/lib/isccfg/include
+
+LIBISCCFG_LIBS = \
+ $(top_builddir)/lib/isccfg/libisccfg.la
+
+LIBISCCC_CFLAGS = \
+ -I$(top_srcdir)/lib/isccc/include/
+
+LIBISCCC_LIBS = \
+ $(top_builddir)/lib/isccc/libisccc.la
+
+LIBBIND9_CFLAGS = \
+ -I$(top_srcdir)/lib/bind9/include
+
+LIBBIND9_LIBS = \
+ $(top_builddir)/lib/bind9/libbind9.la
+
+EXTRA_DIST = testdata
+@HAVE_CMOCKA_TRUE@TESTS = $(check_PROGRAMS)
+LOG_COMPILER = $(top_builddir)/tests/unit-test-driver.sh
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/irs/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tests/irs/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+resconf_test$(EXEEXT): $(resconf_test_OBJECTS) $(resconf_test_DEPENDENCIES) $(EXTRA_resconf_test_DEPENDENCIES)
+ @rm -f resconf_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(resconf_test_OBJECTS) $(resconf_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resconf_test.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+test-local:
+unit-local:
+doc-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS: $(check_PROGRAMS)
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+resconf_test.log: resconf_test$(EXEEXT)
+ @p='resconf_test$(EXEEXT)'; \
+ b='resconf_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/resconf_test.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+doc: doc-am
+
+doc-am: doc-local
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/resconf_test.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+test: test-am
+
+test-am: test-local
+
+uninstall-am:
+
+unit: unit-am
+
+unit-am: unit-local
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-checkPROGRAMS clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir \
+ doc-am doc-local dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am recheck tags tags-am test-am test-local \
+ uninstall uninstall-am unit-am unit-local
+
+.PRECIOUS: Makefile
+
+
+unit-local: check
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/irs/resconf_test.c b/tests/irs/resconf_test.c
new file mode 100644
index 0000000..367898f
--- /dev/null
+++ b/tests/irs/resconf_test.c
@@ -0,0 +1,182 @@
+/*
+ * 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 HAVE_CMOCKA
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/mem.h>
+#include <isc/util.h>
+
+#include <irs/resconf.h>
+
+static isc_mem_t *mctx = NULL;
+
+static void
+setup_test(void) {
+ isc_mem_create(&mctx);
+
+ /*
+ * the caller might run from another directory, but tests
+ * that access test data files must first chdir to the proper
+ * location.
+ */
+ assert_return_code(chdir(TESTS_DIR), 0);
+}
+
+static isc_result_t
+check_number(unsigned int n, unsigned int expected) {
+ return ((n == expected) ? ISC_R_SUCCESS : ISC_R_BADNUMBER);
+}
+
+static isc_result_t
+check_attempts(irs_resconf_t *resconf) {
+ return (check_number(irs_resconf_getattempts(resconf), 4));
+}
+
+static isc_result_t
+check_timeout(irs_resconf_t *resconf) {
+ return (check_number(irs_resconf_gettimeout(resconf), 1));
+}
+
+static isc_result_t
+check_ndots(irs_resconf_t *resconf) {
+ return (check_number(irs_resconf_getndots(resconf), 2));
+}
+
+static isc_result_t
+check_options(irs_resconf_t *resconf) {
+ if (irs_resconf_getattempts(resconf) != 3) {
+ return ISC_R_BADNUMBER; /* default value only */
+ }
+
+ if (irs_resconf_getndots(resconf) != 2) {
+ return ISC_R_BADNUMBER;
+ }
+
+ if (irs_resconf_gettimeout(resconf) != 1) {
+ return ISC_R_BADNUMBER;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/* test irs_resconf_load() */
+static void
+irs_resconf_load_test(void **state) {
+ isc_result_t result;
+ irs_resconf_t *resconf = NULL;
+ unsigned int i;
+ struct {
+ const char *file;
+ isc_result_t loadres;
+ isc_result_t (*check)(irs_resconf_t *resconf);
+ isc_result_t checkres;
+ } tests[] = {
+ { "testdata/domain.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS },
+ { "testdata/nameserver-v4.conf", ISC_R_SUCCESS, NULL,
+ ISC_R_SUCCESS },
+ { "testdata/nameserver-v6.conf", ISC_R_SUCCESS, NULL,
+ ISC_R_SUCCESS },
+ { "testdata/nameserver-v6-scoped.conf", ISC_R_SUCCESS, NULL,
+ ISC_R_SUCCESS },
+ { "testdata/options-attempts.conf", ISC_R_SUCCESS,
+ check_attempts, ISC_R_SUCCESS },
+ { "testdata/options-debug.conf", ISC_R_SUCCESS, NULL,
+ ISC_R_SUCCESS },
+ { "testdata/options-ndots.conf", ISC_R_SUCCESS, check_ndots,
+ ISC_R_SUCCESS },
+ { "testdata/options-timeout.conf", ISC_R_SUCCESS, check_timeout,
+ ISC_R_SUCCESS },
+ { "testdata/options-unknown.conf", ISC_R_SUCCESS, NULL,
+ ISC_R_SUCCESS },
+ { "testdata/options.conf", ISC_R_SUCCESS, check_options,
+ ISC_R_SUCCESS },
+ { "testdata/options-bad-ndots.conf", ISC_R_RANGE, NULL,
+ ISC_R_SUCCESS },
+ { "testdata/options-empty.conf", ISC_R_UNEXPECTEDEND, NULL,
+ ISC_R_SUCCESS },
+ { "testdata/port.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS },
+ { "testdata/resolv.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS },
+ { "testdata/search.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS },
+ { "testdata/sortlist-v4.conf", ISC_R_SUCCESS, NULL,
+ ISC_R_SUCCESS },
+ { "testdata/timeout.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS },
+ { "testdata/unknown.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS }
+ };
+
+ UNUSED(state);
+
+ setup_test();
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[1]); i++) {
+ result = irs_resconf_load(mctx, tests[i].file, &resconf);
+ if (result != tests[i].loadres) {
+ fail_msg("# unexpected result %s loading %s",
+ isc_result_totext(result), tests[i].file);
+ }
+
+ if (result == ISC_R_SUCCESS && resconf == NULL) {
+ fail_msg("# NULL on success loading %s", tests[i].file);
+ } else if (result != ISC_R_SUCCESS && resconf != NULL) {
+ fail_msg("# non-NULL on failure loading %s",
+ tests[i].file);
+ }
+
+ if (resconf != NULL && tests[i].check != NULL) {
+ result = (tests[i].check)(resconf);
+ if (result != tests[i].checkres) {
+ fail_msg("# unexpected result %s loading %s",
+ isc_result_totext(result),
+ tests[i].file);
+ }
+ }
+ if (resconf != NULL) {
+ irs_resconf_destroy(&resconf);
+ }
+ }
+
+ isc_mem_detach(&mctx);
+}
+
+int
+main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(irs_resconf_load_test),
+ };
+
+ return (cmocka_run_group_tests(tests, NULL, NULL));
+}
+
+#else /* HAVE_CMOCKA */
+
+#include <stdio.h>
+
+int
+main(void) {
+ printf("1..0 # Skipped: cmocka not available\n");
+ return (SKIPPED_TEST_EXIT_CODE);
+}
+
+#endif /* if HAVE_CMOCKA */
diff --git a/tests/irs/testdata/domain.conf b/tests/irs/testdata/domain.conf
new file mode 100644
index 0000000..ee43f5c
--- /dev/null
+++ b/tests/irs/testdata/domain.conf
@@ -0,0 +1,12 @@
+# 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.
+
+domain example.com
diff --git a/tests/irs/testdata/nameserver-v4.conf b/tests/irs/testdata/nameserver-v4.conf
new file mode 100644
index 0000000..5054de0
--- /dev/null
+++ b/tests/irs/testdata/nameserver-v4.conf
@@ -0,0 +1,12 @@
+# 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.
+
+nameserver 10.0.0.1
diff --git a/tests/irs/testdata/nameserver-v6-scoped.conf b/tests/irs/testdata/nameserver-v6-scoped.conf
new file mode 100644
index 0000000..d5bd97f
--- /dev/null
+++ b/tests/irs/testdata/nameserver-v6-scoped.conf
@@ -0,0 +1,12 @@
+# 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.
+
+nameserver fe80::1%1
diff --git a/tests/irs/testdata/nameserver-v6.conf b/tests/irs/testdata/nameserver-v6.conf
new file mode 100644
index 0000000..b9ed093
--- /dev/null
+++ b/tests/irs/testdata/nameserver-v6.conf
@@ -0,0 +1,12 @@
+# 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.
+
+nameserver 2001:DB8::1
diff --git a/tests/irs/testdata/options-attempts.conf b/tests/irs/testdata/options-attempts.conf
new file mode 100644
index 0000000..a076f8e
--- /dev/null
+++ b/tests/irs/testdata/options-attempts.conf
@@ -0,0 +1,12 @@
+# 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.
+
+options attempts:4
diff --git a/tests/irs/testdata/options-bad-ndots.conf b/tests/irs/testdata/options-bad-ndots.conf
new file mode 100644
index 0000000..18d3f8b
--- /dev/null
+++ b/tests/irs/testdata/options-bad-ndots.conf
@@ -0,0 +1,13 @@
+# 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.
+
+search example.com example.net
+options ndots:256
diff --git a/tests/irs/testdata/options-debug.conf b/tests/irs/testdata/options-debug.conf
new file mode 100644
index 0000000..04bcf2e
--- /dev/null
+++ b/tests/irs/testdata/options-debug.conf
@@ -0,0 +1,12 @@
+# 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.
+
+options debug
diff --git a/tests/irs/testdata/options-empty.conf b/tests/irs/testdata/options-empty.conf
new file mode 100644
index 0000000..0b1dc9e
--- /dev/null
+++ b/tests/irs/testdata/options-empty.conf
@@ -0,0 +1,13 @@
+# 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.
+
+domain example.com
+options
diff --git a/tests/irs/testdata/options-ndots.conf b/tests/irs/testdata/options-ndots.conf
new file mode 100644
index 0000000..f37c712
--- /dev/null
+++ b/tests/irs/testdata/options-ndots.conf
@@ -0,0 +1,12 @@
+# 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.
+
+options ndots:2
diff --git a/tests/irs/testdata/options-timeout.conf b/tests/irs/testdata/options-timeout.conf
new file mode 100644
index 0000000..96787c4
--- /dev/null
+++ b/tests/irs/testdata/options-timeout.conf
@@ -0,0 +1,12 @@
+# 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.
+
+options timeout:1
diff --git a/tests/irs/testdata/options-unknown.conf b/tests/irs/testdata/options-unknown.conf
new file mode 100644
index 0000000..fdf82b4
--- /dev/null
+++ b/tests/irs/testdata/options-unknown.conf
@@ -0,0 +1,12 @@
+# 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.
+
+options unknown
diff --git a/tests/irs/testdata/options.conf b/tests/irs/testdata/options.conf
new file mode 100644
index 0000000..7a8d5f3
--- /dev/null
+++ b/tests/irs/testdata/options.conf
@@ -0,0 +1,12 @@
+# 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.
+
+options unknown debug timeout:1 ndots:2
diff --git a/tests/irs/testdata/port.conf b/tests/irs/testdata/port.conf
new file mode 100644
index 0000000..54e2094
--- /dev/null
+++ b/tests/irs/testdata/port.conf
@@ -0,0 +1,12 @@
+# 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.
+
+port 5300
diff --git a/tests/irs/testdata/resolv.conf b/tests/irs/testdata/resolv.conf
new file mode 100644
index 0000000..3c14408
--- /dev/null
+++ b/tests/irs/testdata/resolv.conf
@@ -0,0 +1,19 @@
+# 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.
+
+port 5300
+nameserver 10.0.0.1
+nameserver 2001:DB8::1
+search example.com example.net
+sortlist 130.155.160.0/255.255.240.0 130.155.0.0
+timeout 10
+unknown directive
+options unknown debug timeout:1 ndots:2
diff --git a/tests/irs/testdata/search.conf b/tests/irs/testdata/search.conf
new file mode 100644
index 0000000..f019ab9
--- /dev/null
+++ b/tests/irs/testdata/search.conf
@@ -0,0 +1,12 @@
+# 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.
+
+search example.com example.net
diff --git a/tests/irs/testdata/sortlist-v4.conf b/tests/irs/testdata/sortlist-v4.conf
new file mode 100644
index 0000000..3f4d54a
--- /dev/null
+++ b/tests/irs/testdata/sortlist-v4.conf
@@ -0,0 +1,12 @@
+# 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.
+
+sortlist 130.155.160.0/255.255.240.0 130.155.0.0
diff --git a/tests/irs/testdata/timeout.conf b/tests/irs/testdata/timeout.conf
new file mode 100644
index 0000000..2ccb92d
--- /dev/null
+++ b/tests/irs/testdata/timeout.conf
@@ -0,0 +1,12 @@
+# 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.
+
+timeout 10
diff --git a/tests/irs/testdata/unknown.conf b/tests/irs/testdata/unknown.conf
new file mode 100644
index 0000000..0eafb76
--- /dev/null
+++ b/tests/irs/testdata/unknown.conf
@@ -0,0 +1,12 @@
+# 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.
+
+unknown directive
diff --git a/tests/isc/Makefile.am b/tests/isc/Makefile.am
new file mode 100644
index 0000000..488ba50
--- /dev/null
+++ b/tests/isc/Makefile.am
@@ -0,0 +1,115 @@
+include $(top_srcdir)/Makefile.top
+
+AM_CPPFLAGS += \
+ $(LIBISC_CFLAGS) \
+ $(LIBUV_CFLAGS) \
+ -I$(top_srcdir)/lib/isc
+
+LDADD += \
+ $(LIBISC_LIBS) \
+ $(LIBUV_LIBS)
+
+check_PROGRAMS = \
+ aes_test \
+ buffer_test \
+ counter_test \
+ crc64_test \
+ errno_test \
+ file_test \
+ hash_test \
+ heap_test \
+ hmac_test \
+ ht_test \
+ lex_test \
+ md_test \
+ mem_test \
+ netaddr_test \
+ netmgr_test \
+ parse_test \
+ pool_test \
+ quota_test \
+ radix_test \
+ random_test \
+ regex_test \
+ result_test \
+ safe_test \
+ siphash_test \
+ sockaddr_test \
+ stats_test \
+ symtab_test \
+ task_test \
+ taskpool_test \
+ time_test \
+ timer_test
+
+if HAVE_LIBNGHTTP2
+check_PROGRAMS += \
+ doh_test
+
+doh_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(LIBNGHTTP2_CFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+doh_test_LDADD = \
+ $(LDADD) \
+ $(LIBNGHTTP2_LIBS)
+
+doh_test_SOURCES = \
+ doh_test.c \
+ uv_wrap.h
+
+endif HAVE_LIBNGHTTP2
+
+hmac_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+hmac_test_LDADD = \
+ $(LDADD) \
+ $(OPENSSL_LIBS)
+
+md_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+md_test_LDADD = \
+ $(LDADD) \
+ $(OPENSSL_LIBS)
+
+netmgr_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+netmgr_test_LDADD = \
+ $(LDADD) \
+ $(OPENSSL_LIBS)
+
+netmgr_test_SOURCES = \
+ netmgr_test.c \
+ uv_wrap.h
+
+random_test_LDADD = \
+ $(LDADD) \
+ -lm
+
+task_test_CPPFLAGS = \
+ $(AM_CPPFLAGS)
+
+task_test_LDADD = \
+ $(LDADD)
+
+if HAVE_LIBXML2
+task_test_CPPFLAGS += $(LIBXML2_CFLAGS)
+task_test_LDADD += $(LIBXML2_LIBS)
+endif HAVE_LIBXML2
+
+if HAVE_JSON_C
+task_test_CPPFLAGS += $(JSON_C_CFLAGS)
+task_test_LDADD += $(JSON_C_LIBS)
+endif HAVE_JSON_C
+
+
+EXTRA_DIST = testdata
+
+include $(top_srcdir)/Makefile.tests
diff --git a/tests/isc/Makefile.in b/tests/isc/Makefile.in
new file mode 100644
index 0000000..1060d23
--- /dev/null
+++ b/tests/isc/Makefile.in
@@ -0,0 +1,1905 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HOST_MACOS_TRUE@am__append_1 = \
+@HOST_MACOS_TRUE@ -Wl,-flat_namespace
+
+check_PROGRAMS = aes_test$(EXEEXT) buffer_test$(EXEEXT) \
+ counter_test$(EXEEXT) crc64_test$(EXEEXT) errno_test$(EXEEXT) \
+ file_test$(EXEEXT) hash_test$(EXEEXT) heap_test$(EXEEXT) \
+ hmac_test$(EXEEXT) ht_test$(EXEEXT) lex_test$(EXEEXT) \
+ md_test$(EXEEXT) mem_test$(EXEEXT) netaddr_test$(EXEEXT) \
+ netmgr_test$(EXEEXT) parse_test$(EXEEXT) pool_test$(EXEEXT) \
+ quota_test$(EXEEXT) radix_test$(EXEEXT) random_test$(EXEEXT) \
+ regex_test$(EXEEXT) result_test$(EXEEXT) safe_test$(EXEEXT) \
+ siphash_test$(EXEEXT) sockaddr_test$(EXEEXT) \
+ stats_test$(EXEEXT) symtab_test$(EXEEXT) task_test$(EXEEXT) \
+ taskpool_test$(EXEEXT) time_test$(EXEEXT) timer_test$(EXEEXT) \
+ $(am__EXEEXT_1)
+@HAVE_LIBNGHTTP2_TRUE@am__append_2 = \
+@HAVE_LIBNGHTTP2_TRUE@ doh_test
+
+@HAVE_LIBXML2_TRUE@am__append_3 = $(LIBXML2_CFLAGS)
+@HAVE_LIBXML2_TRUE@am__append_4 = $(LIBXML2_LIBS)
+@HAVE_JSON_C_TRUE@am__append_5 = $(JSON_C_CFLAGS)
+@HAVE_JSON_C_TRUE@am__append_6 = $(JSON_C_LIBS)
+subdir = tests/isc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4/ax_jemalloc.m4 \
+ $(top_srcdir)/m4/ax_lib_lmdb.m4 \
+ $(top_srcdir)/m4/ax_perl_module.m4 \
+ $(top_srcdir)/m4/ax_posix_shell.m4 \
+ $(top_srcdir)/m4/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_python_module.m4 \
+ $(top_srcdir)/m4/ax_restore_flags.m4 \
+ $(top_srcdir)/m4/ax_save_flags.m4 $(top_srcdir)/m4/ax_tls.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_LIBNGHTTP2_TRUE@am__EXEEXT_1 = doh_test$(EXEEXT)
+aes_test_SOURCES = aes_test.c
+aes_test_OBJECTS = aes_test.$(OBJEXT)
+aes_test_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+aes_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+buffer_test_SOURCES = buffer_test.c
+buffer_test_OBJECTS = buffer_test.$(OBJEXT)
+buffer_test_LDADD = $(LDADD)
+buffer_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+counter_test_SOURCES = counter_test.c
+counter_test_OBJECTS = counter_test.$(OBJEXT)
+counter_test_LDADD = $(LDADD)
+counter_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+crc64_test_SOURCES = crc64_test.c
+crc64_test_OBJECTS = crc64_test.$(OBJEXT)
+crc64_test_LDADD = $(LDADD)
+crc64_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+am__doh_test_SOURCES_DIST = doh_test.c uv_wrap.h
+@HAVE_LIBNGHTTP2_TRUE@am_doh_test_OBJECTS = \
+@HAVE_LIBNGHTTP2_TRUE@ doh_test-doh_test.$(OBJEXT)
+doh_test_OBJECTS = $(am_doh_test_OBJECTS)
+am__DEPENDENCIES_2 = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+@HAVE_LIBNGHTTP2_TRUE@doh_test_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+@HAVE_LIBNGHTTP2_TRUE@ $(am__DEPENDENCIES_1)
+errno_test_SOURCES = errno_test.c
+errno_test_OBJECTS = errno_test.$(OBJEXT)
+errno_test_LDADD = $(LDADD)
+errno_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+file_test_SOURCES = file_test.c
+file_test_OBJECTS = file_test.$(OBJEXT)
+file_test_LDADD = $(LDADD)
+file_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+hash_test_SOURCES = hash_test.c
+hash_test_OBJECTS = hash_test.$(OBJEXT)
+hash_test_LDADD = $(LDADD)
+hash_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+heap_test_SOURCES = heap_test.c
+heap_test_OBJECTS = heap_test.$(OBJEXT)
+heap_test_LDADD = $(LDADD)
+heap_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+hmac_test_SOURCES = hmac_test.c
+hmac_test_OBJECTS = hmac_test-hmac_test.$(OBJEXT)
+hmac_test_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
+ht_test_SOURCES = ht_test.c
+ht_test_OBJECTS = ht_test.$(OBJEXT)
+ht_test_LDADD = $(LDADD)
+ht_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+lex_test_SOURCES = lex_test.c
+lex_test_OBJECTS = lex_test.$(OBJEXT)
+lex_test_LDADD = $(LDADD)
+lex_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+md_test_SOURCES = md_test.c
+md_test_OBJECTS = md_test-md_test.$(OBJEXT)
+md_test_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
+mem_test_SOURCES = mem_test.c
+mem_test_OBJECTS = mem_test.$(OBJEXT)
+mem_test_LDADD = $(LDADD)
+mem_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+netaddr_test_SOURCES = netaddr_test.c
+netaddr_test_OBJECTS = netaddr_test.$(OBJEXT)
+netaddr_test_LDADD = $(LDADD)
+netaddr_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+am_netmgr_test_OBJECTS = netmgr_test-netmgr_test.$(OBJEXT)
+netmgr_test_OBJECTS = $(am_netmgr_test_OBJECTS)
+netmgr_test_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
+parse_test_SOURCES = parse_test.c
+parse_test_OBJECTS = parse_test.$(OBJEXT)
+parse_test_LDADD = $(LDADD)
+parse_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+pool_test_SOURCES = pool_test.c
+pool_test_OBJECTS = pool_test.$(OBJEXT)
+pool_test_LDADD = $(LDADD)
+pool_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+quota_test_SOURCES = quota_test.c
+quota_test_OBJECTS = quota_test.$(OBJEXT)
+quota_test_LDADD = $(LDADD)
+quota_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+radix_test_SOURCES = radix_test.c
+radix_test_OBJECTS = radix_test.$(OBJEXT)
+radix_test_LDADD = $(LDADD)
+radix_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+random_test_SOURCES = random_test.c
+random_test_OBJECTS = random_test.$(OBJEXT)
+random_test_DEPENDENCIES = $(am__DEPENDENCIES_2)
+regex_test_SOURCES = regex_test.c
+regex_test_OBJECTS = regex_test.$(OBJEXT)
+regex_test_LDADD = $(LDADD)
+regex_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+result_test_SOURCES = result_test.c
+result_test_OBJECTS = result_test.$(OBJEXT)
+result_test_LDADD = $(LDADD)
+result_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+safe_test_SOURCES = safe_test.c
+safe_test_OBJECTS = safe_test.$(OBJEXT)
+safe_test_LDADD = $(LDADD)
+safe_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+siphash_test_SOURCES = siphash_test.c
+siphash_test_OBJECTS = siphash_test.$(OBJEXT)
+siphash_test_LDADD = $(LDADD)
+siphash_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+sockaddr_test_SOURCES = sockaddr_test.c
+sockaddr_test_OBJECTS = sockaddr_test.$(OBJEXT)
+sockaddr_test_LDADD = $(LDADD)
+sockaddr_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+stats_test_SOURCES = stats_test.c
+stats_test_OBJECTS = stats_test.$(OBJEXT)
+stats_test_LDADD = $(LDADD)
+stats_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+symtab_test_SOURCES = symtab_test.c
+symtab_test_OBJECTS = symtab_test.$(OBJEXT)
+symtab_test_LDADD = $(LDADD)
+symtab_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+task_test_SOURCES = task_test.c
+task_test_OBJECTS = task_test-task_test.$(OBJEXT)
+@HAVE_LIBXML2_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
+@HAVE_JSON_C_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+task_test_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_4)
+taskpool_test_SOURCES = taskpool_test.c
+taskpool_test_OBJECTS = taskpool_test.$(OBJEXT)
+taskpool_test_LDADD = $(LDADD)
+taskpool_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+time_test_SOURCES = time_test.c
+time_test_OBJECTS = time_test.$(OBJEXT)
+time_test_LDADD = $(LDADD)
+time_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+timer_test_SOURCES = timer_test.c
+timer_test_OBJECTS = timer_test.$(OBJEXT)
+timer_test_LDADD = $(LDADD)
+timer_test_DEPENDENCIES = $(LIBISC_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/aes_test.Po \
+ ./$(DEPDIR)/buffer_test.Po ./$(DEPDIR)/counter_test.Po \
+ ./$(DEPDIR)/crc64_test.Po ./$(DEPDIR)/doh_test-doh_test.Po \
+ ./$(DEPDIR)/errno_test.Po ./$(DEPDIR)/file_test.Po \
+ ./$(DEPDIR)/hash_test.Po ./$(DEPDIR)/heap_test.Po \
+ ./$(DEPDIR)/hmac_test-hmac_test.Po ./$(DEPDIR)/ht_test.Po \
+ ./$(DEPDIR)/lex_test.Po ./$(DEPDIR)/md_test-md_test.Po \
+ ./$(DEPDIR)/mem_test.Po ./$(DEPDIR)/netaddr_test.Po \
+ ./$(DEPDIR)/netmgr_test-netmgr_test.Po \
+ ./$(DEPDIR)/parse_test.Po ./$(DEPDIR)/pool_test.Po \
+ ./$(DEPDIR)/quota_test.Po ./$(DEPDIR)/radix_test.Po \
+ ./$(DEPDIR)/random_test.Po ./$(DEPDIR)/regex_test.Po \
+ ./$(DEPDIR)/result_test.Po ./$(DEPDIR)/safe_test.Po \
+ ./$(DEPDIR)/siphash_test.Po ./$(DEPDIR)/sockaddr_test.Po \
+ ./$(DEPDIR)/stats_test.Po ./$(DEPDIR)/symtab_test.Po \
+ ./$(DEPDIR)/task_test-task_test.Po \
+ ./$(DEPDIR)/taskpool_test.Po ./$(DEPDIR)/time_test.Po \
+ ./$(DEPDIR)/timer_test.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = aes_test.c buffer_test.c counter_test.c crc64_test.c \
+ $(doh_test_SOURCES) errno_test.c file_test.c hash_test.c \
+ heap_test.c hmac_test.c ht_test.c lex_test.c md_test.c \
+ mem_test.c netaddr_test.c $(netmgr_test_SOURCES) parse_test.c \
+ pool_test.c quota_test.c radix_test.c random_test.c \
+ regex_test.c result_test.c safe_test.c siphash_test.c \
+ sockaddr_test.c stats_test.c symtab_test.c task_test.c \
+ taskpool_test.c time_test.c timer_test.c
+DIST_SOURCES = aes_test.c buffer_test.c counter_test.c crc64_test.c \
+ $(am__doh_test_SOURCES_DIST) errno_test.c file_test.c \
+ hash_test.c heap_test.c hmac_test.c ht_test.c lex_test.c \
+ md_test.c mem_test.c netaddr_test.c $(netmgr_test_SOURCES) \
+ parse_test.c pool_test.c quota_test.c radix_test.c \
+ random_test.c regex_test.c result_test.c safe_test.c \
+ siphash_test.c sockaddr_test.c stats_test.c symtab_test.c \
+ task_test.c taskpool_test.c time_test.c timer_test.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = test-recursive unit-recursive \
+ doc-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/Makefile.tests \
+ $(top_srcdir)/Makefile.top $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CMOCKA_CFLAGS = @CMOCKA_CFLAGS@
+CMOCKA_LIBS = @CMOCKA_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURL = @CURL@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEVELOPER_MODE = @DEVELOPER_MODE@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FSTRM_CAPTURE = @FSTRM_CAPTURE@
+FUZZ_LDFLAGS = @FUZZ_LDFLAGS@
+FUZZ_LOG_COMPILER = @FUZZ_LOG_COMPILER@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@
+JEMALLOC_LIBS = @JEMALLOC_LIBS@
+JSON_C_CFLAGS = @JSON_C_CFLAGS@
+JSON_C_LIBS = @JSON_C_LIBS@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_CONFIG = @KRB5_CONFIG@
+KRB5_LIBS = @KRB5_LIBS@
+LATEXMK = @LATEXMK@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBNGHTTP2_CFLAGS = @LIBNGHTTP2_CFLAGS@
+LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUV_CFLAGS = @LIBUV_CFLAGS@
+LIBUV_LIBS = @LIBUV_LIBS@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIPO = @LIPO@
+LMDB_CFLAGS = @LMDB_CFLAGS@
+LMDB_LIBS = @LMDB_LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAXMINDDB_CFLAGS = @MAXMINDDB_CFLAGS@
+MAXMINDDB_LIBS = @MAXMINDDB_LIBS@
+MAXMINDDB_PREFIX = @MAXMINDDB_PREFIX@
+MKDIR_P = @MKDIR_P@
+NC = @NC@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTEST = @PYTEST@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+READLINE_CFLAGS = @READLINE_CFLAGS@
+READLINE_LIBS = @READLINE_LIBS@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINX_BUILD = @SPHINX_BUILD@
+STD_CFLAGS = @STD_CFLAGS@
+STD_CPPFLAGS = @STD_CPPFLAGS@
+STD_LDFLAGS = @STD_LDFLAGS@
+STRIP = @STRIP@
+TEST_CFLAGS = @TEST_CFLAGS@
+VERSION = @VERSION@
+XELATEX = @XELATEX@
+XSLTPROC = @XSLTPROC@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
+AM_CFLAGS = $(STD_CFLAGS) -I$(top_srcdir)/tests/include $(TEST_CFLAGS)
+AM_CPPFLAGS = $(STD_CPPFLAGS) -include $(top_builddir)/config.h \
+ -I$(srcdir)/include $(LIBISC_CFLAGS) $(LIBUV_CFLAGS) \
+ -I$(top_srcdir)/lib/isc $(CMOCKA_CFLAGS) \
+ -DNAMED_PLUGINDIR=\"$(pkglibdir)\" \
+ -DTESTS_DIR=\"$(abs_srcdir)\"
+AM_LDFLAGS = $(STD_LDFLAGS) $(am__append_1)
+LDADD = $(LIBISC_LIBS) $(LIBUV_LIBS) \
+ $(top_builddir)/tests/libtest/libtest.la $(CMOCKA_LIBS)
+LIBISC_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib/isc/include \
+ -I$(top_builddir)/lib/isc/include
+
+LIBISC_LIBS = $(top_builddir)/lib/isc/libisc.la
+LIBDNS_CFLAGS = \
+ -I$(top_srcdir)/lib/dns/include \
+ -I$(top_builddir)/lib/dns/include
+
+LIBDNS_LIBS = \
+ $(top_builddir)/lib/dns/libdns.la
+
+LIBNS_CFLAGS = \
+ -I$(top_srcdir)/lib/ns/include
+
+LIBNS_LIBS = \
+ $(top_builddir)/lib/ns/libns.la
+
+LIBIRS_CFLAGS = \
+ -I$(top_srcdir)/lib/irs/include
+
+LIBIRS_LIBS = \
+ $(top_builddir)/lib/irs/libirs.la
+
+LIBISCCFG_CFLAGS = \
+ -I$(top_srcdir)/lib/isccfg/include
+
+LIBISCCFG_LIBS = \
+ $(top_builddir)/lib/isccfg/libisccfg.la
+
+LIBISCCC_CFLAGS = \
+ -I$(top_srcdir)/lib/isccc/include/
+
+LIBISCCC_LIBS = \
+ $(top_builddir)/lib/isccc/libisccc.la
+
+LIBBIND9_CFLAGS = \
+ -I$(top_srcdir)/lib/bind9/include
+
+LIBBIND9_LIBS = \
+ $(top_builddir)/lib/bind9/libbind9.la
+
+@HAVE_LIBNGHTTP2_TRUE@doh_test_CPPFLAGS = \
+@HAVE_LIBNGHTTP2_TRUE@ $(AM_CPPFLAGS) \
+@HAVE_LIBNGHTTP2_TRUE@ $(LIBNGHTTP2_CFLAGS) \
+@HAVE_LIBNGHTTP2_TRUE@ $(OPENSSL_CFLAGS)
+
+@HAVE_LIBNGHTTP2_TRUE@doh_test_LDADD = \
+@HAVE_LIBNGHTTP2_TRUE@ $(LDADD) \
+@HAVE_LIBNGHTTP2_TRUE@ $(LIBNGHTTP2_LIBS)
+
+@HAVE_LIBNGHTTP2_TRUE@doh_test_SOURCES = \
+@HAVE_LIBNGHTTP2_TRUE@ doh_test.c \
+@HAVE_LIBNGHTTP2_TRUE@ uv_wrap.h
+
+hmac_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+hmac_test_LDADD = \
+ $(LDADD) \
+ $(OPENSSL_LIBS)
+
+md_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+md_test_LDADD = \
+ $(LDADD) \
+ $(OPENSSL_LIBS)
+
+netmgr_test_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(OPENSSL_CFLAGS)
+
+netmgr_test_LDADD = \
+ $(LDADD) \
+ $(OPENSSL_LIBS)
+
+netmgr_test_SOURCES = \
+ netmgr_test.c \
+ uv_wrap.h
+
+random_test_LDADD = \
+ $(LDADD) \
+ -lm
+
+task_test_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_3) $(am__append_5)
+task_test_LDADD = $(LDADD) $(am__append_4) $(am__append_6)
+EXTRA_DIST = testdata
+@HAVE_CMOCKA_TRUE@TESTS = $(check_PROGRAMS)
+LOG_COMPILER = $(top_builddir)/tests/unit-test-driver.sh
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/isc/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tests/isc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+aes_test$(EXEEXT): $(aes_test_OBJECTS) $(aes_test_DEPENDENCIES) $(EXTRA_aes_test_DEPENDENCIES)
+ @rm -f aes_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(aes_test_OBJECTS) $(aes_test_LDADD) $(LIBS)
+
+buffer_test$(EXEEXT): $(buffer_test_OBJECTS) $(buffer_test_DEPENDENCIES) $(EXTRA_buffer_test_DEPENDENCIES)
+ @rm -f buffer_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(buffer_test_OBJECTS) $(buffer_test_LDADD) $(LIBS)
+
+counter_test$(EXEEXT): $(counter_test_OBJECTS) $(counter_test_DEPENDENCIES) $(EXTRA_counter_test_DEPENDENCIES)
+ @rm -f counter_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(counter_test_OBJECTS) $(counter_test_LDADD) $(LIBS)
+
+crc64_test$(EXEEXT): $(crc64_test_OBJECTS) $(crc64_test_DEPENDENCIES) $(EXTRA_crc64_test_DEPENDENCIES)
+ @rm -f crc64_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(crc64_test_OBJECTS) $(crc64_test_LDADD) $(LIBS)
+
+doh_test$(EXEEXT): $(doh_test_OBJECTS) $(doh_test_DEPENDENCIES) $(EXTRA_doh_test_DEPENDENCIES)
+ @rm -f doh_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(doh_test_OBJECTS) $(doh_test_LDADD) $(LIBS)
+
+errno_test$(EXEEXT): $(errno_test_OBJECTS) $(errno_test_DEPENDENCIES) $(EXTRA_errno_test_DEPENDENCIES)
+ @rm -f errno_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(errno_test_OBJECTS) $(errno_test_LDADD) $(LIBS)
+
+file_test$(EXEEXT): $(file_test_OBJECTS) $(file_test_DEPENDENCIES) $(EXTRA_file_test_DEPENDENCIES)
+ @rm -f file_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(file_test_OBJECTS) $(file_test_LDADD) $(LIBS)
+
+hash_test$(EXEEXT): $(hash_test_OBJECTS) $(hash_test_DEPENDENCIES) $(EXTRA_hash_test_DEPENDENCIES)
+ @rm -f hash_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(hash_test_OBJECTS) $(hash_test_LDADD) $(LIBS)
+
+heap_test$(EXEEXT): $(heap_test_OBJECTS) $(heap_test_DEPENDENCIES) $(EXTRA_heap_test_DEPENDENCIES)
+ @rm -f heap_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(heap_test_OBJECTS) $(heap_test_LDADD) $(LIBS)
+
+hmac_test$(EXEEXT): $(hmac_test_OBJECTS) $(hmac_test_DEPENDENCIES) $(EXTRA_hmac_test_DEPENDENCIES)
+ @rm -f hmac_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(hmac_test_OBJECTS) $(hmac_test_LDADD) $(LIBS)
+
+ht_test$(EXEEXT): $(ht_test_OBJECTS) $(ht_test_DEPENDENCIES) $(EXTRA_ht_test_DEPENDENCIES)
+ @rm -f ht_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ht_test_OBJECTS) $(ht_test_LDADD) $(LIBS)
+
+lex_test$(EXEEXT): $(lex_test_OBJECTS) $(lex_test_DEPENDENCIES) $(EXTRA_lex_test_DEPENDENCIES)
+ @rm -f lex_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lex_test_OBJECTS) $(lex_test_LDADD) $(LIBS)
+
+md_test$(EXEEXT): $(md_test_OBJECTS) $(md_test_DEPENDENCIES) $(EXTRA_md_test_DEPENDENCIES)
+ @rm -f md_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(md_test_OBJECTS) $(md_test_LDADD) $(LIBS)
+
+mem_test$(EXEEXT): $(mem_test_OBJECTS) $(mem_test_DEPENDENCIES) $(EXTRA_mem_test_DEPENDENCIES)
+ @rm -f mem_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(mem_test_OBJECTS) $(mem_test_LDADD) $(LIBS)
+
+netaddr_test$(EXEEXT): $(netaddr_test_OBJECTS) $(netaddr_test_DEPENDENCIES) $(EXTRA_netaddr_test_DEPENDENCIES)
+ @rm -f netaddr_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(netaddr_test_OBJECTS) $(netaddr_test_LDADD) $(LIBS)
+
+netmgr_test$(EXEEXT): $(netmgr_test_OBJECTS) $(netmgr_test_DEPENDENCIES) $(EXTRA_netmgr_test_DEPENDENCIES)
+ @rm -f netmgr_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(netmgr_test_OBJECTS) $(netmgr_test_LDADD) $(LIBS)
+
+parse_test$(EXEEXT): $(parse_test_OBJECTS) $(parse_test_DEPENDENCIES) $(EXTRA_parse_test_DEPENDENCIES)
+ @rm -f parse_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(parse_test_OBJECTS) $(parse_test_LDADD) $(LIBS)
+
+pool_test$(EXEEXT): $(pool_test_OBJECTS) $(pool_test_DEPENDENCIES) $(EXTRA_pool_test_DEPENDENCIES)
+ @rm -f pool_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(pool_test_OBJECTS) $(pool_test_LDADD) $(LIBS)
+
+quota_test$(EXEEXT): $(quota_test_OBJECTS) $(quota_test_DEPENDENCIES) $(EXTRA_quota_test_DEPENDENCIES)
+ @rm -f quota_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(quota_test_OBJECTS) $(quota_test_LDADD) $(LIBS)
+
+radix_test$(EXEEXT): $(radix_test_OBJECTS) $(radix_test_DEPENDENCIES) $(EXTRA_radix_test_DEPENDENCIES)
+ @rm -f radix_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(radix_test_OBJECTS) $(radix_test_LDADD) $(LIBS)
+
+random_test$(EXEEXT): $(random_test_OBJECTS) $(random_test_DEPENDENCIES) $(EXTRA_random_test_DEPENDENCIES)
+ @rm -f random_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(random_test_OBJECTS) $(random_test_LDADD) $(LIBS)
+
+regex_test$(EXEEXT): $(regex_test_OBJECTS) $(regex_test_DEPENDENCIES) $(EXTRA_regex_test_DEPENDENCIES)
+ @rm -f regex_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(regex_test_OBJECTS) $(regex_test_LDADD) $(LIBS)
+
+result_test$(EXEEXT): $(result_test_OBJECTS) $(result_test_DEPENDENCIES) $(EXTRA_result_test_DEPENDENCIES)
+ @rm -f result_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(result_test_OBJECTS) $(result_test_LDADD) $(LIBS)
+
+safe_test$(EXEEXT): $(safe_test_OBJECTS) $(safe_test_DEPENDENCIES) $(EXTRA_safe_test_DEPENDENCIES)
+ @rm -f safe_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(safe_test_OBJECTS) $(safe_test_LDADD) $(LIBS)
+
+siphash_test$(EXEEXT): $(siphash_test_OBJECTS) $(siphash_test_DEPENDENCIES) $(EXTRA_siphash_test_DEPENDENCIES)
+ @rm -f siphash_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(siphash_test_OBJECTS) $(siphash_test_LDADD) $(LIBS)
+
+sockaddr_test$(EXEEXT): $(sockaddr_test_OBJECTS) $(sockaddr_test_DEPENDENCIES) $(EXTRA_sockaddr_test_DEPENDENCIES)
+ @rm -f sockaddr_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sockaddr_test_OBJECTS) $(sockaddr_test_LDADD) $(LIBS)
+
+stats_test$(EXEEXT): $(stats_test_OBJECTS) $(stats_test_DEPENDENCIES) $(EXTRA_stats_test_DEPENDENCIES)
+ @rm -f stats_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(stats_test_OBJECTS) $(stats_test_LDADD) $(LIBS)
+
+symtab_test$(EXEEXT): $(symtab_test_OBJECTS) $(symtab_test_DEPENDENCIES) $(EXTRA_symtab_test_DEPENDENCIES)
+ @rm -f symtab_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(symtab_test_OBJECTS) $(symtab_test_LDADD) $(LIBS)
+
+task_test$(EXEEXT): $(task_test_OBJECTS) $(task_test_DEPENDENCIES) $(EXTRA_task_test_DEPENDENCIES)
+ @rm -f task_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(task_test_OBJECTS) $(task_test_LDADD) $(LIBS)
+
+taskpool_test$(EXEEXT): $(taskpool_test_OBJECTS) $(taskpool_test_DEPENDENCIES) $(EXTRA_taskpool_test_DEPENDENCIES)
+ @rm -f taskpool_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(taskpool_test_OBJECTS) $(taskpool_test_LDADD) $(LIBS)
+
+time_test$(EXEEXT): $(time_test_OBJECTS) $(time_test_DEPENDENCIES) $(EXTRA_time_test_DEPENDENCIES)
+ @rm -f time_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(time_test_OBJECTS) $(time_test_LDADD) $(LIBS)
+
+timer_test$(EXEEXT): $(timer_test_OBJECTS) $(timer_test_DEPENDENCIES) $(EXTRA_timer_test_DEPENDENCIES)
+ @rm -f timer_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(timer_test_OBJECTS) $(timer_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aes_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/counter_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc64_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doh_test-doh_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errno_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac_test-hmac_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ht_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lex_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md_test-md_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netaddr_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netmgr_test-netmgr_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quota_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radix_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/result_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/safe_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/siphash_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockaddr_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symtab_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task_test-task_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/taskpool_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer_test.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+doh_test-doh_test.o: doh_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(doh_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT doh_test-doh_test.o -MD -MP -MF $(DEPDIR)/doh_test-doh_test.Tpo -c -o doh_test-doh_test.o `test -f 'doh_test.c' || echo '$(srcdir)/'`doh_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/doh_test-doh_test.Tpo $(DEPDIR)/doh_test-doh_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='doh_test.c' object='doh_test-doh_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(doh_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o doh_test-doh_test.o `test -f 'doh_test.c' || echo '$(srcdir)/'`doh_test.c
+
+doh_test-doh_test.obj: doh_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(doh_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT doh_test-doh_test.obj -MD -MP -MF $(DEPDIR)/doh_test-doh_test.Tpo -c -o doh_test-doh_test.obj `if test -f 'doh_test.c'; then $(CYGPATH_W) 'doh_test.c'; else $(CYGPATH_W) '$(srcdir)/doh_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/doh_test-doh_test.Tpo $(DEPDIR)/doh_test-doh_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='doh_test.c' object='doh_test-doh_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(doh_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o doh_test-doh_test.obj `if test -f 'doh_test.c'; then $(CYGPATH_W) 'doh_test.c'; else $(CYGPATH_W) '$(srcdir)/doh_test.c'; fi`
+
+hmac_test-hmac_test.o: hmac_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hmac_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hmac_test-hmac_test.o -MD -MP -MF $(DEPDIR)/hmac_test-hmac_test.Tpo -c -o hmac_test-hmac_test.o `test -f 'hmac_test.c' || echo '$(srcdir)/'`hmac_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hmac_test-hmac_test.Tpo $(DEPDIR)/hmac_test-hmac_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hmac_test.c' object='hmac_test-hmac_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hmac_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hmac_test-hmac_test.o `test -f 'hmac_test.c' || echo '$(srcdir)/'`hmac_test.c
+
+hmac_test-hmac_test.obj: hmac_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hmac_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hmac_test-hmac_test.obj -MD -MP -MF $(DEPDIR)/hmac_test-hmac_test.Tpo -c -o hmac_test-hmac_test.obj `if test -f 'hmac_test.c'; then $(CYGPATH_W) 'hmac_test.c'; else $(CYGPATH_W) '$(srcdir)/hmac_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hmac_test-hmac_test.Tpo $(DEPDIR)/hmac_test-hmac_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hmac_test.c' object='hmac_test-hmac_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hmac_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hmac_test-hmac_test.obj `if test -f 'hmac_test.c'; then $(CYGPATH_W) 'hmac_test.c'; else $(CYGPATH_W) '$(srcdir)/hmac_test.c'; fi`
+
+md_test-md_test.o: md_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(md_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT md_test-md_test.o -MD -MP -MF $(DEPDIR)/md_test-md_test.Tpo -c -o md_test-md_test.o `test -f 'md_test.c' || echo '$(srcdir)/'`md_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/md_test-md_test.Tpo $(DEPDIR)/md_test-md_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md_test.c' object='md_test-md_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(md_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o md_test-md_test.o `test -f 'md_test.c' || echo '$(srcdir)/'`md_test.c
+
+md_test-md_test.obj: md_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(md_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT md_test-md_test.obj -MD -MP -MF $(DEPDIR)/md_test-md_test.Tpo -c -o md_test-md_test.obj `if test -f 'md_test.c'; then $(CYGPATH_W) 'md_test.c'; else $(CYGPATH_W) '$(srcdir)/md_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/md_test-md_test.Tpo $(DEPDIR)/md_test-md_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md_test.c' object='md_test-md_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(md_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o md_test-md_test.obj `if test -f 'md_test.c'; then $(CYGPATH_W) 'md_test.c'; else $(CYGPATH_W) '$(srcdir)/md_test.c'; fi`
+
+netmgr_test-netmgr_test.o: netmgr_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(netmgr_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netmgr_test-netmgr_test.o -MD -MP -MF $(DEPDIR)/netmgr_test-netmgr_test.Tpo -c -o netmgr_test-netmgr_test.o `test -f 'netmgr_test.c' || echo '$(srcdir)/'`netmgr_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/netmgr_test-netmgr_test.Tpo $(DEPDIR)/netmgr_test-netmgr_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netmgr_test.c' object='netmgr_test-netmgr_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(netmgr_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netmgr_test-netmgr_test.o `test -f 'netmgr_test.c' || echo '$(srcdir)/'`netmgr_test.c
+
+netmgr_test-netmgr_test.obj: netmgr_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(netmgr_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netmgr_test-netmgr_test.obj -MD -MP -MF $(DEPDIR)/netmgr_test-netmgr_test.Tpo -c -o netmgr_test-netmgr_test.obj `if test -f 'netmgr_test.c'; then $(CYGPATH_W) 'netmgr_test.c'; else $(CYGPATH_W) '$(srcdir)/netmgr_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/netmgr_test-netmgr_test.Tpo $(DEPDIR)/netmgr_test-netmgr_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netmgr_test.c' object='netmgr_test-netmgr_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(netmgr_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netmgr_test-netmgr_test.obj `if test -f 'netmgr_test.c'; then $(CYGPATH_W) 'netmgr_test.c'; else $(CYGPATH_W) '$(srcdir)/netmgr_test.c'; fi`
+
+task_test-task_test.o: task_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(task_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task_test-task_test.o -MD -MP -MF $(DEPDIR)/task_test-task_test.Tpo -c -o task_test-task_test.o `test -f 'task_test.c' || echo '$(srcdir)/'`task_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/task_test-task_test.Tpo $(DEPDIR)/task_test-task_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='task_test.c' object='task_test-task_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(task_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task_test-task_test.o `test -f 'task_test.c' || echo '$(srcdir)/'`task_test.c
+
+task_test-task_test.obj: task_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(task_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task_test-task_test.obj -MD -MP -MF $(DEPDIR)/task_test-task_test.Tpo -c -o task_test-task_test.obj `if test -f 'task_test.c'; then $(CYGPATH_W) 'task_test.c'; else $(CYGPATH_W) '$(srcdir)/task_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/task_test-task_test.Tpo $(DEPDIR)/task_test-task_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='task_test.c' object='task_test-task_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(task_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task_test-task_test.obj `if test -f 'task_test.c'; then $(CYGPATH_W) 'task_test.c'; else $(CYGPATH_W) '$(srcdir)/task_test.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+test-local:
+unit-local:
+doc-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS: $(check_PROGRAMS)
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+aes_test.log: aes_test$(EXEEXT)
+ @p='aes_test$(EXEEXT)'; \
+ b='aes_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+buffer_test.log: buffer_test$(EXEEXT)
+ @p='buffer_test$(EXEEXT)'; \
+ b='buffer_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+counter_test.log: counter_test$(EXEEXT)
+ @p='counter_test$(EXEEXT)'; \
+ b='counter_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+crc64_test.log: crc64_test$(EXEEXT)
+ @p='crc64_test$(EXEEXT)'; \
+ b='crc64_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+errno_test.log: errno_test$(EXEEXT)
+ @p='errno_test$(EXEEXT)'; \
+ b='errno_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+file_test.log: file_test$(EXEEXT)
+ @p='file_test$(EXEEXT)'; \
+ b='file_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+hash_test.log: hash_test$(EXEEXT)
+ @p='hash_test$(EXEEXT)'; \
+ b='hash_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+heap_test.log: heap_test$(EXEEXT)
+ @p='heap_test$(EXEEXT)'; \
+ b='heap_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+hmac_test.log: hmac_test$(EXEEXT)
+ @p='hmac_test$(EXEEXT)'; \
+ b='hmac_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+ht_test.log: ht_test$(EXEEXT)
+ @p='ht_test$(EXEEXT)'; \
+ b='ht_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+lex_test.log: lex_test$(EXEEXT)
+ @p='lex_test$(EXEEXT)'; \
+ b='lex_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+md_test.log: md_test$(EXEEXT)
+ @p='md_test$(EXEEXT)'; \
+ b='md_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+mem_test.log: mem_test$(EXEEXT)
+ @p='mem_test$(EXEEXT)'; \
+ b='mem_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+netaddr_test.log: netaddr_test$(EXEEXT)
+ @p='netaddr_test$(EXEEXT)'; \
+ b='netaddr_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+netmgr_test.log: netmgr_test$(EXEEXT)
+ @p='netmgr_test$(EXEEXT)'; \
+ b='netmgr_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parse_test.log: parse_test$(EXEEXT)
+ @p='parse_test$(EXEEXT)'; \
+ b='parse_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+pool_test.log: pool_test$(EXEEXT)
+ @p='pool_test$(EXEEXT)'; \
+ b='pool_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+quota_test.log: quota_test$(EXEEXT)
+ @p='quota_test$(EXEEXT)'; \
+ b='quota_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+radix_test.log: radix_test$(EXEEXT)
+ @p='radix_test$(EXEEXT)'; \
+ b='radix_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+random_test.log: random_test$(EXEEXT)
+ @p='random_test$(EXEEXT)'; \
+ b='random_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+regex_test.log: regex_test$(EXEEXT)
+ @p='regex_test$(EXEEXT)'; \
+ b='regex_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+result_test.log: result_test$(EXEEXT)
+ @p='result_test$(EXEEXT)'; \
+ b='result_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+safe_test.log: safe_test$(EXEEXT)
+ @p='safe_test$(EXEEXT)'; \
+ b='safe_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+siphash_test.log: siphash_test$(EXEEXT)
+ @p='siphash_test$(EXEEXT)'; \
+ b='siphash_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+sockaddr_test.log: sockaddr_test$(EXEEXT)
+ @p='sockaddr_test$(EXEEXT)'; \
+ b='sockaddr_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+stats_test.log: stats_test$(EXEEXT)
+ @p='stats_test$(EXEEXT)'; \
+ b='stats_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+symtab_test.log: symtab_test$(EXEEXT)
+ @p='symtab_test$(EXEEXT)'; \
+ b='symtab_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+task_test.log: task_test$(EXEEXT)
+ @p='task_test$(EXEEXT)'; \
+ b='task_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+taskpool_test.log: taskpool_test$(EXEEXT)
+ @p='taskpool_test$(EXEEXT)'; \
+ b='taskpool_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+time_test.log: time_test$(EXEEXT)
+ @p='time_test$(EXEEXT)'; \
+ b='time_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+timer_test.log: timer_test$(EXEEXT)
+ @p='timer_test$(EXEEXT)'; \
+ b='timer_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+doh_test.log: doh_test$(EXEEXT)
+ @p='doh_test$(EXEEXT)'; \
+ b='doh_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/aes_test.Po
+ -rm -f ./$(DEPDIR)/buffer_test.Po
+ -rm -f ./$(DEPDIR)/counter_test.Po
+ -rm -f ./$(DEPDIR)/crc64_test.Po
+ -rm -f ./$(DEPDIR)/doh_test-doh_test.Po
+ -rm -f ./$(DEPDIR)/errno_test.Po
+ -rm -f ./$(DEPDIR)/file_test.Po
+ -rm -f ./$(DEPDIR)/hash_test.Po
+ -rm -f ./$(DEPDIR)/heap_test.Po
+ -rm -f ./$(DEPDIR)/hmac_test-hmac_test.Po
+ -rm -f ./$(DEPDIR)/ht_test.Po
+ -rm -f ./$(DEPDIR)/lex_test.Po
+ -rm -f ./$(DEPDIR)/md_test-md_test.Po
+ -rm -f ./$(DEPDIR)/mem_test.Po
+ -rm -f ./$(DEPDIR)/netaddr_test.Po
+ -rm -f ./$(DEPDIR)/netmgr_test-netmgr_test.Po
+ -rm -f ./$(DEPDIR)/parse_test.Po
+ -rm -f ./$(DEPDIR)/pool_test.Po
+ -rm -f ./$(DEPDIR)/quota_test.Po
+ -rm -f ./$(DEPDIR)/radix_test.Po
+ -rm -f ./$(DEPDIR)/random_test.Po
+ -rm -f ./$(DEPDIR)/regex_test.Po
+ -rm -f ./$(DEPDIR)/result_test.Po
+ -rm -f ./$(DEPDIR)/safe_test.Po
+ -rm -f ./$(DEPDIR)/siphash_test.Po
+ -rm -f ./$(DEPDIR)/sockaddr_test.Po
+ -rm -f ./$(DEPDIR)/stats_test.Po
+ -rm -f ./$(DEPDIR)/symtab_test.Po
+ -rm -f ./$(DEPDIR)/task_test-task_test.Po
+ -rm -f ./$(DEPDIR)/taskpool_test.Po
+ -rm -f ./$(DEPDIR)/time_test.Po
+ -rm -f ./$(DEPDIR)/timer_test.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+doc: doc-am
+
+doc-am: doc-local
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/aes_test.Po
+ -rm -f ./$(DEPDIR)/buffer_test.Po
+ -rm -f ./$(DEPDIR)/counter_test.Po
+ -rm -f ./$(DEPDIR)/crc64_test.Po
+ -rm -f ./$(DEPDIR)/doh_test-doh_test.Po
+ -rm -f ./$(DEPDIR)/errno_test.Po
+ -rm -f ./$(DEPDIR)/file_test.Po
+ -rm -f ./$(DEPDIR)/hash_test.Po
+ -rm -f ./$(DEPDIR)/heap_test.Po
+ -rm -f ./$(DEPDIR)/hmac_test-hmac_test.Po
+ -rm -f ./$(DEPDIR)/ht_test.Po
+ -rm -f ./$(DEPDIR)/lex_test.Po
+ -rm -f ./$(DEPDIR)/md_test-md_test.Po
+ -rm -f ./$(DEPDIR)/mem_test.Po
+ -rm -f ./$(DEPDIR)/netaddr_test.Po
+ -rm -f ./$(DEPDIR)/netmgr_test-netmgr_test.Po
+ -rm -f ./$(DEPDIR)/parse_test.Po
+ -rm -f ./$(DEPDIR)/pool_test.Po
+ -rm -f ./$(DEPDIR)/quota_test.Po
+ -rm -f ./$(DEPDIR)/radix_test.Po
+ -rm -f ./$(DEPDIR)/random_test.Po
+ -rm -f ./$(DEPDIR)/regex_test.Po
+ -rm -f ./$(DEPDIR)/result_test.Po
+ -rm -f ./$(DEPDIR)/safe_test.Po
+ -rm -f ./$(DEPDIR)/siphash_test.Po
+ -rm -f ./$(DEPDIR)/sockaddr_test.Po
+ -rm -f ./$(DEPDIR)/stats_test.Po
+ -rm -f ./$(DEPDIR)/symtab_test.Po
+ -rm -f ./$(DEPDIR)/task_test-task_test.Po
+ -rm -f ./$(DEPDIR)/taskpool_test.Po
+ -rm -f ./$(DEPDIR)/time_test.Po
+ -rm -f ./$(DEPDIR)/timer_test.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+test: test-am
+
+test-am: test-local
+
+uninstall-am:
+
+unit: unit-am
+
+unit-am: unit-local
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-checkPROGRAMS clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir \
+ doc-am doc-local dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am recheck tags tags-am test-am test-local \
+ uninstall uninstall-am unit-am unit-local
+
+.PRECIOUS: Makefile
+
+
+unit-local: check
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/isc/aes_test.c b/tests/isc/aes_test.c
new file mode 100644
index 0000000..9e9ea22
--- /dev/null
+++ b/tests/isc/aes_test.c
@@ -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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/aes.h>
+#include <isc/buffer.h>
+#include <isc/hex.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/*
+ * Test data from NIST KAT
+ */
+
+isc_result_t
+tohexstr(unsigned char *d, char *out);
+
+size_t
+fromhexstr(const char *in, unsigned char *d);
+
+unsigned char plaintext[3 * ISC_AES_BLOCK_LENGTH];
+unsigned char ciphertext[ISC_AES_BLOCK_LENGTH];
+char str[2 * ISC_AES_BLOCK_LENGTH + 1];
+unsigned char key[ISC_AES256_KEYLENGTH + 1];
+size_t len;
+
+isc_result_t
+tohexstr(unsigned char *d, char *out) {
+ isc_buffer_t b;
+ isc_region_t r;
+
+ isc_buffer_init(&b, out, 2 * ISC_AES_BLOCK_LENGTH + 1);
+ r.base = d;
+ r.length = ISC_AES_BLOCK_LENGTH;
+ return (isc_hex_totext(&r, 0, "", &b));
+}
+
+size_t
+fromhexstr(const char *in, unsigned char *d) {
+ isc_buffer_t b;
+ isc_result_t ret;
+
+ isc_buffer_init(&b, d, ISC_AES256_KEYLENGTH + 1);
+ ret = isc_hex_decodestring(in, &b);
+ if (ret != ISC_R_SUCCESS) {
+ return (0);
+ }
+ return (isc_buffer_usedlength(&b));
+}
+
+typedef struct aes_testcase {
+ const char *key;
+ const char *input;
+ const char *result;
+} aes_testcase_t;
+
+/* AES 128 test vectors */
+ISC_RUN_TEST_IMPL(isc_aes128_test) {
+ aes_testcase_t testcases[] = { /* Test 1 (KAT ECBVarTxt128 #3) */
+ { "00000000000000000000000000000000",
+ "F0000000000000000000000000000000",
+ "96D9FD5CC4F07441727DF0F33E401A36" },
+ /* Test 2 (KAT ECBVarTxt128 #123) */
+ { "00000000000000000000000000000000",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "F9B0FDA0C4A898F5B9E6F661C4CE4D07" },
+ /* Test 3 (KAT ECBVarKey128 #3) */
+ { "F0000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ "970014D634E2B7650777E8E84D03CCD8" },
+ /* Test 4 (KAT ECBVarKey128 #123) */
+ { "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "00000000000000000000000000000000",
+ "41C78C135ED9E98C096640647265DA1E" },
+ /* Test 5 (KAT ECBGFSbox128 #3) */
+ { "00000000000000000000000000000000",
+ "6A118A874519E64E9963798A503F1D35",
+ "DC43BE40BE0E53712F7E2BF5CA707209" },
+ /* Test 6 (KAT ECBKeySbox128 #3) */
+ { "B6364AC4E1DE1E285EAF144A2415F7A0",
+ "00000000000000000000000000000000",
+ "5D9B05578FC944B3CF1CCF0E746CD581" },
+ { NULL, NULL, NULL }
+ };
+
+ aes_testcase_t *testcase = testcases;
+
+ UNUSED(state);
+
+ while (testcase->key != NULL) {
+ len = fromhexstr(testcase->key, key);
+ assert_int_equal(len, ISC_AES128_KEYLENGTH);
+ len = fromhexstr(testcase->input, plaintext);
+ assert_int_equal(len, ISC_AES_BLOCK_LENGTH);
+ isc_aes128_crypt(key, plaintext, ciphertext);
+ assert_int_equal(tohexstr(ciphertext, str), ISC_R_SUCCESS);
+ assert_string_equal(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+/* AES 192 test vectors */
+ISC_RUN_TEST_IMPL(isc_aes192_test) {
+ aes_testcase_t testcases[] = {
+ /* Test 1 (KAT ECBVarTxt192 #3) */
+ { "000000000000000000000000000000000000000000000000",
+ "F0000000000000000000000000000000",
+ "2A560364CE529EFC21788779568D5555" },
+ /* Test 2 (KAT ECBVarTxt192 #123) */
+ { "000000000000000000000000000000000000000000000000",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "2AABB999F43693175AF65C6C612C46FB" },
+ /* Test 3 (KAT ECBVarKey192 #3) */
+ { "F00000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ "180B09F267C45145DB2F826C2582D35C" },
+ /* Test 4 (KAT ECBVarKey192 #187) */
+ { "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "00000000000000000000000000000000",
+ "EACF1E6C4224EFB38900B185AB1DFD42" },
+ /* Test 5 (KAT ECBGFSbox192 #3) */
+ { "000000000000000000000000000000000000000000000000",
+ "51719783D3185A535BD75ADC65071CE1",
+ "4F354592FF7C8847D2D0870CA9481B7C" },
+ /* Test 6 (KAT ECBKeySbox192 #3) */
+ { "CD62376D5EBB414917F0C78F05266433DC9192A1EC943300",
+ "00000000000000000000000000000000",
+ "7F6C25FF41858561BB62F36492E93C29" },
+ { NULL, NULL, NULL }
+ };
+
+ aes_testcase_t *testcase = testcases;
+
+ while (testcase->key != NULL) {
+ len = fromhexstr(testcase->key, key);
+ assert_int_equal(len, ISC_AES192_KEYLENGTH);
+ len = fromhexstr(testcase->input, plaintext);
+ assert_int_equal(len, ISC_AES_BLOCK_LENGTH);
+ isc_aes192_crypt(key, plaintext, ciphertext);
+ assert_int_equal(tohexstr(ciphertext, str), ISC_R_SUCCESS);
+ assert_string_equal(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+/* AES 256 test vectors */
+ISC_RUN_TEST_IMPL(isc_aes256_test) {
+ aes_testcase_t testcases[] = { /* Test 1 (KAT ECBVarTxt256 #3) */
+ { "00000000000000000000000000000000"
+ "00000000000000000000000000000000",
+ "F0000000000000000000000000000000",
+ "7F2C5ECE07A98D8BEE13C51177395FF7" },
+ /* Test 2 (KAT ECBVarTxt256 #123) */
+ { "00000000000000000000000000000000"
+ "00000000000000000000000000000000",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "7240E524BC51D8C4D440B1BE55D1062C" },
+ /* Test 3 (KAT ECBVarKey256 #3) */
+ { "F0000000000000000000000000000000"
+ "00000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ "1C777679D50037C79491A94DA76A9A35" },
+ /* Test 4 (KAT ECBVarKey256 #251) */
+ { "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "00000000000000000000000000000000",
+ "03720371A04962EAEA0A852E69972858" },
+ /* Test 5 (KAT ECBGFSbox256 #3) */
+ { "00000000000000000000000000000000"
+ "00000000000000000000000000000000",
+ "8A560769D605868AD80D819BDBA03771",
+ "38F2C7AE10612415D27CA190D27DA8B4" },
+ /* Test 6 (KAT ECBKeySbox256 #3) */
+ { "984CA75F4EE8D706F46C2D98C0BF4A45"
+ "F5B00D791C2DFEB191B5ED8E420FD627",
+ "00000000000000000000000000000000",
+ "4307456A9E67813B452E15FA8FFFE398" },
+ { NULL, NULL, NULL }
+ };
+
+ aes_testcase_t *testcase = testcases;
+
+ UNUSED(state);
+
+ while (testcase->key != NULL) {
+ len = fromhexstr(testcase->key, key);
+ assert_int_equal(len, ISC_AES256_KEYLENGTH);
+ len = fromhexstr(testcase->input, plaintext);
+ assert_int_equal(len, ISC_AES_BLOCK_LENGTH);
+ isc_aes256_crypt(key, plaintext, ciphertext);
+ assert_int_equal(tohexstr(ciphertext, str), ISC_R_SUCCESS);
+ assert_string_equal(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_aes128_test)
+ISC_TEST_ENTRY(isc_aes192_test)
+ISC_TEST_ENTRY(isc_aes256_test)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/buffer_test.c b/tests/isc/buffer_test.c
new file mode 100644
index 0000000..1c858d3
--- /dev/null
+++ b/tests/isc/buffer_test.c
@@ -0,0 +1,308 @@
+/*
+ * 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 <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/result.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* reserve space in dynamic buffers */
+ISC_RUN_TEST_IMPL(isc_buffer_reserve) {
+ isc_result_t result;
+ isc_buffer_t *b;
+
+ UNUSED(state);
+
+ b = NULL;
+ isc_buffer_allocate(mctx, &b, 1024);
+ assert_int_equal(b->length, 1024);
+
+ /*
+ * 1024 bytes should already be available, so this call does
+ * nothing.
+ */
+ result = isc_buffer_reserve(&b, 1024);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(ISC_BUFFER_VALID(b));
+ assert_non_null(b);
+ assert_int_equal(b->length, 1024);
+
+ /*
+ * This call should grow it to 2048 bytes as only 1024 bytes are
+ * available in the buffer.
+ */
+ result = isc_buffer_reserve(&b, 1025);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(ISC_BUFFER_VALID(b));
+ assert_non_null(b);
+ assert_int_equal(b->length, 2048);
+
+ /*
+ * 2048 bytes should already be available, so this call does
+ * nothing.
+ */
+ result = isc_buffer_reserve(&b, 2000);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(ISC_BUFFER_VALID(b));
+ assert_non_null(b);
+ assert_int_equal(b->length, 2048);
+
+ /*
+ * This call should grow it to 4096 bytes as only 2048 bytes are
+ * available in the buffer.
+ */
+ result = isc_buffer_reserve(&b, 3000);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_true(ISC_BUFFER_VALID(b));
+ assert_non_null(b);
+ assert_int_equal(b->length, 4096);
+
+ /* Consume some of the buffer so we can run the next test. */
+ isc_buffer_add(b, 4096);
+
+ /*
+ * This call should fail and leave buffer untouched.
+ */
+ result = isc_buffer_reserve(&b, UINT_MAX);
+ assert_int_equal(result, ISC_R_NOMEMORY);
+ assert_true(ISC_BUFFER_VALID(b));
+ assert_non_null(b);
+ assert_int_equal(b->length, 4096);
+
+ isc_buffer_free(&b);
+}
+
+/* dynamic buffer automatic reallocation */
+ISC_RUN_TEST_IMPL(isc_buffer_dynamic) {
+ isc_buffer_t *b;
+ size_t last_length = 10;
+ int i;
+
+ UNUSED(state);
+
+ b = NULL;
+ isc_buffer_allocate(mctx, &b, last_length);
+ assert_non_null(b);
+ assert_int_equal(b->length, last_length);
+
+ isc_buffer_setautorealloc(b, true);
+
+ isc_buffer_putuint8(b, 1);
+
+ for (i = 0; i < 1000; i++) {
+ isc_buffer_putstr(b, "thisisa24charslongstring");
+ }
+ assert_true(b->length - last_length >= 1000 * 24);
+ last_length += 1000 * 24;
+
+ for (i = 0; i < 10000; i++) {
+ isc_buffer_putuint8(b, 1);
+ }
+
+ assert_true(b->length - last_length >= 10000 * 1);
+ last_length += 10000 * 1;
+
+ for (i = 0; i < 10000; i++) {
+ isc_buffer_putuint16(b, 1);
+ }
+
+ assert_true(b->length - last_length >= 10000 * 2);
+
+ last_length += 10000 * 2;
+ for (i = 0; i < 10000; i++) {
+ isc_buffer_putuint24(b, 1);
+ }
+ assert_true(b->length - last_length >= 10000 * 3);
+
+ last_length += 10000 * 3;
+
+ for (i = 0; i < 10000; i++) {
+ isc_buffer_putuint32(b, 1);
+ }
+ assert_true(b->length - last_length >= 10000 * 4);
+
+ isc_buffer_free(&b);
+}
+
+/* copy a region into a buffer */
+ISC_RUN_TEST_IMPL(isc_buffer_copyregion) {
+ unsigned char data[] = { 0x11, 0x22, 0x33, 0x44 };
+ isc_buffer_t *b = NULL;
+ isc_result_t result;
+
+ isc_region_t r = {
+ .base = data,
+ .length = sizeof(data),
+ };
+
+ UNUSED(state);
+
+ isc_buffer_allocate(mctx, &b, sizeof(data));
+
+ /*
+ * Fill originally allocated buffer space.
+ */
+ result = isc_buffer_copyregion(b, &r);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Appending more data to the buffer should fail.
+ */
+ result = isc_buffer_copyregion(b, &r);
+ assert_int_equal(result, ISC_R_NOSPACE);
+
+ /*
+ * Enable auto reallocation and retry. Appending should now succeed.
+ */
+ isc_buffer_setautorealloc(b, true);
+ result = isc_buffer_copyregion(b, &r);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_free(&b);
+}
+
+/* sprintf() into a buffer */
+ISC_RUN_TEST_IMPL(isc_buffer_printf) {
+ unsigned int used, prev_used;
+ const char *empty_fmt;
+ isc_result_t result;
+ isc_buffer_t *b, sb;
+ char buf[8];
+
+ UNUSED(state);
+
+ /*
+ * Prepare a buffer with auto-reallocation enabled.
+ */
+ b = NULL;
+ isc_buffer_allocate(mctx, &b, 0);
+ isc_buffer_setautorealloc(b, true);
+
+ /*
+ * Sanity check.
+ */
+ result = isc_buffer_printf(b, "foo");
+ assert_int_equal(result, ISC_R_SUCCESS);
+ used = isc_buffer_usedlength(b);
+ assert_int_equal(used, 3);
+
+ result = isc_buffer_printf(b, "bar");
+ assert_int_equal(result, ISC_R_SUCCESS);
+ used = isc_buffer_usedlength(b);
+ assert_int_equal(used, 3 + 3);
+
+ /*
+ * Also check the terminating NULL byte is there, even though it is not
+ * part of the buffer's used region.
+ */
+ assert_memory_equal(isc_buffer_current(b), "foobar", 7);
+
+ /*
+ * Skip over data from previous check to prevent failures in previous
+ * check from affecting this one.
+ */
+ prev_used = used;
+ isc_buffer_forward(b, prev_used);
+
+ /*
+ * Some standard usage checks.
+ */
+ isc_buffer_printf(b, "%d", 42);
+ used = isc_buffer_usedlength(b);
+ assert_int_equal(used - prev_used, 2);
+
+ isc_buffer_printf(b, "baz%1X", 42);
+ used = isc_buffer_usedlength(b);
+ assert_int_equal(used - prev_used, 2 + 5);
+
+ isc_buffer_printf(b, "%6.1f", 42.42f);
+ used = isc_buffer_usedlength(b);
+ assert_int_equal(used - prev_used, 2 + 5 + 6);
+
+ /*
+ * Also check the terminating NULL byte is there, even though it is not
+ * part of the buffer's used region.
+ */
+ assert_memory_equal(isc_buffer_current(b), "42baz2A 42.4", 14);
+
+ /*
+ * Check an empty format string is properly handled.
+ *
+ * Note: we don't use a string literal for the format string to
+ * avoid triggering [-Werror=format-zero-length].
+ * Note: we have a dummy third argument as some compilers complain
+ * without it.
+ */
+ prev_used = used;
+ empty_fmt = "";
+ result = isc_buffer_printf(b, empty_fmt, "");
+ assert_int_equal(result, ISC_R_SUCCESS);
+ used = isc_buffer_usedlength(b);
+ assert_int_equal(prev_used, used);
+
+ isc_buffer_free(&b);
+
+ /*
+ * Check overflow on a static buffer.
+ */
+ isc_buffer_init(&sb, buf, sizeof(buf));
+ result = isc_buffer_printf(&sb, "123456");
+ assert_int_equal(result, ISC_R_SUCCESS);
+ used = isc_buffer_usedlength(&sb);
+ assert_int_equal(used, 6);
+
+ result = isc_buffer_printf(&sb, "789");
+ assert_int_equal(result, ISC_R_NOSPACE);
+ used = isc_buffer_usedlength(&sb);
+ assert_int_equal(used, 6);
+
+ result = isc_buffer_printf(&sb, "78");
+ assert_int_equal(result, ISC_R_NOSPACE);
+ used = isc_buffer_usedlength(&sb);
+ assert_int_equal(used, 6);
+
+ result = isc_buffer_printf(&sb, "7");
+ assert_int_equal(result, ISC_R_SUCCESS);
+ used = isc_buffer_usedlength(&sb);
+ assert_int_equal(used, 7);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_buffer_reserve)
+ISC_TEST_ENTRY(isc_buffer_dynamic)
+ISC_TEST_ENTRY(isc_buffer_copyregion)
+ISC_TEST_ENTRY(isc_buffer_printf)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/counter_test.c b/tests/isc/counter_test.c
new file mode 100644
index 0000000..dc8dc50
--- /dev/null
+++ b/tests/isc/counter_test.c
@@ -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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/counter.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* test isc_counter object */
+ISC_RUN_TEST_IMPL(isc_counter) {
+ isc_result_t result;
+ isc_counter_t *counter = NULL;
+ int i;
+
+ UNUSED(state);
+
+ result = isc_counter_create(mctx, 0, &counter);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (i = 0; i < 10; i++) {
+ result = isc_counter_increment(counter);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ assert_int_equal(isc_counter_used(counter), 10);
+
+ isc_counter_setlimit(counter, 15);
+ for (i = 0; i < 10; i++) {
+ result = isc_counter_increment(counter);
+ if (result != ISC_R_SUCCESS) {
+ break;
+ }
+ }
+
+ assert_int_equal(isc_counter_used(counter), 15);
+
+ isc_counter_detach(&counter);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_counter)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/crc64_test.c b/tests/isc/crc64_test.c
new file mode 100644
index 0000000..cb96437
--- /dev/null
+++ b/tests/isc/crc64_test.c
@@ -0,0 +1,84 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/crc64.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+#define TEST_INPUT(x) (x), sizeof(x) - 1
+
+ISC_RUN_TEST_IMPL(isc_crc64_init) {
+ uint64_t crc;
+
+ isc_crc64_init(&crc);
+ assert_int_equal(crc, 0xffffffffffffffffUL);
+}
+
+static void
+_crc64(const char *buf, size_t buflen, const char *result, const int repeats) {
+ uint64_t crc;
+
+ isc_crc64_init(&crc);
+ assert_int_equal(crc, 0xffffffffffffffffUL);
+
+ for (int i = 0; i < repeats; i++) {
+ isc_crc64_update(&crc, buf, buflen);
+ }
+
+ isc_crc64_final(&crc);
+
+ char hex[16 + 1];
+ snprintf(hex, sizeof(hex), "%016" PRIX64, crc);
+
+ assert_memory_equal(hex, result, (result ? strlen(result) : 0));
+}
+
+/* 64-bit cyclic redundancy check */
+ISC_RUN_TEST_IMPL(isc_crc64) {
+ _crc64(TEST_INPUT(""), "0000000000000000", 1);
+ _crc64(TEST_INPUT("a"), "CE73F427ACC0A99A", 1);
+ _crc64(TEST_INPUT("abc"), "048B813AF9F49702", 1);
+ _crc64(TEST_INPUT("message digest"), "5273F9EA7A357BF4", 1);
+ _crc64(TEST_INPUT("abcdefghijklmnopqrstuvwxyz"), "59F079F9218BAAA1", 1);
+ _crc64(TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"
+ "nopqrstuvwxyz0123456789"),
+ "A36DA8F71E78B6FB", 1);
+ _crc64(TEST_INPUT("123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890"),
+ "81E5EB73C8E7874A", 1);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_crc64_init)
+ISC_TEST_ENTRY(isc_crc64)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/doh_test.c b/tests/isc/doh_test.c
new file mode 100644
index 0000000..090fb8f
--- /dev/null
+++ b/tests/isc/doh_test.c
@@ -0,0 +1,2307 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <uv.h>
+
+/*
+ * As a workaround, include an OpenSSL header file before including cmocka.h,
+ * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a
+ * redefined malloc in cmocka.h.
+ */
+#include <openssl/err.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/atomic.h>
+#include <isc/buffer.h>
+#include <isc/condition.h>
+#include <isc/mutex.h>
+#include <isc/netmgr.h>
+#include <isc/nonce.h>
+#include <isc/os.h>
+#include <isc/print.h>
+#include <isc/refcount.h>
+#include <isc/sockaddr.h>
+#include <isc/thread.h>
+
+#include "uv_wrap.h"
+#define KEEP_BEFORE
+
+#include "netmgr/http.c"
+#include "netmgr/netmgr-int.h"
+#include "netmgr/uv-compat.c"
+#include "netmgr/uv-compat.h"
+#include "netmgr_p.h"
+
+#include <tests/isc.h>
+
+#define MAX_NM 2
+
+static isc_sockaddr_t tcp_listen_addr;
+
+static uint64_t send_magic = 0;
+static uint64_t stop_magic = 0;
+
+static uv_buf_t send_msg = { .base = (char *)&send_magic,
+ .len = sizeof(send_magic) };
+
+static atomic_int_fast64_t active_cconnects = 0;
+static atomic_int_fast64_t nsends = 0;
+static atomic_int_fast64_t ssends = 0;
+static atomic_int_fast64_t sreads = 0;
+static atomic_int_fast64_t csends = 0;
+static atomic_int_fast64_t creads = 0;
+static atomic_int_fast64_t ctimeouts = 0;
+static atomic_int_fast64_t total_sends = 0;
+
+static atomic_bool was_error = false;
+
+static bool reuse_supported = true;
+static bool noanswer = false;
+
+static atomic_bool POST = true;
+
+static atomic_bool slowdown = false;
+
+static atomic_bool use_TLS = false;
+static isc_tlsctx_t *server_tlsctx = NULL;
+static isc_tlsctx_t *client_tlsctx = NULL;
+static isc_tlsctx_client_session_cache_t *client_sess_cache = NULL;
+
+static isc_quota_t listener_quota;
+static atomic_bool check_listener_quota = false;
+
+static isc_nm_http_endpoints_t *endpoints = NULL;
+
+static bool skip_long_tests = false;
+
+/* Timeout for soft-timeout tests (0.05 seconds) */
+#define T_SOFT 50
+
+#define NSENDS 100
+#define NWRITES 10
+
+#define CHECK_RANGE_FULL(v) \
+ { \
+ int __v = atomic_load(&v); \
+ assert_true(__v >= atomic_load(&total_sends)); \
+ }
+
+#define CHECK_RANGE_HALF(v) \
+ { \
+ int __v = atomic_load(&v); \
+ assert_true(__v >= atomic_load(&total_sends) / 2); \
+ }
+
+/* Enable this to print values while running tests */
+#undef PRINT_DEBUG
+#ifdef PRINT_DEBUG
+#define X(v) fprintf(stderr, #v " = %" PRIu64 "\n", atomic_load(&v))
+#else
+#define X(v)
+#endif
+
+#define SKIP_IN_CI \
+ if (skip_long_tests) { \
+ skip(); \
+ return; \
+ }
+
+typedef struct csdata {
+ isc_nm_recv_cb_t reply_cb;
+ void *cb_arg;
+ isc_region_t region;
+} csdata_t;
+
+static void
+connect_send_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
+ csdata_t data;
+
+ (void)atomic_fetch_sub(&active_cconnects, 1);
+ memmove(&data, arg, sizeof(data));
+ isc_mem_put(handle->sock->mgr->mctx, arg, sizeof(data));
+ if (result != ISC_R_SUCCESS) {
+ goto error;
+ }
+
+ REQUIRE(VALID_NMHANDLE(handle));
+
+ result = isc__nm_http_request(handle, &data.region, data.reply_cb,
+ data.cb_arg);
+ if (result != ISC_R_SUCCESS) {
+ goto error;
+ }
+
+ isc_mem_put(handle->sock->mgr->mctx, data.region.base,
+ data.region.length);
+ return;
+error:
+ data.reply_cb(handle, result, NULL, data.cb_arg);
+ isc_mem_put(handle->sock->mgr->mctx, data.region.base,
+ data.region.length);
+ if (result == ISC_R_TOOMANYOPENFILES) {
+ atomic_store(&slowdown, true);
+ } else {
+ atomic_store(&was_error, true);
+ }
+}
+
+static void
+connect_send_request(isc_nm_t *mgr, const char *uri, bool post,
+ isc_region_t *region, isc_nm_recv_cb_t cb, void *cbarg,
+ bool tls, unsigned int timeout) {
+ isc_region_t copy;
+ csdata_t *data = NULL;
+ isc_tlsctx_t *ctx = NULL;
+
+ copy = (isc_region_t){ .base = isc_mem_get(mgr->mctx, region->length),
+ .length = region->length };
+ memmove(copy.base, region->base, region->length);
+ data = isc_mem_get(mgr->mctx, sizeof(*data));
+ *data = (csdata_t){ .reply_cb = cb, .cb_arg = cbarg, .region = copy };
+ if (tls) {
+ ctx = client_tlsctx;
+ }
+
+ isc_nm_httpconnect(mgr, NULL, &tcp_listen_addr, uri, post,
+ connect_send_cb, data, ctx, client_sess_cache,
+ timeout, 0);
+}
+
+static int
+setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
+ isc_result_t result;
+ socklen_t addrlen = sizeof(*addr);
+ int fd;
+ int r;
+
+ isc_sockaddr_fromin6(addr, &in6addr_loopback, 0);
+
+ fd = socket(AF_INET6, family, 0);
+ if (fd < 0) {
+ perror("setup_ephemeral_port: socket()");
+ return (-1);
+ }
+
+ r = bind(fd, (const struct sockaddr *)&addr->type.sa,
+ sizeof(addr->type.sin6));
+ if (r != 0) {
+ perror("setup_ephemeral_port: bind()");
+ isc__nm_closesocket(fd);
+ return (r);
+ }
+
+ r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen);
+ if (r != 0) {
+ perror("setup_ephemeral_port: getsockname()");
+ isc__nm_closesocket(fd);
+ return (r);
+ }
+
+ result = isc__nm_socket_reuse(fd);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
+ fprintf(stderr,
+ "setup_ephemeral_port: isc__nm_socket_reuse(): %s",
+ isc_result_totext(result));
+ close(fd);
+ return (-1);
+ }
+
+ result = isc__nm_socket_reuse_lb(fd);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
+ fprintf(stderr,
+ "setup_ephemeral_port: isc__nm_socket_reuse_lb(): %s",
+ isc_result_totext(result));
+ close(fd);
+ return (-1);
+ }
+ if (result == ISC_R_NOTIMPLEMENTED) {
+ reuse_supported = false;
+ }
+
+#if IPV6_RECVERR
+#define setsockopt_on(socket, level, name) \
+ setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
+
+ r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR);
+ if (r != 0) {
+ perror("setup_ephemeral_port");
+ close(fd);
+ return (r);
+ }
+#endif
+
+ return (fd);
+}
+
+/* Generic */
+
+static void
+noop_read_cb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
+ void *cbarg) {
+ UNUSED(handle);
+ UNUSED(result);
+ UNUSED(region);
+ UNUSED(cbarg);
+}
+
+thread_local uint8_t tcp_buffer_storage[4096];
+thread_local size_t tcp_buffer_length = 0;
+
+static int
+setup_test(void **state) {
+ char *env_workers = getenv("ISC_TASK_WORKERS");
+ size_t nworkers;
+ uv_os_sock_t tcp_listen_sock = -1;
+ isc_nm_t **nm = NULL;
+
+ tcp_listen_addr = (isc_sockaddr_t){ .length = 0 };
+ tcp_listen_sock = setup_ephemeral_port(&tcp_listen_addr, SOCK_STREAM);
+ if (tcp_listen_sock < 0) {
+ return (-1);
+ }
+ close(tcp_listen_sock);
+ tcp_listen_sock = -1;
+
+ if (env_workers != NULL) {
+ workers = atoi(env_workers);
+ } else {
+ workers = isc_os_ncpus();
+ }
+ INSIST(workers > 0);
+ nworkers = ISC_MAX(ISC_MIN(workers, 32), 1);
+
+ if (!reuse_supported || getenv("CI") != NULL) {
+ skip_long_tests = true;
+ }
+
+ atomic_store(&total_sends, NSENDS * NWRITES);
+ atomic_store(&nsends, atomic_load(&total_sends));
+
+ atomic_store(&csends, 0);
+ atomic_store(&creads, 0);
+ atomic_store(&sreads, 0);
+ atomic_store(&ssends, 0);
+ atomic_store(&ctimeouts, 0);
+ atomic_store(&active_cconnects, 0);
+
+ atomic_store(&was_error, false);
+
+ atomic_store(&POST, false);
+ atomic_store(&use_TLS, false);
+
+ noanswer = false;
+
+ isc_nonce_buf(&send_magic, sizeof(send_magic));
+ isc_nonce_buf(&stop_magic, sizeof(stop_magic));
+ if (send_magic == stop_magic) {
+ return (-1);
+ }
+
+ nm = isc_mem_get(mctx, MAX_NM * sizeof(nm[0]));
+ for (size_t i = 0; i < MAX_NM; i++) {
+ isc__netmgr_create(mctx, nworkers, &nm[i]);
+ assert_non_null(nm[i]);
+ }
+
+ server_tlsctx = NULL;
+ isc_tlsctx_createserver(NULL, NULL, &server_tlsctx);
+ isc_tlsctx_enable_http2server_alpn(server_tlsctx);
+ client_tlsctx = NULL;
+ isc_tlsctx_createclient(&client_tlsctx);
+ isc_tlsctx_enable_http2client_alpn(client_tlsctx);
+ isc_tlsctx_client_session_cache_create(
+ mctx, client_tlsctx,
+ ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE,
+ &client_sess_cache);
+
+ isc_quota_init(&listener_quota, 0);
+ atomic_store(&check_listener_quota, false);
+
+ INSIST(endpoints == NULL);
+ endpoints = isc_nm_http_endpoints_new(mctx);
+
+ *state = nm;
+
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+
+ for (size_t i = 0; i < MAX_NM; i++) {
+ isc__netmgr_destroy(&nm[i]);
+ assert_null(nm[i]);
+ }
+ isc_mem_put(mctx, nm, MAX_NM * sizeof(nm[0]));
+
+ if (server_tlsctx != NULL) {
+ isc_tlsctx_free(&server_tlsctx);
+ }
+ if (client_tlsctx != NULL) {
+ isc_tlsctx_free(&client_tlsctx);
+ }
+
+ isc_tlsctx_client_session_cache_detach(&client_sess_cache);
+
+ isc_quota_destroy(&listener_quota);
+
+ isc_nm_http_endpoints_detach(&endpoints);
+
+ return (0);
+}
+
+thread_local size_t nwrites = NWRITES;
+
+static void
+sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf,
+ size_t outbuf_len, const char *append) {
+ isc_nm_http_makeuri(https, sa, NULL, 0, append, outbuf, outbuf_len);
+}
+
+static isc_quota_t *
+init_listener_quota(size_t nthreads) {
+ isc_quota_t *quotap = NULL;
+ if (atomic_load(&check_listener_quota)) {
+ unsigned max_quota = ISC_MAX(nthreads / 2, 1);
+ isc_quota_max(&listener_quota, max_quota);
+ quotap = &listener_quota;
+ }
+ return (quotap);
+}
+
+static void
+doh_receive_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *cbarg) {
+ assert_non_null(handle);
+ UNUSED(cbarg);
+ UNUSED(region);
+
+ if (eresult == ISC_R_SUCCESS) {
+ (void)atomic_fetch_sub(&nsends, 1);
+ atomic_fetch_add(&csends, 1);
+ atomic_fetch_add(&creads, 1);
+ } else {
+ /* We failed to connect; try again */
+ atomic_store(&was_error, true);
+ }
+}
+
+static void
+doh_reply_sent_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
+ UNUSED(eresult);
+ UNUSED(cbarg);
+
+ assert_non_null(handle);
+
+ if (eresult == ISC_R_SUCCESS) {
+ atomic_fetch_add(&ssends, 1);
+ }
+}
+
+static void
+doh_receive_request_cb(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *cbarg) {
+ uint64_t magic = 0;
+
+ UNUSED(cbarg);
+ assert_non_null(handle);
+
+ if (eresult != ISC_R_SUCCESS) {
+ atomic_store(&was_error, true);
+ return;
+ }
+
+ atomic_fetch_add(&sreads, 1);
+
+ memmove(tcp_buffer_storage + tcp_buffer_length, region->base,
+ region->length);
+ tcp_buffer_length += region->length;
+
+ while (tcp_buffer_length >= sizeof(magic)) {
+ magic = *(uint64_t *)tcp_buffer_storage;
+ assert_true(magic == stop_magic || magic == send_magic);
+
+ tcp_buffer_length -= sizeof(magic);
+ memmove(tcp_buffer_storage, tcp_buffer_storage + sizeof(magic),
+ tcp_buffer_length);
+
+ if (magic == send_magic) {
+ if (!noanswer) {
+ isc_nm_send(handle, region, doh_reply_sent_cb,
+ NULL);
+ }
+ return;
+ } else if (magic == stop_magic) {
+ /*
+ * We are done, so we don't send anything back.
+ * There should be no more packets in the buffer.
+ */
+ assert_int_equal(tcp_buffer_length, 0);
+ }
+ }
+}
+
+ISC_RUN_TEST_IMPL(mock_doh_uv_tcp_bind) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ WILL_RETURN(uv_tcp_bind, UV_EADDRINUSE);
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ noop_read_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_not_equal(result, ISC_R_SUCCESS);
+ assert_null(listen_sock);
+
+ RESET_RETURN;
+}
+
+static void
+doh_noop(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ char req_url[256];
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ noop_read_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
+ ISC_NM_HTTP_DEFAULT_PATH);
+ connect_send_request(connect_nm, req_url, atomic_load(&POST),
+ &(isc_region_t){ .base = (uint8_t *)send_msg.base,
+ .length = send_msg.len },
+ noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ assert_int_equal(0, atomic_load(&csends));
+ assert_int_equal(0, atomic_load(&creads));
+ assert_int_equal(0, atomic_load(&sreads));
+ assert_int_equal(0, atomic_load(&ssends));
+}
+
+ISC_RUN_TEST_IMPL(doh_noop_POST) {
+ atomic_store(&POST, true);
+ doh_noop(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_noop_GET) {
+ atomic_store(&POST, false);
+ doh_noop(state);
+}
+
+static void
+doh_noresponse(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ char req_url[256];
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ noop_read_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
+ ISC_NM_HTTP_DEFAULT_PATH);
+ connect_send_request(connect_nm, req_url, atomic_load(&POST),
+ &(isc_region_t){ .base = (uint8_t *)send_msg.base,
+ .length = send_msg.len },
+ noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+}
+
+ISC_RUN_TEST_IMPL(doh_noresponse_POST) {
+ atomic_store(&POST, true);
+ doh_noresponse(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_noresponse_GET) {
+ atomic_store(&POST, false);
+ doh_noresponse(state);
+}
+
+static void
+timeout_query_sent_cb(isc_nmhandle_t *handle, isc_result_t eresult,
+ void *cbarg) {
+ UNUSED(eresult);
+ UNUSED(cbarg);
+
+ assert_non_null(handle);
+
+ if (eresult == ISC_R_SUCCESS) {
+ atomic_fetch_add(&csends, 1);
+ }
+
+ isc_nmhandle_detach(&handle);
+}
+
+static void
+timeout_retry_cb(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *arg) {
+ UNUSED(region);
+ UNUSED(arg);
+
+ assert_non_null(handle);
+
+ atomic_fetch_add(&ctimeouts, 1);
+
+ if (eresult == ISC_R_TIMEDOUT && atomic_load(&ctimeouts) < 5) {
+ isc_nmhandle_settimeout(handle, T_SOFT);
+ return;
+ }
+
+ isc_nmhandle_detach(&handle);
+}
+
+static void
+timeout_request_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
+ isc_nmhandle_t *sendhandle = NULL;
+ isc_nmhandle_t *readhandle = NULL;
+
+ REQUIRE(VALID_NMHANDLE(handle));
+
+ if (result != ISC_R_SUCCESS) {
+ goto error;
+ }
+
+ isc_nmhandle_attach(handle, &sendhandle);
+ isc_nm_send(handle,
+ &(isc_region_t){ .base = (uint8_t *)send_msg.base,
+ .length = send_msg.len },
+ timeout_query_sent_cb, arg);
+
+ isc_nmhandle_attach(handle, &readhandle);
+ isc_nm_read(handle, timeout_retry_cb, NULL);
+ return;
+
+error:
+ atomic_store(&was_error, true);
+}
+
+static void
+doh_timeout_recovery(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_tlsctx_t *ctx = atomic_load(&use_TLS) ? server_tlsctx : NULL;
+ char req_url[256];
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ doh_receive_request_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Accept connections but don't send responses, forcing client
+ * reads to time out.
+ */
+ noanswer = true;
+
+ /*
+ * Shorten all the TCP client timeouts to 0.05 seconds.
+ * timeout_retry_cb() will give up after five timeouts.
+ */
+ isc_nm_settimeouts(connect_nm, T_SOFT, T_SOFT, T_SOFT, T_SOFT);
+ sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
+ ISC_NM_HTTP_DEFAULT_PATH);
+ isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url,
+ atomic_load(&POST), timeout_request_cb, NULL, ctx,
+ client_sess_cache, T_SOFT, 0);
+
+ /*
+ * Sleep until sends reaches 5.
+ */
+ for (size_t i = 0; i < 1000; i++) {
+ if (atomic_load(&ctimeouts) == 5) {
+ break;
+ }
+ isc_test_nap(1);
+ }
+ assert_true(atomic_load(&ctimeouts) == 5);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+}
+
+ISC_RUN_TEST_IMPL(doh_timeout_recovery_POST) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ doh_timeout_recovery(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_timeout_recovery_GET) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ doh_timeout_recovery(state);
+}
+
+static void
+doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *cbarg) {
+ UNUSED(region);
+
+ if (eresult != ISC_R_SUCCESS) {
+ atomic_store(&was_error, true);
+ return;
+ }
+
+ assert_non_null(handle);
+
+ int_fast64_t sends = atomic_fetch_sub(&nsends, 1);
+ atomic_fetch_add(&csends, 1);
+ atomic_fetch_add(&creads, 1);
+ if (sends > 0 && cbarg == NULL) {
+ size_t i;
+ for (i = 0; i < NWRITES / 2; i++) {
+ eresult = isc__nm_http_request(
+ handle,
+ &(isc_region_t){
+ .base = (uint8_t *)send_msg.base,
+ .length = send_msg.len },
+ doh_receive_send_reply_cb, (void *)1);
+ if (eresult == ISC_R_CANCELED) {
+ break;
+ }
+ assert_true(eresult == ISC_R_SUCCESS);
+ }
+ }
+}
+
+static isc_threadresult_t
+doh_connect_thread(isc_threadarg_t arg) {
+ isc_nm_t *connect_nm = (isc_nm_t *)arg;
+ char req_url[256];
+ int64_t sends = atomic_load(&nsends);
+
+ sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
+ sizeof(req_url), ISC_NM_HTTP_DEFAULT_PATH);
+
+ while (sends > 0) {
+ /*
+ * We need to back off and slow down if we start getting
+ * errors, to prevent a thundering herd problem.
+ */
+ int_fast64_t active = atomic_fetch_add(&active_cconnects, 1);
+ if (atomic_load(&slowdown) || active > workers) {
+ isc_test_nap(active - workers);
+ atomic_store(&slowdown, false);
+ }
+ connect_send_request(
+ connect_nm, req_url, atomic_load(&POST),
+ &(isc_region_t){ .base = (uint8_t *)send_msg.base,
+ .length = send_msg.len },
+ doh_receive_send_reply_cb, NULL, atomic_load(&use_TLS),
+ 30000);
+ sends = atomic_load(&nsends);
+ }
+
+ return ((isc_threadresult_t)0);
+}
+
+static void
+doh_recv_one(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ char req_url[256];
+ isc_quota_t *quotap = init_listener_quota(workers);
+
+ atomic_store(&total_sends, 1);
+
+ atomic_store(&nsends, atomic_load(&total_sends));
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ doh_receive_request_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
+ atomic_load(&use_TLS) ? server_tlsctx : NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
+ sizeof(req_url), ISC_NM_HTTP_DEFAULT_PATH);
+ connect_send_request(connect_nm, req_url, atomic_load(&POST),
+ &(isc_region_t){ .base = (uint8_t *)send_msg.base,
+ .length = send_msg.len },
+ doh_receive_reply_cb, NULL, atomic_load(&use_TLS),
+ 30000);
+
+ while (atomic_load(&nsends) > 0) {
+ if (atomic_load(&was_error)) {
+ break;
+ }
+ isc_thread_yield();
+ }
+
+ while (atomic_load(&ssends) != 1 || atomic_load(&sreads) != 1 ||
+ atomic_load(&csends) != 1)
+ {
+ if (atomic_load(&was_error)) {
+ break;
+ }
+ isc_thread_yield();
+ }
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(total_sends);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ assert_int_equal(atomic_load(&csends), 1);
+ assert_int_equal(atomic_load(&creads), 1);
+ assert_int_equal(atomic_load(&sreads), 1);
+ assert_int_equal(atomic_load(&ssends), 1);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_one_POST) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ doh_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_one_GET) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ doh_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_one_POST_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ doh_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_one_GET_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ doh_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_one_POST_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_one_GET_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_one_POST_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_one_GET_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_one(state);
+}
+
+static void
+doh_connect_send_two_requests_cb(isc_nmhandle_t *handle, isc_result_t result,
+ void *arg) {
+ REQUIRE(VALID_NMHANDLE(handle));
+ if (result != ISC_R_SUCCESS) {
+ goto error;
+ }
+
+ result = isc__nm_http_request(
+ handle,
+ &(isc_region_t){ .base = (uint8_t *)send_msg.base,
+ .length = send_msg.len },
+ doh_receive_reply_cb, arg);
+ if (result != ISC_R_SUCCESS) {
+ goto error;
+ }
+
+ result = isc__nm_http_request(
+ handle,
+ &(isc_region_t){ .base = (uint8_t *)send_msg.base,
+ .length = send_msg.len },
+ doh_receive_reply_cb, arg);
+ if (result != ISC_R_SUCCESS) {
+ goto error;
+ }
+ return;
+error:
+ atomic_store(&was_error, true);
+}
+
+static void
+doh_recv_two(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ char req_url[256];
+ isc_tlsctx_t *ctx = NULL;
+ isc_quota_t *quotap = init_listener_quota(workers);
+
+ atomic_store(&total_sends, 2);
+
+ atomic_store(&nsends, atomic_load(&total_sends));
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ doh_receive_request_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
+ atomic_load(&use_TLS) ? server_tlsctx : NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
+ sizeof(req_url), ISC_NM_HTTP_DEFAULT_PATH);
+
+ if (atomic_load(&use_TLS)) {
+ ctx = client_tlsctx;
+ }
+
+ isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url,
+ atomic_load(&POST), doh_connect_send_two_requests_cb,
+ NULL, ctx, client_sess_cache, 5000, 0);
+
+ while (atomic_load(&nsends) > 0) {
+ if (atomic_load(&was_error)) {
+ break;
+ }
+ isc_thread_yield();
+ }
+
+ while (atomic_load(&ssends) != 2 || atomic_load(&sreads) != 2 ||
+ atomic_load(&csends) != 2)
+ {
+ if (atomic_load(&was_error)) {
+ break;
+ }
+ isc_thread_yield();
+ }
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(total_sends);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ assert_int_equal(atomic_load(&csends), 2);
+ assert_int_equal(atomic_load(&creads), 2);
+ assert_int_equal(atomic_load(&sreads), 2);
+ assert_int_equal(atomic_load(&ssends), 2);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_two_POST) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ doh_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_two_GET) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ doh_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_two_POST_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ doh_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_two_GET_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ doh_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_two_POST_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_two_GET_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_two_POST_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_two_GET_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_two(state);
+}
+
+static void
+doh_recv_send(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
+ isc_thread_t threads[32] = { 0 };
+ isc_quota_t *quotap = init_listener_quota(workers);
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ doh_receive_request_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
+ atomic_load(&use_TLS) ? server_tlsctx : NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (size_t i = 0; i < nthreads; i++) {
+ isc_thread_create(doh_connect_thread, connect_nm, &threads[i]);
+ }
+
+ /* wait for the all responses from the server */
+ while (atomic_load(&ssends) < atomic_load(&total_sends)) {
+ if (atomic_load(&was_error)) {
+ break;
+ }
+ isc_test_nap(1);
+ }
+
+ for (size_t i = 0; i < nthreads; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(total_sends);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_FULL(csends);
+ CHECK_RANGE_FULL(creads);
+ CHECK_RANGE_FULL(sreads);
+ CHECK_RANGE_FULL(ssends);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_send_POST) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ doh_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_send_GET) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ doh_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_send_POST_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ atomic_store(&use_TLS, true);
+ doh_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_send_GET_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ atomic_store(&use_TLS, true);
+ doh_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_send_POST_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_send_GET_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_send_POST_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ atomic_store(&use_TLS, true);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_send_GET_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ atomic_store(&use_TLS, true);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_send(state);
+}
+
+static void
+doh_recv_half_send(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
+ isc_thread_t threads[32] = { 0 };
+ isc_quota_t *quotap = init_listener_quota(workers);
+
+ atomic_store(&total_sends, atomic_load(&total_sends) / 2);
+
+ atomic_store(&nsends, atomic_load(&total_sends));
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ doh_receive_request_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
+ atomic_load(&use_TLS) ? server_tlsctx : NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (size_t i = 0; i < nthreads; i++) {
+ isc_thread_create(doh_connect_thread, connect_nm, &threads[i]);
+ }
+
+ while (atomic_load(&nsends) > 0) {
+ isc_thread_yield();
+ }
+
+ isc__netmgr_shutdown(connect_nm);
+
+ for (size_t i = 0; i < nthreads; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(total_sends);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_half_send_POST) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ doh_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_half_send_GET) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ doh_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_half_send_POST_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ doh_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_half_send_GET_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ doh_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_half_send_POST_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_half_send_GET_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_half_send_POST_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_recv_half_send_GET_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_recv_half_send(state);
+}
+
+static void
+doh_half_recv_send(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
+ isc_thread_t threads[32] = { 0 };
+ isc_quota_t *quotap = init_listener_quota(workers);
+
+ atomic_store(&total_sends, atomic_load(&total_sends) / 2);
+
+ atomic_store(&nsends, atomic_load(&total_sends));
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ doh_receive_request_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
+ atomic_load(&use_TLS) ? server_tlsctx : NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (size_t i = 0; i < nthreads; i++) {
+ isc_thread_create(doh_connect_thread, connect_nm, &threads[i]);
+ }
+
+ while (atomic_load(&nsends) > 0) {
+ isc_thread_yield();
+ }
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ for (size_t i = 0; i < nthreads; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc__netmgr_shutdown(connect_nm);
+
+ X(total_sends);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_send_POST) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ doh_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_send_GET) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ doh_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_send_POST_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ doh_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_send_GET_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ doh_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_send_POST_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_send_GET_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_send_POST_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_send_GET_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_half_recv_send(state);
+}
+
+static void
+doh_half_recv_half_send(void **state) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
+ isc_thread_t threads[32] = { 0 };
+ isc_quota_t *quotap = init_listener_quota(workers);
+
+ atomic_store(&total_sends, atomic_load(&total_sends) / 2);
+
+ atomic_store(&nsends, atomic_load(&total_sends));
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ doh_receive_request_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
+ atomic_load(&use_TLS) ? server_tlsctx : NULL,
+ endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (size_t i = 0; i < nthreads; i++) {
+ isc_thread_create(doh_connect_thread, connect_nm, &threads[i]);
+ }
+
+ while (atomic_load(&nsends) > 0) {
+ isc_thread_yield();
+ }
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ for (size_t i = 0; i < nthreads; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ X(total_sends);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ doh_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ doh_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ doh_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET_TLS) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ doh_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, true);
+ atomic_store(&check_listener_quota, true);
+ doh_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET_TLS_quota) {
+ SKIP_IN_CI;
+
+ atomic_store(&use_TLS, true);
+ atomic_store(&POST, false);
+ atomic_store(&check_listener_quota, true);
+ doh_half_recv_half_send(state);
+}
+
+/* See: GL #2858, !5319 */
+ISC_RUN_TEST_IMPL(doh_bad_connect_uri) {
+ isc_nm_t **nm = (isc_nm_t **)*state;
+ isc_nm_t *listen_nm = nm[0];
+ isc_nm_t *connect_nm = nm[1];
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ char req_url[256];
+ isc_quota_t *quotap = init_listener_quota(workers);
+
+ atomic_store(&total_sends, 1);
+
+ atomic_store(&nsends, atomic_load(&total_sends));
+
+ result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
+ doh_receive_request_cb, NULL, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
+ server_tlsctx, endpoints, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * "https://::1:XXXX/dns-query" is a bad URI, it should be
+ * "https://[::1]:XXXX/dns-query"
+ */
+ (void)snprintf(req_url, sizeof(req_url), "https://::1:%u/%s",
+ isc_sockaddr_getport(&tcp_listen_addr),
+ ISC_NM_HTTP_DEFAULT_PATH);
+ connect_send_request(connect_nm, req_url, atomic_load(&POST),
+ &(isc_region_t){ .base = (uint8_t *)send_msg.base,
+ .length = send_msg.len },
+ doh_receive_reply_cb, NULL, true, 30000);
+
+ while (atomic_load(&nsends) > 0) {
+ if (atomic_load(&was_error)) {
+ break;
+ }
+ isc_thread_yield();
+ }
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(total_sends);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ /* As we used an ill-formed URI, there ought to be an error. */
+ assert_true(atomic_load(&was_error));
+ assert_int_equal(atomic_load(&csends), 0);
+ assert_int_equal(atomic_load(&creads), 0);
+ assert_int_equal(atomic_load(&sreads), 0);
+ assert_int_equal(atomic_load(&ssends), 0);
+}
+
+ISC_RUN_TEST_IMPL(doh_parse_GET_query_string) {
+ UNUSED(state);
+ /* valid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] =
+ "dns=AAABAAABAAAAAAAAAWE-"
+ "NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3"
+ "QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_true(ret);
+ assert_non_null(queryp);
+ assert_true(len > 0);
+ assert_true(len == strlen(str) - 4);
+ assert_true(memcmp(queryp, str + 4, len) == 0);
+ }
+ /* valid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] =
+ "?dns=AAABAAABAAAAAAAAAWE-"
+ "NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3"
+ "QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_true(ret);
+ assert_non_null(queryp);
+ assert_true(len > 0);
+ assert_true(len == strlen(str) - 6);
+ assert_true(memcmp(queryp, str + 5, len) == 0);
+ }
+ /* valid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?dns=123&dns=567";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_true(ret);
+ assert_non_null(queryp);
+ assert_true(len > 0);
+ assert_true(len == 3);
+ assert_true(memcmp(queryp, "567", 3) == 0);
+ }
+ /* valid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?name1=123&dns=567&name2=123&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_true(ret);
+ assert_non_null(queryp);
+ assert_true(len > 0);
+ assert_true(len == 3);
+ assert_true(memcmp(queryp, "567", 3) == 0);
+ }
+ /* complex, but still valid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] =
+ "?title=%D0%92%D1%96%D0%B4%D1%81%D0%BE%D1%82%D0%BA%D0%"
+ "BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%"
+ "D0%BD%D0%BD%D1%8F&dns=123&veaction=edit&section=0";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_true(ret);
+ assert_non_null(queryp);
+ assert_true(len > 0);
+ assert_true(len == 3);
+ assert_true(memcmp(queryp, "123", 3) == 0);
+ }
+ /* invalid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] =
+ "?title=%D0%92%D1%96%D0%B4%D1%81%D0%BE%D1%82%D0%BA%D0%"
+ "BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%"
+ "D0%BD%D0%BD%D1%8F&veaction=edit&section=0";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_false(ret);
+ assert_null(queryp);
+ assert_true(len == 0);
+ }
+ /* invalid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_false(ret);
+ assert_null(queryp);
+ assert_true(len == 0);
+ }
+ /* invalid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_false(ret);
+ assert_null(queryp);
+ assert_true(len == 0);
+ }
+ /* invalid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?dns&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_false(ret);
+ assert_null(queryp);
+ assert_true(len == 0);
+ }
+ /* invalid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?dns=&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_false(ret);
+ assert_null(queryp);
+ assert_true(len == 0);
+ }
+ /* invalid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?dns=123&&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_false(ret);
+ assert_null(queryp);
+ assert_true(len == 0);
+ }
+ /* valid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?dns=123%12&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_true(ret);
+ assert_non_null(queryp);
+ assert_true(len > 0);
+ assert_true(len == 6);
+ assert_true(memcmp(queryp, "123%12", 6) == 0);
+ }
+ /* invalid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?dns=123%ZZ&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_false(ret);
+ assert_null(queryp);
+ assert_true(len == 0);
+ }
+ /* invalid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?dns=123%%&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_false(ret);
+ assert_null(queryp);
+ assert_true(len == 0);
+ }
+ /* invalid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?dns=123%AZ&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_false(ret);
+ assert_null(queryp);
+ assert_true(len == 0);
+ }
+ /* valid */
+ {
+ bool ret;
+ const char *queryp = NULL;
+ size_t len = 0;
+ char str[] = "?dns=123%0AZ&";
+
+ ret = isc__nm_parse_httpquery(str, &queryp, &len);
+ assert_true(ret);
+ assert_non_null(queryp);
+ assert_true(len > 0);
+ assert_true(len == 7);
+ assert_true(memcmp(queryp, "123%0AZ", 7) == 0);
+ }
+}
+
+ISC_RUN_TEST_IMPL(doh_base64url_to_base64) {
+ UNUSED(state);
+ char *res;
+ size_t res_len = 0;
+ /* valid */
+ {
+ char test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4";
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4=";
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char test[] = "YW55IGNhcm5hbCBwbGVhcw";
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhcw==";
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char test[] = "YW55IGNhcm5hbCBwbGVhc3Vy";
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhc3Vy";
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char test[] = "YW55IGNhcm5hbCBwbGVhc3U";
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhc3U=";
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char test[] = "YW55IGNhcm5hbCBwbGVhcw";
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhcw==";
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char test[] = "PDw_Pz8-Pg";
+ char res_test[] = "PDw/Pz8+Pg==";
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char test[] = "PDw_Pz8-Pg";
+ char res_test[] = "PDw/Pz8+Pg==";
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ NULL);
+ assert_non_null(res);
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* invalid */
+ {
+ char test[] = "YW55IGNhcm5hbCBwbGVhcw";
+ res_len = 0;
+
+ res = isc__nm_base64url_to_base64(mctx, test, 0, &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+ /* invalid */
+ {
+ char test[] = "";
+ res_len = 0;
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+ /* invalid */
+ {
+ char test[] = "PDw_Pz8-Pg==";
+ res_len = 0;
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+ /* invalid */
+ {
+ char test[] = "PDw_Pz8-Pg%3D%3D"; /* percent encoded "==" at the
+ end */
+ res_len = 0;
+
+ res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
+ &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+ /* invalid */
+ {
+ res_len = 0;
+
+ res = isc__nm_base64url_to_base64(mctx, NULL, 31231, &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+}
+
+ISC_RUN_TEST_IMPL(doh_base64_to_base64url) {
+ char *res;
+ size_t res_len = 0;
+ UNUSED(state);
+ /* valid */
+ {
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4";
+ char test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4=";
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhcw";
+ char test[] = "YW55IGNhcm5hbCBwbGVhcw==";
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhc3Vy";
+ char test[] = "YW55IGNhcm5hbCBwbGVhc3Vy";
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhc3U";
+ char test[] = "YW55IGNhcm5hbCBwbGVhc3U=";
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char res_test[] = "YW55IGNhcm5hbCBwbGVhcw";
+ char test[] = "YW55IGNhcm5hbCBwbGVhcw==";
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char res_test[] = "PDw_Pz8-Pg";
+ char test[] = "PDw/Pz8+Pg==";
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ &res_len);
+ assert_non_null(res);
+ assert_true(res_len == strlen(res_test));
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* valid */
+ {
+ char res_test[] = "PDw_Pz8-Pg";
+ char test[] = "PDw/Pz8+Pg==";
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ NULL);
+ assert_non_null(res);
+ assert_true(strcmp(res, res_test) == 0);
+ isc_mem_free(mctx, res);
+ }
+ /* invalid */
+ {
+ char test[] = "YW55IGNhcm5hbCBwbGVhcw";
+ res_len = 0;
+
+ res = isc__nm_base64_to_base64url(mctx, test, 0, &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+ /* invalid */
+ {
+ char test[] = "";
+ res_len = 0;
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+ /* invalid */
+ {
+ char test[] = "PDw_Pz8-Pg==";
+ res_len = 0;
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+ /* invalid */
+ {
+ char test[] = "PDw_Pz8-Pg%3D%3D"; /* percent encoded "==" at the
+ end */
+ res_len = 0;
+
+ res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
+ &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+ /* invalid */
+ {
+ res_len = 0;
+
+ res = isc__nm_base64_to_base64url(mctx, NULL, 31231, &res_len);
+ assert_null(res);
+ assert_true(res_len == 0);
+ }
+}
+
+ISC_RUN_TEST_IMPL(doh_path_validation) {
+ UNUSED(state);
+
+ assert_true(isc_nm_http_path_isvalid("/"));
+ assert_true(isc_nm_http_path_isvalid(ISC_NM_HTTP_DEFAULT_PATH));
+ assert_false(isc_nm_http_path_isvalid("laaaa"));
+ assert_false(isc_nm_http_path_isvalid(""));
+ assert_false(isc_nm_http_path_isvalid("//"));
+ assert_true(isc_nm_http_path_isvalid("/lala///"));
+ assert_true(isc_nm_http_path_isvalid("/lalaaaaaa"));
+ assert_true(isc_nm_http_path_isvalid("/lalaaa/la/la/la"));
+ assert_true(isc_nm_http_path_isvalid("/la/a"));
+ assert_true(isc_nm_http_path_isvalid("/la+la"));
+ assert_true(isc_nm_http_path_isvalid("/la&la/la*la/l-a_/la!/la\'"));
+ assert_true(isc_nm_http_path_isvalid("/la/(la)/la"));
+ assert_true(isc_nm_http_path_isvalid("/la,la,la"));
+ assert_true(isc_nm_http_path_isvalid("/la-'la'-la"));
+ assert_true(isc_nm_http_path_isvalid("/la:la=la"));
+ assert_true(isc_nm_http_path_isvalid("/l@l@l@"));
+ assert_false(isc_nm_http_path_isvalid("/#lala"));
+ assert_true(isc_nm_http_path_isvalid("/lala;la"));
+ assert_false(
+ isc_nm_http_path_isvalid("la&la/laalaala*lala/l-al_a/lal!/"));
+ assert_true(isc_nm_http_path_isvalid("/Lal/lAla.jpg"));
+
+ /* had to replace ? with ! because it does not verify a query string */
+ assert_true(isc_nm_http_path_isvalid("/watch!v=oavMtUWDBTM"));
+ assert_false(isc_nm_http_path_isvalid("/watch?v=dQw4w9WgXcQ"));
+ assert_true(isc_nm_http_path_isvalid("/datatracker.ietf.org/doc/html/"
+ "rfc2616"));
+ assert_true(isc_nm_http_path_isvalid("/doc/html/rfc8484"));
+ assert_true(isc_nm_http_path_isvalid("/123"));
+}
+
+ISC_RUN_TEST_IMPL(doh_connect_makeuri) {
+ struct in_addr localhostv4 = { .s_addr = ntohl(INADDR_LOOPBACK) };
+ isc_sockaddr_t sa;
+ char uri[256];
+ UNUSED(state);
+
+ /* Firstly, test URI generation using isc_sockaddr_t */
+ isc_sockaddr_fromin(&sa, &localhostv4, 0);
+ uri[0] = '\0';
+ isc_nm_http_makeuri(true, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
+ sizeof(uri));
+ assert_true(strcmp("https://127.0.0.1:443/dns-query", uri) == 0);
+
+ uri[0] = '\0';
+ isc_nm_http_makeuri(false, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
+ sizeof(uri));
+ assert_true(strcmp("http://127.0.0.1:80/dns-query", uri) == 0);
+
+ /*
+ * The port value should be ignored, because we can get one from
+ * the isc_sockaddr_t object.
+ */
+ uri[0] = '\0';
+ isc_nm_http_makeuri(true, &sa, NULL, 44343, ISC_NM_HTTP_DEFAULT_PATH,
+ uri, sizeof(uri));
+ assert_true(strcmp("https://127.0.0.1:443/dns-query", uri) == 0);
+
+ uri[0] = '\0';
+ isc_nm_http_makeuri(false, &sa, NULL, 8080, ISC_NM_HTTP_DEFAULT_PATH,
+ uri, sizeof(uri));
+ assert_true(strcmp("http://127.0.0.1:80/dns-query", uri) == 0);
+
+ /* IPv6 */
+ isc_sockaddr_fromin6(&sa, &in6addr_loopback, 0);
+ uri[0] = '\0';
+ isc_nm_http_makeuri(true, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
+ sizeof(uri));
+ assert_true(strcmp("https://[::1]:443/dns-query", uri) == 0);
+
+ uri[0] = '\0';
+ isc_nm_http_makeuri(false, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
+ sizeof(uri));
+ assert_true(strcmp("http://[::1]:80/dns-query", uri) == 0);
+
+ /*
+ * The port value should be ignored, because we can get one from
+ * the isc_sockaddr_t object.
+ */
+ uri[0] = '\0';
+ isc_nm_http_makeuri(true, &sa, NULL, 44343, ISC_NM_HTTP_DEFAULT_PATH,
+ uri, sizeof(uri));
+ assert_true(strcmp("https://[::1]:443/dns-query", uri) == 0);
+
+ uri[0] = '\0';
+ isc_nm_http_makeuri(false, &sa, NULL, 8080, ISC_NM_HTTP_DEFAULT_PATH,
+ uri, sizeof(uri));
+ assert_true(strcmp("http://[::1]:80/dns-query", uri) == 0);
+
+ /* Try to set the port numbers. */
+ isc_sockaddr_setport(&sa, 44343);
+ uri[0] = '\0';
+ isc_nm_http_makeuri(true, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
+ sizeof(uri));
+ assert_true(strcmp("https://[::1]:44343/dns-query", uri) == 0);
+
+ isc_sockaddr_setport(&sa, 8080);
+ uri[0] = '\0';
+ isc_nm_http_makeuri(false, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
+ sizeof(uri));
+ assert_true(strcmp("http://[::1]:8080/dns-query", uri) == 0);
+
+ /*
+ * Try to make a URI using a hostname and a port number. The
+ * isc_sockaddr_t object will be ignored.
+ */
+ isc_sockaddr_any(&sa);
+ uri[0] = '\0';
+ isc_nm_http_makeuri(true, &sa, "example.com", 0,
+ ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
+ assert_true(strcmp("https://example.com:443/dns-query", uri) == 0);
+
+ uri[0] = '\0';
+ isc_nm_http_makeuri(false, &sa, "example.com", 0,
+ ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
+ assert_true(strcmp("http://example.com:80/dns-query", uri) == 0);
+
+ /* Try to set the port numbers. */
+ isc_sockaddr_setport(&sa, 443);
+ uri[0] = '\0';
+ isc_nm_http_makeuri(true, &sa, "example.com", 44343,
+ ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
+ assert_true(strcmp("https://example.com:44343/dns-query", uri) == 0);
+
+ isc_sockaddr_setport(&sa, 80);
+ uri[0] = '\0';
+ isc_nm_http_makeuri(false, &sa, "example.com", 8080,
+ ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
+ assert_true(strcmp("http://example.com:8080/dns-query", uri) == 0);
+
+ /* IPv4 as the hostname - nothing fancy here */
+ uri[0] = '\0';
+ isc_nm_http_makeuri(false, NULL, "127.0.0.1", 8080,
+ ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
+ assert_true(strcmp("http://127.0.0.1:8080/dns-query", uri) == 0);
+
+ uri[0] = '\0';
+ isc_nm_http_makeuri(true, NULL, "127.0.0.1", 44343,
+ ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
+ assert_true(strcmp("https://127.0.0.1:44343/dns-query", uri) == 0);
+
+ /*
+ * A peculiar edge case: IPv6 given as the hostname (notice
+ * the brackets)
+ */
+ uri[0] = '\0';
+ isc_nm_http_makeuri(false, NULL, "::1", 8080, ISC_NM_HTTP_DEFAULT_PATH,
+ uri, sizeof(uri));
+ assert_true(strcmp("http://[::1]:8080/dns-query", uri) == 0);
+
+ uri[0] = '\0';
+ isc_nm_http_makeuri(true, NULL, "[::1]", 44343,
+ ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
+ assert_true(strcmp("https://[::1]:44343/dns-query", uri) == 0);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(mock_doh_uv_tcp_bind, setup_test, teardown_test)
+ISC_TEST_ENTRY(doh_parse_GET_query_string)
+ISC_TEST_ENTRY(doh_base64url_to_base64)
+ISC_TEST_ENTRY(doh_base64_to_base64url)
+ISC_TEST_ENTRY(doh_path_validation)
+ISC_TEST_ENTRY(doh_connect_makeuri)
+ISC_TEST_ENTRY_CUSTOM(doh_noop_POST, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_noop_GET, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_noresponse_POST, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_noresponse_GET, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_timeout_recovery_POST, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_timeout_recovery_GET, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST_TLS_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET_TLS_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST_TLS_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET_TLS_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET_TLS_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST_TLS_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET_TLS_quota, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST_TLS_quota, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST_TLS, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET_TLS_quota, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST_TLS_quota, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET_TLS, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST_TLS, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET_quota, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST_quota, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET_TLS_quota, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST_TLS_quota, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(doh_bad_connect_uri, setup_test, teardown_test)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/errno_test.c b/tests/isc/errno_test.c
new file mode 100644
index 0000000..fbfe56a
--- /dev/null
+++ b/tests/isc/errno_test.c
@@ -0,0 +1,109 @@
+/*
+ * 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 <errno.h>
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/errno.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+typedef struct {
+ int err;
+ isc_result_t result;
+} testpair_t;
+
+testpair_t testpair[] = { { EPERM, ISC_R_NOPERM },
+ { ENOENT, ISC_R_FILENOTFOUND },
+ { EIO, ISC_R_IOERROR },
+ { EBADF, ISC_R_INVALIDFILE },
+ { ENOMEM, ISC_R_NOMEMORY },
+ { EACCES, ISC_R_NOPERM },
+ { EEXIST, ISC_R_FILEEXISTS },
+ { ENOTDIR, ISC_R_INVALIDFILE },
+ { EINVAL, ISC_R_INVALIDFILE },
+ { ENFILE, ISC_R_TOOMANYOPENFILES },
+ { EMFILE, ISC_R_TOOMANYOPENFILES },
+ { EPIPE, ISC_R_CONNECTIONRESET },
+ { ENAMETOOLONG, ISC_R_INVALIDFILE },
+ { ELOOP, ISC_R_INVALIDFILE },
+#ifdef EOVERFLOW
+ { EOVERFLOW, ISC_R_RANGE },
+#endif /* ifdef EOVERFLOW */
+#ifdef EAFNOSUPPORT
+ { EAFNOSUPPORT, ISC_R_FAMILYNOSUPPORT },
+#endif /* ifdef EAFNOSUPPORT */
+#ifdef EADDRINUSE
+ { EADDRINUSE, ISC_R_ADDRINUSE },
+#endif /* ifdef EADDRINUSE */
+ { EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL },
+#ifdef ENETDOWN
+ { ENETDOWN, ISC_R_NETDOWN },
+#endif /* ifdef ENETDOWN */
+#ifdef ENETUNREACH
+ { ENETUNREACH, ISC_R_NETUNREACH },
+#endif /* ifdef ENETUNREACH */
+#ifdef ECONNABORTED
+ { ECONNABORTED, ISC_R_CONNECTIONRESET },
+#endif /* ifdef ECONNABORTED */
+#ifdef ECONNRESET
+ { ECONNRESET, ISC_R_CONNECTIONRESET },
+#endif /* ifdef ECONNRESET */
+#ifdef ENOBUFS
+ { ENOBUFS, ISC_R_NORESOURCES },
+#endif /* ifdef ENOBUFS */
+#ifdef ENOTCONN
+ { ENOTCONN, ISC_R_NOTCONNECTED },
+#endif /* ifdef ENOTCONN */
+#ifdef ETIMEDOUT
+ { ETIMEDOUT, ISC_R_TIMEDOUT },
+#endif /* ifdef ETIMEDOUT */
+ { ECONNREFUSED, ISC_R_CONNREFUSED },
+#ifdef EHOSTDOWN
+ { EHOSTDOWN, ISC_R_HOSTDOWN },
+#endif /* ifdef EHOSTDOWN */
+#ifdef EHOSTUNREACH
+ { EHOSTUNREACH, ISC_R_HOSTUNREACH },
+#endif /* ifdef EHOSTUNREACH */
+ { 0, ISC_R_UNEXPECTED } };
+
+/* convert errno to ISC result */
+ISC_RUN_TEST_IMPL(isc_errno_toresult) {
+ isc_result_t result, expect;
+ size_t i;
+
+ for (i = 0; i < sizeof(testpair) / sizeof(testpair[0]); i++) {
+ result = isc_errno_toresult(testpair[i].err);
+ expect = testpair[i].result;
+ assert_int_equal(result, expect);
+ }
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_errno_toresult)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/file_test.c b/tests/isc/file_test.c
new file mode 100644
index 0000000..6b75ba2
--- /dev/null
+++ b/tests/isc/file_test.c
@@ -0,0 +1,141 @@
+/*
+ * 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 <fcntl.h>
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/file.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+#define NAME "internal"
+#define SHA "3bed2cb3a3acf7b6a8ef408420cc682d5520e26976d354254f528c965612054f"
+#define TRUNC_SHA "3bed2cb3a3acf7b6"
+
+#define BAD1 "in/internal"
+#define BADHASH1 "8bbb97a888791399"
+
+#define BAD2 "Internal"
+#define BADHASH2 "2ea1842b445b0c81"
+
+#define F(x) "testdata/file/" x ".test"
+
+static void
+touch(const char *filename) {
+ int fd;
+
+ unlink(filename);
+ fd = creat(filename, 0644);
+ if (fd != -1) {
+ close(fd);
+ }
+}
+
+/* test sanitized filenames */
+ISC_RUN_TEST_IMPL(isc_file_sanitize) {
+ isc_result_t result;
+ char buf[1024];
+
+ UNUSED(state);
+
+ assert_return_code(chdir(TESTS_DIR), 0);
+
+ result = isc_file_sanitize("testdata/file", NAME, "test", buf, 1024);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(strcmp(buf, F(NAME)), 0);
+
+ touch(F(TRUNC_SHA));
+ result = isc_file_sanitize("testdata/file", NAME, "test", buf, 1024);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(strcmp(buf, F(TRUNC_SHA)), 0);
+
+ touch(F(SHA));
+ result = isc_file_sanitize("testdata/file", NAME, "test", buf, 1024);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(strcmp(buf, F(SHA)), 0);
+
+ result = isc_file_sanitize("testdata/file", BAD1, "test", buf, 1024);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(strcmp(buf, F(BADHASH1)), 0);
+
+ result = isc_file_sanitize("testdata/file", BAD2, "test", buf, 1024);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(strcmp(buf, F(BADHASH2)), 0);
+
+ unlink(F(TRUNC_SHA));
+ unlink(F(SHA));
+}
+
+/* test filename templates */
+ISC_RUN_TEST_IMPL(isc_file_template) {
+ isc_result_t result;
+ char buf[1024];
+
+ UNUSED(state);
+
+ assert_return_code(chdir(TESTS_DIR), 0);
+
+ result = isc_file_template("/absolute/path", "file-XXXXXXXX", buf,
+ sizeof(buf));
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, "/absolute/file-XXXXXXXX");
+
+ result = isc_file_template("relative/path", "file-XXXXXXXX", buf,
+ sizeof(buf));
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, "relative/file-XXXXXXXX");
+
+ result = isc_file_template("/trailing/slash/", "file-XXXXXXXX", buf,
+ sizeof(buf));
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, "/trailing/slash/file-XXXXXXXX");
+
+ result = isc_file_template("relative/trailing/slash/", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, "relative/trailing/slash/file-XXXXXXXX");
+
+ result = isc_file_template("/", "file-XXXXXXXX", buf, sizeof(buf));
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, "/file-XXXXXXXX");
+
+ result = isc_file_template("noslash", "file-XXXXXXXX", buf,
+ sizeof(buf));
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, "file-XXXXXXXX");
+
+ result = isc_file_template(NULL, "file-XXXXXXXX", buf, sizeof(buf));
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(buf, "file-XXXXXXXX");
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_file_sanitize)
+ISC_TEST_ENTRY(isc_file_template)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/hash_test.c b/tests/isc/hash_test.c
new file mode 100644
index 0000000..10a8c27
--- /dev/null
+++ b/tests/isc/hash_test.c
@@ -0,0 +1,96 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/hex.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* Hash function test */
+ISC_RUN_TEST_IMPL(isc_hash_function) {
+ unsigned int h1;
+ unsigned int h2;
+
+ UNUSED(state);
+
+ /* Immutability of hash function */
+ h1 = isc_hash_function(NULL, 0, true);
+ h2 = isc_hash_function(NULL, 0, true);
+
+ assert_int_equal(h1, h2);
+
+ /* Hash function characteristics */
+ h1 = isc_hash_function("Hello world", 12, true);
+ h2 = isc_hash_function("Hello world", 12, true);
+
+ assert_int_equal(h1, h2);
+
+ /* Case */
+ h1 = isc_hash_function("Hello world", 12, false);
+ h2 = isc_hash_function("heLLo WorLd", 12, false);
+
+ assert_int_equal(h1, h2);
+
+ /* Unequal */
+ h1 = isc_hash_function("Hello world", 12, true);
+ h2 = isc_hash_function("heLLo WorLd", 12, true);
+
+ assert_int_not_equal(h1, h2);
+}
+
+/* Hash function initializer test */
+ISC_RUN_TEST_IMPL(isc_hash_initializer) {
+ unsigned int h1;
+ unsigned int h2;
+
+ UNUSED(state);
+
+ h1 = isc_hash_function("Hello world", 12, true);
+ h2 = isc_hash_function("Hello world", 12, true);
+
+ assert_int_equal(h1, h2);
+
+ isc_hash_set_initializer(isc_hash_get_initializer());
+
+ /* Hash value must not change */
+ h2 = isc_hash_function("Hello world", 12, true);
+
+ assert_int_equal(h1, h2);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_hash_function)
+ISC_TEST_ENTRY(isc_hash_initializer)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/heap_test.c b/tests/isc/heap_test.c
new file mode 100644
index 0000000..19e3ba5
--- /dev/null
+++ b/tests/isc/heap_test.c
@@ -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.
+ */
+
+/* ! \file */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/heap.h>
+#include <isc/mem.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+struct e {
+ unsigned int value;
+ unsigned int index;
+};
+
+static bool
+compare(void *p1, void *p2) {
+ struct e *e1 = p1;
+ struct e *e2 = p2;
+
+ return (e1->value < e2->value);
+}
+
+static void
+idx(void *p, unsigned int i) {
+ struct e *e = p;
+
+ e->index = i;
+}
+
+/* test isc_heap_delete() */
+ISC_RUN_TEST_IMPL(isc_heap_delete) {
+ isc_heap_t *heap = NULL;
+ struct e e1 = { 100, 0 };
+
+ UNUSED(state);
+
+ isc_heap_create(mctx, compare, idx, 0, &heap);
+ assert_non_null(heap);
+
+ isc_heap_insert(heap, &e1);
+ assert_int_equal(e1.index, 1);
+
+ isc_heap_delete(heap, e1.index);
+ assert_int_equal(e1.index, 0);
+
+ isc_heap_destroy(&heap);
+ assert_null(heap);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_heap_delete)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/hmac_test.c b/tests/isc/hmac_test.c
new file mode 100644
index 0000000..093c6b2
--- /dev/null
+++ b/tests/isc/hmac_test.c
@@ -0,0 +1,926 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * As a workaround, include an OpenSSL header file before including cmocka.h,
+ * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a
+ * redefined malloc in cmocka.h.
+ */
+#include <openssl/err.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/hex.h>
+#include <isc/hmac.h>
+#include <isc/region.h>
+#include <isc/result.h>
+
+#include "hmac.c"
+
+#include <tests/isc.h>
+
+#define TEST_INPUT(x) (x), sizeof(x) - 1
+
+static int
+_setup(void **state) {
+ isc_hmac_t *hmac = isc_hmac_new();
+ if (hmac == NULL) {
+ return (-1);
+ }
+ *state = hmac;
+ return (0);
+}
+
+static int
+_teardown(void **state) {
+ if (*state == NULL) {
+ return (-1);
+ }
+ isc_hmac_free(*state);
+ return (0);
+}
+
+static int
+_reset(void **state) {
+ if (*state == NULL) {
+ return (-1);
+ }
+ if (isc_hmac_reset(*state) != ISC_R_SUCCESS) {
+ return (-1);
+ }
+ return (0);
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_new) {
+ UNUSED(state);
+
+ isc_hmac_t *hmac = isc_hmac_new();
+ assert_non_null(hmac);
+ isc_hmac_free(hmac); /* Cleanup */
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_free) {
+ UNUSED(state);
+
+ isc_hmac_t *hmac = isc_hmac_new();
+ assert_non_null(hmac);
+ isc_hmac_free(hmac); /* Test freeing valid message digest context */
+ isc_hmac_free(NULL); /* Test freeing NULL argument */
+}
+
+static void
+isc_hmac_test(isc_hmac_t *hmac, const void *key, size_t keylen,
+ const isc_md_type_t *type, const char *buf, size_t buflen,
+ const char *result, const size_t repeats) {
+ isc_result_t res;
+
+ assert_non_null(hmac);
+ assert_int_equal(isc_hmac_init(hmac, key, keylen, type), ISC_R_SUCCESS);
+
+ for (size_t i = 0; i < repeats; i++) {
+ assert_int_equal(isc_hmac_update(hmac,
+ (const unsigned char *)buf,
+ buflen),
+ ISC_R_SUCCESS);
+ }
+
+ unsigned char digest[ISC_MAX_MD_SIZE];
+ unsigned int digestlen = sizeof(digest);
+ assert_int_equal(isc_hmac_final(hmac, digest, &digestlen),
+ ISC_R_SUCCESS);
+
+ char hexdigest[ISC_MAX_MD_SIZE * 2 + 3];
+ isc_region_t r = { .base = digest, .length = digestlen };
+ isc_buffer_t b;
+ isc_buffer_init(&b, hexdigest, sizeof(hexdigest));
+
+ res = isc_hex_totext(&r, 0, "", &b);
+
+ assert_return_code(res, ISC_R_SUCCESS);
+
+ assert_memory_equal(hexdigest, result, (result ? strlen(result) : 0));
+ assert_int_equal(isc_hmac_reset(hmac), ISC_R_SUCCESS);
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_init) {
+ isc_hmac_t *hmac = *state;
+ assert_non_null(hmac);
+
+ expect_assert_failure(isc_hmac_init(NULL, "", 0, ISC_MD_MD5));
+
+ assert_int_equal(isc_hmac_init(hmac, "", 0, NULL),
+ ISC_R_NOTIMPLEMENTED);
+
+ expect_assert_failure(isc_hmac_init(hmac, NULL, 0, ISC_MD_MD5));
+
+ assert_int_equal(isc_hmac_init(hmac, "", 0, ISC_MD_MD5), ISC_R_SUCCESS);
+ assert_int_equal(isc_hmac_reset(hmac), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_hmac_init(hmac, "", 0, ISC_MD_SHA1),
+ ISC_R_SUCCESS);
+ assert_int_equal(isc_hmac_reset(hmac), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_hmac_init(hmac, "", 0, ISC_MD_SHA224),
+ ISC_R_SUCCESS);
+ assert_int_equal(isc_hmac_reset(hmac), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_hmac_init(hmac, "", 0, ISC_MD_SHA256),
+ ISC_R_SUCCESS);
+ assert_int_equal(isc_hmac_reset(hmac), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_hmac_init(hmac, "", 0, ISC_MD_SHA384),
+ ISC_R_SUCCESS);
+ assert_int_equal(isc_hmac_reset(hmac), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_hmac_init(hmac, "", 0, ISC_MD_SHA512),
+ ISC_R_SUCCESS);
+ assert_int_equal(isc_hmac_reset(hmac), ISC_R_SUCCESS);
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_update) {
+ isc_hmac_t *hmac = *state;
+ assert_non_null(hmac);
+
+ /* Uses message digest context initialized in isc_hmac_init_test() */
+ expect_assert_failure(isc_hmac_update(NULL, NULL, 0));
+
+ assert_int_equal(isc_hmac_update(hmac, NULL, 100), ISC_R_SUCCESS);
+ assert_int_equal(isc_hmac_update(hmac, (const unsigned char *)"", 0),
+ ISC_R_SUCCESS);
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_reset) {
+ isc_hmac_t *hmac = *state;
+#if 0
+ unsigned char digest[ISC_MAX_MD_SIZE] __attribute((unused));
+ unsigned int digestlen __attribute((unused));
+#endif /* if 0 */
+
+ assert_non_null(hmac);
+
+ assert_int_equal(isc_hmac_init(hmac, "", 0, ISC_MD_SHA512),
+ ISC_R_SUCCESS);
+ assert_int_equal(isc_hmac_update(hmac, (const unsigned char *)"a", 1),
+ ISC_R_SUCCESS);
+ assert_int_equal(isc_hmac_update(hmac, (const unsigned char *)"b", 1),
+ ISC_R_SUCCESS);
+
+ assert_int_equal(isc_hmac_reset(hmac), ISC_R_SUCCESS);
+
+#if 0
+ /*
+ * This test would require OpenSSL compiled with mock_assert(),
+ * so this could be only manually checked that the test will
+ * segfault when called by hand
+ */
+ expect_assert_failure(isc_hmac_final(hmac, digest, &digestlen));
+#endif /* if 0 */
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_final) {
+ isc_hmac_t *hmac = *state;
+ assert_non_null(hmac);
+
+ unsigned char digest[ISC_MAX_MD_SIZE];
+ unsigned int digestlen = sizeof(digest);
+
+ /* Fail when message digest context is empty */
+ expect_assert_failure(isc_hmac_final(NULL, digest, &digestlen));
+ /* Fail when output buffer is empty */
+ expect_assert_failure(isc_hmac_final(hmac, NULL, &digestlen));
+
+ assert_int_equal(isc_hmac_init(hmac, "", 0, ISC_MD_SHA512),
+ ISC_R_SUCCESS);
+ /* Fail when the digest length pointer is empty */
+ expect_assert_failure(isc_hmac_final(hmac, digest, NULL));
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_md5) {
+ isc_hmac_t *hmac = *state;
+
+ /* Test 0 */
+ isc_hmac_test(hmac, TEST_INPUT(""), ISC_MD_MD5, TEST_INPUT(""),
+ "74E6F7298A9C2D168935F58C001BAD88", 1);
+
+ /* Test 1 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b"),
+ ISC_MD_MD5,
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "9294727A3638BB1C13F48EF8158BFC9D", 1);
+
+ /* Test 2 */
+ isc_hmac_test(hmac, TEST_INPUT("Jefe"), ISC_MD_MD5,
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79"
+ "\x61\x20\x77\x61\x6e\x74\x20\x66\x6f"
+ "\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "750C783E6AB0B503EAA86E310A5DB738", 1);
+
+ /* Test 3 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_MD5,
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "56BE34521D144C88DBB8C733F0E8B3F6", 1);
+ /* Test 4 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19"),
+ ISC_MD_MD5,
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "697EAF0ACA3A3AEA3A75164746FFAA79", 1);
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"),
+ ISC_MD_MD5,
+ TEST_INPUT("Test With Truncation"),
+ "4C1A03424B55E07FE7F27BE1",
+ 1);
+ /* Test 6 -- unimplemented optional functionality */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_MD5,
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "AA4AE5E15272D00E95705637CE8A3B55ED402112",
+ 1);
+ /* Test 7 -- unimplemented optional functionality */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_MD5,
+ TEST_INPUT("Test Using Larger Than Block-Size Key and "
+ "Larger Than One Block-Size Data"),
+ "E8E99D0F45237D786D6BBAA7965C7808BBFF1A91",
+ 1);
+#endif /* if 0 */
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_sha1) {
+ isc_hmac_t *hmac = *state;
+
+ /* Test 0 */
+ isc_hmac_test(hmac, TEST_INPUT(""), ISC_MD_SHA1, TEST_INPUT(""),
+ "FBDB1D1B18AA6C08324B7D64B71FB76370690E1D", 1);
+
+ /* Test 1 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
+ ISC_MD_SHA1,
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "B617318655057264E28BC0B6FB378C8EF146BE00", 1);
+ /* Test 2 */
+ isc_hmac_test(hmac, TEST_INPUT("Jefe"), ISC_MD_SHA1,
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79", 1);
+ /* Test 3 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_SHA1,
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "125D7342B9AC11CD91A39AF48AA17B4F63F175D3", 1);
+ /* Test 4 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19"),
+ ISC_MD_SHA1,
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "4C9007F4026250C6BC8414F9BF50C86C2D7235DA", 1);
+#if 0
+ /* Test 5 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"),
+ ISC_MD_SHA1,
+ TEST_INPUT("Test With Truncation"),
+ "4C1A03424B55E07FE7F27BE1",
+ 1);
+#endif /* if 0 */
+ /* Test 6 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_SHA1,
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "AA4AE5E15272D00E95705637CE8A3B55ED402112", 1);
+ /* Test 7 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_SHA1,
+ TEST_INPUT("Test Using Larger Than Block-Size Key and "
+ "Larger Than One Block-Size Data"),
+ "E8E99D0F45237D786D6BBAA7965C7808BBFF1A91", 1);
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_sha224) {
+ isc_hmac_t *hmac = *state;
+
+ /* Test 0 */
+ isc_hmac_test(hmac, TEST_INPUT(""), ISC_MD_SHA224, TEST_INPUT(""),
+ "5CE14F72894662213E2748D2A6BA234B74263910CEDDE2F5"
+ "A9271524",
+ 1);
+
+ /* Test 1 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
+ ISC_MD_SHA224,
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "896FB1128ABBDF196832107CD49DF33F47B4B1169912BA"
+ "4F53684B22",
+ 1);
+ /* Test 2 */
+ isc_hmac_test(hmac, TEST_INPUT("Jefe"), ISC_MD_SHA224,
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "A30E01098BC6DBBF45690F3A7E9E6D0F8BBEA2A39E61480"
+ "08FD05E44",
+ 1);
+ /* Test 3 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_SHA224,
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "7FB3CB3588C6C1F6FFA9694D7D6AD2649365B0C1F65D69"
+ "D1EC8333EA",
+ 1);
+ /* Test 4 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19"),
+ ISC_MD_SHA224,
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "6C11506874013CAC6A2ABC1BB382627CEC6A90D86EFC01"
+ "2DE7AFEC5A",
+ 1);
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"),
+ ISC_MD_SHA224,
+ TEST_INPUT("Test With Truncation"),
+ "4C1A03424B55E07FE7F27BE1",
+ 1);
+#endif /* if 0 */
+ /* Test 6 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa"),
+ ISC_MD_SHA224,
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "95E9A0DB962095ADAEBE9B2D6F0DBCE2D499F112F2D2B7"
+ "273FA6870E",
+ 1);
+ /* Test 7 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa"),
+ ISC_MD_SHA224,
+ TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20"
+ "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67"
+ "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
+ "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20"
+ "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67"
+ "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c"
+ "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64"
+ "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b"
+ "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74"
+ "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65"
+ "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62"
+ "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20"
+ "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41"
+ "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68"
+ "\x6d\x2e"),
+ "3A854166AC5D9F023F54D517D0B39DBD946770DB9C2B95"
+ "C9F6F565D1",
+ 1);
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_sha256) {
+ isc_hmac_t *hmac = *state;
+
+ /* Test 0 */
+ isc_hmac_test(hmac, TEST_INPUT(""), ISC_MD_SHA256, TEST_INPUT(""),
+ "B613679A0814D9EC772F95D778C35FC5FF1697C493715653"
+ "C6C712144292C5AD",
+ 1);
+
+ /* Test 1 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
+ ISC_MD_SHA256,
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "B0344C61D8DB38535CA8AFCEAF0BF12B881DC200C9833D"
+ "A726E9376C2E32CFF7",
+ 1);
+ /* Test 2 */
+ isc_hmac_test(hmac, TEST_INPUT("Jefe"), ISC_MD_SHA256,
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "5BDCC146BF60754E6A042426089575C75A003F089D2739"
+ "839DEC58B964EC3843",
+ 1);
+ /* Test 3 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_SHA256,
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "773EA91E36800E46854DB8EBD09181A72959098B3EF8C1"
+ "22D9635514CED565FE",
+ 1);
+ /* Test 4 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19"),
+ ISC_MD_SHA256,
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "82558A389A443C0EA4CC819899F2083A85F0FAA3E578F8"
+ "077A2E3FF46729665B",
+ 1);
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"),
+ ISC_MD_SHA256,
+ TEST_INPUT("Test With Truncation"),
+ "4C1A03424B55E07FE7F27BE1",
+ 1);
+#endif /* if 0 */
+ /* Test 6 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa"),
+ ISC_MD_SHA256,
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "60E431591EE0B67F0D8A26AACBF5B77F8E0BC6213728C5"
+ "140546040F0EE37F54",
+ 1);
+ /* Test 7 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa"),
+ ISC_MD_SHA256,
+ TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20"
+ "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67"
+ "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
+ "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20"
+ "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67"
+ "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c"
+ "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64"
+ "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b"
+ "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74"
+ "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65"
+ "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62"
+ "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20"
+ "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41"
+ "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68"
+ "\x6d\x2e"),
+ "9B09FFA71B942FCB27635FBCD5B0E944BFDC63644F0713"
+ "938A7F51535C3A35E2",
+ 1);
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_sha384) {
+ isc_hmac_t *hmac = *state;
+
+ /* Test 0 */
+ isc_hmac_test(hmac, TEST_INPUT(""), ISC_MD_SHA384, TEST_INPUT(""),
+ "6C1F2EE938FAD2E24BD91298474382CA218C75DB3D83E114"
+ "B3D4367776D14D3551289E75E8209CD4B792302840234ADC",
+ 1);
+
+ /* Test 1 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
+ ISC_MD_SHA384,
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "AFD03944D84895626B0825F4AB46907F15F9DADBE4101E"
+ "C682AA034C7CEBC59CFAEA9EA9076EDE7F4AF152"
+ "E8B2FA9CB6",
+ 1);
+ /* Test 2 */
+ isc_hmac_test(hmac, TEST_INPUT("Jefe"), ISC_MD_SHA384,
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "AF45D2E376484031617F78D2B58A6B1B9C7EF464F5A01B"
+ "47E42EC3736322445E8E2240CA5E69E2C78B3239"
+ "ECFAB21649",
+ 1);
+ /* Test 3 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_SHA384,
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "88062608D3E6AD8A0AA2ACE014C8A86F0AA635D947AC9F"
+ "EBE83EF4E55966144B2A5AB39DC13814B94E3AB6"
+ "E101A34F27",
+ 1);
+ /* Test 4 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19"),
+ ISC_MD_SHA384,
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "3E8A69B7783C25851933AB6290AF6CA77A998148085000"
+ "9CC5577C6E1F573B4E6801DD23C4A7D679CCF8A3"
+ "86C674CFFB",
+ 1);
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"),
+ ISC_MD_SHA384,
+ TEST_INPUT("Test With Truncation"),
+ "4C1A03424B55E07FE7F27BE1",
+ 1);
+#endif /* if 0 */
+ /* Test 6 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa"),
+ ISC_MD_SHA384,
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "4ECE084485813E9088D2C63A041BC5B44F9EF1012A2B58"
+ "8F3CD11F05033AC4C60C2EF6AB4030FE8296248D"
+ "F163F44952",
+ 1);
+ /* Test 7 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa"),
+ ISC_MD_SHA384,
+ TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20"
+ "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67"
+ "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
+ "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20"
+ "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67"
+ "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c"
+ "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64"
+ "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b"
+ "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74"
+ "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65"
+ "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62"
+ "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20"
+ "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41"
+ "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68"
+ "\x6d\x2e"),
+ "6617178E941F020D351E2F254E8FD32C602420FEB0B8FB"
+ "9ADCCEBB82461E99C5A678CC31E799176D3860E6"
+ "110C46523E",
+ 1);
+}
+
+ISC_RUN_TEST_IMPL(isc_hmac_sha512) {
+ isc_hmac_t *hmac = *state;
+
+ /* Test 0 */
+ isc_hmac_test(hmac, TEST_INPUT(""), ISC_MD_SHA512, TEST_INPUT(""),
+ "B936CEE86C9F87AA5D3C6F2E84CB5A4239A5FE50480A6EC6"
+ "6B70AB5B1F4AC6730C6C515421B327EC1D69402E53DFB49A"
+ "D7381EB067B338FD7B0CB22247225D47",
+ 1);
+
+ /* Test 1 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
+ ISC_MD_SHA512,
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "87AA7CDEA5EF619D4FF0B4241A1D6CB02379F4E2CE4EC2"
+ "787AD0B30545E17CDEDAA833B7D6B8A702038B27"
+ "4EAEA3F4E4BE9D914EEB61F1702E696C203A126854",
+ 1);
+ /* Test 2 */
+ isc_hmac_test(hmac, TEST_INPUT("Jefe"), ISC_MD_SHA512,
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "164B7A7BFCF819E2E395FBE73B56E0A387BD64222E831F"
+ "D610270CD7EA2505549758BF75C05A994A6D034F"
+ "65F8F0E6FDCAEAB1A34D4A6B4B636E070A38BCE737",
+ 1);
+ /* Test 3 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
+ ISC_MD_SHA512,
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "FA73B0089D56A284EFB0F0756C890BE9B1B5DBDD8EE81A"
+ "3655F83E33B2279D39BF3E848279A722C806B485"
+ "A47E67C807B946A337BEE8942674278859E13292FB",
+ 1);
+ /* Test 4 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19"),
+ ISC_MD_SHA512,
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "B0BA465637458C6990E5A8C5F61D4AF7E576D97FF94B87"
+ "2DE76F8050361EE3DBA91CA5C11AA25EB4D67927"
+ "5CC5788063A5F19741120C4F2DE2ADEBEB10A298DD",
+ 1);
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"),
+ ISC_MD_SHA512,
+ TEST_INPUT("Test With Truncation"),
+ "4C1A03424B55E07FE7F27BE1",
+ 1);
+#endif /* if 0 */
+ /* Test 6 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa"),
+ ISC_MD_SHA512,
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "80B24263C7C1A3EBB71493C1DD7BE8B49B46D1F41B4AEE"
+ "C1121B013783F8F3526B56D037E05F2598BD0FD2"
+ "215D6A1E5295E64F73F63F0AEC8B915A985D786598",
+ 1);
+ /* Test 7 */
+ isc_hmac_test(hmac,
+ TEST_INPUT("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa"),
+ ISC_MD_SHA512,
+ TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20"
+ "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67"
+ "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
+ "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20"
+ "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67"
+ "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c"
+ "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64"
+ "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b"
+ "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74"
+ "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65"
+ "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62"
+ "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20"
+ "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41"
+ "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68"
+ "\x6d\x2e"),
+ "E37B6A775DC87DBAA4DFA9F96E5E3FFDDEBD71F8867289"
+ "865DF5A32D20CDC944B6022CAC3C4982B10D5EEB"
+ "55C3E4DE15134676FB6DE0446065C97440FA8C6A58",
+ 1);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_hmac_new)
+ISC_TEST_ENTRY_CUSTOM(isc_hmac_init, _reset, _reset)
+
+ISC_TEST_ENTRY_CUSTOM(isc_hmac_reset, _reset, _reset)
+
+ISC_TEST_ENTRY(isc_hmac_md5)
+ISC_TEST_ENTRY(isc_hmac_sha1)
+ISC_TEST_ENTRY(isc_hmac_sha224)
+ISC_TEST_ENTRY(isc_hmac_sha256)
+ISC_TEST_ENTRY(isc_hmac_sha384)
+ISC_TEST_ENTRY(isc_hmac_sha512)
+
+ISC_TEST_ENTRY_CUSTOM(isc_hmac_update, _reset, _reset)
+ISC_TEST_ENTRY_CUSTOM(isc_hmac_final, _reset, _reset)
+
+ISC_TEST_ENTRY(isc_hmac_free)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN_CUSTOM(_setup, _teardown)
diff --git a/tests/isc/ht_test.c b/tests/isc/ht_test.c
new file mode 100644
index 0000000..89e18f3
--- /dev/null
+++ b/tests/isc/ht_test.c
@@ -0,0 +1,322 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/hash.h>
+#include <isc/ht.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* INCLUDE LAST */
+
+#define mctx __mctx
+#include "ht.c"
+#undef mctx
+
+static void
+test_ht_full(int bits, uintptr_t count) {
+ isc_ht_t *ht = NULL;
+ isc_result_t result;
+ uintptr_t i;
+
+ isc_ht_init(&ht, mctx, bits, ISC_HT_CASE_SENSITIVE);
+ assert_non_null(ht);
+
+ for (i = 1; i < count; i++) {
+ /*
+ * Note: snprintf() is followed with strlcat()
+ * to ensure we are always filling the 16 byte key.
+ */
+ unsigned char key[16];
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, key, 16, (void *)i);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, key, 16, &f);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_ptr_equal((void *)i, (void *)f);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, key, 16, (void *)i);
+ assert_int_equal(result, ISC_R_EXISTS);
+ }
+
+ for (i = 1; i < count; i++) {
+ char key[64];
+ /*
+ * Note: the key size is now strlen(key) which is bigger
+ * then the keys added above.
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, (const unsigned char *)key, strlen(key),
+ (void *)i);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ /*
+ * Note: case of KEY is now in capitals,
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " KEY of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, key, 16, &f);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+ assert_null(f);
+ }
+
+ for (i = 1; i < count; i++) {
+ char key[64];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, (const unsigned char *)key,
+ strlen(key), &f);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_ptr_equal(f, (void *)i);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_delete(ht, key, 16);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_ht_find(ht, key, 16, &f);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+ assert_null(f);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ /*
+ * Note: upper case KEY.
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " KEY of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, key, 16, (void *)i);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ for (i = 1; i < count; i++) {
+ char key[64];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_delete(ht, (const unsigned char *)key,
+ strlen(key));
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_ht_find(ht, (const unsigned char *)key,
+ strlen(key), &f);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+ assert_null(f);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ /*
+ * Note: case of KEY is now in capitals,
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " KEY of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, key, 16, &f);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_ptr_equal((void *)i, (void *)f);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, key, 16, &f);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+ assert_null(f);
+ }
+
+ isc_ht_destroy(&ht);
+ assert_null(ht);
+}
+
+static void
+test_ht_iterator(void) {
+ isc_ht_t *ht = NULL;
+ isc_result_t result;
+ isc_ht_iter_t *iter = NULL;
+ uintptr_t i;
+ uintptr_t count = 10000;
+ uint32_t walked;
+ unsigned char key[16];
+ size_t tksize;
+
+ isc_ht_init(&ht, mctx, 16, ISC_HT_CASE_SENSITIVE);
+ assert_non_null(ht);
+ for (i = 1; i <= count; i++) {
+ /*
+ * Note that the string we're snprintfing is always > 16 bytes
+ * so we are always filling the key.
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, key, 16, (void *)i);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ walked = 0;
+ isc_ht_iter_create(ht, &iter);
+
+ for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
+ result = isc_ht_iter_next(iter))
+ {
+ unsigned char *tkey = NULL;
+ void *v = NULL;
+
+ isc_ht_iter_current(iter, &v);
+ isc_ht_iter_currentkey(iter, &tkey, &tksize);
+ assert_int_equal(tksize, 16);
+ i = (uintptr_t)v;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
+ assert_memory_equal(key, tkey, 16);
+ walked++;
+ }
+ assert_int_equal(walked, count);
+ assert_int_equal(result, ISC_R_NOMORE);
+
+ /* erase odd */
+ walked = 0;
+ result = isc_ht_iter_first(iter);
+ while (result == ISC_R_SUCCESS) {
+ unsigned char *tkey = NULL;
+ void *v = NULL;
+
+ isc_ht_iter_current(iter, &v);
+ isc_ht_iter_currentkey(iter, &tkey, &tksize);
+ assert_int_equal(tksize, 16);
+ i = (uintptr_t)v;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
+ assert_memory_equal(key, tkey, 16);
+ if ((uintptr_t)v % 2 == 0) {
+ result = isc_ht_iter_delcurrent_next(iter);
+ } else {
+ result = isc_ht_iter_next(iter);
+ }
+ walked++;
+ }
+ assert_int_equal(result, ISC_R_NOMORE);
+ assert_int_equal(walked, count);
+
+ /* erase even */
+ walked = 0;
+ result = isc_ht_iter_first(iter);
+ while (result == ISC_R_SUCCESS) {
+ unsigned char *tkey = NULL;
+ void *v = NULL;
+
+ isc_ht_iter_current(iter, &v);
+ isc_ht_iter_currentkey(iter, &tkey, &tksize);
+ assert_int_equal(tksize, 16);
+ i = (uintptr_t)v;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
+ assert_memory_equal(key, tkey, 16);
+ if ((uintptr_t)v % 2 == 1) {
+ result = isc_ht_iter_delcurrent_next(iter);
+ } else {
+ result = isc_ht_iter_next(iter);
+ }
+ walked++;
+ }
+ assert_int_equal(result, ISC_R_NOMORE);
+ assert_int_equal(walked, count / 2);
+
+ walked = 0;
+ for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
+ result = isc_ht_iter_next(iter))
+ {
+ walked++;
+ }
+
+ assert_int_equal(result, ISC_R_NOMORE);
+ assert_int_equal(walked, 0);
+
+ isc_ht_iter_destroy(&iter);
+ assert_null(iter);
+
+ isc_ht_destroy(&ht);
+ assert_null(ht);
+}
+
+/* 20 bit, 200K elements test */
+ISC_RUN_TEST_IMPL(isc_ht_20) {
+ UNUSED(state);
+ test_ht_full(20, 200000);
+}
+
+/* 8 bit, 20000 elements crowded test */
+ISC_RUN_TEST_IMPL(isc_ht_8) {
+ UNUSED(state);
+ test_ht_full(8, 20000);
+}
+
+ISC_RUN_TEST_IMPL(isc_ht_1) {
+ UNUSED(state);
+ test_ht_full(1, 100);
+}
+
+/* test hashtable iterator */
+
+ISC_RUN_TEST_IMPL(isc_ht_iterator) {
+ UNUSED(state);
+ test_ht_iterator();
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(isc_ht_20)
+ISC_TEST_ENTRY(isc_ht_8)
+ISC_TEST_ENTRY(isc_ht_1)
+ISC_TEST_ENTRY(isc_ht_iterator)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/lex_test.c b/tests/isc/lex_test.c
new file mode 100644
index 0000000..47a40dd
--- /dev/null
+++ b/tests/isc/lex_test.c
@@ -0,0 +1,355 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+#define AS_STR(x) (x).value.as_textregion.base
+
+/* check handling of 0xff */
+ISC_RUN_TEST_IMPL(lex_0xff) {
+ isc_result_t result;
+ isc_lex_t *lex = NULL;
+ isc_buffer_t death_buf;
+ isc_token_t token;
+
+ unsigned char death[] = { EOF, 'A' };
+
+ UNUSED(state);
+
+ result = isc_lex_create(mctx, 1024, &lex);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_init(&death_buf, &death[0], sizeof(death));
+ isc_buffer_add(&death_buf, sizeof(death));
+
+ result = isc_lex_openbuffer(lex, &death_buf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_lex_gettoken(lex, 0, &token);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_lex_destroy(&lex);
+}
+
+/* check setting of source line */
+ISC_RUN_TEST_IMPL(lex_setline) {
+ isc_result_t result;
+ isc_lex_t *lex = NULL;
+ unsigned char text[] = "text\nto\nbe\nprocessed\nby\nlexer";
+ isc_buffer_t buf;
+ isc_token_t token;
+ unsigned long line;
+ int i;
+
+ UNUSED(state);
+
+ result = isc_lex_create(mctx, 1024, &lex);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_init(&buf, &text[0], sizeof(text));
+ isc_buffer_add(&buf, sizeof(text));
+
+ result = isc_lex_openbuffer(lex, &buf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_lex_setsourceline(lex, 100);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (i = 0; i < 6; i++) {
+ result = isc_lex_gettoken(lex, 0, &token);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ line = isc_lex_getsourceline(lex);
+ assert_int_equal(line, 100U + i);
+ }
+
+ result = isc_lex_gettoken(lex, 0, &token);
+ assert_int_equal(result, ISC_R_EOF);
+
+ line = isc_lex_getsourceline(lex);
+ assert_int_equal(line, 105U);
+
+ isc_lex_destroy(&lex);
+}
+
+static struct {
+ const char *text;
+ const char *string_value;
+ isc_result_t string_result;
+ isc_tokentype_t string_type;
+ const char *qstring_value;
+ isc_result_t qstring_result;
+ isc_tokentype_t qstring_type;
+ const char *qvpair_value;
+ isc_result_t qvpair_result;
+ isc_tokentype_t qvpair_type;
+} parse_tests[] = {
+ { "", "", ISC_R_SUCCESS, isc_tokentype_eof, "", ISC_R_SUCCESS,
+ isc_tokentype_eof, "", ISC_R_SUCCESS, isc_tokentype_eof },
+ { "1234", "1234", ISC_R_SUCCESS, isc_tokentype_string, "1234",
+ ISC_R_SUCCESS, isc_tokentype_string, "1234", ISC_R_SUCCESS,
+ isc_tokentype_string },
+ { "1234=", "1234=", ISC_R_SUCCESS, isc_tokentype_string,
+ "1234=", ISC_R_SUCCESS, isc_tokentype_string, "1234=", ISC_R_SUCCESS,
+ isc_tokentype_vpair },
+ { "1234=foo", "1234=foo", ISC_R_SUCCESS, isc_tokentype_string,
+ "1234=foo", ISC_R_SUCCESS, isc_tokentype_string, "1234=foo",
+ ISC_R_SUCCESS, isc_tokentype_vpair },
+ { "1234=\"foo", "1234=\"foo", ISC_R_SUCCESS, isc_tokentype_string,
+ "1234=\"foo", ISC_R_SUCCESS, isc_tokentype_string, NULL,
+ ISC_R_UNEXPECTEDEND, 0 },
+ { "1234=\"foo\"", "1234=\"foo\"", ISC_R_SUCCESS, isc_tokentype_string,
+ "1234=\"foo\"", ISC_R_SUCCESS, isc_tokentype_string, "1234=foo",
+ ISC_R_SUCCESS, isc_tokentype_qvpair },
+ { "key", "key", ISC_R_SUCCESS, isc_tokentype_string, "key",
+ ISC_R_SUCCESS, isc_tokentype_string, "key", ISC_R_SUCCESS,
+ isc_tokentype_string },
+ { "\"key=", "\"key=", ISC_R_SUCCESS, isc_tokentype_string, NULL,
+ ISC_R_UNEXPECTEDEND, 0, "\"key=", ISC_R_SUCCESS,
+ isc_tokentype_vpair },
+ { "\"key=\"", "\"key=\"", ISC_R_SUCCESS, isc_tokentype_string, "key=",
+ ISC_R_SUCCESS, isc_tokentype_qstring, NULL, ISC_R_UNEXPECTEDEND, 0 },
+ { "key=\"\"", "key=\"\"", ISC_R_SUCCESS, isc_tokentype_string,
+ "key=\"\"", ISC_R_SUCCESS, isc_tokentype_string,
+ "key=", ISC_R_SUCCESS, isc_tokentype_qvpair },
+ { "key=\"a b\"", "key=\"a", ISC_R_SUCCESS, isc_tokentype_string,
+ "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=a b",
+ ISC_R_SUCCESS, isc_tokentype_qvpair },
+ { "key=\"a\tb\"", "key=\"a", ISC_R_SUCCESS, isc_tokentype_string,
+ "key=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=a\tb",
+ ISC_R_SUCCESS, isc_tokentype_qvpair },
+ /* double quote not immediately after '=' is not special. */
+ { "key=c\"a b\"", "key=c\"a", ISC_R_SUCCESS, isc_tokentype_string,
+ "key=c\"a", ISC_R_SUCCESS, isc_tokentype_string, "key=c\"a",
+ ISC_R_SUCCESS, isc_tokentype_vpair },
+ /* remove special meaning for '=' by escaping */
+ { "key\\=", "key\\=", ISC_R_SUCCESS, isc_tokentype_string,
+ "key\\=", ISC_R_SUCCESS, isc_tokentype_string,
+ "key\\=", ISC_R_SUCCESS, isc_tokentype_string },
+ { "key\\=\"a\"", "key\\=\"a\"", ISC_R_SUCCESS, isc_tokentype_string,
+ "key\\=\"a\"", ISC_R_SUCCESS, isc_tokentype_string, "key\\=\"a\"",
+ ISC_R_SUCCESS, isc_tokentype_string },
+ { "key\\=\"a \"", "key\\=\"a", ISC_R_SUCCESS, isc_tokentype_string,
+ "key\\=\"a", ISC_R_SUCCESS, isc_tokentype_string, "key\\=\"a",
+ ISC_R_SUCCESS, isc_tokentype_string },
+ /* vpair with a key of 'key\=' (would need to be deescaped) */
+ { "key\\==", "key\\==", ISC_R_SUCCESS, isc_tokentype_string,
+ "key\\==", ISC_R_SUCCESS, isc_tokentype_string,
+ "key\\==", ISC_R_SUCCESS, isc_tokentype_vpair },
+ { "key\\==\"\"", "key\\==\"\"", ISC_R_SUCCESS, isc_tokentype_string,
+ "key\\==\"\"", ISC_R_SUCCESS, isc_tokentype_string,
+ "key\\==", ISC_R_SUCCESS, isc_tokentype_qvpair },
+ { "key=\\\\\\\\", "key=\\\\\\\\", ISC_R_SUCCESS, isc_tokentype_string,
+ "key=\\\\\\\\", ISC_R_SUCCESS, isc_tokentype_string, "key=\\\\\\\\",
+ ISC_R_SUCCESS, isc_tokentype_vpair },
+ { "key=\\\\\\\"", "key=\\\\\\\"", ISC_R_SUCCESS, isc_tokentype_string,
+ "key=\\\\\\\"", ISC_R_SUCCESS, isc_tokentype_string, "key=\\\\\\\"",
+ ISC_R_SUCCESS, isc_tokentype_vpair },
+ /* incomplete escape sequence */
+ { "key=\\\"\\", NULL, ISC_R_UNEXPECTEDEND, isc_tokentype_string, NULL,
+ ISC_R_UNEXPECTEDEND, 0, NULL, ISC_R_UNEXPECTEDEND, 0 },
+ /* incomplete escape sequence */
+ { "key=\\", NULL, ISC_R_UNEXPECTEDEND, isc_tokentype_string, NULL,
+ ISC_R_UNEXPECTEDEND, 0, NULL, ISC_R_UNEXPECTEDEND, 0 },
+};
+
+/*%
+ * string
+ */
+ISC_RUN_TEST_IMPL(lex_string) {
+ isc_buffer_t buf;
+ isc_lex_t *lex = NULL;
+ isc_result_t result;
+ isc_token_t token;
+ size_t i;
+
+ UNUSED(state);
+
+ for (i = 0; i < ARRAY_SIZE(parse_tests); i++) {
+ result = isc_lex_create(mctx, 1024, &lex);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_constinit(&buf, parse_tests[i].text,
+ strlen(parse_tests[i].text));
+ isc_buffer_add(&buf, strlen(parse_tests[i].text));
+
+ result = isc_lex_openbuffer(lex, &buf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_lex_setsourceline(lex, 100);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(&token, 0, sizeof(token));
+ result = isc_lex_getmastertoken(lex, &token,
+ isc_tokentype_string, true);
+
+ assert_int_equal(result, parse_tests[i].string_result);
+ if (result == ISC_R_SUCCESS) {
+ switch (token.type) {
+ case isc_tokentype_string:
+ case isc_tokentype_qstring:
+ case isc_tokentype_vpair:
+ case isc_tokentype_qvpair:
+ assert_int_equal(token.type,
+ parse_tests[i].string_type);
+ assert_string_equal(
+ AS_STR(token),
+ parse_tests[i].string_value);
+ break;
+ default:
+ assert_int_equal(token.type,
+ parse_tests[i].string_type);
+ break;
+ }
+ }
+
+ isc_lex_destroy(&lex);
+ }
+}
+
+/*%
+ * qstring
+ */
+ISC_RUN_TEST_IMPL(lex_qstring) {
+ isc_buffer_t buf;
+ isc_lex_t *lex = NULL;
+ isc_result_t result;
+ isc_token_t token;
+ size_t i;
+
+ UNUSED(state);
+
+ for (i = 0; i < ARRAY_SIZE(parse_tests); i++) {
+ result = isc_lex_create(mctx, 1024, &lex);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_constinit(&buf, parse_tests[i].text,
+ strlen(parse_tests[i].text));
+ isc_buffer_add(&buf, strlen(parse_tests[i].text));
+
+ result = isc_lex_openbuffer(lex, &buf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_lex_setsourceline(lex, 100);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(&token, 0, sizeof(token));
+ result = isc_lex_getmastertoken(lex, &token,
+ isc_tokentype_qstring, true);
+
+ assert_int_equal(result, parse_tests[i].qstring_result);
+ if (result == ISC_R_SUCCESS) {
+ switch (token.type) {
+ case isc_tokentype_string:
+ case isc_tokentype_qstring:
+ case isc_tokentype_vpair:
+ case isc_tokentype_qvpair:
+ assert_int_equal(token.type,
+ parse_tests[i].qstring_type);
+ assert_string_equal(
+ AS_STR(token),
+ parse_tests[i].qstring_value);
+ break;
+ default:
+ assert_int_equal(token.type,
+ parse_tests[i].qstring_type);
+ break;
+ }
+ }
+
+ isc_lex_destroy(&lex);
+ }
+}
+
+/*%
+ * keypair is <string>=<qstring>. This has implications double quotes
+ * in key names.
+ */
+ISC_RUN_TEST_IMPL(lex_keypair) {
+ isc_buffer_t buf;
+ isc_lex_t *lex = NULL;
+ isc_result_t result;
+ isc_token_t token;
+ size_t i;
+
+ UNUSED(state);
+
+ for (i = 0; i < ARRAY_SIZE(parse_tests); i++) {
+ result = isc_lex_create(mctx, 1024, &lex);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_constinit(&buf, parse_tests[i].text,
+ strlen(parse_tests[i].text));
+ isc_buffer_add(&buf, strlen(parse_tests[i].text));
+
+ result = isc_lex_openbuffer(lex, &buf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_lex_setsourceline(lex, 100);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(&token, 0, sizeof(token));
+ result = isc_lex_getmastertoken(lex, &token,
+ isc_tokentype_qvpair, true);
+
+ assert_int_equal(result, parse_tests[i].qvpair_result);
+ if (result == ISC_R_SUCCESS) {
+ switch (token.type) {
+ case isc_tokentype_string:
+ case isc_tokentype_qstring:
+ case isc_tokentype_vpair:
+ case isc_tokentype_qvpair:
+ assert_int_equal(token.type,
+ parse_tests[i].qvpair_type);
+ assert_string_equal(
+ AS_STR(token),
+ parse_tests[i].qvpair_value);
+ break;
+ default:
+ assert_int_equal(token.type,
+ parse_tests[i].qvpair_type);
+ break;
+ }
+ }
+
+ isc_lex_destroy(&lex);
+ }
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(lex_0xff)
+ISC_TEST_ENTRY(lex_keypair)
+ISC_TEST_ENTRY(lex_setline)
+ISC_TEST_ENTRY(lex_string)
+ISC_TEST_ENTRY(lex_qstring)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/md_test.c b/tests/isc/md_test.c
new file mode 100644
index 0000000..aff12e4
--- /dev/null
+++ b/tests/isc/md_test.c
@@ -0,0 +1,555 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+
+/* For FIPS_mode() */
+#include <openssl/crypto.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/hex.h>
+#include <isc/md.h>
+#include <isc/region.h>
+#include <isc/result.h>
+
+#include "md.c"
+
+#include <tests/isc.h>
+
+#define TEST_INPUT(x) (x), sizeof(x) - 1
+
+static int
+_setup(void **state) {
+ isc_md_t *md = isc_md_new();
+ if (md == NULL) {
+ return (-1);
+ }
+ *state = md;
+ return (0);
+}
+
+static int
+_teardown(void **state) {
+ if (*state == NULL) {
+ return (-1);
+ }
+ isc_md_free(*state);
+ return (0);
+}
+
+static int
+_reset(void **state) {
+ if (*state == NULL) {
+ return (-1);
+ }
+ if (isc_md_reset(*state) != ISC_R_SUCCESS) {
+ return (-1);
+ }
+ return (0);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_new) {
+ isc_md_t *md = isc_md_new();
+ assert_non_null(md);
+ isc_md_free(md); /* Cleanup */
+}
+
+ISC_RUN_TEST_IMPL(isc_md_free) {
+ isc_md_t *md = isc_md_new();
+ assert_non_null(md);
+ isc_md_free(md); /* Test freeing valid message digest context */
+ isc_md_free(NULL); /* Test freeing NULL argument */
+}
+
+static void
+isc_md_test(isc_md_t *md, const isc_md_type_t *type, const char *buf,
+ size_t buflen, const char *result, const size_t repeats) {
+ isc_result_t res;
+
+ assert_non_null(md);
+ assert_int_equal(isc_md_init(md, type), ISC_R_SUCCESS);
+
+ for (size_t i = 0; i < repeats; i++) {
+ assert_int_equal(
+ isc_md_update(md, (const unsigned char *)buf, buflen),
+ ISC_R_SUCCESS);
+ }
+
+ unsigned char digest[ISC_MAX_MD_SIZE];
+ unsigned int digestlen;
+ assert_int_equal(isc_md_final(md, digest, &digestlen), ISC_R_SUCCESS);
+
+ char hexdigest[ISC_MAX_MD_SIZE * 2 + 3];
+ isc_region_t r = { .base = digest, .length = digestlen };
+ isc_buffer_t b;
+ isc_buffer_init(&b, hexdigest, sizeof(hexdigest));
+
+ res = isc_hex_totext(&r, 0, "", &b);
+
+ assert_return_code(res, ISC_R_SUCCESS);
+
+ assert_memory_equal(hexdigest, result, (result ? strlen(result) : 0));
+ assert_int_equal(isc_md_reset(md), ISC_R_SUCCESS);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_init) {
+ isc_md_t *md = *state;
+ assert_non_null(md);
+
+ expect_assert_failure(isc_md_init(NULL, ISC_MD_MD5));
+
+ assert_int_equal(isc_md_init(md, NULL), ISC_R_NOTIMPLEMENTED);
+
+ assert_int_equal(isc_md_init(md, ISC_MD_MD5), ISC_R_SUCCESS);
+ assert_int_equal(isc_md_reset(md), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_md_init(md, ISC_MD_SHA1), ISC_R_SUCCESS);
+ assert_int_equal(isc_md_reset(md), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_md_init(md, ISC_MD_SHA224), ISC_R_SUCCESS);
+ assert_int_equal(isc_md_reset(md), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_md_init(md, ISC_MD_SHA256), ISC_R_SUCCESS);
+ assert_int_equal(isc_md_reset(md), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_md_init(md, ISC_MD_SHA384), ISC_R_SUCCESS);
+ assert_int_equal(isc_md_reset(md), ISC_R_SUCCESS);
+
+ assert_int_equal(isc_md_init(md, ISC_MD_SHA512), ISC_R_SUCCESS);
+ assert_int_equal(isc_md_reset(md), ISC_R_SUCCESS);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_update) {
+ isc_md_t *md = *state;
+ assert_non_null(md);
+
+ /* Uses message digest context initialized in isc_md_init_test() */
+ expect_assert_failure(isc_md_update(NULL, NULL, 0));
+
+ assert_int_equal(isc_md_update(md, NULL, 100), ISC_R_SUCCESS);
+ assert_int_equal(isc_md_update(md, (const unsigned char *)"", 0),
+ ISC_R_SUCCESS);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_reset) {
+ isc_md_t *md = *state;
+#if 0
+ unsigned char digest[ISC_MAX_MD_SIZE] __attribute((unused));
+ unsigned int digestlen __attribute((unused));
+#endif /* if 0 */
+
+ assert_non_null(md);
+
+ assert_int_equal(isc_md_init(md, ISC_MD_SHA512), ISC_R_SUCCESS);
+ assert_int_equal(isc_md_update(md, (const unsigned char *)"a", 1),
+ ISC_R_SUCCESS);
+ assert_int_equal(isc_md_update(md, (const unsigned char *)"b", 1),
+ ISC_R_SUCCESS);
+
+ assert_int_equal(isc_md_reset(md), ISC_R_SUCCESS);
+
+#if 0
+ /*
+ * This test would require OpenSSL compiled with mock_assert(),
+ * so this could be only manually checked that the test will
+ * segfault when called by hand
+ */
+ expect_assert_failure(isc_md_final(md,digest,&digestlen));
+#endif /* if 0 */
+}
+
+ISC_RUN_TEST_IMPL(isc_md_final) {
+ isc_md_t *md = *state;
+ assert_non_null(md);
+
+ unsigned char digest[ISC_MAX_MD_SIZE];
+ unsigned int digestlen;
+
+ /* Fail when message digest context is empty */
+ expect_assert_failure(isc_md_final(NULL, digest, &digestlen));
+ /* Fail when output buffer is empty */
+ expect_assert_failure(isc_md_final(md, NULL, &digestlen));
+
+ assert_int_equal(isc_md_init(md, ISC_MD_SHA512), ISC_R_SUCCESS);
+ assert_int_equal(isc_md_final(md, digest, NULL), ISC_R_SUCCESS);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_md5) {
+ isc_md_t *md = *state;
+ isc_md_test(md, ISC_MD_MD5, NULL, 0, NULL, 0);
+ isc_md_test(md, ISC_MD_MD5, TEST_INPUT(""),
+ "D41D8CD98F00B204E9800998ECF8427E", 1);
+ isc_md_test(md, ISC_MD_MD5, TEST_INPUT("a"),
+ "0CC175B9C0F1B6A831C399E269772661", 1);
+ isc_md_test(md, ISC_MD_MD5, TEST_INPUT("abc"),
+ "900150983CD24FB0D6963F7D28E17F72", 1);
+ isc_md_test(md, ISC_MD_MD5, TEST_INPUT("message digest"),
+ "F96B697D7CB7938D525A2F31AAF161D0", 1);
+ isc_md_test(md, ISC_MD_MD5, TEST_INPUT("abcdefghijklmnopqrstuvwxyz"),
+ "C3FCD3D76192E4007DFB496CCA67E13B", 1);
+ isc_md_test(md, ISC_MD_MD5,
+ TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"
+ "nopqrstuvwxyz0123456789"),
+ "D174AB98D277D9F5A5611C2C9F419D9F", 1);
+ isc_md_test(md, ISC_MD_MD5,
+ TEST_INPUT("123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890"),
+ "57EDF4A22BE3C955AC49DA2E2107B67A", 1);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_sha1) {
+ isc_md_t *md = *state;
+ isc_md_test(md, ISC_MD_SHA1, NULL, 0, NULL, 0);
+ isc_md_test(md, ISC_MD_SHA1, TEST_INPUT(""),
+ "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", 1);
+ isc_md_test(md, ISC_MD_SHA1, TEST_INPUT("abc"),
+ "A9993E364706816ABA3E25717850C26C9CD0D89D", 1);
+ isc_md_test(md, ISC_MD_SHA1,
+ TEST_INPUT("abcdbcdecdefdefgefghfghighijhijkijk"
+ "ljklmklmnlmnomnopnopq"),
+ "84983E441C3BD26EBAAE4AA1F95129E5E54670F1", 1);
+ isc_md_test(md, ISC_MD_SHA1, TEST_INPUT("a"),
+ "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F", 1000000);
+ isc_md_test(md, ISC_MD_SHA1,
+ TEST_INPUT("01234567012345670123456701234567"),
+ "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452", 20);
+ isc_md_test(md, ISC_MD_SHA1, TEST_INPUT("\x5e"),
+ "5E6F80A34A9798CAFC6A5DB96CC57BA4C4DB59C2", 1);
+ isc_md_test(md, ISC_MD_SHA1,
+ TEST_INPUT("\x9a\x7d\xfd\xf1\xec\xea\xd0\x6e\xd6\x46"
+ "\xaa\x55\xfe\x75\x71\x46"),
+ "82ABFF6605DBE1C17DEF12A394FA22A82B544A35", 1);
+ isc_md_test(md, ISC_MD_SHA1,
+ TEST_INPUT("\xf7\x8f\x92\x14\x1b\xcd\x17\x0a\xe8\x9b"
+ "\x4f\xba\x15\xa1\xd5\x9f\x3f\xd8\x4d\x22"
+ "\x3c\x92\x51\xbd\xac\xbb\xae\x61\xd0\x5e"
+ "\xd1\x15\xa0\x6a\x7c\xe1\x17\xb7\xbe\xea"
+ "\xd2\x44\x21\xde\xd9\xc3\x25\x92\xbd\x57"
+ "\xed\xea\xe3\x9c\x39\xfa\x1f\xe8\x94\x6a"
+ "\x84\xd0\xcf\x1f\x7b\xee\xad\x17\x13\xe2"
+ "\xe0\x95\x98\x97\x34\x7f\x67\xc8\x0b\x04"
+ "\x00\xc2\x09\x81\x5d\x6b\x10\xa6\x83\x83"
+ "\x6f\xd5\x56\x2a\x56\xca\xb1\xa2\x8e\x81"
+ "\xb6\x57\x66\x54\x63\x1c\xf1\x65\x66\xb8"
+ "\x6e\x3b\x33\xa1\x08\xb0\x53\x07\xc0\x0a"
+ "\xff\x14\xa7\x68\xed\x73\x50\x60\x6a\x0f"
+ "\x85\xe6\xa9\x1d\x39\x6f\x5b\x5c\xbe\x57"
+ "\x7f\x9b\x38\x80\x7c\x7d\x52\x3d\x6d\x79"
+ "\x2f\x6e\xbc\x24\xa4\xec\xf2\xb3\xa4\x27"
+ "\xcd\xbb\xfb"),
+ "CB0082C8F197D260991BA6A460E76E202BAD27B3", 1);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_sha224) {
+ isc_md_t *md = *state;
+
+ isc_md_test(md, ISC_MD_SHA224, NULL, 0, NULL, 0);
+ isc_md_test(md, ISC_MD_SHA224, TEST_INPUT(""),
+ "D14A028C2A3A2BC9476102BB288234C415A2B01F828EA62AC5B3E42F",
+ 1);
+ isc_md_test(md, ISC_MD_SHA224, TEST_INPUT("abc"),
+ "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7"
+ "E36C9DA7",
+ 1);
+ isc_md_test(md, ISC_MD_SHA224,
+ TEST_INPUT("abcdbcdecdefdefgefghfghighijhijkijklj"
+ "klmklmnlmnomnopnopq"),
+ "75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B"
+ "1952522525",
+ 1);
+ isc_md_test(md, ISC_MD_SHA224, TEST_INPUT("a"),
+ "20794655980C91D8BBB4C1EA97618A4BF03F42581948B2"
+ "EE4EE7AD67",
+ 1000000);
+ isc_md_test(md, ISC_MD_SHA224,
+ TEST_INPUT("01234567012345670123456701234567"),
+ "567F69F168CD7844E65259CE658FE7AADFA25216E68ECA"
+ "0EB7AB8262",
+ 20);
+ isc_md_test(md, ISC_MD_SHA224, TEST_INPUT("\x07"),
+ "00ECD5F138422B8AD74C9799FD826C531BAD2FCABC7450"
+ "BEE2AA8C2A",
+ 1);
+ isc_md_test(md, ISC_MD_SHA224,
+ TEST_INPUT("\x18\x80\x40\x05\xdd\x4f\xbd\x15\x56\x29"
+ "\x9d\x6f\x9d\x93\xdf\x62"),
+ "DF90D78AA78821C99B40BA4C966921ACCD8FFB1E98AC38"
+ "8E56191DB1",
+ 1);
+ isc_md_test(md, ISC_MD_SHA224,
+ TEST_INPUT("\x55\xb2\x10\x07\x9c\x61\xb5\x3a\xdd\x52"
+ "\x06\x22\xd1\xac\x97\xd5\xcd\xbe\x8c\xb3"
+ "\x3a\xa0\xae\x34\x45\x17\xbe\xe4\xd7\xba"
+ "\x09\xab\xc8\x53\x3c\x52\x50\x88\x7a\x43"
+ "\xbe\xbb\xac\x90\x6c\x2e\x18\x37\xf2\x6b"
+ "\x36\xa5\x9a\xe3\xbe\x78\x14\xd5\x06\x89"
+ "\x6b\x71\x8b\x2a\x38\x3e\xcd\xac\x16\xb9"
+ "\x61\x25\x55\x3f\x41\x6f\xf3\x2c\x66\x74"
+ "\xc7\x45\x99\xa9\x00\x53\x86\xd9\xce\x11"
+ "\x12\x24\x5f\x48\xee\x47\x0d\x39\x6c\x1e"
+ "\xd6\x3b\x92\x67\x0c\xa5\x6e\xc8\x4d\xee"
+ "\xa8\x14\xb6\x13\x5e\xca\x54\x39\x2b\xde"
+ "\xdb\x94\x89\xbc\x9b\x87\x5a\x8b\xaf\x0d"
+ "\xc1\xae\x78\x57\x36\x91\x4a\xb7\xda\xa2"
+ "\x64\xbc\x07\x9d\x26\x9f\x2c\x0d\x7e\xdd"
+ "\xd8\x10\xa4\x26\x14\x5a\x07\x76\xf6\x7c"
+ "\x87\x82\x73"),
+ "0B31894EC8937AD9B91BDFBCBA294D9ADEFAA18E09305E"
+ "9F20D5C3A4",
+ 1);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_sha256) {
+ isc_md_t *md = *state;
+
+ isc_md_test(md, ISC_MD_SHA256, NULL, 0, NULL, 0);
+ isc_md_test(md, ISC_MD_SHA256, TEST_INPUT(""),
+ "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B93"
+ "4CA495991B7852B855",
+ 1);
+
+ isc_md_test(md, ISC_MD_SHA256, TEST_INPUT("abc"),
+ "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A"
+ "9CB410FF61F20015AD",
+ 1);
+ isc_md_test(md, ISC_MD_SHA256,
+ TEST_INPUT("abcdbcdecdefdefgefghfghighijhijkijkljk"
+ "lmklmnlmnomnopnopq"),
+ "248D6A61D20638B8E5C026930C3E6039A33CE45964FF21"
+ "67F6ECEDD419DB06C1",
+ 1);
+ isc_md_test(md, ISC_MD_SHA256, TEST_INPUT("a"),
+ "CDC76E5C9914FB9281A1C7E284D73E67F1809A48A49720"
+ "0E046D39CCC7112CD0",
+ 1000000);
+ isc_md_test(md, ISC_MD_SHA256,
+ TEST_INPUT("01234567012345670123456701234567"),
+ "594847328451BDFA85056225462CC1D867D877FB388DF0"
+ "CE35F25AB5562BFBB5",
+ 20);
+ isc_md_test(md, ISC_MD_SHA256, TEST_INPUT("\x19"),
+ "68AA2E2EE5DFF96E3355E6C7EE373E3D6A4E17F75F9518"
+ "D843709C0C9BC3E3D4",
+ 1);
+ isc_md_test(md, ISC_MD_SHA256,
+ TEST_INPUT("\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3"
+ "\x88\x7a\xb2\xcd\x68\x46\x52"),
+ "175EE69B02BA9B58E2B0A5FD13819CEA573F3940A94F82"
+ "5128CF4209BEABB4E8",
+ 1);
+ isc_md_test(md, ISC_MD_SHA256,
+ TEST_INPUT("\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1"
+ "\x2b\x20\x52\x7a\xfe\xf0\x4d\x8a\x05\x69"
+ "\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76"
+ "\x00\x00\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08"
+ "\x3a\xa3\x9d\x81\x0d\xb3\x10\x77\x7d\xab"
+ "\x8b\x1e\x7f\x02\xb8\x4a\x26\xc7\x73\x32"
+ "\x5f\x8b\x23\x74\xde\x7a\x4b\x5a\x58\xcb"
+ "\x5c\x5c\xf3\x5b\xce\xe6\xfb\x94\x6e\x5b"
+ "\xd6\x94\xfa\x59\x3a\x8b\xeb\x3f\x9d\x65"
+ "\x92\xec\xed\xaa\x66\xca\x82\xa2\x9d\x0c"
+ "\x51\xbc\xf9\x33\x62\x30\xe5\xd7\x84\xe4"
+ "\xc0\xa4\x3f\x8d\x79\xa3\x0a\x16\x5c\xba"
+ "\xbe\x45\x2b\x77\x4b\x9c\x71\x09\xa9\x7d"
+ "\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc"
+ "\x10\x6a\xad\x5a\x9f\xdd\x30\x82\x57\x69"
+ "\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39"
+ "\x3d\x54\xd6"),
+ "97DBCA7DF46D62C8A422C941DD7E835B8AD3361763F7E9"
+ "B2D95F4F0DA6E1CCBC",
+ 1);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_sha384) {
+ isc_md_t *md = *state;
+
+ isc_md_test(md, ISC_MD_SHA384, NULL, 0, NULL, 0);
+ isc_md_test(md, ISC_MD_SHA384, TEST_INPUT(""),
+ "38B060A751AC96384CD9327EB1B1E36A21FDB71114BE07"
+ "434C0CC7BF63F6E1DA274EDEBFE76F65FBD51AD2F14898"
+ "B95B"
+ "",
+ 1);
+ isc_md_test(md, ISC_MD_SHA384, TEST_INPUT("abc"),
+ "CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1"
+ "631A8B605A43FF5BED8086072BA1E7CC2358BAEC"
+ "A134C825A7",
+ 1);
+ isc_md_test(md, ISC_MD_SHA384,
+ TEST_INPUT("abcdefghbcdefghicdefghijdefghijkefghijkl"
+ "fghijklmghijklmnhijklmnoijklmnopjklmnopq"
+ "klmnopqrlmnopqrsmnopqrstnopqrstu"),
+ "09330C33F71147E83D192FC782CD1B4753111B173B3B05"
+ "D22FA08086E3B0F712FCC7C71A557E2DB966C3E9"
+ "FA91746039",
+ 1);
+ isc_md_test(md, ISC_MD_SHA384, TEST_INPUT("a"),
+ "9D0E1809716474CB086E834E310A4A1CED149E9C00F248"
+ "527972CEC5704C2A5B07B8B3DC38ECC4EBAE97DD"
+ "D87F3D8985",
+ 1000000);
+ isc_md_test(md, ISC_MD_SHA384,
+ TEST_INPUT("01234567012345670123456701234567"),
+ "2FC64A4F500DDB6828F6A3430B8DD72A368EB7F3A8322A"
+ "70BC84275B9C0B3AB00D27A5CC3C2D224AA6B61A"
+ "0D79FB4596",
+ 20);
+ isc_md_test(md, ISC_MD_SHA384, TEST_INPUT("\xb9"),
+ "BC8089A19007C0B14195F4ECC74094FEC64F01F9092928"
+ "2C2FB392881578208AD466828B1C6C283D2722CF"
+ "0AD1AB6938",
+ 1);
+ isc_md_test(md, ISC_MD_SHA384,
+ TEST_INPUT("\xa4\x1c\x49\x77\x79\xc0\x37\x5f\xf1"
+ "\x0a\x7f\x4e\x08\x59\x17\x39"),
+ "C9A68443A005812256B8EC76B00516F0DBB74FAB26D665"
+ "913F194B6FFB0E91EA9967566B58109CBC675CC2"
+ "08E4C823F7",
+ 1);
+ isc_md_test(md, ISC_MD_SHA384,
+ TEST_INPUT("\x39\x96\x69\xe2\x8f\x6b\x9c\x6d\xbc\xbb"
+ "\x69\x12\xec\x10\xff\xcf\x74\x79\x03\x49"
+ "\xb7\xdc\x8f\xbe\x4a\x8e\x7b\x3b\x56\x21"
+ "\xdb\x0f\x3e\x7d\xc8\x7f\x82\x32\x64\xbb"
+ "\xe4\x0d\x18\x11\xc9\xea\x20\x61\xe1\xc8"
+ "\x4a\xd1\x0a\x23\xfa\xc1\x72\x7e\x72\x02"
+ "\xfc\x3f\x50\x42\xe6\xbf\x58\xcb\xa8\xa2"
+ "\x74\x6e\x1f\x64\xf9\xb9\xea\x35\x2c\x71"
+ "\x15\x07\x05\x3c\xf4\xe5\x33\x9d\x52\x86"
+ "\x5f\x25\xcc\x22\xb5\xe8\x77\x84\xa1\x2f"
+ "\xc9\x61\xd6\x6c\xb6\xe8\x95\x73\x19\x9a"
+ "\x2c\xe6\x56\x5c\xbd\xf1\x3d\xca\x40\x38"
+ "\x32\xcf\xcb\x0e\x8b\x72\x11\xe8\x3a\xf3"
+ "\x2a\x11\xac\x17\x92\x9f\xf1\xc0\x73\xa5"
+ "\x1c\xc0\x27\xaa\xed\xef\xf8\x5a\xad\x7c"
+ "\x2b\x7c\x5a\x80\x3e\x24\x04\xd9\x6d\x2a"
+ "\x77\x35\x7b\xda\x1a\x6d\xae\xed\x17\x15"
+ "\x1c\xb9\xbc\x51\x25\xa4\x22\xe9\x41\xde"
+ "\x0c\xa0\xfc\x50\x11\xc2\x3e\xcf\xfe\xfd"
+ "\xd0\x96\x76\x71\x1c\xf3\xdb\x0a\x34\x40"
+ "\x72\x0e\x16\x15\xc1\xf2\x2f\xbc\x3c\x72"
+ "\x1d\xe5\x21\xe1\xb9\x9b\xa1\xbd\x55\x77"
+ "\x40\x86\x42\x14\x7e\xd0\x96"),
+ "4F440DB1E6EDD2899FA335F09515AA025EE177A79F4B4A"
+ "AF38E42B5C4DE660F5DE8FB2A5B2FBD2A3CBFFD2"
+ "0CFF1288C0",
+ 1);
+}
+
+ISC_RUN_TEST_IMPL(isc_md_sha512) {
+ isc_md_t *md = *state;
+
+ isc_md_test(md, ISC_MD_SHA512, NULL, 0, NULL, 0);
+ isc_md_test(md, ISC_MD_SHA512, TEST_INPUT(""),
+ "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715"
+ "DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877E"
+ "EC2F63B931BD47417A81A538327AF927DA3E",
+ 1);
+ isc_md_test(md, ISC_MD_SHA512, TEST_INPUT("abc"),
+ "DDAF35A193617ABACC417349AE20413112E6FA4E89A97E"
+ "A20A9EEEE64B55D39A2192992A274FC1A836BA3C"
+ "23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F",
+ 1);
+ isc_md_test(md, ISC_MD_SHA512,
+ TEST_INPUT("abcdefghbcdefghicdefghijdefghijkefghijkl"
+ "fghijklmghijklmnhijklmnoijklmnopjklmnopq"
+ "klmnopqrlmnopqrsmnopqrstnopqrstu"),
+ "8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7F"
+ "A17299AEADB6889018501D289E4900F7E4331B99"
+ "DEC4B5433AC7D329EEB6DD26545E96E55B874BE909",
+ 1);
+ isc_md_test(md, ISC_MD_SHA512, TEST_INPUT("a"),
+ "E718483D0CE769644E2E42C7BC15B4638E1F98B13B2044"
+ "285632A803AFA973EBDE0FF244877EA60A4CB043"
+ "2CE577C31BEB009C5C2C49AA2E4EADB217AD8CC09B",
+ 1000000);
+ isc_md_test(md, ISC_MD_SHA512,
+ TEST_INPUT("01234567012345670123456701234567"),
+ "89D05BA632C699C31231DED4FFC127D5A894DAD412C0E0"
+ "24DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF"
+ "33C765CB510813A39CD5A84C4ACAA64D3F3FB7BAE9",
+ 20);
+ isc_md_test(md, ISC_MD_SHA512, TEST_INPUT("\xD0"),
+ "9992202938E882E73E20F6B69E68A0A7149090423D93C8"
+ "1BAB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA"
+ "8306826C4AD6E74CECE9631BFA8A549B4AB3FBBA15",
+ 1);
+ isc_md_test(md, ISC_MD_SHA512,
+ TEST_INPUT("\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81"
+ "\x6e\x9d\x98\xbf\xf0\xa0"),
+ "CB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75AC"
+ "BDD1C153C9828924C3DDEDAAFE669C5FDD0BC66F"
+ "630F6773988213EB1B16F517AD0DE4B2F0C95C90F8",
+ 1);
+ isc_md_test(md, ISC_MD_SHA512,
+ TEST_INPUT("\xa5\x5f\x20\xc4\x11\xaa\xd1\x32\x80\x7a"
+ "\x50\x2d\x65\x82\x4e\x31\xa2\x30\x54\x32"
+ "\xaa\x3d\x06\xd3\xe2\x82\xa8\xd8\x4e\x0d"
+ "\xe1\xde\x69\x74\xbf\x49\x54\x69\xfc\x7f"
+ "\x33\x8f\x80\x54\xd5\x8c\x26\xc4\x93\x60"
+ "\xc3\xe8\x7a\xf5\x65\x23\xac\xf6\xd8\x9d"
+ "\x03\xe5\x6f\xf2\xf8\x68\x00\x2b\xc3\xe4"
+ "\x31\xed\xc4\x4d\xf2\xf0\x22\x3d\x4b\xb3"
+ "\xb2\x43\x58\x6e\x1a\x7d\x92\x49\x36\x69"
+ "\x4f\xcb\xba\xf8\x8d\x95\x19\xe4\xeb\x50"
+ "\xa6\x44\xf8\xe4\xf9\x5e\xb0\xea\x95\xbc"
+ "\x44\x65\xc8\x82\x1a\xac\xd2\xfe\x15\xab"
+ "\x49\x81\x16\x4b\xbb\x6d\xc3\x2f\x96\x90"
+ "\x87\xa1\x45\xb0\xd9\xcc\x9c\x67\xc2\x2b"
+ "\x76\x32\x99\x41\x9c\xc4\x12\x8b\xe9\xa0"
+ "\x77\xb3\xac\xe6\x34\x06\x4e\x6d\x99\x28"
+ "\x35\x13\xdc\x06\xe7\x51\x5d\x0d\x73\x13"
+ "\x2e\x9a\x0d\xc6\xd3\xb1\xf8\xb2\x46\xf1"
+ "\xa9\x8a\x3f\xc7\x29\x41\xb1\xe3\xbb\x20"
+ "\x98\xe8\xbf\x16\xf2\x68\xd6\x4f\x0b\x0f"
+ "\x47\x07\xfe\x1e\xa1\xa1\x79\x1b\xa2\xf3"
+ "\xc0\xc7\x58\xe5\xf5\x51\x86\x3a\x96\xc9"
+ "\x49\xad\x47\xd7\xfb\x40\xd2"),
+ "C665BEFB36DA189D78822D10528CBF3B12B3EEF7260399"
+ "09C1A16A270D48719377966B957A878E72058477"
+ "9A62825C18DA26415E49A7176A894E7510FD1451F5",
+ 1);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_md_new)
+
+ISC_TEST_ENTRY_CUSTOM(isc_md_init, _reset, _reset)
+
+ISC_TEST_ENTRY_CUSTOM(isc_md_reset, _reset, _reset)
+
+ISC_TEST_ENTRY(isc_md_md5)
+ISC_TEST_ENTRY(isc_md_sha1)
+
+ISC_TEST_ENTRY(isc_md_sha224)
+ISC_TEST_ENTRY(isc_md_sha256)
+ISC_TEST_ENTRY(isc_md_sha384)
+ISC_TEST_ENTRY(isc_md_sha512)
+
+ISC_TEST_ENTRY_CUSTOM(isc_md_update, _reset, _reset)
+ISC_TEST_ENTRY_CUSTOM(isc_md_final, _reset, _reset)
+
+ISC_TEST_ENTRY(isc_md_free)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN_CUSTOM(_setup, _teardown)
diff --git a/tests/isc/mem_test.c b/tests/isc/mem_test.c
new file mode 100644
index 0000000..f2bbdbd
--- /dev/null
+++ b/tests/isc/mem_test.c
@@ -0,0 +1,521 @@
+/*
+ * 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 <fcntl.h>
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/atomic.h>
+#include <isc/file.h>
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/os.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/stdio.h>
+#include <isc/thread.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include "mem_p.h"
+
+#include <tests/isc.h>
+
+#define MP1_FREEMAX 10
+#define MP1_FILLCNT 10
+#define MP1_MAXALLOC 30
+
+#define MP2_FREEMAX 25
+#define MP2_FILLCNT 25
+
+/* general memory system tests */
+ISC_RUN_TEST_IMPL(isc_mem) {
+ void *items1[50];
+ void *items2[50];
+ void *tmp;
+ isc_mempool_t *mp1 = NULL, *mp2 = NULL;
+ unsigned int i, j;
+ int rval;
+
+ UNUSED(state);
+
+ isc_mempool_create(mctx, 24, &mp1);
+ isc_mempool_create(mctx, 31, &mp2);
+
+ isc_mempool_setfreemax(mp1, MP1_FREEMAX);
+ isc_mempool_setfillcount(mp1, MP1_FILLCNT);
+
+ /*
+ * Allocate MP1_MAXALLOC items from the pool. This is our max.
+ */
+ for (i = 0; i < MP1_MAXALLOC; i++) {
+ items1[i] = isc_mempool_get(mp1);
+ assert_non_null(items1[i]);
+ }
+
+ /*
+ * 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;
+ }
+
+#if !__SANITIZE_ADDRESS__
+ rval = isc_mempool_getfreecount(mp1);
+ assert_int_equal(rval, 10);
+#endif /* !__SANITIZE_ADDRESS__ */
+
+ rval = isc_mempool_getallocated(mp1);
+ assert_int_equal(rval, 19);
+
+ /*
+ * 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 < 500000; j++) {
+ for (i = 0; i < 50; i++) {
+ items2[i] = isc_mempool_get(mp2);
+ assert_non_null(items2[i]);
+ }
+ 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 < MP1_MAXALLOC; i++) {
+ isc_mempool_put(mp1, items1[i]);
+ items1[i] = NULL;
+ }
+
+ isc_mempool_destroy(&mp1);
+ isc_mempool_destroy(&mp2);
+
+ isc_mempool_create(mctx, 2, &mp1);
+
+ tmp = isc_mempool_get(mp1);
+ assert_non_null(tmp);
+
+ isc_mempool_put(mp1, tmp);
+
+ isc_mempool_destroy(&mp1);
+}
+
+#if defined(HAVE_MALLOC_NP_H) || defined(HAVE_JEMALLOC)
+/* aligned memory system tests */
+ISC_RUN_TEST_IMPL(isc_mem_aligned) {
+ isc_mem_t *mctx2 = NULL;
+ void *ptr;
+ size_t alignment;
+ uintptr_t aligned;
+
+ UNUSED(state);
+
+ /* Check different alignment sizes up to the page size */
+ for (alignment = sizeof(void *); alignment <= 4096; alignment *= 2) {
+ size_t size = alignment / 2 - 1;
+ ptr = isc_mem_get_aligned(mctx, size, alignment);
+
+ /* Check if the pointer is properly aligned */
+ aligned = (((uintptr_t)ptr / alignment) * alignment);
+ assert_ptr_equal(aligned, (uintptr_t)ptr);
+
+ /* Check if we can resize to <alignment, 2*alignment> range */
+ ptr = isc_mem_reget_aligned(mctx, ptr, size,
+ size * 2 + alignment, alignment);
+
+ /* Check if the pointer is still properly aligned */
+ aligned = (((uintptr_t)ptr / alignment) * alignment);
+ assert_ptr_equal(aligned, (uintptr_t)ptr);
+
+ isc_mem_put_aligned(mctx, ptr, size * 2 + alignment, alignment);
+
+ /* Check whether isc_mem_putanddetach_detach() also works */
+ isc_mem_create(&mctx2);
+ ptr = isc_mem_get_aligned(mctx2, size, alignment);
+ isc_mem_putanddetach_aligned(&mctx2, ptr, size, alignment);
+ }
+}
+#endif /* defined(HAVE_MALLOC_NP_H) || defined(HAVE_JEMALLOC) */
+
+/* test TotalUse calculation */
+ISC_RUN_TEST_IMPL(isc_mem_total) {
+ isc_mem_t *mctx2 = NULL;
+ size_t before, after;
+ ssize_t diff;
+ int i;
+
+ UNUSED(state);
+
+ /* Local alloc, free */
+ mctx2 = NULL;
+ isc_mem_create(&mctx2);
+
+ before = isc_mem_total(mctx2);
+
+ for (i = 0; i < 100000; i++) {
+ void *ptr;
+
+ ptr = isc_mem_get(mctx2, 2048);
+ isc_mem_put(mctx2, ptr, 2048);
+ }
+
+ after = isc_mem_total(mctx2);
+ diff = after - before;
+
+ assert_int_equal(diff, (2048) * 100000);
+
+ /* ISC_MEMFLAG_INTERNAL */
+
+ before = isc_mem_total(mctx);
+
+ for (i = 0; i < 100000; i++) {
+ void *ptr;
+
+ ptr = isc_mem_get(mctx, 2048);
+ isc_mem_put(mctx, ptr, 2048);
+ }
+
+ after = isc_mem_total(mctx);
+ diff = after - before;
+
+ assert_int_equal(diff, (2048) * 100000);
+
+ isc_mem_destroy(&mctx2);
+}
+
+/* test InUse calculation */
+ISC_RUN_TEST_IMPL(isc_mem_inuse) {
+ isc_mem_t *mctx2 = NULL;
+ size_t before, after;
+ ssize_t diff;
+ void *ptr;
+
+ UNUSED(state);
+
+ mctx2 = NULL;
+ isc_mem_create(&mctx2);
+
+ before = isc_mem_inuse(mctx2);
+ ptr = isc_mem_allocate(mctx2, 1024000);
+ isc_mem_free(mctx2, ptr);
+ after = isc_mem_inuse(mctx2);
+
+ diff = after - before;
+
+ assert_int_equal(diff, 0);
+
+ isc_mem_destroy(&mctx2);
+}
+
+ISC_RUN_TEST_IMPL(isc_mem_zeroget) {
+ uint8_t *data = NULL;
+ UNUSED(state);
+
+ data = isc_mem_get(mctx, 0);
+ assert_non_null(data);
+ isc_mem_put(mctx, data, 0);
+}
+
+#define REGET_INIT_SIZE 1024
+#define REGET_GROW_SIZE 2048
+#define REGET_SHRINK_SIZE 512
+
+ISC_RUN_TEST_IMPL(isc_mem_reget) {
+ uint8_t *data = NULL;
+
+ UNUSED(state);
+
+ /* test that we can reget NULL */
+ data = isc_mem_reget(mctx, NULL, 0, REGET_INIT_SIZE);
+ assert_non_null(data);
+ isc_mem_put(mctx, data, REGET_INIT_SIZE);
+
+ /* test that we can re-get a zero-length allocation */
+ data = isc_mem_get(mctx, 0);
+ assert_non_null(data);
+
+ data = isc_mem_reget(mctx, data, 0, REGET_INIT_SIZE);
+ assert_non_null(data);
+
+ for (size_t i = 0; i < REGET_INIT_SIZE; i++) {
+ data[i] = i % UINT8_MAX;
+ }
+
+ data = isc_mem_reget(mctx, data, REGET_INIT_SIZE, REGET_GROW_SIZE);
+ assert_non_null(data);
+
+ for (size_t i = 0; i < REGET_INIT_SIZE; i++) {
+ assert_int_equal(data[i], i % UINT8_MAX);
+ }
+
+ for (size_t i = REGET_GROW_SIZE; i > 0; i--) {
+ data[i - 1] = i % UINT8_MAX;
+ }
+
+ data = isc_mem_reget(mctx, data, REGET_GROW_SIZE, REGET_SHRINK_SIZE);
+ assert_non_null(data);
+
+ for (size_t i = REGET_SHRINK_SIZE; i > 0; i--) {
+ assert_int_equal(data[i - 1], i % UINT8_MAX);
+ }
+
+ isc_mem_put(mctx, data, REGET_SHRINK_SIZE);
+}
+
+#if ISC_MEM_TRACKLINES
+
+/* test mem with no flags */
+ISC_RUN_TEST_IMPL(isc_mem_noflags) {
+ isc_result_t result;
+ isc_mem_t *mctx2 = NULL;
+ char buf[4096], *p, *q;
+ FILE *f;
+ void *ptr;
+
+ result = isc_stdio_open("mem.output", "w", &f);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ UNUSED(state);
+
+ isc_mem_create(&mctx2);
+ isc_mem_debugging = 0;
+ ptr = isc_mem_get(mctx2, 2048);
+ assert_non_null(ptr);
+ isc__mem_printactive(mctx2, f);
+ isc_mem_put(mctx2, ptr, 2048);
+ isc_mem_destroy(&mctx2);
+ isc_stdio_close(f);
+
+ memset(buf, 0, sizeof(buf));
+ result = isc_stdio_open("mem.output", "r", &f);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_stdio_read(buf, sizeof(buf), 1, f, NULL);
+ assert_int_equal(result, ISC_R_EOF);
+ isc_stdio_close(f);
+ isc_file_remove("mem.output");
+
+ buf[sizeof(buf) - 1] = 0;
+
+ p = strchr(buf, '\n');
+ assert_non_null(p);
+ assert_in_range(p, 0, buf + sizeof(buf) - 3);
+ p += 2;
+ q = strchr(p, '\n');
+ assert_non_null(q);
+ *q = '\0';
+ assert_string_equal(p, "None.");
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+}
+
+/* test mem with record flag */
+ISC_RUN_TEST_IMPL(isc_mem_recordflag) {
+ isc_result_t result;
+ isc_mem_t *mctx2 = NULL;
+ char buf[4096], *p;
+ FILE *f;
+ void *ptr;
+
+ result = isc_stdio_open("mem.output", "w", &f);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ UNUSED(state);
+
+ isc_mem_create(&mctx2);
+ ptr = isc_mem_get(mctx2, 2048);
+ assert_non_null(ptr);
+ isc__mem_printactive(mctx2, f);
+ isc_mem_put(mctx2, ptr, 2048);
+ isc_mem_destroy(&mctx2);
+ isc_stdio_close(f);
+
+ memset(buf, 0, sizeof(buf));
+ result = isc_stdio_open("mem.output", "r", &f);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_stdio_read(buf, sizeof(buf), 1, f, NULL);
+ assert_int_equal(result, ISC_R_EOF);
+ isc_stdio_close(f);
+ isc_file_remove("mem.output");
+
+ buf[sizeof(buf) - 1] = 0;
+
+ p = strchr(buf, '\n');
+ assert_non_null(p);
+ assert_in_range(p, 0, buf + sizeof(buf) - 3);
+ assert_memory_equal(p + 2, "ptr ", 4);
+ p = strchr(p + 1, '\n');
+ assert_non_null(p);
+ assert_int_equal(strlen(p), 1);
+}
+
+/* test mem with trace flag */
+ISC_RUN_TEST_IMPL(isc_mem_traceflag) {
+ isc_result_t result;
+ isc_mem_t *mctx2 = NULL;
+ char buf[4096], *p;
+ FILE *f;
+ void *ptr;
+
+ /* redirect stderr so we can check trace output */
+ f = freopen("mem.output", "w", stderr);
+ assert_non_null(f);
+
+ UNUSED(state);
+
+ isc_mem_create(&mctx2);
+ isc_mem_debugging = ISC_MEM_DEBUGTRACE;
+ ptr = isc_mem_get(mctx2, 2048);
+ assert_non_null(ptr);
+ isc__mem_printactive(mctx2, f);
+ isc_mem_put(mctx2, ptr, 2048);
+ isc_mem_destroy(&mctx2);
+ isc_stdio_close(f);
+
+ memset(buf, 0, sizeof(buf));
+ result = isc_stdio_open("mem.output", "r", &f);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_stdio_read(buf, sizeof(buf), 1, f, NULL);
+ assert_int_equal(result, ISC_R_EOF);
+ isc_stdio_close(f);
+ isc_file_remove("mem.output");
+
+ /* return stderr to TTY so we can see errors */
+ f = freopen("/dev/tty", "w", stderr);
+
+ buf[sizeof(buf) - 1] = 0;
+
+ assert_memory_equal(buf, "add ", 4);
+ p = strchr(buf, '\n');
+ assert_non_null(p);
+ p = strchr(p + 1, '\n');
+ assert_non_null(p);
+ assert_in_range(p, 0, buf + sizeof(buf) - 3);
+ assert_memory_equal(p + 2, "ptr ", 4);
+ p = strchr(p + 1, '\n');
+ assert_non_null(p);
+ assert_memory_equal(p + 1, "del ", 4);
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+}
+#endif /* if ISC_MEM_TRACKLINES */
+
+#if !defined(__SANITIZE_THREAD__)
+
+#define ITERS 512
+#define NUM_ITEMS 1024 /* 768 */
+#define ITEM_SIZE 65534
+
+static atomic_size_t mem_size;
+
+static isc_threadresult_t
+mem_thread(isc_threadarg_t arg) {
+ isc_mem_t *mctx2 = (isc_mem_t *)arg;
+ void *items[NUM_ITEMS];
+ size_t size = atomic_load(&mem_size);
+ while (!atomic_compare_exchange_weak(&mem_size, &size, size / 2)) {
+ ;
+ }
+
+ for (int i = 0; i < ITERS; i++) {
+ for (int j = 0; j < NUM_ITEMS; j++) {
+ items[j] = isc_mem_get(mctx2, size);
+ }
+ for (int j = 0; j < NUM_ITEMS; j++) {
+ isc_mem_put(mctx2, items[j], size);
+ }
+ }
+
+ return ((isc_threadresult_t)0);
+}
+
+ISC_RUN_TEST_IMPL(isc_mem_benchmark) {
+ int nthreads = ISC_MAX(ISC_MIN(isc_os_ncpus(), 32), 1);
+ isc_thread_t threads[32];
+ isc_time_t ts1, ts2;
+ double t;
+ isc_result_t result;
+
+ UNUSED(state);
+
+ atomic_init(&mem_size, ITEM_SIZE);
+
+ result = isc_time_now(&ts1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (int i = 0; i < nthreads; i++) {
+ isc_thread_create(mem_thread, mctx, &threads[i]);
+ }
+ for (int i = 0; i < nthreads; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ result = isc_time_now(&ts2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ t = isc_time_microdiff(&ts2, &ts1);
+
+ printf("[ TIME ] isc_mem_benchmark: "
+ "%d isc_mem_{get,put} calls, %f seconds, %f "
+ "calls/second\n",
+ nthreads * ITERS * NUM_ITEMS, t / 1000000.0,
+ (nthreads * ITERS * NUM_ITEMS) / (t / 1000000.0));
+}
+
+#endif /* __SANITIZE_THREAD */
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_mem)
+#if defined(HAVE_MALLOC_NP_H) || defined(HAVE_JEMALLOC)
+ISC_TEST_ENTRY(isc_mem_aligned)
+#endif /* defined(HAVE_MALLOC_NP_H) || defined(HAVE_JEMALLOC) */
+ISC_TEST_ENTRY(isc_mem_total)
+ISC_TEST_ENTRY(isc_mem_inuse)
+ISC_TEST_ENTRY(isc_mem_zeroget)
+ISC_TEST_ENTRY(isc_mem_reget)
+
+#if !defined(__SANITIZE_THREAD__)
+ISC_TEST_ENTRY(isc_mem_benchmark)
+#endif /* __SANITIZE_THREAD__ */
+#if ISC_MEM_TRACKLINES
+ISC_TEST_ENTRY(isc_mem_noflags)
+ISC_TEST_ENTRY(isc_mem_recordflag)
+/*
+ * traceflag_test closes stderr, which causes weird
+ * side effects for any next test trying to use libuv.
+ * This test has to be the last one to avoid problems.
+ */
+ISC_TEST_ENTRY(isc_mem_traceflag)
+#endif /* if ISC_MEM_TRACKLINES */
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/netaddr_test.c b/tests/isc/netaddr_test.c
new file mode 100644
index 0000000..2394e11
--- /dev/null
+++ b/tests/isc/netaddr_test.c
@@ -0,0 +1,145 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/netaddr.h>
+#include <isc/sockaddr.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* test isc_netaddr_isnetzero() */
+ISC_RUN_TEST_IMPL(netaddr_isnetzero) {
+ unsigned int i;
+ struct in_addr ina;
+ struct {
+ const char *address;
+ bool expect;
+ } tests[] = { { "0.0.0.0", true }, { "0.0.0.1", true },
+ { "0.0.1.2", true }, { "0.1.2.3", true },
+ { "10.0.0.0", false }, { "10.9.0.0", false },
+ { "10.9.8.0", false }, { "10.9.8.7", false },
+ { "127.0.0.0", false }, { "127.0.0.1", false } };
+ isc_netaddr_t netaddr;
+
+ UNUSED(state);
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ bool result;
+ ina.s_addr = inet_addr(tests[i].address);
+ isc_netaddr_fromin(&netaddr, &ina);
+ result = isc_netaddr_isnetzero(&netaddr);
+ assert_int_equal(result, tests[i].expect);
+ }
+}
+
+/* test isc_netaddr_masktoprefixlen() calculates correct prefix lengths */
+ISC_RUN_TEST_IMPL(netaddr_masktoprefixlen) {
+ struct in_addr na_a;
+ struct in_addr na_b;
+ struct in_addr na_c;
+ struct in_addr na_d;
+ isc_netaddr_t ina_a;
+ isc_netaddr_t ina_b;
+ isc_netaddr_t ina_c;
+ isc_netaddr_t ina_d;
+ unsigned int plen;
+
+ UNUSED(state);
+
+ assert_true(inet_pton(AF_INET, "0.0.0.0", &na_a) >= 0);
+ assert_true(inet_pton(AF_INET, "255.255.255.254", &na_b) >= 0);
+ assert_true(inet_pton(AF_INET, "255.255.255.255", &na_c) >= 0);
+ assert_true(inet_pton(AF_INET, "255.255.255.0", &na_d) >= 0);
+
+ isc_netaddr_fromin(&ina_a, &na_a);
+ isc_netaddr_fromin(&ina_b, &na_b);
+ isc_netaddr_fromin(&ina_c, &na_c);
+ isc_netaddr_fromin(&ina_d, &na_d);
+
+ assert_int_equal(isc_netaddr_masktoprefixlen(&ina_a, &plen),
+ ISC_R_SUCCESS);
+ assert_int_equal(plen, 0);
+
+ assert_int_equal(isc_netaddr_masktoprefixlen(&ina_b, &plen),
+ ISC_R_SUCCESS);
+ assert_int_equal(plen, 31);
+
+ assert_int_equal(isc_netaddr_masktoprefixlen(&ina_c, &plen),
+ ISC_R_SUCCESS);
+ assert_int_equal(plen, 32);
+
+ assert_int_equal(isc_netaddr_masktoprefixlen(&ina_d, &plen),
+ ISC_R_SUCCESS);
+ assert_int_equal(plen, 24);
+}
+
+/* check multicast addresses are detected properly */
+ISC_RUN_TEST_IMPL(netaddr_multicast) {
+ unsigned int i;
+ struct {
+ int family;
+ const char *addr;
+ bool is_multicast;
+ } tests[] = {
+ { AF_INET, "1.2.3.4", false }, { AF_INET, "4.3.2.1", false },
+ { AF_INET, "224.1.1.1", true }, { AF_INET, "1.1.1.244", false },
+ { AF_INET6, "::1", false }, { AF_INET6, "ff02::1", true }
+ };
+
+ UNUSED(state);
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ isc_netaddr_t na;
+ struct in_addr in;
+ struct in6_addr in6;
+ int r;
+
+ if (tests[i].family == AF_INET) {
+ r = inet_pton(AF_INET, tests[i].addr,
+ (unsigned char *)&in);
+ assert_int_equal(r, 1);
+ isc_netaddr_fromin(&na, &in);
+ } else {
+ r = inet_pton(AF_INET6, tests[i].addr,
+ (unsigned char *)&in6);
+ assert_int_equal(r, 1);
+ isc_netaddr_fromin6(&na, &in6);
+ }
+
+ assert_int_equal(isc_netaddr_ismulticast(&na),
+ tests[i].is_multicast);
+ }
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(netaddr_isnetzero)
+ISC_TEST_ENTRY(netaddr_masktoprefixlen)
+ISC_TEST_ENTRY(netaddr_multicast)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/netmgr_test.c b/tests/isc/netmgr_test.c
new file mode 100644
index 0000000..a20db6b
--- /dev/null
+++ b/tests/isc/netmgr_test.c
@@ -0,0 +1,2897 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <uv.h>
+
+/*
+ * As a workaround, include an OpenSSL header file before including cmocka.h,
+ * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a
+ * redefined malloc in cmocka.h.
+ */
+#include <openssl/err.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/nonce.h>
+#include <isc/os.h>
+#include <isc/quota.h>
+#include <isc/refcount.h>
+#include <isc/sockaddr.h>
+#include <isc/thread.h>
+#include <isc/tls.h>
+#include <isc/util.h>
+
+#include "uv_wrap.h"
+#define KEEP_BEFORE
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include "netmgr/netmgr-int.h"
+#include "netmgr/udp.c"
+#include "netmgr/uv-compat.c"
+#include "netmgr/uv-compat.h"
+#include "netmgr_p.h"
+#pragma GCC diagnostic pop
+
+#include <tests/isc.h>
+
+typedef void (*stream_connect_function)(isc_nm_t *nm);
+
+static void
+connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg);
+static void
+connect_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *cbarg);
+
+isc_nm_t *listen_nm = NULL;
+isc_nm_t *connect_nm = NULL;
+
+static isc_sockaddr_t udp_listen_addr;
+static isc_sockaddr_t udp_connect_addr;
+
+static isc_sockaddr_t tcp_listen_addr;
+static isc_sockaddr_t tcp_connect_addr;
+static isc_tlsctx_t *tcp_listen_tlsctx = NULL;
+static isc_tlsctx_t *tcp_connect_tlsctx = NULL;
+static isc_tlsctx_client_session_cache_t *tcp_tlsctx_client_sess_cache = NULL;
+
+static uint64_t send_magic = 0;
+static uint64_t stop_magic = 0;
+
+static isc_region_t send_msg = { .base = (unsigned char *)&send_magic,
+ .length = sizeof(send_magic) };
+
+static isc_region_t stop_msg = { .base = (unsigned char *)&stop_magic,
+ .length = sizeof(stop_magic) };
+
+static atomic_bool do_send = false;
+
+static atomic_int_fast64_t nsends;
+static int_fast64_t esends; /* expected sends */
+
+static atomic_int_fast64_t ssends = 0;
+static atomic_int_fast64_t sreads = 0;
+static atomic_int_fast64_t saccepts = 0;
+
+static atomic_int_fast64_t cconnects = 0;
+static atomic_int_fast64_t csends = 0;
+static atomic_int_fast64_t creads = 0;
+static atomic_int_fast64_t ctimeouts = 0;
+
+static isc_refcount_t active_cconnects;
+static isc_refcount_t active_csends;
+static isc_refcount_t active_creads;
+static isc_refcount_t active_ssends;
+static isc_refcount_t active_sreads;
+
+static isc_quota_t listener_quota;
+static atomic_bool check_listener_quota;
+
+static bool skip_long_tests = false;
+
+static bool allow_send_back = false;
+static bool noanswer = false;
+static bool stream_use_TLS = false;
+
+static isc_nm_recv_cb_t connect_readcb = NULL;
+
+#define SKIP_IN_CI \
+ if (skip_long_tests) { \
+ skip(); \
+ return; \
+ }
+
+#define NSENDS 100
+
+/* Timeout for soft-timeout tests (0.05 seconds) */
+#define T_SOFT 50
+
+/* Timeouts in miliseconds */
+#define T_INIT 120 * 1000
+#define T_IDLE 120 * 1000
+#define T_KEEPALIVE 120 * 1000
+#define T_ADVERTISED 120 * 1000
+#define T_CONNECT 30 * 1000
+
+/* Wait for 1 second (1000 milliseconds) */
+#define WAIT_REPEATS 1000
+#define T_WAIT 1 /* 1 millisecond */
+
+#define WAIT_FOR(v, op, val) \
+ { \
+ X(v); \
+ int_fast64_t __r = WAIT_REPEATS; \
+ int_fast64_t __o = 0; \
+ do { \
+ int_fast64_t __l = atomic_load(&v); \
+ if (__l op val) { \
+ break; \
+ }; \
+ if (__o == __l) { \
+ __r--; \
+ } else { \
+ __r = WAIT_REPEATS; \
+ } \
+ __o = __l; \
+ isc_test_nap(T_WAIT); \
+ } while (__r > 0); \
+ X(v); \
+ P(__r); \
+ assert_true(atomic_load(&v) op val); \
+ }
+
+#define WAIT_FOR_EQ(v, val) WAIT_FOR(v, ==, val)
+#define WAIT_FOR_NE(v, val) WAIT_FOR(v, !=, val)
+#define WAIT_FOR_LE(v, val) WAIT_FOR(v, <=, val)
+#define WAIT_FOR_LT(v, val) WAIT_FOR(v, <, val)
+#define WAIT_FOR_GE(v, val) WAIT_FOR(v, >=, val)
+#define WAIT_FOR_GT(v, val) WAIT_FOR(v, >, val)
+
+#define DONE() atomic_store(&do_send, false);
+
+#define CHECK_RANGE_FULL(v) \
+ { \
+ int __v = atomic_load(&v); \
+ assert_true(__v > 1); \
+ }
+
+#define CHECK_RANGE_HALF(v) \
+ { \
+ int __v = atomic_load(&v); \
+ assert_true(__v > 1); \
+ }
+
+/* Enable this to print values while running tests */
+#undef PRINT_DEBUG
+#ifdef PRINT_DEBUG
+#define X(v) \
+ fprintf(stderr, "%s:%s:%d:%s = %" PRId64 "\n", __func__, __FILE__, \
+ __LINE__, #v, atomic_load(&v))
+#define P(v) fprintf(stderr, #v " = %" PRId64 "\n", v)
+#define F() \
+ fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, \
+ isc_result_totext(eresult), cbarg)
+#else
+#define X(v)
+#define P(v)
+#define F()
+#endif
+
+#define atomic_assert_int_eq(val, exp) assert_int_equal(atomic_load(&val), exp)
+#define atomic_assert_int_ne(val, exp) \
+ assert_int_not_equal(atomic_load(&val), exp)
+#define atomic_assert_int_le(val, exp) assert_true(atomic_load(&val) <= exp)
+#define atomic_assert_int_lt(val, exp) assert_true(atomic_load(&val) > exp)
+#define atomic_assert_int_ge(val, exp) assert_true(atomic_load(&val) >= exp)
+#define atomic_assert_int_gt(val, exp) assert_true(atomic_load(&val) > exp)
+
+static int
+setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
+ socklen_t addrlen = sizeof(*addr);
+ uv_os_sock_t fd;
+ int r;
+
+ isc_sockaddr_fromin6(addr, &in6addr_loopback, 0);
+
+ fd = socket(AF_INET6, family, 0);
+ if (fd < 0) {
+ perror("setup_ephemeral_port: socket()");
+ return (-1);
+ }
+
+ r = bind(fd, (const struct sockaddr *)&addr->type.sa,
+ sizeof(addr->type.sin6));
+ if (r != 0) {
+ perror("setup_ephemeral_port: bind()");
+ isc__nm_closesocket(fd);
+ return (r);
+ }
+
+ r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen);
+ if (r != 0) {
+ perror("setup_ephemeral_port: getsockname()");
+ isc__nm_closesocket(fd);
+ return (r);
+ }
+
+#if IPV6_RECVERR
+#define setsockopt_on(socket, level, name) \
+ setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
+
+ r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR);
+ if (r != 0) {
+ perror("setup_ephemeral_port");
+ isc__nm_closesocket(fd);
+ return (r);
+ }
+#endif
+
+ return (fd);
+}
+
+static int
+setup_test(void **state __attribute__((unused))) {
+ char *env_workers = getenv("ISC_TASK_WORKERS");
+ uv_os_sock_t tcp_listen_sock = -1;
+ uv_os_sock_t udp_listen_sock = -1;
+ size_t nworkers;
+
+ if (env_workers != NULL) {
+ workers = atoi(env_workers);
+ } else {
+ workers = isc_os_ncpus();
+ }
+ INSIST(workers > 0);
+ nworkers = ISC_MAX(ISC_MIN(workers, 32), 1);
+
+ if (getenv("CI") != NULL && getenv("CI_ENABLE_ALL_TESTS") == NULL) {
+ skip_long_tests = true;
+ esends = nworkers;
+ } else {
+ esends = NSENDS * nworkers;
+ }
+
+ udp_connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0);
+
+ udp_listen_addr = (isc_sockaddr_t){ .length = 0 };
+ udp_listen_sock = setup_ephemeral_port(&udp_listen_addr, SOCK_DGRAM);
+ if (udp_listen_sock < 0) {
+ return (-1);
+ }
+ isc__nm_closesocket(udp_listen_sock);
+ udp_listen_sock = -1;
+
+ tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
+
+ tcp_listen_addr = (isc_sockaddr_t){ .length = 0 };
+ tcp_listen_sock = setup_ephemeral_port(&tcp_listen_addr, SOCK_STREAM);
+ if (tcp_listen_sock < 0) {
+ return (-1);
+ }
+ isc__nm_closesocket(tcp_listen_sock);
+ tcp_listen_sock = -1;
+
+ atomic_store(&do_send, true);
+ atomic_store(&nsends, esends);
+
+ atomic_store(&saccepts, 0);
+ atomic_store(&sreads, 0);
+ atomic_store(&ssends, 0);
+
+ atomic_store(&cconnects, 0);
+ atomic_store(&csends, 0);
+ atomic_store(&creads, 0);
+ atomic_store(&ctimeouts, 0);
+ allow_send_back = false;
+ stream_use_TLS = false;
+
+ isc_refcount_init(&active_cconnects, 0);
+ isc_refcount_init(&active_csends, 0);
+ isc_refcount_init(&active_creads, 0);
+ isc_refcount_init(&active_ssends, 0);
+ isc_refcount_init(&active_sreads, 0);
+
+ isc_nonce_buf(&send_magic, sizeof(send_magic));
+ isc_nonce_buf(&stop_magic, sizeof(stop_magic));
+ if (send_magic == stop_magic) {
+ return (-1);
+ }
+
+ isc__netmgr_create(mctx, nworkers, &listen_nm);
+ assert_non_null(listen_nm);
+ isc_nm_settimeouts(listen_nm, T_INIT, T_IDLE, T_KEEPALIVE,
+ T_ADVERTISED);
+
+ isc__netmgr_create(mctx, nworkers, &connect_nm);
+ assert_non_null(connect_nm);
+ isc_nm_settimeouts(connect_nm, T_INIT, T_IDLE, T_KEEPALIVE,
+ T_ADVERTISED);
+
+ isc_quota_init(&listener_quota, 0);
+ atomic_store(&check_listener_quota, false);
+
+ connect_readcb = connect_read_cb;
+ noanswer = false;
+
+ if (isc_tlsctx_createserver(NULL, NULL, &tcp_listen_tlsctx) !=
+ ISC_R_SUCCESS)
+ {
+ return (-1);
+ }
+ if (isc_tlsctx_createclient(&tcp_connect_tlsctx) != ISC_R_SUCCESS) {
+ return (-1);
+ }
+
+ isc_tlsctx_enable_dot_client_alpn(tcp_connect_tlsctx);
+
+ isc_tlsctx_client_session_cache_create(
+ mctx, tcp_connect_tlsctx,
+ ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE,
+ &tcp_tlsctx_client_sess_cache);
+
+ return (0);
+}
+
+static int
+teardown_test(void **state __attribute__((unused))) {
+ UNUSED(state);
+
+ isc_tlsctx_free(&tcp_connect_tlsctx);
+ isc_tlsctx_free(&tcp_listen_tlsctx);
+
+ isc__netmgr_destroy(&connect_nm);
+ assert_null(connect_nm);
+
+ isc__netmgr_destroy(&listen_nm);
+ assert_null(listen_nm);
+
+ WAIT_FOR_EQ(active_cconnects, 0);
+ WAIT_FOR_EQ(active_csends, 0);
+ WAIT_FOR_EQ(active_csends, 0);
+ WAIT_FOR_EQ(active_ssends, 0);
+ WAIT_FOR_EQ(active_sreads, 0);
+
+ isc_refcount_destroy(&active_cconnects);
+ isc_refcount_destroy(&active_csends);
+ isc_refcount_destroy(&active_creads);
+ isc_refcount_destroy(&active_ssends);
+ isc_refcount_destroy(&active_sreads);
+
+ isc_tlsctx_client_session_cache_detach(&tcp_tlsctx_client_sess_cache);
+
+ return (0);
+}
+
+/* Callbacks */
+
+static void
+noop_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
+ void *cbarg) {
+ UNUSED(handle);
+ UNUSED(eresult);
+ UNUSED(region);
+ UNUSED(cbarg);
+}
+
+static unsigned int
+noop_accept_cb(isc_nmhandle_t *handle, unsigned int result, void *cbarg) {
+ UNUSED(handle);
+ UNUSED(cbarg);
+
+ if (result == ISC_R_SUCCESS) {
+ (void)atomic_fetch_add(&saccepts, 1);
+ }
+
+ return (0);
+}
+
+static void
+connect_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg);
+
+static void
+connect_send(isc_nmhandle_t *handle);
+
+static void
+connect_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
+ isc_nmhandle_t *sendhandle = handle;
+
+ assert_non_null(sendhandle);
+
+ UNUSED(cbarg);
+
+ F();
+
+ if (eresult != ISC_R_SUCCESS) {
+ /* Send failed, we need to stop reading too */
+ isc_nm_cancelread(handle);
+ goto unref;
+ }
+
+ atomic_fetch_add(&csends, 1);
+unref:
+ isc_refcount_decrement(&active_csends);
+ isc_nmhandle_detach(&sendhandle);
+}
+
+static void
+connect_send(isc_nmhandle_t *handle) {
+ isc_nmhandle_t *sendhandle = NULL;
+ isc_refcount_increment0(&active_csends);
+ isc_nmhandle_attach(handle, &sendhandle);
+ isc_nmhandle_setwritetimeout(handle, T_IDLE);
+ if (atomic_fetch_sub(&nsends, 1) > 1) {
+ isc_nm_send(sendhandle, &send_msg, connect_send_cb, NULL);
+ } else {
+ isc_nm_send(sendhandle, &stop_msg, connect_send_cb, NULL);
+ }
+}
+
+static void
+connect_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *cbarg) {
+ uint64_t magic = 0;
+
+ UNUSED(cbarg);
+
+ assert_non_null(handle);
+
+ F();
+
+ if (eresult != ISC_R_SUCCESS) {
+ goto unref;
+ }
+
+ assert_true(region->length >= sizeof(magic));
+
+ atomic_fetch_add(&creads, 1);
+
+ memmove(&magic, region->base, sizeof(magic));
+
+ assert_true(magic == stop_magic || magic == send_magic);
+
+ if (magic == send_magic && allow_send_back) {
+ connect_send(handle);
+ return;
+ }
+
+unref:
+ isc_refcount_decrement(&active_creads);
+ isc_nmhandle_detach(&handle);
+}
+
+static void
+connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
+ isc_nmhandle_t *readhandle = NULL;
+
+ UNUSED(cbarg);
+
+ F();
+
+ isc_refcount_decrement(&active_cconnects);
+
+ if (eresult != ISC_R_SUCCESS || connect_readcb == NULL) {
+ return;
+ }
+
+ atomic_fetch_add(&cconnects, 1);
+
+ isc_refcount_increment0(&active_creads);
+ isc_nmhandle_attach(handle, &readhandle);
+ isc_nm_read(handle, connect_readcb, NULL);
+
+ connect_send(handle);
+}
+
+static void
+listen_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
+ isc_nmhandle_t *sendhandle = handle;
+
+ UNUSED(cbarg);
+ UNUSED(eresult);
+
+ assert_non_null(sendhandle);
+
+ F();
+
+ if (eresult != ISC_R_SUCCESS) {
+ goto unref;
+ }
+
+ atomic_fetch_add(&ssends, 1);
+unref:
+ isc_nmhandle_detach(&sendhandle);
+ isc_refcount_decrement(&active_ssends);
+}
+
+static void
+listen_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *cbarg) {
+ uint64_t magic = 0;
+
+ assert_non_null(handle);
+
+ F();
+
+ if (eresult != ISC_R_SUCCESS) {
+ goto unref;
+ }
+
+ atomic_fetch_add(&sreads, 1);
+
+ assert_true(region->length >= sizeof(magic));
+
+ memmove(&magic, region->base, sizeof(magic));
+ assert_true(magic == stop_magic || magic == send_magic);
+
+ if (magic == send_magic) {
+ if (!noanswer) {
+ isc_nmhandle_t *sendhandle = NULL;
+ isc_nmhandle_attach(handle, &sendhandle);
+ isc_refcount_increment0(&active_ssends);
+ isc_nmhandle_setwritetimeout(sendhandle, T_IDLE);
+ isc_nm_send(sendhandle, &send_msg, listen_send_cb,
+ cbarg);
+ }
+ return;
+ }
+
+unref:
+ if (handle == cbarg) {
+ isc_refcount_decrement(&active_sreads);
+ isc_nmhandle_detach(&handle);
+ }
+}
+
+static isc_result_t
+listen_accept_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
+ UNUSED(handle);
+ UNUSED(cbarg);
+
+ F();
+
+ return (eresult);
+}
+
+static isc_result_t
+stream_accept_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
+ isc_nmhandle_t *readhandle = NULL;
+
+ UNUSED(cbarg);
+
+ F();
+
+ if (eresult != ISC_R_SUCCESS) {
+ return (eresult);
+ }
+
+ atomic_fetch_add(&saccepts, 1);
+
+ isc_refcount_increment0(&active_sreads);
+ isc_nmhandle_attach(handle, &readhandle);
+ isc_nm_read(handle, listen_read_cb, readhandle);
+
+ return (ISC_R_SUCCESS);
+}
+
+typedef void (*connect_func)(isc_nm_t *);
+
+static isc_threadresult_t
+connect_thread(isc_threadarg_t arg) {
+ connect_func connect = (connect_func)arg;
+ isc_sockaddr_t connect_addr;
+
+ connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&connect_addr, &in6addr_loopback, 0);
+
+ while (atomic_load(&do_send)) {
+ uint_fast32_t active =
+ isc_refcount_increment0(&active_cconnects);
+ if (active > workers) {
+ /*
+ * If we have more active connections than workers,
+ * start slowing down the connections to prevent the
+ * thundering herd problem.
+ */
+ isc_test_nap(active - workers);
+ }
+ connect(connect_nm);
+ }
+
+ return ((isc_threadresult_t)0);
+}
+
+/* UDP */
+
+static void
+udp_connect(isc_nm_t *nm) {
+ isc_nm_udpconnect(nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+}
+
+ISC_RUN_TEST_IMPL(mock_listenudp_uv_udp_open) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ WILL_RETURN(uv_udp_open, UV_ENOMEM);
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, noop_recv_cb,
+ NULL, 0, &listen_sock);
+ assert_int_not_equal(result, ISC_R_SUCCESS);
+ assert_null(listen_sock);
+
+ RESET_RETURN;
+}
+
+ISC_RUN_TEST_IMPL(mock_listenudp_uv_udp_bind) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ WILL_RETURN(uv_udp_bind, UV_EADDRINUSE);
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, noop_recv_cb,
+ NULL, 0, &listen_sock);
+ assert_int_not_equal(result, ISC_R_SUCCESS);
+ assert_null(listen_sock);
+
+ RESET_RETURN;
+}
+
+ISC_RUN_TEST_IMPL(mock_listenudp_uv_udp_recv_start) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ WILL_RETURN(uv_udp_recv_start, UV_EADDRINUSE);
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, noop_recv_cb,
+ NULL, 0, &listen_sock);
+ assert_int_not_equal(result, ISC_R_SUCCESS);
+ assert_null(listen_sock);
+
+ RESET_RETURN;
+}
+
+ISC_RUN_TEST_IMPL(mock_udpconnect_uv_udp_open) {
+ WILL_RETURN(uv_udp_open, UV_ENOMEM);
+
+ connect_readcb = NULL;
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+ isc__netmgr_shutdown(connect_nm);
+
+ RESET_RETURN;
+}
+
+ISC_RUN_TEST_IMPL(mock_udpconnect_uv_udp_bind) {
+ WILL_RETURN(uv_udp_bind, UV_ENOMEM);
+
+ connect_readcb = NULL;
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+ isc__netmgr_shutdown(connect_nm);
+
+ RESET_RETURN;
+}
+
+#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
+ISC_RUN_TEST_IMPL(mock_udpconnect_uv_udp_connect) {
+ WILL_RETURN(uv_udp_connect, UV_ENOMEM);
+
+ connect_readcb = NULL;
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+ isc__netmgr_shutdown(connect_nm);
+
+ RESET_RETURN;
+}
+#endif
+
+ISC_RUN_TEST_IMPL(mock_udpconnect_uv_recv_buffer_size) {
+ WILL_RETURN(uv_recv_buffer_size, UV_ENOMEM);
+
+ connect_readcb = NULL;
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+ isc__netmgr_shutdown(connect_nm);
+
+ RESET_RETURN;
+}
+
+ISC_RUN_TEST_IMPL(mock_udpconnect_uv_send_buffer_size) {
+ WILL_RETURN(uv_send_buffer_size, UV_ENOMEM);
+
+ connect_readcb = NULL;
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+ isc__netmgr_shutdown(connect_nm);
+
+ RESET_RETURN;
+}
+
+ISC_RUN_TEST_IMPL(udp_noop) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, noop_recv_cb,
+ NULL, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ connect_readcb = NULL;
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+ isc__netmgr_shutdown(connect_nm);
+
+ atomic_assert_int_eq(cconnects, 0);
+ atomic_assert_int_eq(csends, 0);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+ISC_RUN_TEST_IMPL(udp_noresponse) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, noop_recv_cb,
+ NULL, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_EQ(csends, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 1);
+ atomic_assert_int_eq(csends, 1);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+static void
+timeout_retry_cb(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *cbarg) {
+ UNUSED(region);
+ UNUSED(cbarg);
+
+ assert_non_null(handle);
+
+ F();
+
+ if (eresult == ISC_R_TIMEDOUT && atomic_load(&csends) < 5) {
+ isc_nmhandle_settimeout(handle, T_SOFT);
+ connect_send(handle);
+ return;
+ }
+
+ atomic_fetch_add(&ctimeouts, 1);
+
+ isc_refcount_decrement(&active_creads);
+ isc_nmhandle_detach(&handle);
+}
+
+ISC_RUN_TEST_IMPL(udp_timeout_recovery) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ SKIP_IN_CI;
+
+ /*
+ * Listen using the noop callback so that client reads will time out.
+ */
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, noop_recv_cb,
+ NULL, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Connect with client timeout set to 0.05 seconds, then sleep for at
+ * least a second for each 'tick'. timeout_retry_cb() will give up
+ * after five timeouts.
+ */
+ connect_readcb = timeout_retry_cb;
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_SOFT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_GE(csends, 1);
+ WAIT_FOR_GE(csends, 2);
+ WAIT_FOR_GE(csends, 3);
+ WAIT_FOR_GE(csends, 4);
+ WAIT_FOR_EQ(csends, 5);
+ WAIT_FOR_EQ(ctimeouts, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+}
+
+ISC_RUN_TEST_IMPL(udp_recv_one) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ atomic_store(&nsends, 1);
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, listen_read_cb,
+ NULL, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_LE(nsends, 0);
+ WAIT_FOR_EQ(csends, 1);
+ WAIT_FOR_EQ(sreads, 1);
+ WAIT_FOR_EQ(ssends, 0);
+ WAIT_FOR_EQ(creads, 0);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 1);
+ atomic_assert_int_eq(csends, 1);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 1);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+ISC_RUN_TEST_IMPL(udp_recv_two) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ atomic_store(&nsends, 2);
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, listen_read_cb,
+ NULL, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_udpconnect(connect_nm, &udp_connect_addr, &udp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 2);
+ WAIT_FOR_LE(nsends, 0);
+ WAIT_FOR_EQ(csends, 2);
+ WAIT_FOR_EQ(sreads, 2);
+ WAIT_FOR_EQ(ssends, 1);
+ WAIT_FOR_EQ(creads, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 2);
+ atomic_assert_int_eq(csends, 2);
+ atomic_assert_int_eq(creads, 1);
+ atomic_assert_int_eq(sreads, 2);
+ atomic_assert_int_eq(ssends, 1);
+}
+
+ISC_RUN_TEST_IMPL(udp_recv_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, listen_read_cb,
+ NULL, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, udp_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends);
+ WAIT_FOR_GE(csends, esends);
+ WAIT_FOR_GE(sreads, esends);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_FULL(csends);
+ CHECK_RANGE_FULL(creads);
+ CHECK_RANGE_FULL(sreads);
+ CHECK_RANGE_FULL(ssends);
+}
+
+ISC_RUN_TEST_IMPL(udp_recv_half_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, listen_read_cb,
+ NULL, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, udp_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends / 2);
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_FULL(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+ISC_RUN_TEST_IMPL(udp_half_recv_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, listen_read_cb,
+ NULL, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, udp_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends / 2);
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ /* Try to send a little while longer */
+ isc_test_nap((esends / 2) * 10);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_FULL(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+ISC_RUN_TEST_IMPL(udp_half_recv_half_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listenudp(listen_nm, &udp_listen_addr, listen_read_cb,
+ NULL, 0, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, udp_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends / 2);
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_FULL(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+/* Common stream protocols code */
+
+static isc_quota_t *
+tcp_listener_init_quota(size_t nthreads) {
+ isc_quota_t *quotap = NULL;
+ if (atomic_load(&check_listener_quota)) {
+ unsigned max_quota = ISC_MAX(nthreads / 2, 1);
+ isc_quota_max(&listener_quota, max_quota);
+ quotap = &listener_quota;
+ }
+ return (quotap);
+}
+
+static void
+tcp_connect(isc_nm_t *nm) {
+ isc_nm_tcpconnect(nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+}
+
+#if HAVE_LIBNGHTTP2
+static void
+tls_connect(isc_nm_t *nm);
+#endif
+
+static stream_connect_function
+get_stream_connect_function(void) {
+#if HAVE_LIBNGHTTP2
+ if (stream_use_TLS) {
+ return (tls_connect);
+ }
+#endif
+ return (tcp_connect);
+}
+
+static isc_result_t
+stream_listen(isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
+ size_t extrahandlesize, int backlog, isc_quota_t *quota,
+ isc_nmsocket_t **sockp) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+#if HAVE_LIBNGHTTP2
+ if (stream_use_TLS) {
+ result = isc_nm_listentls(listen_nm, &tcp_listen_addr,
+ accept_cb, accept_cbarg,
+ extrahandlesize, backlog, quota,
+ tcp_listen_tlsctx, sockp);
+ return (result);
+ }
+#endif
+ result = isc_nm_listentcp(listen_nm, &tcp_listen_addr, accept_cb,
+ accept_cbarg, extrahandlesize, backlog, quota,
+ sockp);
+
+ return (result);
+}
+
+static void
+stream_connect(isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
+ size_t extrahandlesize) {
+#if HAVE_LIBNGHTTP2
+ if (stream_use_TLS) {
+ isc_nm_tlsconnect(connect_nm, &tcp_connect_addr,
+ &tcp_listen_addr, cb, cbarg,
+ tcp_connect_tlsctx,
+ tcp_tlsctx_client_sess_cache, timeout, 0);
+ return;
+ }
+#endif
+ isc_nm_tcpconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr, cb,
+ cbarg, timeout, extrahandlesize);
+}
+
+static void
+stream_noop(void **state __attribute__((unused))) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ result = stream_listen(noop_accept_cb, NULL, 0, 0, NULL, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ connect_readcb = NULL;
+ isc_refcount_increment0(&active_cconnects);
+ stream_connect(connect_connect_cb, NULL, T_CONNECT, 0);
+ isc__netmgr_shutdown(connect_nm);
+
+ atomic_assert_int_eq(cconnects, 0);
+ atomic_assert_int_eq(csends, 0);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+static void
+stream_noresponse(void **state __attribute__((unused))) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ result = stream_listen(noop_accept_cb, NULL, 0, 0, NULL, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ stream_connect(connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_EQ(saccepts, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 1);
+ atomic_assert_int_eq(saccepts, 1);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+static void
+stream_timeout_recovery(void **state __attribute__((unused))) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ SKIP_IN_CI;
+
+ /*
+ * Accept connections but don't send responses, forcing client
+ * reads to time out.
+ */
+ noanswer = true;
+ result = stream_listen(stream_accept_cb, NULL, 0, 0, NULL,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Shorten all the client timeouts to 0.05 seconds.
+ */
+ isc_nm_settimeouts(connect_nm, T_SOFT, T_SOFT, T_SOFT, T_SOFT);
+ connect_readcb = timeout_retry_cb;
+ isc_refcount_increment0(&active_cconnects);
+ stream_connect(connect_connect_cb, NULL, T_SOFT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_GE(csends, 1);
+ WAIT_FOR_GE(csends, 2);
+ WAIT_FOR_GE(csends, 3);
+ WAIT_FOR_GE(csends, 4);
+ WAIT_FOR_EQ(csends, 5);
+ WAIT_FOR_EQ(ctimeouts, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+}
+
+static void
+stream_recv_one(void **state __attribute__((unused))) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_quota_t *quotap = tcp_listener_init_quota(1);
+
+ atomic_store(&nsends, 1);
+
+ result = stream_listen(stream_accept_cb, NULL, 0, 0, quotap,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ stream_connect(connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_LE(nsends, 0);
+ WAIT_FOR_EQ(csends, 1);
+ WAIT_FOR_EQ(sreads, 1);
+ WAIT_FOR_EQ(ssends, 0);
+ WAIT_FOR_EQ(creads, 0);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 1);
+ atomic_assert_int_eq(csends, 1);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 1);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+static void
+stream_recv_two(void **state __attribute__((unused))) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_quota_t *quotap = tcp_listener_init_quota(1);
+
+ atomic_store(&nsends, 2);
+
+ result = stream_listen(stream_accept_cb, NULL, 0, 0, quotap,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ stream_connect(connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+
+ isc_refcount_increment0(&active_cconnects);
+ stream_connect(connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 2);
+ WAIT_FOR_LE(nsends, 0);
+ WAIT_FOR_EQ(csends, 2);
+ WAIT_FOR_EQ(sreads, 2);
+ WAIT_FOR_EQ(ssends, 1);
+ WAIT_FOR_EQ(creads, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 2);
+ atomic_assert_int_eq(csends, 2);
+ atomic_assert_int_eq(creads, 1);
+ atomic_assert_int_eq(sreads, 2);
+ atomic_assert_int_eq(ssends, 1);
+}
+
+static void
+stream_recv_send(void **state __attribute__((unused))) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+ isc_quota_t *quotap = tcp_listener_init_quota(workers);
+
+ SKIP_IN_CI;
+
+ result = stream_listen(stream_accept_cb, NULL, 0, 0, quotap,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, get_stream_connect_function(),
+ &threads[i]);
+ }
+
+ if (allow_send_back) {
+ WAIT_FOR_GE(cconnects, 1);
+ } else {
+ WAIT_FOR_GE(cconnects, esends);
+ }
+ WAIT_FOR_GE(csends, esends);
+ WAIT_FOR_GE(sreads, esends);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_FULL(csends);
+ CHECK_RANGE_FULL(creads);
+ CHECK_RANGE_FULL(sreads);
+ CHECK_RANGE_FULL(ssends);
+}
+
+static void
+stream_recv_half_send(void **state __attribute__((unused))) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+ isc_quota_t *quotap = tcp_listener_init_quota(workers);
+
+ SKIP_IN_CI;
+
+ result = stream_listen(stream_accept_cb, NULL, 0, 0, quotap,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, get_stream_connect_function(),
+ &threads[i]);
+ }
+
+ if (allow_send_back) {
+ WAIT_FOR_GE(cconnects, 1);
+ } else {
+ WAIT_FOR_GE(cconnects, esends / 2);
+ }
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+static void
+stream_half_recv_send(void **state __attribute__((unused))) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+ isc_quota_t *quotap = tcp_listener_init_quota(workers);
+
+ SKIP_IN_CI;
+
+ result = stream_listen(stream_accept_cb, NULL, 0, 0, quotap,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, get_stream_connect_function(),
+ &threads[i]);
+ }
+
+ if (allow_send_back) {
+ WAIT_FOR_GE(cconnects, 1);
+ } else {
+ WAIT_FOR_GE(cconnects, esends / 2);
+ }
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ /* Try to send a little while longer */
+ isc_test_nap((esends / 2) * 10);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+static void
+stream_half_recv_half_send(void **state __attribute__((unused))) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+ isc_quota_t *quotap = tcp_listener_init_quota(workers);
+
+ SKIP_IN_CI;
+
+ result = stream_listen(stream_accept_cb, NULL, 0, 0, quotap,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, get_stream_connect_function(),
+ &threads[i]);
+ }
+
+ if (allow_send_back) {
+ WAIT_FOR_GE(cconnects, 1);
+ } else {
+ WAIT_FOR_GE(cconnects, esends / 2);
+ }
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+/* TCP */
+ISC_RUN_TEST_IMPL(tcp_noop) { stream_noop(state); }
+
+ISC_RUN_TEST_IMPL(tcp_noresponse) { stream_noresponse(state); }
+
+ISC_RUN_TEST_IMPL(tcp_timeout_recovery) { stream_timeout_recovery(state); }
+
+ISC_RUN_TEST_IMPL(tcp_recv_one) { stream_recv_one(state); }
+
+ISC_RUN_TEST_IMPL(tcp_recv_two) { stream_recv_two(state); }
+
+ISC_RUN_TEST_IMPL(tcp_recv_send) {
+ SKIP_IN_CI;
+ stream_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_recv_half_send) {
+ SKIP_IN_CI;
+ stream_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_half_recv_send) {
+ SKIP_IN_CI;
+ stream_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_half_recv_half_send) {
+ SKIP_IN_CI;
+ stream_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_recv_send_sendback) {
+ SKIP_IN_CI;
+ stream_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_recv_half_send_sendback) {
+ SKIP_IN_CI;
+ stream_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_half_recv_send_sendback) {
+ SKIP_IN_CI;
+ stream_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_half_recv_half_send_sendback) {
+ SKIP_IN_CI;
+ stream_half_recv_half_send(state);
+}
+
+/* TCP Quota */
+
+ISC_RUN_TEST_IMPL(tcp_recv_one_quota) {
+ atomic_store(&check_listener_quota, true);
+ stream_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_recv_two_quota) {
+ atomic_store(&check_listener_quota, true);
+ stream_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_recv_send_quota) {
+ SKIP_IN_CI;
+ atomic_store(&check_listener_quota, true);
+ stream_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_recv_half_send_quota) {
+ SKIP_IN_CI;
+ atomic_store(&check_listener_quota, true);
+ stream_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_half_recv_send_quota) {
+ SKIP_IN_CI;
+ atomic_store(&check_listener_quota, true);
+ stream_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_half_recv_half_send_quota) {
+ SKIP_IN_CI;
+ atomic_store(&check_listener_quota, true);
+ stream_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_recv_send_quota_sendback) {
+ SKIP_IN_CI;
+ atomic_store(&check_listener_quota, true);
+ allow_send_back = true;
+ stream_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_recv_half_send_quota_sendback) {
+ SKIP_IN_CI;
+ atomic_store(&check_listener_quota, true);
+ allow_send_back = true;
+ stream_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_half_recv_send_quota_sendback) {
+ SKIP_IN_CI;
+ atomic_store(&check_listener_quota, true);
+ allow_send_back = true;
+ stream_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tcp_half_recv_half_send_quota_sendback) {
+ SKIP_IN_CI;
+ atomic_store(&check_listener_quota, true);
+ allow_send_back = true;
+ stream_half_recv_half_send(state);
+}
+
+/* TCPDNS */
+
+static void
+tcpdns_connect(isc_nm_t *nm) {
+ isc_nm_tcpdnsconnect(nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+}
+
+ISC_RUN_TEST_IMPL(tcpdns_noop) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ result = isc_nm_listentcpdns(listen_nm, &tcp_listen_addr, noop_recv_cb,
+ NULL, noop_accept_cb, NULL, 0, 0, NULL,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ connect_readcb = NULL;
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tcpdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+ isc__netmgr_shutdown(connect_nm);
+
+ atomic_assert_int_eq(cconnects, 0);
+ atomic_assert_int_eq(csends, 0);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+ISC_RUN_TEST_IMPL(tcpdns_noresponse) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ isc_refcount_increment0(&active_cconnects);
+ result = isc_nm_listentcpdns(listen_nm, &tcp_listen_addr, noop_recv_cb,
+ NULL, noop_accept_cb, NULL, 0, 0, NULL,
+ &listen_sock);
+ if (result != ISC_R_SUCCESS) {
+ isc_refcount_decrement(&active_cconnects);
+ isc_test_nap(1);
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_nm_tcpdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_EQ(saccepts, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 1);
+ atomic_assert_int_eq(saccepts, 1);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+ISC_RUN_TEST_IMPL(tcpdns_timeout_recovery) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ SKIP_IN_CI;
+
+ /*
+ * Accept connections but don't send responses, forcing client
+ * reads to time out.
+ */
+ noanswer = true;
+ result = isc_nm_listentcpdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Shorten all the TCP client timeouts to 0.05 seconds, connect,
+ * then sleep for at least a second for each 'tick'.
+ * timeout_retry_cb() will give up after five timeouts.
+ */
+ connect_readcb = timeout_retry_cb;
+ isc_nm_settimeouts(connect_nm, T_SOFT, T_SOFT, T_SOFT, T_SOFT);
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tcpdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_SOFT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_GE(csends, 1);
+ WAIT_FOR_GE(csends, 2);
+ WAIT_FOR_GE(csends, 3);
+ WAIT_FOR_GE(csends, 4);
+ WAIT_FOR_EQ(csends, 5);
+ WAIT_FOR_EQ(ctimeouts, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+}
+
+ISC_RUN_TEST_IMPL(tcpdns_recv_one) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ atomic_store(&nsends, 1);
+
+ result = isc_nm_listentcpdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tcpdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_LE(nsends, 0);
+ WAIT_FOR_EQ(csends, 1);
+ WAIT_FOR_EQ(sreads, 1);
+ WAIT_FOR_EQ(ssends, 0);
+ WAIT_FOR_EQ(creads, 0);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 1);
+ atomic_assert_int_eq(csends, 1);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 1);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+ISC_RUN_TEST_IMPL(tcpdns_recv_two) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ atomic_store(&nsends, 2);
+
+ result = isc_nm_listentcpdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tcpdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 1);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tcpdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0);
+
+ WAIT_FOR_EQ(cconnects, 2);
+
+ WAIT_FOR_LE(nsends, 0);
+ WAIT_FOR_EQ(csends, 2);
+ WAIT_FOR_EQ(sreads, 2);
+ WAIT_FOR_EQ(ssends, 1);
+ WAIT_FOR_EQ(creads, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 2);
+ atomic_assert_int_eq(csends, 2);
+ atomic_assert_int_eq(creads, 1);
+ atomic_assert_int_eq(sreads, 2);
+ atomic_assert_int_eq(ssends, 1);
+}
+
+ISC_RUN_TEST_IMPL(tcpdns_recv_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listentcpdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, tcpdns_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends);
+ WAIT_FOR_GE(csends, esends);
+ WAIT_FOR_GE(sreads, esends);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_FULL(csends);
+ CHECK_RANGE_FULL(creads);
+ CHECK_RANGE_FULL(sreads);
+ CHECK_RANGE_FULL(ssends);
+}
+
+ISC_RUN_TEST_IMPL(tcpdns_recv_half_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listentcpdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, tcpdns_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends / 2);
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+ISC_RUN_TEST_IMPL(tcpdns_half_recv_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listentcpdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, tcpdns_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends / 2);
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ /* Try to send a little while longer */
+ isc_test_nap((esends / 2) * 10);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+ISC_RUN_TEST_IMPL(tcpdns_half_recv_half_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listentcpdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, tcpdns_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends / 2);
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+/* TLS */
+
+#if HAVE_LIBNGHTTP2
+static void
+tls_connect(isc_nm_t *nm) {
+ isc_nm_tlsconnect(nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, tcp_connect_tlsctx,
+ tcp_tlsctx_client_sess_cache, T_CONNECT, 0);
+}
+
+ISC_RUN_TEST_IMPL(tls_noop) {
+ stream_use_TLS = true;
+ stream_noop(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_noresponse) {
+ stream_use_TLS = true;
+ stream_noresponse(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_timeout_recovery) {
+ stream_use_TLS = true;
+ stream_timeout_recovery(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_one) {
+ stream_use_TLS = true;
+ stream_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_two) {
+ stream_use_TLS = true;
+ stream_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_send) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ stream_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_half_send) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ stream_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_half_recv_send) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ stream_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_half_recv_half_send) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ stream_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_send_sendback) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ allow_send_back = true;
+ stream_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_half_send_sendback) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ allow_send_back = true;
+ stream_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_half_recv_send_sendback) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ allow_send_back = true;
+ stream_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_half_recv_half_send_sendback) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ allow_send_back = true;
+ stream_half_recv_half_send(state);
+}
+
+/* TLS quota */
+
+ISC_RUN_TEST_IMPL(tls_recv_one_quota) {
+ stream_use_TLS = true;
+ atomic_store(&check_listener_quota, true);
+ stream_recv_one(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_two_quota) {
+ stream_use_TLS = true;
+ atomic_store(&check_listener_quota, true);
+ stream_recv_two(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_send_quota) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ atomic_store(&check_listener_quota, true);
+ stream_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_half_send_quota) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ atomic_store(&check_listener_quota, true);
+ stream_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_half_recv_send_quota) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ atomic_store(&check_listener_quota, true);
+ stream_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_half_recv_half_send_quota) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ atomic_store(&check_listener_quota, true);
+ stream_half_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_send_quota_sendback) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ allow_send_back = true;
+ atomic_store(&check_listener_quota, true);
+ stream_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_recv_half_send_quota_sendback) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ allow_send_back = true;
+ atomic_store(&check_listener_quota, true);
+ stream_recv_half_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_half_recv_send_quota_sendback) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ allow_send_back = true;
+ atomic_store(&check_listener_quota, true);
+ stream_half_recv_send(state);
+}
+
+ISC_RUN_TEST_IMPL(tls_half_recv_half_send_quota_sendback) {
+ SKIP_IN_CI;
+ stream_use_TLS = true;
+ allow_send_back = true;
+ atomic_store(&check_listener_quota, true);
+ stream_half_recv_half_send(state);
+}
+#endif
+
+/* TLSDNS */
+
+static void
+tlsdns_connect(isc_nm_t *nm) {
+ isc_nm_tlsdnsconnect(nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0,
+ tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_noop) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr, noop_recv_cb,
+ NULL, noop_accept_cb, NULL, 0, 0, NULL,
+ tcp_listen_tlsctx, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ connect_readcb = NULL;
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0,
+ tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ atomic_assert_int_eq(cconnects, 0);
+ atomic_assert_int_eq(csends, 0);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_noresponse) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_sockaddr_t connect_addr;
+
+ connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&connect_addr, &in6addr_loopback, 0);
+
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr, noop_recv_cb,
+ NULL, noop_accept_cb, NULL, 0, 0, NULL,
+ tcp_listen_tlsctx, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tlsdnsconnect(connect_nm, &connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0,
+ tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_EQ(saccepts, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 1);
+ atomic_assert_int_eq(saccepts, 1);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_timeout_recovery) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_sockaddr_t connect_addr;
+
+ SKIP_IN_CI;
+
+ connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&connect_addr, &in6addr_loopback, 0);
+
+ /*
+ * Accept connections but don't send responses, forcing client
+ * reads to time out.
+ */
+ noanswer = true;
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, tcp_listen_tlsctx,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Shorten all the TCP client timeouts to 0.05 seconds, connect,
+ * then sleep for at least a second for each 'tick'.
+ * timeout_retry_cb() will give up after five timeouts.
+ */
+ connect_readcb = timeout_retry_cb;
+ isc_nm_settimeouts(connect_nm, T_SOFT, T_SOFT, T_SOFT, T_SOFT);
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_SOFT, 0,
+ tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_GE(csends, 1);
+ WAIT_FOR_GE(csends, 2);
+ WAIT_FOR_GE(csends, 3);
+ WAIT_FOR_GE(csends, 4);
+ WAIT_FOR_EQ(csends, 5);
+ WAIT_FOR_EQ(ctimeouts, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_recv_one) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ atomic_store(&nsends, 1);
+
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, tcp_listen_tlsctx,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0,
+ tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
+
+ WAIT_FOR_EQ(cconnects, 1);
+ WAIT_FOR_LE(nsends, 0);
+ WAIT_FOR_EQ(csends, 1);
+ WAIT_FOR_EQ(sreads, 1);
+ WAIT_FOR_EQ(ssends, 0);
+ WAIT_FOR_EQ(creads, 0);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 1);
+ atomic_assert_int_eq(csends, 1);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 1);
+ atomic_assert_int_eq(ssends, 0);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_recv_two) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+
+ atomic_store(&nsends, 2);
+
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, tcp_listen_tlsctx,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0,
+ tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
+
+ WAIT_FOR_EQ(cconnects, 1);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tlsdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0,
+ tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
+
+ WAIT_FOR_EQ(cconnects, 2);
+
+ WAIT_FOR_LE(nsends, 0);
+ WAIT_FOR_EQ(csends, 2);
+ WAIT_FOR_EQ(sreads, 2);
+ WAIT_FOR_EQ(ssends, 1);
+ WAIT_FOR_EQ(creads, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 2);
+ atomic_assert_int_eq(csends, 2);
+ atomic_assert_int_eq(creads, 1);
+ atomic_assert_int_eq(sreads, 2);
+ atomic_assert_int_eq(ssends, 1);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_recv_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, tcp_listen_tlsctx,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, tlsdns_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends);
+ WAIT_FOR_GE(csends, esends);
+ WAIT_FOR_GE(sreads, esends);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_FULL(csends);
+ CHECK_RANGE_FULL(creads);
+ CHECK_RANGE_FULL(sreads);
+ CHECK_RANGE_FULL(ssends);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_recv_half_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, tcp_listen_tlsctx,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, tlsdns_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends / 2);
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_half_recv_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, tcp_listen_tlsctx,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, tlsdns_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends / 2);
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ /* Try to send a little while longer */
+ isc_test_nap((esends / 2) * 10);
+
+ isc__netmgr_shutdown(connect_nm);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_half_recv_half_send) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_thread_t threads[workers];
+
+ SKIP_IN_CI;
+
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr,
+ listen_read_cb, NULL, listen_accept_cb,
+ NULL, 0, 0, NULL, tcp_listen_tlsctx,
+ &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ memset(threads, 0, sizeof(threads));
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_create(connect_thread, tlsdns_connect, &threads[i]);
+ }
+
+ WAIT_FOR_GE(cconnects, esends / 2);
+ WAIT_FOR_GE(csends, esends / 2);
+ WAIT_FOR_GE(sreads, esends / 2);
+ WAIT_FOR_GE(ssends, esends / 2);
+ WAIT_FOR_GE(creads, esends / 2);
+
+ isc__netmgr_shutdown(connect_nm);
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+
+ DONE();
+ for (size_t i = 0; i < workers; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ CHECK_RANGE_HALF(csends);
+ CHECK_RANGE_HALF(creads);
+ CHECK_RANGE_HALF(sreads);
+ CHECK_RANGE_HALF(ssends);
+}
+
+static void
+tlsdns_connect_connect_noalpn(isc_nmhandle_t *handle, isc_result_t eresult,
+ void *cbarg) {
+ isc_nmhandle_t *readhandle = NULL;
+
+ UNUSED(cbarg);
+
+ F();
+
+ isc_refcount_decrement(&active_cconnects);
+
+ if (eresult != ISC_R_SUCCESS || connect_readcb == NULL ||
+ isc_nm_xfr_checkperm(handle) != ISC_R_SUCCESS)
+ {
+ return;
+ }
+
+ atomic_fetch_add(&cconnects, 1);
+
+ isc_refcount_increment0(&active_creads);
+ isc_nmhandle_attach(handle, &readhandle);
+ isc_nm_read(handle, connect_readcb, NULL);
+
+ connect_send(handle);
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_connect_noalpn) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_sockaddr_t connect_addr;
+ isc_tlsctx_t *connect_tlsctx_noalpn = NULL;
+
+ result = isc_tlsctx_createclient(&connect_tlsctx_noalpn);
+ assert_true(result == ISC_R_SUCCESS);
+
+ connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&connect_addr, &in6addr_loopback, 0);
+
+ result = isc_nm_listentlsdns(listen_nm, &tcp_listen_addr, noop_recv_cb,
+ NULL, noop_accept_cb, NULL, 0, 0, NULL,
+ tcp_listen_tlsctx, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tlsdnsconnect(connect_nm, &connect_addr, &tcp_listen_addr,
+ tlsdns_connect_connect_noalpn, NULL, T_CONNECT, 0,
+ connect_tlsctx_noalpn, NULL);
+
+ WAIT_FOR_EQ(active_cconnects, 0);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(cconnects, 0);
+ atomic_assert_int_eq(csends, 0);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+
+ isc_tlsctx_free(&connect_tlsctx_noalpn);
+}
+
+#ifdef HAVE_LIBNGHTTP2
+
+static isc_result_t
+tls_accept_cb_noalpn(isc_nmhandle_t *handle, isc_result_t eresult,
+ void *cbarg) {
+ F();
+
+ if (eresult != ISC_R_SUCCESS) {
+ return (eresult);
+ }
+
+ atomic_fetch_add(&saccepts, 1);
+
+ if (isc_nm_xfr_checkperm(handle) != ISC_R_SUCCESS) {
+ return (ISC_R_FAILURE);
+ }
+
+ return (stream_accept_cb(handle, eresult, cbarg));
+}
+
+ISC_RUN_TEST_IMPL(tlsdns_listen_noalpn) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_nmsocket_t *listen_sock = NULL;
+ isc_sockaddr_t connect_addr;
+ isc_tlsctx_t *server_tlsctx_noalpn = NULL;
+
+ result = isc_tlsctx_createserver(NULL, NULL, &server_tlsctx_noalpn);
+ assert_true(result == ISC_R_SUCCESS);
+
+ connect_addr = (isc_sockaddr_t){ .length = 0 };
+ isc_sockaddr_fromin6(&connect_addr, &in6addr_loopback, 0);
+
+ /* We use TLS stream listener here intentionally, as it does not
+ * try to do ALPN. */
+ result = isc_nm_listentls(listen_nm, &tcp_listen_addr,
+ tls_accept_cb_noalpn, NULL, 0, 0, NULL,
+ server_tlsctx_noalpn, &listen_sock);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_refcount_increment0(&active_cconnects);
+ isc_nm_tlsdnsconnect(connect_nm, &connect_addr, &tcp_listen_addr,
+ connect_connect_cb, NULL, T_CONNECT, 0,
+ tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache);
+
+ WAIT_FOR_EQ(saccepts, 1);
+ WAIT_FOR_EQ(cconnects, 1);
+
+ isc_nm_stoplistening(listen_sock);
+ isc_nmsocket_close(&listen_sock);
+ assert_null(listen_sock);
+ isc__netmgr_shutdown(connect_nm);
+
+ X(cconnects);
+ X(csends);
+ X(creads);
+ X(sreads);
+ X(ssends);
+
+ atomic_assert_int_eq(saccepts, 1);
+ atomic_assert_int_eq(cconnects, 1);
+ atomic_assert_int_eq(creads, 0);
+ atomic_assert_int_eq(sreads, 0);
+ atomic_assert_int_eq(ssends, 0);
+
+ isc_tlsctx_free(&server_tlsctx_noalpn);
+}
+#endif /* HAVE_LIBNGHTTP2 */
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(mock_listenudp_uv_udp_open, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(mock_listenudp_uv_udp_bind, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(mock_listenudp_uv_udp_recv_start, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_udp_open, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_udp_bind, setup_test, teardown_test)
+#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
+ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_udp_connect, setup_test, teardown_test)
+#endif
+ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_recv_buffer_size, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_send_buffer_size, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(udp_noop, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(udp_noresponse, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(udp_timeout_recovery, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(udp_recv_one, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(udp_recv_two, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(udp_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(udp_recv_half_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(udp_half_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(udp_half_recv_half_send, setup_test, teardown_test)
+
+/* TCP */
+ISC_TEST_ENTRY_CUSTOM(tcp_noop, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_noresponse, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_timeout_recovery, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_one, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_two, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_half_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_half_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_half_recv_half_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_send_sendback, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_half_send_sendback, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_half_recv_send_sendback, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_half_recv_half_send_sendback, setup_test,
+ teardown_test)
+
+/* TCP Quota */
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_one_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_two_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_send_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_half_send_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_half_recv_send_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_half_recv_half_send_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_send_quota_sendback, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_recv_half_send_quota_sendback, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_half_recv_send_quota_sendback, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcp_half_recv_half_send_quota_sendback, setup_test,
+ teardown_test)
+
+/* TCPDNS */
+ISC_TEST_ENTRY_CUSTOM(tcpdns_recv_one, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcpdns_recv_two, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcpdns_noop, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcpdns_noresponse, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcpdns_timeout_recovery, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcpdns_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcpdns_recv_half_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcpdns_half_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tcpdns_half_recv_half_send, setup_test, teardown_test)
+
+#if HAVE_LIBNGHTTP2
+/* TLS */
+ISC_TEST_ENTRY_CUSTOM(tls_noop, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_noresponse, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_timeout_recovery, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_one, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_two, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_half_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_half_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_half_recv_half_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_send_sendback, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_half_send_sendback, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_half_recv_send_sendback, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_half_recv_half_send_sendback, setup_test,
+ teardown_test)
+
+/* TLS quota */
+ISC_TEST_ENTRY_CUSTOM(tls_recv_one_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_two_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_send_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_half_send_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_half_recv_send_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_half_recv_half_send_quota, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_send_quota_sendback, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_recv_half_send_quota_sendback, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_half_recv_send_quota_sendback, setup_test,
+ teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tls_half_recv_half_send_quota_sendback, setup_test,
+ teardown_test)
+#endif
+
+/* TLSDNS */
+ISC_TEST_ENTRY_CUSTOM(tlsdns_recv_one, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tlsdns_recv_two, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tlsdns_noop, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tlsdns_noresponse, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tlsdns_timeout_recovery, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tlsdns_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tlsdns_recv_half_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tlsdns_half_recv_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tlsdns_half_recv_half_send, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(tlsdns_connect_noalpn, setup_test, teardown_test)
+#ifdef HAVE_LIBNGHTTP2
+ISC_TEST_ENTRY_CUSTOM(tlsdns_listen_noalpn, setup_test, teardown_test)
+#endif
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/parse_test.c b/tests/isc/parse_test.c
new file mode 100644
index 0000000..a5b516a
--- /dev/null
+++ b/tests/isc/parse_test.c
@@ -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.
+ */
+
+/*! \file */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/parseint.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* Test for 32 bit overflow on 64 bit machines in isc_parse_uint32 */
+ISC_RUN_TEST_IMPL(parse_overflow) {
+ isc_result_t result;
+ uint32_t output;
+
+ result = isc_parse_uint32(&output, "1234567890", 10);
+ assert_int_equal(ISC_R_SUCCESS, result);
+ assert_int_equal(1234567890, output);
+
+ result = isc_parse_uint32(&output, "123456789012345", 10);
+ assert_int_equal(ISC_R_RANGE, result);
+
+ result = isc_parse_uint32(&output, "12345678901234567890", 10);
+ assert_int_equal(ISC_R_RANGE, result);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(parse_overflow)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/pool_test.c b/tests/isc/pool_test.c
new file mode 100644
index 0000000..35d556f
--- /dev/null
+++ b/tests/isc/pool_test.c
@@ -0,0 +1,153 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/mem.h>
+#include <isc/pool.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+static isc_result_t
+poolinit(void **target, void *arg) {
+ isc_result_t result;
+
+ isc_taskmgr_t *mgr = (isc_taskmgr_t *)arg;
+ isc_task_t *task = NULL;
+ result = isc_task_create(mgr, 0, &task);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ *target = (void *)task;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+poolfree(void **target) {
+ isc_task_t *task = *(isc_task_t **)target;
+ isc_task_destroy(&task);
+ *target = NULL;
+}
+
+/* Create a pool */
+ISC_RUN_TEST_IMPL(create_pool) {
+ isc_result_t result;
+ isc_pool_t *pool = NULL;
+
+ UNUSED(state);
+
+ result = isc_pool_create(mctx, 8, poolfree, poolinit, taskmgr, &pool);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_pool_count(pool), 8);
+
+ isc_pool_destroy(&pool);
+ assert_null(pool);
+}
+
+/* Resize a pool */
+ISC_RUN_TEST_IMPL(expand_pool) {
+ isc_result_t result;
+ isc_pool_t *pool1 = NULL, *pool2 = NULL, *hold = NULL;
+
+ UNUSED(state);
+
+ result = isc_pool_create(mctx, 10, poolfree, poolinit, taskmgr, &pool1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_pool_count(pool1), 10);
+
+ /* resizing to a smaller size should have no effect */
+ hold = pool1;
+ result = isc_pool_expand(&pool1, 5, &pool2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_pool_count(pool2), 10);
+ assert_ptr_equal(pool2, hold);
+ assert_null(pool1);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to the same size should have no effect */
+ hold = pool1;
+ result = isc_pool_expand(&pool1, 10, &pool2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_pool_count(pool2), 10);
+ assert_ptr_equal(pool2, hold);
+ assert_null(pool1);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to larger size should make a new pool */
+ hold = pool1;
+ result = isc_pool_expand(&pool1, 20, &pool2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_pool_count(pool2), 20);
+ assert_ptr_not_equal(pool2, hold);
+ assert_null(pool1);
+
+ isc_pool_destroy(&pool2);
+ assert_null(pool2);
+}
+
+/* Get objects */
+ISC_RUN_TEST_IMPL(get_objects) {
+ isc_result_t result;
+ isc_pool_t *pool = NULL;
+ void *item;
+ isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
+
+ UNUSED(state);
+
+ result = isc_pool_create(mctx, 2, poolfree, poolinit, taskmgr, &pool);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_pool_count(pool), 2);
+
+ item = isc_pool_get(pool);
+ assert_non_null(item);
+ isc_task_attach((isc_task_t *)item, &task1);
+
+ item = isc_pool_get(pool);
+ assert_non_null(item);
+ isc_task_attach((isc_task_t *)item, &task2);
+
+ item = isc_pool_get(pool);
+ assert_non_null(item);
+ isc_task_attach((isc_task_t *)item, &task3);
+
+ isc_task_detach(&task1);
+ isc_task_detach(&task2);
+ isc_task_detach(&task3);
+
+ isc_pool_destroy(&pool);
+ assert_null(pool);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(create_pool, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(expand_pool, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(get_objects, setup_managers, teardown_managers)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/quota_test.c b/tests/isc/quota_test.c
new file mode 100644
index 0000000..9b202b9
--- /dev/null
+++ b/tests/isc/quota_test.c
@@ -0,0 +1,341 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/quota.h>
+#include <isc/result.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include "netmgr/uv-compat.h"
+
+#include <tests/isc.h>
+
+ISC_RUN_TEST_IMPL(isc_quota_get_set) {
+ UNUSED(state);
+ isc_quota_t quota;
+ isc_quota_t *quota2 = NULL;
+ isc_quota_init(&quota, 100);
+
+ assert_int_equal(isc_quota_getmax(&quota), 100);
+ assert_int_equal(isc_quota_getsoft(&quota), 0);
+
+ isc_quota_max(&quota, 50);
+ isc_quota_soft(&quota, 30);
+
+ assert_int_equal(isc_quota_getmax(&quota), 50);
+ assert_int_equal(isc_quota_getsoft(&quota), 30);
+
+ assert_int_equal(isc_quota_getused(&quota), 0);
+ isc_quota_attach(&quota, &quota2);
+ assert_int_equal(isc_quota_getused(&quota), 1);
+ isc_quota_detach(&quota2);
+ assert_int_equal(isc_quota_getused(&quota), 0);
+ isc_quota_destroy(&quota);
+}
+
+static void
+add_quota(isc_quota_t *source, isc_quota_t **target,
+ isc_result_t expected_result, int expected_used) {
+ isc_result_t result;
+
+ *target = NULL;
+
+ result = isc_quota_attach(source, target);
+ assert_int_equal(result, expected_result);
+
+ switch (expected_result) {
+ case ISC_R_SUCCESS:
+ case ISC_R_SOFTQUOTA:
+ assert_ptr_equal(*target, source);
+ break;
+ default:
+ assert_null(*target);
+ break;
+ }
+
+ assert_int_equal(isc_quota_getused(source), expected_used);
+}
+
+ISC_RUN_TEST_IMPL(isc_quota_hard) {
+ isc_quota_t quota;
+ isc_quota_t *quotas[110];
+ int i;
+ UNUSED(state);
+
+ isc_quota_init(&quota, 100);
+
+ for (i = 0; i < 100; i++) {
+ add_quota(&quota, &quotas[i], ISC_R_SUCCESS, i + 1);
+ }
+
+ add_quota(&quota, &quotas[100], ISC_R_QUOTA, 100);
+
+ assert_int_equal(isc_quota_getused(&quota), 100);
+
+ isc_quota_detach(&quotas[0]);
+ assert_null(quotas[0]);
+
+ add_quota(&quota, &quotas[100], ISC_R_SUCCESS, 100);
+ add_quota(&quota, &quotas[101], ISC_R_QUOTA, 100);
+
+ for (i = 100; i > 0; i--) {
+ isc_quota_detach(&quotas[i]);
+ assert_null(quotas[i]);
+ assert_int_equal(isc_quota_getused(&quota), i - 1);
+ }
+ assert_int_equal(isc_quota_getused(&quota), 0);
+ isc_quota_destroy(&quota);
+}
+
+ISC_RUN_TEST_IMPL(isc_quota_soft) {
+ isc_quota_t quota;
+ isc_quota_t *quotas[110];
+ int i;
+ UNUSED(state);
+
+ isc_quota_init(&quota, 100);
+ isc_quota_soft(&quota, 50);
+
+ for (i = 0; i < 50; i++) {
+ add_quota(&quota, &quotas[i], ISC_R_SUCCESS, i + 1);
+ }
+ for (i = 50; i < 100; i++) {
+ add_quota(&quota, &quotas[i], ISC_R_SOFTQUOTA, i + 1);
+ }
+
+ add_quota(&quota, &quotas[i], ISC_R_QUOTA, 100);
+
+ for (i = 99; i >= 0; i--) {
+ isc_quota_detach(&quotas[i]);
+ assert_null(quotas[i]);
+ assert_int_equal(isc_quota_getused(&quota), i);
+ }
+ assert_int_equal(isc_quota_getused(&quota), 0);
+ isc_quota_destroy(&quota);
+}
+
+static atomic_uint_fast32_t cb_calls = 0;
+static isc_quota_cb_t cbs[30];
+static isc_quota_t *qp;
+
+static void
+callback(isc_quota_t *quota, void *data) {
+ int val = *(int *)data;
+ /* Callback is not called if we get the quota directly */
+ assert_int_not_equal(val, -1);
+
+ /* We get the proper quota pointer */
+ assert_ptr_equal(quota, qp);
+
+ /* Verify that the callbacks are called in order */
+ int v = atomic_fetch_add_relaxed(&cb_calls, 1);
+ assert_int_equal(v, val);
+
+ /*
+ * First 5 will be detached by the test function,
+ * for the last 5 - do a 'chain detach'.
+ */
+ if (v >= 5) {
+ isc_quota_detach(&quota);
+ }
+}
+
+ISC_RUN_TEST_IMPL(isc_quota_callback) {
+ isc_result_t result;
+ isc_quota_t quota;
+ isc_quota_t *quotas[30];
+ qp = &quota;
+ /*
+ * - 10 calls that end with SUCCESS
+ * - 10 calls that end with SOFTQUOTA
+ * - 10 callbacks
+ */
+ int ints[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ int i;
+ UNUSED(state);
+
+ isc_quota_init(&quota, 20);
+ isc_quota_soft(&quota, 10);
+
+ for (i = 0; i < 10; i++) {
+ quotas[i] = NULL;
+ isc_quota_cb_init(&cbs[i], callback, &ints[i]);
+ result = isc_quota_attach_cb(&quota, &quotas[i], &cbs[i]);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_ptr_equal(quotas[i], &quota);
+ assert_int_equal(isc_quota_getused(&quota), i + 1);
+ }
+ for (i = 10; i < 20; i++) {
+ quotas[i] = NULL;
+ isc_quota_cb_init(&cbs[i], callback, &ints[i]);
+ result = isc_quota_attach_cb(&quota, &quotas[i], &cbs[i]);
+ assert_int_equal(result, ISC_R_SOFTQUOTA);
+ assert_ptr_equal(quotas[i], &quota);
+ assert_int_equal(isc_quota_getused(&quota), i + 1);
+ }
+
+ for (i = 20; i < 30; i++) {
+ quotas[i] = NULL;
+ isc_quota_cb_init(&cbs[i], callback, &ints[i]);
+ result = isc_quota_attach_cb(&quota, &quotas[i], &cbs[i]);
+ assert_int_equal(result, ISC_R_QUOTA);
+ assert_ptr_equal(quotas[i], NULL);
+ assert_int_equal(isc_quota_getused(&quota), 20);
+ }
+ assert_int_equal(atomic_load(&cb_calls), 0);
+
+ for (i = 0; i < 5; i++) {
+ isc_quota_detach(&quotas[i]);
+ assert_null(quotas[i]);
+ assert_int_equal(isc_quota_getused(&quota), 20);
+ assert_int_equal(atomic_load(&cb_calls), i + 1);
+ }
+ /* That should cause a chain reaction */
+ isc_quota_detach(&quotas[5]);
+ assert_int_equal(atomic_load(&cb_calls), 10);
+
+ /* Release the quotas that we did not released in the callback */
+ for (i = 0; i < 5; i++) {
+ qp = &quota;
+ isc_quota_detach(&qp);
+ }
+
+ for (i = 6; i < 20; i++) {
+ isc_quota_detach(&quotas[i]);
+ assert_null(quotas[i]);
+ assert_int_equal(isc_quota_getused(&quota), 19 - i);
+ }
+ assert_int_equal(atomic_load(&cb_calls), 10);
+
+ assert_int_equal(isc_quota_getused(&quota), 0);
+ isc_quota_destroy(&quota);
+}
+
+/*
+ * Multithreaded quota callback test:
+ * - quota set to 100
+ * - 10 threads, each trying to get 100 quotas.
+ * - creates a separate thread to release it after 10ms
+ */
+
+typedef struct qthreadinfo {
+ atomic_uint_fast32_t direct;
+ atomic_uint_fast32_t callback;
+ isc_quota_t *quota;
+ isc_quota_cb_t callbacks[100];
+} qthreadinfo_t;
+
+static atomic_uint_fast32_t g_tnum = 0;
+/* at most 10 * 100 quota_detach threads */
+isc_thread_t g_threads[10 * 100];
+
+static void *
+quota_detach(void *quotap) {
+ isc_quota_t *quota = (isc_quota_t *)quotap;
+ uv_sleep(10);
+ isc_quota_detach(&quota);
+ return ((isc_threadresult_t)0);
+}
+
+static void
+quota_callback(isc_quota_t *quota, void *data) {
+ qthreadinfo_t *qti = (qthreadinfo_t *)data;
+ atomic_fetch_add_relaxed(&qti->callback, 1);
+ int tnum = atomic_fetch_add_relaxed(&g_tnum, 1);
+ isc_thread_create(quota_detach, quota, &g_threads[tnum]);
+}
+
+static isc_threadresult_t
+quota_thread(void *qtip) {
+ qthreadinfo_t *qti = (qthreadinfo_t *)qtip;
+ for (int i = 0; i < 100; i++) {
+ isc_quota_cb_init(&qti->callbacks[i], quota_callback, qti);
+ isc_quota_t *quota = NULL;
+ isc_result_t result = isc_quota_attach_cb(qti->quota, &quota,
+ &qti->callbacks[i]);
+ if (result == ISC_R_SUCCESS) {
+ atomic_fetch_add_relaxed(&qti->direct, 1);
+ int tnum = atomic_fetch_add_relaxed(&g_tnum, 1);
+ isc_thread_create(quota_detach, quota,
+ &g_threads[tnum]);
+ }
+ }
+ return ((isc_threadresult_t)0);
+}
+
+ISC_RUN_TEST_IMPL(isc_quota_callback_mt) {
+ UNUSED(state);
+ isc_quota_t quota;
+ int i;
+
+ isc_quota_init(&quota, 100);
+ static qthreadinfo_t qtis[10];
+ isc_thread_t threads[10];
+ for (i = 0; i < 10; i++) {
+ atomic_init(&qtis[i].direct, 0);
+ atomic_init(&qtis[i].callback, 0);
+ qtis[i].quota = &quota;
+ isc_thread_create(quota_thread, &qtis[i], &threads[i]);
+ }
+ for (i = 0; i < 10; i++) {
+ isc_thread_join(threads[i], NULL);
+ }
+
+ for (i = 0; i < (int)atomic_load(&g_tnum); i++) {
+ isc_thread_join(g_threads[i], NULL);
+ }
+ int direct = 0, ncallback = 0;
+
+ for (i = 0; i < 10; i++) {
+ direct += atomic_load(&qtis[i].direct);
+ ncallback += atomic_load(&qtis[i].callback);
+ }
+ /* Total quota gained must be 10 threads * 100 tries */
+ assert_int_equal(direct + ncallback, 10 * 100);
+ /*
+ * At least 100 must be direct, the rest is virtually random:
+ * - in a regular run I'm constantly getting 100:900 ratio
+ * - under rr - usually around ~120:880
+ * - under rr -h - 1000:0
+ */
+ assert_true(direct >= 100);
+
+ isc_quota_destroy(&quota);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_quota_get_set)
+ISC_TEST_ENTRY(isc_quota_hard)
+ISC_TEST_ENTRY(isc_quota_soft)
+ISC_TEST_ENTRY(isc_quota_callback)
+ISC_TEST_ENTRY(isc_quota_callback_mt)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/radix_test.c b/tests/isc/radix_test.c
new file mode 100644
index 0000000..fe589fe
--- /dev/null
+++ b/tests/isc/radix_test.c
@@ -0,0 +1,136 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/mem.h>
+#include <isc/netaddr.h>
+#include <isc/radix.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* test radix node removal */
+ISC_RUN_TEST_IMPL(isc_radix_remove) {
+ isc_radix_tree_t *radix = NULL;
+ isc_radix_node_t *node;
+ isc_prefix_t prefix;
+ isc_result_t result;
+ struct in_addr in_addr;
+ isc_netaddr_t netaddr;
+
+ UNUSED(state);
+
+ result = isc_radix_create(mctx, &radix, 32);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ in_addr.s_addr = inet_addr("1.1.1.1");
+ isc_netaddr_fromin(&netaddr, &in_addr);
+ NETADDR_TO_PREFIX_T(&netaddr, prefix, 32);
+
+ node = NULL;
+ result = isc_radix_insert(radix, &node, NULL, &prefix);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ node->data[0] = (void *)32;
+ isc_refcount_destroy(&prefix.refcount);
+
+ in_addr.s_addr = inet_addr("1.0.0.0");
+ isc_netaddr_fromin(&netaddr, &in_addr);
+ NETADDR_TO_PREFIX_T(&netaddr, prefix, 8);
+
+ node = NULL;
+ result = isc_radix_insert(radix, &node, NULL, &prefix);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ node->data[0] = (void *)8;
+ isc_refcount_destroy(&prefix.refcount);
+
+ in_addr.s_addr = inet_addr("1.1.1.0");
+ isc_netaddr_fromin(&netaddr, &in_addr);
+ NETADDR_TO_PREFIX_T(&netaddr, prefix, 24);
+
+ node = NULL;
+ result = isc_radix_insert(radix, &node, NULL, &prefix);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ node->data[0] = (void *)24;
+ isc_refcount_destroy(&prefix.refcount);
+
+ isc_radix_remove(radix, node);
+
+ isc_radix_destroy(radix, NULL);
+}
+
+/* test radix searching */
+ISC_RUN_TEST_IMPL(isc_radix_search) {
+ isc_radix_tree_t *radix = NULL;
+ isc_radix_node_t *node;
+ isc_prefix_t prefix;
+ isc_result_t result;
+ struct in_addr in_addr;
+ isc_netaddr_t netaddr;
+
+ UNUSED(state);
+
+ result = isc_radix_create(mctx, &radix, 32);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ in_addr.s_addr = inet_addr("3.3.3.0");
+ isc_netaddr_fromin(&netaddr, &in_addr);
+ NETADDR_TO_PREFIX_T(&netaddr, prefix, 24);
+
+ node = NULL;
+ result = isc_radix_insert(radix, &node, NULL, &prefix);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ node->data[0] = (void *)1;
+ isc_refcount_destroy(&prefix.refcount);
+
+ in_addr.s_addr = inet_addr("3.3.0.0");
+ isc_netaddr_fromin(&netaddr, &in_addr);
+ NETADDR_TO_PREFIX_T(&netaddr, prefix, 16);
+
+ node = NULL;
+ result = isc_radix_insert(radix, &node, NULL, &prefix);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ node->data[0] = (void *)2;
+ isc_refcount_destroy(&prefix.refcount);
+
+ in_addr.s_addr = inet_addr("3.3.3.3");
+ isc_netaddr_fromin(&netaddr, &in_addr);
+ NETADDR_TO_PREFIX_T(&netaddr, prefix, 22);
+
+ node = NULL;
+ result = isc_radix_search(radix, &node, &prefix);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_ptr_equal(node->data[0], (void *)2);
+
+ isc_refcount_destroy(&prefix.refcount);
+
+ isc_radix_destroy(radix, NULL);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_radix_remove)
+ISC_TEST_ENTRY(isc_radix_search)
+
+ISC_TEST_LIST_END
+ISC_TEST_MAIN
diff --git a/tests/isc/random_test.c b/tests/isc/random_test.c
new file mode 100644
index 0000000..1935846
--- /dev/null
+++ b/tests/isc/random_test.c
@@ -0,0 +1,787 @@
+/*
+ * 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.
+ */
+
+/*
+ * IMPORTANT NOTE:
+ * These tests work by generating a large number of pseudo-random numbers
+ * and then statistically analyzing them to determine whether they seem
+ * random. The test is expected to fail on occasion by random happenstance.
+ */
+
+#include <inttypes.h>
+#include <math.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/commandline.h>
+#include <isc/mem.h>
+#include <isc/nonce.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+#define REPS 25000
+
+typedef double(pvalue_func_t)(uint16_t *values, size_t length);
+
+/* igamc(), igam(), etc. were adapted (and cleaned up) from the Cephes
+ * math library:
+ *
+ * Cephes Math Library Release 2.8: June, 2000
+ * Copyright 1985, 1987, 2000 by Stephen L. Moshier
+ *
+ * The Cephes math library was released into the public domain as part
+ * of netlib.
+ */
+
+static double MACHEP = 1.11022302462515654042E-16;
+static double MAXLOG = 7.09782712893383996843E2;
+static double big = 4.503599627370496e15;
+static double biginv = 2.22044604925031308085e-16;
+
+static double
+igamc(double a, double x);
+static double
+igam(double a, double x);
+
+typedef enum {
+ ISC_RANDOM8,
+ ISC_RANDOM16,
+ ISC_RANDOM32,
+ ISC_RANDOM_BYTES,
+ ISC_RANDOM_UNIFORM,
+ ISC_NONCE_BYTES
+} isc_random_func;
+
+static double
+igamc(double a, double x) {
+ double ans, ax, c, r, t, y, z;
+ double pkm1, pkm2, qkm1, qkm2;
+
+ if ((x <= 0) || (a <= 0)) {
+ return (1.0);
+ }
+
+ if ((x < 1.0) || (x < a)) {
+ return (1.0 - igam(a, x));
+ }
+
+ ax = a * log(x) - x - lgamma(a);
+ if (ax < -MAXLOG) {
+ print_error("# igamc: UNDERFLOW, ax=%f\n", ax);
+ return (0.0);
+ }
+ ax = exp(ax);
+
+ /* continued fraction */
+ y = 1.0 - a;
+ z = x + y + 1.0;
+ c = 0.0;
+ pkm2 = 1.0;
+ qkm2 = x;
+ pkm1 = x + 1.0;
+ qkm1 = z * x;
+ ans = pkm1 / qkm1;
+
+ do {
+ double yc, pk, qk;
+ c += 1.0;
+ y += 1.0;
+ z += 2.0;
+ yc = y * c;
+ pk = pkm1 * z - pkm2 * yc;
+ qk = qkm1 * z - qkm2 * yc;
+ if (qk != 0) {
+ r = pk / qk;
+ t = fabs((ans - r) / r);
+ ans = r;
+ } else {
+ t = 1.0;
+ }
+
+ pkm2 = pkm1;
+ pkm1 = pk;
+ qkm2 = qkm1;
+ qkm1 = qk;
+
+ if (fabs(pk) > big) {
+ pkm2 *= biginv;
+ pkm1 *= biginv;
+ qkm2 *= biginv;
+ qkm1 *= biginv;
+ }
+ } while (t > MACHEP);
+
+ return (ans * ax);
+}
+
+static double
+igam(double a, double x) {
+ double ans, ax, c, r;
+
+ if ((x <= 0) || (a <= 0)) {
+ return (0.0);
+ }
+
+ if ((x > 1.0) && (x > a)) {
+ return (1.0 - igamc(a, x));
+ }
+
+ /* Compute x**a * exp(-x) / md_gamma(a) */
+ ax = a * log(x) - x - lgamma(a);
+ if (ax < -MAXLOG) {
+ print_error("# igam: UNDERFLOW, ax=%f\n", ax);
+ return (0.0);
+ }
+ ax = exp(ax);
+
+ /* power series */
+ r = a;
+ c = 1.0;
+ ans = 1.0;
+
+ do {
+ r += 1.0;
+ c *= x / r;
+ ans += c;
+ } while (c / ans > MACHEP);
+
+ return (ans * ax / a);
+}
+
+static int8_t scounts_table[65536];
+static uint8_t bitcounts_table[65536];
+
+static int8_t
+scount_calculate(uint16_t n) {
+ int i;
+ int8_t sc;
+
+ sc = 0;
+ for (i = 0; i < 16; i++) {
+ uint16_t lsb;
+
+ lsb = n & 1;
+ if (lsb != 0) {
+ sc += 1;
+ } else {
+ sc -= 1;
+ }
+
+ n >>= 1;
+ }
+
+ return (sc);
+}
+
+static uint8_t
+bitcount_calculate(uint16_t n) {
+ int i;
+ uint8_t bc;
+
+ bc = 0;
+ for (i = 0; i < 16; i++) {
+ uint16_t lsb;
+
+ lsb = n & 1;
+ if (lsb != 0) {
+ bc += 1;
+ }
+
+ n >>= 1;
+ }
+
+ return (bc);
+}
+
+static void
+tables_init(void) {
+ uint32_t i;
+
+ for (i = 0; i < 65536; i++) {
+ scounts_table[i] = scount_calculate(i);
+ bitcounts_table[i] = bitcount_calculate(i);
+ }
+}
+
+/*
+ * The following code for computing Marsaglia's rank is based on the
+ * implementation in cdbinrnk.c from the diehard tests by George
+ * Marsaglia.
+ *
+ * This function destroys (modifies) the data passed in bits.
+ */
+static uint32_t
+matrix_binaryrank(uint32_t *bits, size_t rows, size_t cols) {
+ unsigned int rt = 0;
+ uint32_t rank = 0;
+ uint32_t tmp;
+
+ for (size_t k = 0; k < rows; k++) {
+ size_t i = k;
+
+ while (rt >= cols || ((bits[i] >> rt) & 1) == 0) {
+ i++;
+
+ if (i < rows) {
+ continue;
+ } else {
+ rt++;
+ if (rt < cols) {
+ i = k;
+ continue;
+ }
+ }
+
+ return (rank);
+ }
+
+ rank++;
+ if (i != k) {
+ tmp = bits[i];
+ bits[i] = bits[k];
+ bits[k] = tmp;
+ }
+
+ for (size_t j = i + 1; j < rows; j++) {
+ if (((bits[j] >> rt) & 1) == 0) {
+ continue;
+ } else {
+ bits[j] ^= bits[k];
+ }
+ }
+
+ rt++;
+ }
+
+ return (rank);
+}
+
+static void
+random_test(pvalue_func_t *func, isc_random_func test_func) {
+ uint32_t m;
+ uint32_t j;
+ uint32_t histogram[11] = { 0 };
+ uint32_t passed;
+ double proportion;
+ double p_hat;
+ double lower_confidence, higher_confidence;
+ double chi_square;
+ double p_value_t;
+ double alpha;
+
+ tables_init();
+
+ m = 1000;
+ passed = 0;
+
+ for (j = 0; j < m; j++) {
+ uint32_t i;
+ uint32_t values[REPS];
+ uint16_t *uniform_values;
+ double p_value;
+
+ switch (test_func) {
+ case ISC_RANDOM8:
+ for (i = 0; i < (sizeof(values) / sizeof(*values)); i++)
+ {
+ values[i] = isc_random8();
+ }
+ break;
+ case ISC_RANDOM16:
+ for (i = 0; i < (sizeof(values) / sizeof(*values)); i++)
+ {
+ values[i] = isc_random16();
+ }
+ break;
+ case ISC_RANDOM32:
+ for (i = 0; i < (sizeof(values) / sizeof(*values)); i++)
+ {
+ values[i] = isc_random32();
+ }
+ break;
+ case ISC_RANDOM_BYTES:
+ isc_random_buf(values, sizeof(values));
+ break;
+ case ISC_RANDOM_UNIFORM:
+ uniform_values = (uint16_t *)values;
+ for (i = 0;
+ i < (sizeof(values) / (sizeof(*uniform_values)));
+ i++)
+ {
+ uniform_values[i] =
+ isc_random_uniform(UINT16_MAX);
+ }
+ break;
+ case ISC_NONCE_BYTES:
+ isc_nonce_buf(values, sizeof(values));
+ break;
+ }
+
+ p_value = (*func)((uint16_t *)values, REPS * 2);
+ if (p_value >= 0.01) {
+ passed++;
+ }
+
+ assert_in_range(p_value, 0.0, 1.0);
+
+ i = (int)floor(p_value * 10);
+ histogram[i]++;
+ }
+
+ /*
+ * Check proportion of sequences passing a test (see section
+ * 4.2.1 in NIST SP 800-22).
+ */
+ alpha = 0.01; /* the significance level */
+ proportion = (double)passed / (double)m;
+ p_hat = 1.0 - alpha;
+ lower_confidence = p_hat - (3.0 * sqrt((p_hat * (1.0 - p_hat)) / m));
+ higher_confidence = p_hat + (3.0 * sqrt((p_hat * (1.0 - p_hat)) / m));
+
+ assert_in_range(proportion, lower_confidence, higher_confidence);
+
+ /*
+ * Check uniform distribution of p-values (see section 4.2.2 in
+ * NIST SP 800-22).
+ */
+
+ /* Fold histogram[10] (p_value = 1.0) into histogram[9] for
+ * interval [0.9, 1.0]
+ */
+ histogram[9] += histogram[10];
+ histogram[10] = 0;
+
+ /* Pre-requisite that at least 55 sequences are processed. */
+ assert_true(m >= 55);
+
+ chi_square = 0.0;
+ for (j = 0; j < 10; j++) {
+ double numer;
+ double denom;
+
+ numer = (histogram[j] - (m / 10.0)) *
+ (histogram[j] - (m / 10.0));
+ denom = m / 10.0;
+ chi_square += numer / denom;
+ }
+
+ p_value_t = igamc(9 / 2.0, chi_square / 2.0);
+
+ assert_true(p_value_t >= 0.0001);
+}
+
+/*
+ * This is a frequency (monobits) test taken from the NIST SP 800-22
+ * RANDOM test suite.
+ */
+static double
+monobit(uint16_t *values, size_t length) {
+ size_t i;
+ int32_t scount;
+ uint32_t numbits;
+ double s_obs;
+ double p_value;
+
+ UNUSED(mctx);
+
+ numbits = length * sizeof(*values) * 8;
+ scount = 0;
+
+ for (i = 0; i < length; i++) {
+ scount += scounts_table[values[i]];
+ }
+
+ /* Preconditions (section 2.1.7 in NIST SP 800-22) */
+ assert_true(numbits >= 100);
+
+ s_obs = abs(scount) / sqrt(numbits);
+ p_value = erfc(s_obs / sqrt(2.0));
+
+ return (p_value);
+}
+
+/*
+ * This is the runs test taken from the NIST SP 800-22 RNG test suite.
+ */
+static double
+runs(uint16_t *values, size_t length) {
+ size_t i;
+ uint32_t bcount;
+ uint32_t numbits;
+ double pi;
+ double tau;
+ uint32_t j;
+ uint32_t b;
+ uint8_t bit_prev;
+ uint32_t v_obs;
+ double numer;
+ double denom;
+ double p_value;
+
+ UNUSED(mctx);
+
+ numbits = length * sizeof(*values) * 8;
+ bcount = 0;
+
+ for (i = 0; i < length; i++) {
+ bcount += bitcounts_table[values[i]];
+ }
+
+ pi = (double)bcount / (double)numbits;
+ tau = 2.0 / sqrt(numbits);
+
+ /* Preconditions (section 2.3.7 in NIST SP 800-22) */
+ assert_true(numbits >= 100);
+
+ /*
+ * Pre-condition implied from the monobit test. This can fail
+ * for some sequences, and the p-value is taken as 0 in these
+ * cases.
+ */
+ if (fabs(pi - 0.5) >= tau) {
+ return (0.0);
+ }
+
+ /* Compute v_obs */
+ j = 0;
+ b = 14;
+ bit_prev = (values[j] & (1U << 15)) == 0 ? 0 : 1;
+
+ v_obs = 0;
+
+ for (i = 1; i < numbits; i++) {
+ uint8_t bit_this = (values[j] & (1U << b)) == 0 ? 0 : 1;
+ if (b == 0) {
+ b = 15;
+ j++;
+ } else {
+ b--;
+ }
+
+ v_obs += bit_this ^ bit_prev;
+
+ bit_prev = bit_this;
+ }
+
+ v_obs += 1;
+
+ numer = fabs(v_obs - (2.0 * numbits * pi * (1.0 - pi)));
+ denom = 2.0 * sqrt(2.0 * numbits) * pi * (1.0 - pi);
+
+ p_value = erfc(numer / denom);
+
+ return (p_value);
+}
+
+/*
+ * This is the block frequency test taken from the NIST SP 800-22 RNG
+ * test suite.
+ */
+static double
+blockfrequency(uint16_t *values, size_t length) {
+ uint32_t i;
+ uint32_t numbits;
+ uint32_t mbits;
+ uint32_t mwords;
+ uint32_t numblocks;
+ double *pi;
+ double chi_square;
+ double p_value;
+
+ numbits = length * sizeof(*values) * 8;
+ mbits = 32000;
+ mwords = mbits / 16;
+ numblocks = numbits / mbits;
+
+ /* Preconditions (section 2.2.7 in NIST SP 800-22) */
+ assert_true(numbits >= 100);
+ assert_true(mbits >= 20);
+ assert_true((double)mbits > (0.01 * numbits));
+ assert_true(numblocks < 100);
+ assert_true(numbits >= (mbits * numblocks));
+
+ pi = isc_mem_get(mctx, numblocks * sizeof(double));
+ assert_non_null(pi);
+
+ for (i = 0; i < numblocks; i++) {
+ uint32_t j;
+ pi[i] = 0.0;
+ for (j = 0; j < mwords; j++) {
+ uint32_t idx;
+
+ idx = i * mwords + j;
+ pi[i] += bitcounts_table[values[idx]];
+ }
+ pi[i] /= mbits;
+ }
+
+ /* Compute chi_square */
+ chi_square = 0.0;
+ for (i = 0; i < numblocks; i++) {
+ chi_square += (pi[i] - 0.5) * (pi[i] - 0.5);
+ }
+
+ chi_square *= 4 * mbits;
+
+ isc_mem_put(mctx, pi, numblocks * sizeof(double));
+
+ p_value = igamc(numblocks * 0.5, chi_square * 0.5);
+
+ return (p_value);
+}
+
+/*
+ * This is the binary matrix rank test taken from the NIST SP 800-22 RNG
+ * test suite.
+ */
+static double
+binarymatrixrank(uint16_t *values, size_t length) {
+ uint32_t i;
+ size_t matrix_m;
+ size_t matrix_q;
+ uint32_t num_matrices;
+ size_t numbits;
+ uint32_t fm_0;
+ uint32_t fm_1;
+ uint32_t fm_rest;
+ double term1;
+ double term2;
+ double term3;
+ double chi_square;
+ double p_value;
+
+ UNUSED(mctx);
+
+ matrix_m = 32;
+ matrix_q = 32;
+ num_matrices = length / ((matrix_m * matrix_q) / 16);
+ numbits = num_matrices * matrix_m * matrix_q;
+
+ /* Preconditions (section 2.5.7 in NIST SP 800-22) */
+ assert_int_equal(matrix_m, 32);
+ assert_int_equal(matrix_q, 32);
+ assert_true(numbits >= (38 * matrix_m * matrix_q));
+
+ fm_0 = 0;
+ fm_1 = 0;
+ fm_rest = 0;
+ for (i = 0; i < num_matrices; i++) {
+ /*
+ * Each uint32_t supplies 32 bits, so a 32x32 bit matrix
+ * takes up uint32_t array of size 32.
+ */
+ uint32_t bits[32];
+ int j;
+ uint32_t rank;
+
+ for (j = 0; j < 32; j++) {
+ size_t idx;
+ uint32_t r1;
+ uint32_t r2;
+
+ idx = i * ((matrix_m * matrix_q) / 16);
+ idx += j * 2;
+
+ r1 = values[idx];
+ r2 = values[idx + 1];
+ bits[j] = (r1 << 16) | r2;
+ }
+
+ rank = matrix_binaryrank(bits, matrix_m, matrix_q);
+
+ if (rank == matrix_m) {
+ fm_0++;
+ } else if (rank == (matrix_m - 1)) {
+ fm_1++;
+ } else {
+ fm_rest++;
+ }
+ }
+
+ /* Compute chi_square */
+ term1 = ((fm_0 - (0.2888 * num_matrices)) *
+ (fm_0 - (0.2888 * num_matrices))) /
+ (0.2888 * num_matrices);
+ term2 = ((fm_1 - (0.5776 * num_matrices)) *
+ (fm_1 - (0.5776 * num_matrices))) /
+ (0.5776 * num_matrices);
+ term3 = ((fm_rest - (0.1336 * num_matrices)) *
+ (fm_rest - (0.1336 * num_matrices))) /
+ (0.1336 * num_matrices);
+
+ chi_square = term1 + term2 + term3;
+
+ p_value = exp(-chi_square * 0.5);
+
+ return (p_value);
+}
+
+/***
+ *** Tests for isc_random32() function
+ ***/
+
+/* Monobit test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random32_monobit) {
+ UNUSED(state);
+
+ random_test(monobit, ISC_RANDOM32);
+}
+
+/* Runs test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random32_runs) {
+ UNUSED(state);
+
+ random_test(runs, ISC_RANDOM32);
+}
+
+/* Block frequency test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random32_blockfrequency) {
+ UNUSED(state);
+
+ random_test(blockfrequency, ISC_RANDOM32);
+}
+
+/* Binary matrix rank test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random32_binarymatrixrank) {
+ UNUSED(state);
+
+ random_test(binarymatrixrank, ISC_RANDOM32);
+}
+
+/***
+ *** Tests for isc_random_bytes() function
+ ***/
+
+/* Monobit test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random_bytes_monobit) {
+ UNUSED(state);
+
+ random_test(monobit, ISC_RANDOM_BYTES);
+}
+
+/* Runs test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random_bytes_runs) {
+ UNUSED(state);
+
+ random_test(runs, ISC_RANDOM_BYTES);
+}
+
+/* Block frequency test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random_bytes_blockfrequency) {
+ UNUSED(state);
+
+ random_test(blockfrequency, ISC_RANDOM_BYTES);
+}
+
+/* Binary matrix rank test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random_bytes_binarymatrixrank) {
+ UNUSED(state);
+
+ random_test(binarymatrixrank, ISC_RANDOM_BYTES);
+}
+
+/***
+ *** Tests for isc_random_uniform() function:
+ ***/
+
+/* Monobit test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random_uniform_monobit) {
+ UNUSED(state);
+
+ random_test(monobit, ISC_RANDOM_UNIFORM);
+}
+
+/* Runs test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random_uniform_runs) {
+ UNUSED(state);
+
+ random_test(runs, ISC_RANDOM_UNIFORM);
+}
+
+/* Block frequency test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random_uniform_blockfrequency) {
+ UNUSED(state);
+
+ random_test(blockfrequency, ISC_RANDOM_UNIFORM);
+}
+
+/* Binary matrix rank test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_random_uniform_binarymatrixrank) {
+ UNUSED(state);
+
+ random_test(binarymatrixrank, ISC_RANDOM_UNIFORM);
+}
+
+/* Tests for isc_nonce_bytes() function */
+
+/* Monobit test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_nonce_bytes_monobit) {
+ UNUSED(state);
+
+ random_test(monobit, ISC_NONCE_BYTES);
+}
+
+/* Runs test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_nonce_bytes_runs) {
+ UNUSED(state);
+
+ random_test(runs, ISC_NONCE_BYTES);
+}
+
+/* Block frequency test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_nonce_bytes_blockfrequency) {
+ UNUSED(state);
+
+ random_test(blockfrequency, ISC_NONCE_BYTES);
+}
+
+/* Binary matrix rank test for the RANDOM */
+ISC_RUN_TEST_IMPL(isc_nonce_bytes_binarymatrixrank) {
+ UNUSED(state);
+
+ random_test(binarymatrixrank, ISC_NONCE_BYTES);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_random32_monobit)
+ISC_TEST_ENTRY(isc_random32_runs)
+ISC_TEST_ENTRY(isc_random32_blockfrequency)
+ISC_TEST_ENTRY(isc_random32_binarymatrixrank)
+ISC_TEST_ENTRY(isc_random_bytes_monobit)
+ISC_TEST_ENTRY(isc_random_bytes_runs)
+ISC_TEST_ENTRY(isc_random_bytes_blockfrequency)
+ISC_TEST_ENTRY(isc_random_bytes_binarymatrixrank)
+ISC_TEST_ENTRY(isc_random_uniform_monobit)
+ISC_TEST_ENTRY(isc_random_uniform_runs)
+ISC_TEST_ENTRY(isc_random_uniform_blockfrequency)
+ISC_TEST_ENTRY(isc_random_uniform_binarymatrixrank)
+ISC_TEST_ENTRY(isc_nonce_bytes_monobit)
+ISC_TEST_ENTRY(isc_nonce_bytes_runs)
+ISC_TEST_ENTRY(isc_nonce_bytes_blockfrequency)
+ISC_TEST_ENTRY(isc_nonce_bytes_binarymatrixrank)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/regex_test.c b/tests/isc/regex_test.c
new file mode 100644
index 0000000..12051f1
--- /dev/null
+++ b/tests/isc/regex_test.c
@@ -0,0 +1,2335 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif /* ifdef HAVE_REGEX_H */
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/commandline.h>
+#include <isc/print.h>
+#include <isc/regex.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* test isc_regex_validate() */
+ISC_RUN_TEST_IMPL(regex_validate) {
+ /*
+ * test regex were generated using http://code.google.com/p/regfuzz/
+ * modified to use only printable characters
+ */
+ struct {
+ const char *expression;
+ int expect;
+ int exception; /* regcomp accepts but is
+ * disallowed. */
+ } tests[] = {
+ { "", -1, 0 },
+ { "*", -1, 0 },
+ { ".*", 0, 0 },
+ { ".**", -1, 0 },
+ { ".*\?", -1, 0 },
+ { ".*+", -1, 0 },
+ { "+", -1, 0 },
+ { ".+", 0, 0 },
+ { ".++", -1, 0 },
+ { ".+\?", -1, 0 },
+ { ".+*", -1, 0 },
+ { "\?", -1, 0 },
+ { ".\?", 0, 0 },
+ { ".\?\?", -1, 0 },
+ { ".\?*", -1, 0 },
+ { ".\?+", -1, 0 },
+ { "(", -1, 0 },
+ { "()", 1, 0 },
+ { "(|)", -1, 0 },
+ { "(a|)", -1, 0 },
+ { "(|b)", -1, 0 },
+ { ".{", 0, 0 },
+ { ".{1", -1, 0 },
+ { ".\\{1", 0, 0 },
+ { ".{1}", 0, 0 },
+ { ".\\{1}", 0, 0 },
+ { ".{,", 0, 0 },
+ { ".{,}", 0, 0 },
+ { ".{1,}", 0, 0 },
+ { ".\\{1,}", 0, 0 },
+ { ".{1,\\}", -1, 0 },
+ { ".{1,", -1, 0 },
+ { ".\\{1,", 0, 0 },
+ { ".{1,2}", 0, 0 },
+ { ".{1,2}*", -1, 0 },
+ { ".{1,2}+", -1, 0 },
+ { ".{1,2}\?", -1, 0 },
+ { ".{1,2", -1, 0 },
+ { ".{2,1}", -1, 0 },
+ { "[", -1, 0 },
+ { "[]", -1, 0 },
+ { "[]]", 0, 0 },
+ { "[[]", 0, 0 },
+ { "[^]", -1, 0 },
+ { "[1-2-3]", -1, 0 },
+ { "[1-22-3]", 0, 0 },
+ { "[+--23]", 0, 0 },
+ { "[+--]", 0, 0 },
+ { "[-1]", 0, 0 },
+ { "[1-]", 0, 0 },
+ { "[[.^.]]", 0, 0 },
+ { "[^]]", 0, 0 },
+ { "[^^]", 0, 0 },
+ { "[]]\?", 0, 0 },
+ { "[[]\?", 0, 0 },
+ { "[[..]]", -1, 0 },
+ { "[[...]]", 0, 0 },
+ { "[[..5.]--]", -1, 0 },
+ { "[[.+.]--]", 0, 0 },
+ { "[[..+.]--]", -1, 0 },
+ { "[[.5.]--]", -1, 0 },
+ { "[1-[=x=]]", -1, 0 },
+ { "[[:alpha:]]", 0, 0 },
+ { "[[:alpha:]", -1, 0 },
+ { "[[:alnum:]]", 0, 0 },
+ { "[[:alnum:]", -1, 0 },
+ { "[[:digit:]]", 0, 0 },
+ { "[[:digit:]", -1, 0 },
+ { "[[:punct:]]", 0, 0 },
+ { "[[:punct:]", -1, 0 },
+ { "[[:graph:]]", 0, 0 },
+ { "[[:graph:]", -1, 0 },
+ { "[[:space:]]", 0, 0 },
+ { "[[:space:]", -1, 0 },
+ { "[[:blank:]]", 0, 0 },
+ { "[[:blank:]", -1, 0 },
+ { "[[:upper:]]", 0, 0 },
+ { "[[:upper:]", -1, 0 },
+ { "[[:cntrl:]]", 0, 0 },
+ { "[[:cntrl:]", -1, 0 },
+ { "[[:print:]]", 0, 0 },
+ { "[[:print:]", -1, 0 },
+ { "[[:xdigit:]]", 0, 0 },
+ { "[[:xdigit:]", -1, 0 },
+ { "[[:unknown:]]", -1, 0 },
+ { "\\[", 0, 0 },
+ { "(a)\\1", 1, 0 },
+ { "(a)\\2", -1, 1 },
+ { "\\0", 0, 0 },
+ { "[[][:g(\?(raph:][:alnu)(\?{m:][:space:]h]<Z3})AAA)S[:space:]"
+ "{176,}",
+ 0, 0 },
+ { "(()IIIIIIII(III[[[[[[[[[[[[[[[[[[^[[[[[[[[ [^ "
+ " "
+ "fX][:ascii:].)N[:a(\?<!lpha:])][:punct:]e*y+)a{-124,223}",
+ 3, 0 },
+ { "(pP\\\\\\(\?<!"
+ "\\\\\\\\\\\\\\\\\\\\\\lRRRRRRRRRRRRRRRRBBBBBBBBBBBBBBBB))"
+ "kkkkkkkkkkkkkkkkkkkkk|^",
+ 1, 0 },
+ { "[^[^[{111}(\?=(\?:(\?>/"
+ "r(\?<(\?=!(\?(\?!<!Q(\?:=0_{Meqipm`(\?((\?{x|N)))))|))+]+]Z)"
+ "O{,-215}])}))___________________{}",
+ 0, 0 },
+ { "[C{,-218(\?=}E^< ]PP-Ga)t``````````````````````````{138}", 0,
+ 0 },
+ { "[^h(\?<!(\?>Nn(\?#])))", 0, 0 },
+ { "[(\?!(\?<=[^{,37}AAAA(AAAAAAAAAAAAA])", 0, 0 },
+ { "[^((\?(\?:ms(\?<!xims:A{}(\?{*</H(\?=xL "
+ "$(\?<!,[})))*)qqqqqqqqqqqqqqqqqq)]"
+ "33333333333333333333333333333{[:graph:]p)-+( "
+ "oqD]){-10,}-{247}_______________________X-e[:alpha:][:"
+ "upperword:]_(______wwwwwwwww "
+ "/c[:upperword:][:alnum:][:alnum:][:pun(\?{ct:])[:blankcntrl:"
+ "]})*_*",
+ 2, 0 },
+ { "[(\?<!:lowerprin(\?{t:]{}}){113,})[:punct:]"
+ "IIIIIIIIIIIIIIIIIIIIIIII",
+ 0, 0 },
+ { "PP)", 0, 0 },
+ { "(([^(\?<!((\?>\?=[])p.]}8X[:blankcntrl:],{-119,94})XmF1.{)-)"
+ "[:upperword:])[:digit:]{zg-q",
+ 2, 0 },
+ { "[^[({(\?#254}))Z[l][x50]=444444444444(4444444444u[:punct:]"
+ "\?[:punct:(\?!])])",
+ 1, 0 },
+ { "[^[^[^([^((*4[(^((\?<=])Ec)", 0, 0 },
+ { "(0)Y:8biiiiiiiiiiiiiiiiiii", 1, 0 },
+ { "[^w(\?!)P::::::::::::::(\?#::(\?<=:::::::::]\"\"{}["
+ "3333333333333333(\?<=33333(\?!)9Xja][:alph(\?<=a:])xB1)("
+ "PX8Cf\?4444)qq[:digit:])",
+ 1, 0 },
+ { "([U[^[^].]^m]/306KS7JJJJJJJJ{})", 1, 0 },
+ { "[^[^([^[(\?!(\?>8j`Wg2(\?{,(\?>!#N++++(\?<![++++++)+"
+ "44444444bA:K(\?<!O3([:digit:]3]}}}}}}}}}}}}}}}}}}}}}}}}LP})"
+ "S",
+ 0, 0 },
+ { "[({(\?{,(\?(=213}*))})]WWWWWWWWWWWWWWW[:alnum:])", 0, 0 },
+ { "[:(\?<=ascii:])", 0, 0 },
+ { "[U(\?#)(\?<=+HzE])[:punct:]{-207,170}\?s.!", 0, 0 },
+ { "{}z=jU75~n#soD\"&\?UL`X{xxxxxxxxxxxxxxxxxxxx(xxxxxx${-246,"
+ "27}[:graph:]g\"{_bX)[:alnum:][:punct:]{-79,}-",
+ 1, 0 },
+ { "[^{,-186}@@@@[^(\?{@@(\?>@+(\?>l.]}))*\\BCYX]^W{52,123}("
+ "lXislccccccccccccccccc)-*)",
+ 1, 0 },
+ { "(x42+,)7=]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]", 1, 0 },
+ { "[^(*[:graph:]q/TH\?B(\?{P)]})uZn[:digit:]+2", 0, 0 },
+ { "([XXXXXXXXXXXXXXXXXXXXX[(:alnum:][:space:]i%[:upperw(\?=o("
+ "\?#rd:])) ",
+ 1, 0 },
+ { "(@@@@)", 1, 0 },
+ { "{-18,}[:as[(\?>^[cii:]]{}>+{-46,}{,95}[:punct:]{}"
+ "99999999999999])-{-134}'sK$"
+ "wCKjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj",
+ 0, 0 },
+ { "(l[:alpha:(\?!]))", 1, 0 },
+ { "[[^(\?{]|JJ[:alph(a:]X{})B^][:lowerprint:]n-219{-32}{19,105}"
+ "k4P}){,-144}",
+ 0, 0 },
+ { "[[^]P[:punct:][:alpha:][:xdigit:]syh]|W#JS*(m<2,P-RK)cA@", 1,
+ 0 },
+ { "([^((\?({\?<=)}){[^}^]{}])^P4[:punct:[]$)]", 1, 0 },
+ { "([(\?#:(\?{space:]}):{}{-242,}n)F[:alpha:]3$)d4H3up6qS[:"
+ "blankcntrl:]B:C{}[:upperword:]r",
+ 1, 0 },
+ { "([(\?:]))[:digit:]mLV.{}", 1, 0 },
+ { "[^PPP-[]{[,50}{128,}]111111111111111]p", 0, 0 },
+ { "[^([^([^([[^[([^[^[[2[[[[[[[[[[[[[^[[[[(\?(\?{:[[[[[[(\?([-["
+ ":ascii:]--*)",
+ -1, 0 },
+ { ")!F^DA/ZZZZZZZZZZZZZZZZZZ", 0, 0 },
+ { "[[[[[[[((\?=\?(\?>([[[[[[[^[[[[(\?()[[[K(\?#))])))]7Y[:"
+ "space:]{,-96}pP)[:ascii:]u{-88}:N{-251}uo",
+ 0, 0 },
+ { "t[:x(\?<=digit:])eYYYYYYYYYYYYYYYYYY{,-220}A", 0, 0 },
+ { "[[({10,}[:graph:]Pdddddd(\?#X)])[:alnum:(]]L-C){,50}[:"
+ "blankcntrl:]p[:gra(ph:]){66,}",
+ 0, 0 },
+ { "[^[^]*4br]w[:digit(\?::]n99999999999999999)P[:punct:]pP", 0,
+ 0 },
+ { "[:digit:]{67,247}!N{122})VrXe", 0, 0 },
+ { "[:xdigit:]^[:xdigit:]Z[:alnum:]^^^^1[:upperword:(\?=])[:"
+ "lowerprint:]*JJ-",
+ 0, 0 },
+ { "[[(\?imsximsx:^*e(){,3[6}](V~\?^[:asc(\?!ii:]I.dZ))]$^"
+ "AAAAAAAAAAAAAAAAAAAAAAAA[:space:]k)]",
+ 1, 0 },
+ { "W{,112}[:lowerp(\?<!rint:]$#GT>R7~t'"
+ "\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"9,O).",
+ 0, 0 },
+ { "[^{6((\?>\?:4}(\?<=G))f)"
+ "KKKKKKKKKKKKKKKKKKKKKKKKKKKKKpppppppp(\?=ppppp]{,-101}|[:"
+ "blankcntrl:]Z{-182})",
+ 0, 0 },
+ { "([:punct:]@^,,,,,,,,,,,,,,,,,,,,,,,,,,0\?:-o8NPIIIIIIIII)"
+ "pPKKKKKKKKKKKKKKKKKKKK",
+ 1, 0 },
+ { "([^[[^[^]]]])", 1, 0 },
+ { "[([^[(333\"(\?#\\\\[)(\?isx-x:\"Tx]')", 0, 0 },
+ { "[[n>^>T%.zzzzzzzzzzzzzzzzz$&|Fk.1o7^o, "
+ "^8{202,-12}$[:alnum:]]G[:upperword:]V[:xdigit:]L|[:"
+ "upperword:]KKKKKKKKKKKKYX\"\")xJ "
+ "~B@[{,-68}/][:upperword:]QI.",
+ 0, 0 },
+ { "[^[]tN^hy3\"d@v T[GE\?^~{124,10(\?{2}]})\?[:upperword:]O", 0,
+ 0 },
+ { "d.``````````````````````````[:up(\?=perword:]"
+ "RRRRRRRRRRRRRRR)",
+ 0, 0 },
+ { "[Z{{{{{{{{{{{{{(\?={(\?<!{{{{{{{{{(\?>{{J6N:H[tA+mN3Zmf:p\?]"
+ "\?){-181,82}S4n.b[:lowerpri(\?{nt:]|"
+ "ggggggggggggggggggggggggggggggg}))4)",
+ 0, 0 },
+ { "[^((/////[^////[^/////////[(^/////]fI{240}{-120}+]R]GA)", 0,
+ 0 },
+ { "[-(\?#.)(\?())[:alpha:](\?={(\?#}r)[:space:]PPW]o)", 0, 0 },
+ { "[:lowerp(\?{rint:]})201{46,}[:a[^scii:]0Q{37,}][:blankcntrl:"
+ "]1331",
+ 0, 0 },
+ { "[^(\?!(\?#)\\GIwxKKKKKKKKKK'$KKKKKKKK]l)bbb^&\?", 0, 0 },
+ { "[:ascii:]*[:sp(\?<=ace:])", 0, 0 },
+ { "({-66,}Z{})0I{-111,}[:punct(\?():])", 1, 0 },
+ { "[[^(\?!()%%%%%%%%%%%%%(\?:%%%%%%%%%%%%%%%%)t(\?{VX>B#6sUU("
+ "\?<!UUUUUU(\?=UUU[^UUUUUUUUUUUU(\?((\?:UPPPPPPPPPPP)"
+ "PPPPPPPPPPPPPPP]ffffffffffffffffffffffff)^[:space:]"
+ "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww{243}9[:lowerprint:]Dv[:"
+ "graph:])][:blankcntrl:]V%E[:graph:]})[:space:]{-83,}cQZ{}4{-"
+ "23,135}",
+ 0, 0 },
+ { "({,-76[}]O[:xdi(\?<!git:])\?5))))))))\?d[:lowerprint:]"
+ "b666666[:graph:]c",
+ 1, 0 },
+ { "{}{-145,}[:(\?(spa)ce:])f", 0, 0 },
+ { "[([^].{116,243}]T*[[^:punct(\?[{[^:(\?<!]]8()])[:alnum:])})]"
+ "N{}{,243}*[n]][:graph:]",
+ 1, 0 },
+ { "[^w]8888888888888888_________(__________[:ascii:]BdqTE$^0|"
+ "MNto*i#############[^#################])",
+ 1, 0 },
+ { "[^[[[<[()\?]GGG{,26[}[:alnum:]SSSSS.gggggggg[:graph:]"
+ "CCCCCCCCCCC{79,}{138,191}][:di(git:]u]@]"
+ "JJJJJJJJJJJJJJJJJJJJJJJ[:graph:(\?:][:alnum:]])[:alnum:])]",
+ 0, 0 },
+ { "[^(((BBBBBBBBBB(\?>BBBZvvvvvvvvvv(\?m(sximsx:vvv)iiiiiiii)))"
+ "j>Rs:Sm]0MMMMMMMMMMM|@F)Y]*^#EEEEEEE)*",
+ 0, 0 },
+ { "([^([(U(\?!)<<<<<<<<<<(\?#<<<<(\?<!<<<)(\?=L.{73,})+]n9U}fk%"
+ "Jn}'b Na<%yyyyyyyyyyyy)){-198,}]))[:space:].pP361U]3s@u_9AU "
+ "Te/{s`6=IMZdL1|.ySRo",
+ 1, 0 },
+ { "[[((\?<=\?>(\?#){}]{}`){1,82}){-143[,}]^G", 0, 0 },
+ { "[:digit:]W|[:up(\?<!perword:]{,-101}llllllllllllllllll[:"
+ "upperword:])mmYYYYYYYYYYYYYYYYYYYYYYY*",
+ 0, 0 },
+ { "@NHy)", 0, 0 },
+ { "([^[^]][:alnum:]222[^22222222(\?{2222222222222222][:lo(\?:"
+ "werprint:][:xdigit:]^[:blankcntrl:]s+N)[:alpha:]-"
+ "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWxxxxxxxxxxxxxxxxxxxxxxxxxxD["
+ ":space:]U)TTTTTTTTTTfffffffffffzzzzzzzzzzzzzzzzzzzzzzzzz})",
+ 1, 0 },
+ { "[^[^[[^[][^[]pP([^\?[^<=(\?=]){158,})]]]][:digit:]]"
+ "K22222222222p^dUKJ`\">@]",
+ 1, 0 },
+ { "[^[^[(\?imsximsx::p(\?{unct:][(\?>:ascii:]5w)]{159}\\Q\?@C]"
+ "4(44444444}[^)|)[:graph:]]C:b)",
+ 1, 0 },
+ { "[^[[(tYri[W<8%1(\?='yt][:lowerprint:[]))1r]][:alnum:][:"
+ "digit:]{48}{-52,-183}+][:alpha:]r][:upperword:]\?{-105,155}{"
+ "-55,-87}pPN#############################{63,232}]",
+ 0, 0 },
+ { "[*(\?>L(\?<(\?>=))]&&&&&&&(&&&&&&&&&&&&&&&&&&))[|WIX]{-62,-"
+ "114}S K=HW60XE<2+W",
+ 1, 0 },
+ { "(00000000000)z\\\\*t{}R{88}[:alnum:]*", 1, 0 },
+ { "(([^(\?=\?gggggg[gLw)]{-250,}[:xdigit:]yZ[:g(raph:]8QNr[:"
+ "space:][:blankcntrl:]A)][:digit:]D)[:xdigit:])",
+ 2, 0 },
+ { "[^([^,(\?<!]*))]", 0, 0 },
+ { "[^(\?{[:alnum:]]}}}}}}}}}}}}}}}}}}}}}}}){-83}", 0, 0 },
+ { "WWWWWWWW[:alnum(\?<=(\?#:]{,-1})@OSSS)[:digit:]", 0, 0 },
+ { "[^(\?!*]+G)", 0, 0 },
+ { "[LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL>s8.>[^{}$(\?(]]XXXXXXX)"
+ "XXXXXXXXXXXXXX[:alpha:]Whii\?p[:xdigit:])+",
+ 0, 0 },
+ { "(7777[:blankcntrl:])", 1, 0 },
+ { "[^C[:digit:]]{}YYYY(YYYYYYYYYYYYYYYY)", 1, 0 },
+ { "on|,#tve%F(w-::::::::::::::::::::::::::::*=->)", 1, 0 },
+ { "([((\?=(\?!((\?=')))27(<{})S-vvvvvvvvvv(\?="
+ "vvvvvvvvvvvvvvvvv[:punct:][:alnum:]}}}}}}}}}}}}}}}}}}}}}}}"
+ "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPgggggggggggggggggggggggggg(\?#("
+ "\?#gggggg<X){}]{-164,61})>+))uQ)W>[:punct:][:xdigit:][:"
+ "digit:][:punct:]{}[:digit:][:space:]){,-105}=xiAyf}o[:alpha:"
+ "]akZSYK+sl{",
+ 1, 0 },
+ { "[^[^]/S:Hq<[:upperword:(\?<=]W[:alnum:]X])1973", 0, 0 },
+ { "[[^[[^([^VVVV(\?!(VVVVVVVVVVVVVVVVVVVVV[VVVVX][^]2))"
+ "98ppppppppppppppppppppppppppppppp/////////////////////"
+ "b.]G{-101,}[:[ascii:]P].=~])AAAAAAAAAAAAA2{-153,}]]]]]]]]]]]"
+ "]]]]]]]]]]]]]]]]]]]]][:alnum:][:lowerprint:]WN/"
+ "D!rD]|4444{180}]V_@3lW#lat]",
+ 0, 0 },
+ { "[^[^([^TTTTT(\?:T(\?:T7777{,59}])[:graph:][:ascii(\?<=:]))f]"
+ "AD{,-43}%%%%%%%%%%%%%%%%)S|[:digit:]FZm<[:blankcntrl:]QT&xj*"
+ "{-114,}$[:xdigit:]042][:xdig[it:]{-180}027[:alpha:][:ascii:]"
+ "[:lowerprint:][:xdigit:]^|[:alnum:][^Mi]z!suQ{-44,-32}[:"
+ "digit:]]",
+ 0, 0 },
+ { ")", 0, 0 },
+ { "''''''''''[:a(\?imsxisx:lnum:])P", 0, 0 },
+ { "(([{20(\?<=8}[:alnum:]pP$`(\?#N)wRH[:graph:]aaaaaaaaaaaaaa("
+ "\?=aaaaaaaaaaaaaaaaP]a)))[:punct:]-\?)A^",
+ 2, 0 },
+ { "[^(.//"
+ "[:punct:]&-333333333333333333333333333(\?<!33)"
+ "LLLLLLLLLLLLLLLLL[:alnum:]$1]~8]|^\"A[:xdigit:]\?[:ascii:]{"
+ "128,}{,-74}[:graph:]{157}3N){-196,184}D",
+ 0, 0 },
+ { "[^($(\?{(\?<=)[#)]})[:space:]]nWML0D{}", 0, 0 },
+ { ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,[^]x{213,-93}(\?{A7]V{}})", 0,
+ 0 },
+ { "[k(\?=*)+^[f(])r_H6", 0, 0 },
+ { "[(\?#(\?{)]q})", 0, 0 },
+ { "([GLLLLLLLLLL(\?!((\?:LLLLLLLL]))C#T$Y))^|>W90DDDDDDDDDDD[^"
+ "DDDDDDDDDDDDDDDDDDDD]B[:punct:]c/",
+ 1, 0 },
+ { "[^(\?<!)(\?{b}){,199}A[:space:]+++++++(\?!++++++++{36}Tn])",
+ 0, 0 },
+ { "()[:alpha:]a", 1, 0 },
+ { "[(\?(:blan)kcntrl:])lUUUUUUUUUUUUUUUUUUUUUUU", 0, 0 },
+ { "[^[^(s[[[[[[[[[[[[[[(\?#[[[[[[[)\?`````][:blankcntrl:(\?>]|)"
+ "p1EmmmmmmmmmmmmmmmmmmmmmmmmmmmmL{-241}666666666666666666666)"
+ "]^bLDDDDDDDDDDDDD]",
+ 0, 0 },
+ { "[nn(\?<!nnnnn(\?#n8)=````````````````````{41,}]U,cb*%Y[:"
+ "graph:]).[:alnum:]\\\\\\\\\\gt",
+ 0, 0 },
+ { "()\?5{,-195}lm*Ga[:space:]Y", 1, 0 },
+ { "[(\?:].di)c", 0, 0 },
+ { "([([^([\?{})Za,$S(\?!p(\?{++(\?##V(\?<!Evuil.2(\?<![^[h|[^']"
+ "C)*\"]5]",
+ 1, 0 },
+ { "[((^24(\?#4[^Kkj{}))]]{232}47)077[:alpha:]zzzzzzzz{}", 0,
+ 0 },
+ { "[^(\?:[^F]o$h)-iV%]", 0, 0 },
+ { "[[^[([((([^(\?{[^((\?=)kaSx(\?imsximsx:w3A[`%+A$I{,62}ns&Y!#"
+ "ay "
+ "o9YAo{Y>1((\?>\?#45)Z{,108}{}11111111111111111111111111qqqq)"
+ "\?][:lowerprint:]mbo#)@",
+ 0, 0 },
+ { "[^iii8(888888(\?<!8^]))s", 0, 0 },
+ { "([[(\?(\?:({^]}[)[(r)])G]{,-87}", 1, 0 },
+ { "([[^{249,}(\?>(\?=)]]T()[:bl(\?!ankcntrl:]=jjjjjjjjjjjjjjjj-"
+ ")))t{}[:alpha:]-\":i! Gn[A4Ym7<<<<<<<<<<<<<<<<]",
+ 2, 0 },
+ { "^{}{[^,241(\?#}(\?m(\?ixim:sximsx:]t))+oD)", 0, 0 },
+ { "5[(\?#:xdigit:])", 0, 0 },
+ { "[^f{(\?>,22(9}[^[^])6KKKKKKKKKKKKK)]RRRRRRRRfuK99999999C}"
+ "osnNR]BgCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[:blankcntrl:]",
+ 0, 0 },
+ { "[^(\?=U){24,}W-{,17(\?:3[^}]q.nQ#PU_|i$$$$$$$$$$$$$$+)[:dig("
+ "\?<!it:]){-98}\?[:upperword:]]",
+ -1, 0 },
+ { "[(\?<=[0(\?!72])euE.]{,-159}[:alnum:]t-:l\?)$"
+ "yyyyyyyyyyyyyyyyyyyyyyyyyyfffffffffffffffffffffffffff",
+ 0, 0 },
+ { "[^[^]q[:asc(\?imsxmsx:ii:]JJJJJJJJJJJJJJJJJJJJ[:graph:]]$)`#"
+ "DdY^qqqqqqqqqqqqqqqqqqqqqqqqqqqu>4^4ta[:alpha:]",
+ 0, 0 },
+ { "(((b0HN)q))p5<T())`7JJv{'cv'#L8BNz", 4, 0 },
+ { "[pFp2VttBg(\?<=7777777777777|TTTTTTTTTTTTTTT[:space:]Z]^p\"["
+ ":blankcntrl:])",
+ 0, 0 },
+ { ")aM@@@@@@@@@@@@@", 0, 0 },
+ { "([^[(\?<![^])", 1, 0 },
+ { "()Z[:ascii:]", 1, 0 },
+ { "(fuPPo)..........................[:xdigit:]{}{,4}*kkkkkkkCx#"
+ ",_=&~)|.2x",
+ 1, 0 },
+ { "[+(\?<=){}++++++[:alnum:](\?=+]s)[:alnum:]~~~~~~"
+ "XXXXXXXXXXXXXXX.[:digit:]",
+ 0, 0 },
+ { "[{}[^^(\?(]))CCCCCCCCCCCCCCCCCCCCEg2cF]{}3", 0, 0 },
+ { "([[[^[^[^([[^[^([(\?<=G[[)=(\?!===(\?isximsx:==(\?#==[^====="
+ "(\?{==================$T[[^^u_TiC.Fo.02>X)uH]$})354b[:alnum:"
+ "]]]EVVVVVVVVVVVVVVVVVVVVVVVVVVVVVz[:digi(\?(t:][:upperword:]"
+ ")",
+ 1, 0 },
+ { "([:blankcntrl:]t-){121,}[:ascii:]444444{}[:graph:]E040", 1,
+ 0 },
+ { "[^{134,}]DzQ\?{-30,191})z,\?1Vfq!z}cgv)ERK)1T/=f\?>'", 0,
+ 0 },
+ { "@v)<yN]'l-/"
+ "KKKKKKKBBBBBBBBBBBBBMa2eLA[:digit(\?<!:])\"\"e|l$&m`_yn[:"
+ "blankcntrl:]uuuuuuuuuuuuuuuuuuu[:punct:]",
+ 0, 0 },
+ { "[[999999999999999(\?<=(\?:(\?ixmx:(\?>))])Y]|){,10}\?{}", 0,
+ 0 },
+ { "([[[(\?!^]P-AA[AAAAAA[A[^A)r]+B]])", 1, 0 },
+ { "3}|[:ascii:][:punct:]()", 1, 0 },
+ { "()dw", 1, 0 },
+ { "[N]{})))))))))))))))))))))))", 0, 0 },
+ { "[[[^([[(\?()(\?#)++([^\?{+++[^+++++++++++(\?!+(\?=+++++++r9/"
+ "n]N7{-219}{-91}pP[:punct:]T]mROm+~[:digit:][:digit:])Y:",
+ 0, 0 },
+ { "[^'Pu[(\?<!D&]_a[:alnum:]E<,F%4&[:xdigit:])][:lowerprint:]",
+ 0, 0 },
+ { "tttt(tttttttttt*uKKUUUUU)", 1, 0 },
+ { "([:ascii:]GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG)+kX______________{"
+ "}GGGGG\?TUH3,{67,77}|[:graph:]C{,-136}{}[:upperword:[]{,-6}&"
+ "]T84]n={C",
+ 1, 0 },
+ { "[:upperword:]DC[:u(\?<=pperword:]*d`H0\?m>~\?N|z#Ar--SO{,-"
+ "141}076)G\?{,-110}M+-[:alpha:]",
+ 0, 0 },
+ { "{,-214}{,10(9})", 1, 0 },
+ { "([^xxxxxxxxxxxxxxxxxMMMMMMMMMMMMMMXW])].[:punct:]Q`{-63,63}"
+ "Uua[:alnum:]\?OQssb#L@@@@@@@@(@@@)[:graph:]",
+ 2, 0 },
+ { "[[^(\?!```[^``````````````(\?<=``(\?>````````M/////(\?!/////"
+ "///////////////"
+ "[^GD!|#li]~)*.$]))Tq!]C[:lowerprint:]Qk[{}]]"
+ "JJJJJJJJJJJJJJJJJJJJJJJ{e])c",
+ 0, 0 },
+ { "$[5(7ES])[:xdigit:]%{MRMtYD&aS&g6jp&ghJ@:!I~4%{"
+ "P\?0vvvvvvvvvvvvvvvvvvvv\\\\\\\\\\\\\\\\\\\\\\\\x54[:"
+ "lowerprint:][:upperword:]",
+ 0, 0 },
+ { "[((([(\?((\?>[:alnum:][):as(\?<!cii:(\?:]Re))K|)|^){-28,89}"
+ "l<H.<H:N)QKuuuuuuuuw8E136P)^)[:ascii:]][:xdigit:]-",
+ 0, 0 },
+ { "(pjvA'x]=D\"qUby\\+'R)r\?C22[:ascii:]", 1, 0 },
+ { "[]*b~y C=#P\"6(gD%#-[^FBt{}]${-244}", 0, 0 },
+ { "[:up(\?!pe(\?=rword:])lA-'yb\"Xk|K_V\"/"
+ "@}:&zUA-)W#{-178,-142}(){-202,}",
+ 1, 0 },
+ { "()1.WldRA-!!!!!!!!!!!!!!!!!", 1, 0 },
+ { "lZZZZZZZZZZZZZZZ(Z[:al(\?:num:])"
+ "ttttttttttttttttttttttttttttttg.)6$yyy",
+ 1, 0 },
+ { "[([^([^[^(([([^[^(([[$(\?{P(\?=(\?<(\?!=(\?#P[^Y])<GA[:"
+ "ascii:][(\?#(\?<!:alpha:](B{100,})]}))\?)XU=",
+ 1, 0 },
+ { "[[dVw{6(\?{9,}2222kkkkkkkkkkkkkkkkkkkkkkkkkk|{}*E]]{}SB{35}-"
+ "w%{eh})<{-178,}",
+ 0, 0 },
+ { "(D(~))", 2, 0 },
+ { "[(:alpha:]{,90}Z|)[:ascii:]Du\?[:grap[^h:]^w+|{}][:ascii:]",
+ 0, 0 },
+ { "[:p(\?<=unct:]kkkkkkkkkkkkkkkkkkkk)", 0, 0 },
+ { "{}[:((\?<!dig((\?#it(\?#:]())p))ZZZZZZZZZZ[:blankcntrl:]){}{"
+ "-124,})[:ascii:]",
+ 1, 0 },
+ { "[[:graph:]{168}lRRRRRRRRRRRRR(\?#RRRRRRRRRRRRRRRRR)rrrr(\?("
+ "rrrrrr)rrrrrrrS[(\?<!@f)6>{,-49})q${98,}J\?]){",
+ 0, 0 },
+ { "([:pu(\?(nc)t:]F{-32,-102}+)\?cpP[:lowerprint:].^)", 1, 0 },
+ { "([{}{210,-238}]1:h)", 1, 0 },
+ { "([]QQQQ[QQQQQQQQQQQQQQQQQQ][:digit:]Z{-20,}Slllllll[:space:]"
+ "C^(@{-174,-156}fx{cf2c}{-242,}rBBBBBBBBBBBBBBBBBBc[:alpha:]"
+ "N\?))$[:graph:][:ascii:]P+nnnnnnnnnnnnnnnnnnnnnnn1N$r>>>>>>>"
+ ">>>>>>>>>>>>>>>>>(>>{,88}{,-234}__________)[:upperword:]R.[:"
+ "alnum:][:lowerprint:]^}\"",
+ 3, 0 },
+ { "([^(\?=]-))$", 1, 0 },
+ { "([:ascii:]\?,D[:upperword:][:xdigit:]tttttttttttt[^tt(\?<!"
+ "ttttttttt21f|.(pP[:punct:])])rrrrrrrr)",
+ 1, 0 },
+ { "([{1(\?=16}iiiiiiiiii((\?<=iiiiiiiiiiiiiiiiii|ZZZZZZZZZZZ("
+ "\?(\?#{ZZZZZZZ))c}))<<<<<(\?#<<<<<<<<<<<d7CVq8]w{-148,-168}"
+ "\\Gp){-230,}D3",
+ 1, 0 },
+ { "[^8888(88888888888EX].[:alnum:]){}", 0, 0 },
+ { "([^][^)2]-[:lower(\?=print:]{,79}[:graph:]n)", 1, 0 },
+ { "[bSi\?x_mp(C)0{64}[:space:]hhh(\?(hhh)hhL){5,130}'w\"$l&[:"
+ "xdigit:][:alpha:]IIIIIIIIIIIIIIIIIIIIIII+-SOOOOOOOOOOOO "
+ " (\?( ) ]f)ed",
+ 0, 0 },
+ { "[[^[(^(C.Jl[^X&Rb64a+Sd])'m[:alpha:])]]]{134,}", 0, 0 },
+ { "()L", 1, 0 },
+ { "[[(({224,(\?#88})@======(\?!=========(\?{=)PPP)i^@p(\?([:"
+ "punct:]})^^[^^^^^^^^^^^^^^^^^^^^^@)m]|{CS{,-3}168)-[:xdigit:"
+ "][:upperword:]hnD=Bns)z)AAAAAAAAAAAAAAAAAAAAAAA[^A{}"
+ "ccccccccccc)SZ]Q-p.sD]]+P",
+ 0, 0 },
+ { "[[^[^]{135,}66666666666666666666[6(666i2M9.!uhmT\?JMm.*(\?!+"
+ ")[:alpha:]eeeeeeeeeeeeeeeeeeeeeeeeeee]]])ZZ[:blankcntrl:][:"
+ "ascii:]",
+ 0, 0 },
+ { "(13[3Ux>{,10}[(\?<=:xdigit:]))PL9{-89,-181}F'''''''''", 1,
+ 0 },
+ { "[^.|(\?{af]})^$XE!$", 0, 0 },
+ { "(WWWWWWWWWWWWWWWWWWWWWWWWWWWW#J)", 1, 0 },
+ { "({}}M7we-216)L[:digit:][:upperword:]", 1, 0 },
+ { "([:aln[^u(\?=m:]))].z", 1, 0 },
+ { "([:alpha:]{(92})%6{41,136})Vij@[:alnum:][:lowerprint:]", 2,
+ 0 },
+ { "[[[++(\?{+++{}})n{{137,}{51,-177}Z[]M*[:ascii:]{(-29,-47}2)$"
+ "e^{,-195}{-156,}^]{}{-225,69}A]{-222,}{,20}m[:blankcntrl:]",
+ 1, 0 },
+ { ")l)[:alnum:][:graph:]g8TTTTTTTTTTTTTTTTLLLLLLLLLLLLLLLLL", 0,
+ 0 },
+ { "[([(\?<=.(\?{)/})mmmmmmmm(\?(mmmmm]{-154,-176}*S)I]", 0, 0 },
+ { "[(([{(\?(\?<!im(\?imsix:sim(sx:,141}])D)l{,42}ttttt[(\?::"
+ "punct:])){-162,-141}{-26,})dU@@@@@@@@@@@@@@@ "
+ "S)\\A\?w|VVVVVVVVV)X.kN{,21}{-208,-52}>[:lowerprint:][:"
+ "ascii:]e-]]]]]]]]]]]]]]]]]]]]]",
+ 0, 0 },
+ { "[^({}(){(66(\?=,}[^]'''''QQQQQQQQQ).P#>^){86,168}Z[(\?<!:"
+ "lowerprint:]{-166,-70}<k",
+ 0, 0 },
+ { "APP[:alpha:][:alnum:]nd[:upperword:(\?(]^"
+ "xxxxxxxxxxxxxxxxxxx)xxxxxxxxx{-70}[:punct:]l)U-",
+ 0, 0 },
+ { "[^(.\"od~(6({[^(\?<!228}\?)\?)######(\?:#########z "
+ ")c(\?<!aQ`(\?{UKSwu[})][^-17]{11,}}][:ascii:]))^RiH+WyspP["
+ "qi&)=p6])[:space:]{-221,}]6p",
+ 0, 0 },
+ { "{-78}()[:xdigit:]{155}{,-92}", 1, 0 },
+ { "[(\?>Q{,147}_____________(\?!______uuuuuuuuuuuuuTr]){74,179}"
+ "{}){,103}{-209,16}*RRRRRRRRRRRRRRRRw{,87}9{144}[:ascii:]'<"
+ "Ab",
+ 0, 0 },
+ { "([666c] {-171}yc,8-k_)EEEEEEEEEEEEEEEEEEEEE<", 1, 0 },
+ { "[^(\?>(\?<!)2(\?imim:)6HwN)^|fc!(\?(d]75))065)G", 0, 0 },
+ { "[[^xDB[:alnum:][:xdigit:]][:digit:]jW]([:alpha:])", 1, 0 },
+ { "[ds~T+[x55[:digit:]X[JJJJJJJ.[(\?::upperword:]){,-14}][:"
+ "xdigit:]bbbbbbbbbbb",
+ 0, 0 },
+ { "[qqqqq(\?<=qqqq(\?(qqq)^G[):ascii:]])W", 0, 0 },
+ { "[:space:]JJJJJJ[:alph(\?<!a:]|[:ascii:(\?(])[:x)digit:]- "
+ "XSstG[:g(\?>raph:])^)Ny6RF_ndoU9@*rxW{4,41}4{}",
+ 0, 0 },
+ { "[:punct:]{162,}j[:aln(um:].....................[^...]\?>z[:"
+ "l[owerprint:]){55,222}]",
+ 0, 0 },
+ { "(>vWa)OXcccccccccccccccccccccccc[:alpha:]C{,-10}81|m1D^T)[:"
+ "lowerprint:]''''[:alpha:]l",
+ 1, 0 },
+ { "(XZcgM/UI-/"
+ "mZq-222){-85,-196}[:alpha:]{114}rrrrrrrrrrrrrrrrrrrrrrrr{,"
+ "157}ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZLkD-&&&&&&&&&&&&&&&-][:"
+ "alnum:]{}{,111}[:digit:]",
+ 1, 0 },
+ { "[^(\?:]MMMMMMMMMMMMMMMMMMMMMMMMMMM)cK["
+ "KKKKKKKKKKKKKKKKKKKKKKKK]P{146}",
+ 0, 0 },
+ { "([^[^wqesa)n\?L(\?<=FH+G[^rCGmfD]w)m1D\"%}]])", 1, 0 },
+ { "[((\?:[^.HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH|S)xd)*[:space:](])["
+ ":xdigit:]ngr'G#/B]-----------------------------",
+ 0, 0 },
+ { ")[:lowerprint(\?<=(:]l))G p", 0, 0 },
+ { "[^[^(\?<(\?<(=(\?imsximx:![(((\?<!\?(^))\?]^)[:xdigit:][:"
+ "graph:]{-104,})Gf+GD*qc)c]f))])",
+ 0, 0 },
+ { "[^([\?())P[:alnum:]w]{-186,-139}-[:space:]RN3w[Fmvpl[:space:"
+ "][:digit:]&&&&&&&&&&&&}(\?#}}}}}}}}}}}}}}}}}}}])z",
+ 0, 0 },
+ { "([[^^*C[()f][(\?=:punct([\?#:]o)]V)]%%%%%%%%%%%%%%%%%%%%%%%%"
+ "%%%%%%[^x{1f948})]]",
+ 1, 0 },
+ { "[(:xdigit:])zE", 0, 0 },
+ { "[:pu(\?(nc)t:])(a*){-51}", 1, 0 },
+ { "[^(.NKKKKKKKKKKKKKKKKKKKKKKKK-[:upperword:][:space:]`MPi>",
+ -1, 0 },
+ { "Nvvv[vv.][:alnu[^m:]+|Crrrrrrrrrrrrrrrrrrrrr[:xdigit:]j1n)v#"
+ "]",
+ 0, 0 },
+ { "[^#}[(\?>:alnum:]).QQQQ[^QQQQQQ!!![!!!!!!!-s.n]se]{-238,}Tf]"
+ "p4721",
+ 0, 0 },
+ { "([((\?#\?<=)+)Hr:-H]z[:graph:].{}oooooo(ooooooooo][:punct:]"
+ "k<gXG@@@@@@@@@@@@@@@@@@@{,-176}){}L`)$",
+ 2, 0 },
+ { "({,249}{-73,}Z&&&&&&&&Ds35MB<v)qqqqqqqqqqqqqqqqqqqqqqqqq", 1,
+ 0 },
+ { "[^.N][:blankcntrl:]))))))))))))))))))))))))))))))", 0, 0 },
+ { "(()*){198,}", 2, 0 },
+ { "{-237,}220{}[:ascii:]```````(`````````````\?{-115,185}){,-"
+ "18}[:punct:]'|Kk",
+ 1, 0 },
+ { "[(\?()])", 0, 0 },
+ { "([(\?#[:alnum:]CQ)}}}}}}}}(\?>}}}}}}}(}}}}}\?310[|))xA5r][[^"
+ ":ascii:]^{,-156}{])CCCCCCCCCCC-145]FzwOD_u\?",
+ 1, 0 },
+ { "[^[^[]{-163}{(-203}[(\?!:upperword:]PPGjZ[:xdi(\?=git(\?#:]{"
+ "-73}s)qqqq(qqqqqqqqqqqqqqqqqq{173,210}[:xdigit:(\?<(\?>=]WW["
+ "^WWWWWWW\?*O)))Q){}08)[(\?(\?<=#:blankcntrl:]{90,}]U)])L)"
+ "ooooooooooooooooooooooooooox--^c[:ascii:]])s)",
+ 2, 0 },
+ { "[(\?!:punc(\?imximx:t[^:]4F<}!)]'M-)tKKKa4904", 0, 0 },
+ { "[^^{}\\(\?<!\\\\\\\\\\\\\\\\\\(\?#\\\\\\\\[:punct:](\?>)"
+ "T000000000(\?(000)00000))+])",
+ 0, 0 },
+ { "L[:p(\?#unct:])", 0, 0 },
+ { "[:upperw(\?<!ord:])", 0, 0 },
+ { "@$\"\"\"\"\"\"\"[\"\"\"\"\"\"\"\"\"\"[^(\"\"\"\"\"(\"\"][]))"
+ "*U{223,138}*o```````````````(\?=[```````````````]{238}"
+ "mmmPPPPPPPPPPPPPPP&&&&&&&&&&&&&&&&&&)sF$[:digit:[]]",
+ 0, 0 },
+ { "[^#Txx[xxxlPB(\?><[^U/)]]{}X3333333333(3333333f*])", 1, 0 },
+ { "<<<<<<<<<<<<<<<[^<<<<<<<<<.][(\?#:ascii:])[:xdigit:]|^", 0,
+ 0 },
+ { "([:punct:]{}){-167,}{-59,}Pd\"", 1, 0 },
+ { "[((\?#{,214})t$)VVV[:xdigit:]{104(\?<=}D][:graph:])|H){1,}{-"
+ "176,}",
+ 0, 0 },
+ { "[[([[^N,,,,,(\?=,,(\?#(\?:,,,,,,,,,,,[^,,,,,,,,,,]<,~4::_.A]"
+ "){-52,}-[:alnum:]Pnnnnnnnnnnnnnnnnnn)d",
+ 0, 0 },
+ { "{-18(3,})uT{4,}", 1, 0 },
+ { "[^[^[(p+c(\?<!b$))(\?:EU(\?(.][^{}]3[:xdigi[^t):][:punct(\?>"
+ ":])[])][:s[^pace:]][:alnum:][:alpha:]]kw06E",
+ 0, 0 },
+ { "[^^^^^^JJJJJJJJ(JJ(\?=JJ(.6[:space:]H]{231,}A^eqqq)[:ascii:("
+ "\?>(])[(\?>:spa(\?:ce:]xxxxxxxxx)@_t-))"
+ "138GNNNNNNNNNNNNNNNNNNNNNNNNNN[:digit:]no!`#E\?&[:"
+ "lowerprint:].)[:graph:]{86,}[:digit:][:alnum:]",
+ 0, 0 },
+ { "[:g(\?<=raph:]a{114,146}(){}0Y[:bl(ankcntrl:])D)\?", 1, 0 },
+ { "[^[^]*H{-192,96}S|]G)6B-kLB", 0, 0 },
+ { "[[^[^][/"
+ "NS8`um(\?{82&{((\?{\?<!-[110,-88}]m)})kkkkkkkk$$$$$$$$$$$$[^"
+ "$$$$$@n%BuK@X!P)y0v!^]YY[YYY[YYYYYYYYYYYYYYYYYY///////"
+ "{}{{{{{{{{{{{{{oiiii})]8{-2[53}w{82,}]{,245}]{-134}]"
+ "fffffffffffffffffff]\"I>DW>9tN%{113}{unE",
+ 0, 0 },
+ { "[:(\?(alpha:]`))Y2sCqWQ104", 0, 0 },
+ { "(([^()Wcccccccc(\?{cccccccccccccccccc(\?<!c(ccccc[:space:]$)"
+ "(\?>)FZ{}{}`|||||||||||||*````````````````````````````'="
+ "dLQmx/"
+ "Y.A7j'o}jn{}:})][:punct:]$|,-)!&Y:Ys#"
+ "ykL7JJJJJJJJJJJJJJJJJJJJJJJJJ8yex>#mv[:punct:](x@)$[:uppe("
+ "\?<!rword:])_)",
+ 3, 0 },
+ { "[[(^HHHHHHHHHHHH(\?imsximx:HH(HHHHHH(\?{HH[HH])qjR>9))i})]a!"
+ "lBW3p{A=or)ShE%[:punct:]{}]5r",
+ 0, 0 },
+ { "[:pu[nc[^t:]]]}}}}}}}[}}}}}}}(\?#}])@@@@@@@@@@@@@@@@@@"
+ "DDDDDDDDDDDDDDDDDDD\?]xA2\?",
+ 0, 0 },
+ { "(.[:alpha:]xB7[:alnu(\?{m:]})RRRRRRRRRRRRRRRRRRRRRRRRRRRL)[:"
+ "space:]G\?",
+ 1, 0 },
+ { "[:blan(\?<!(\?=kcntrl:]){71,})!ooooooooooooN", 0, 0 },
+ { "()e$$$$$$$$$$$$$$$$$$$$iiiiiiii", 1, 0 },
+ { "(b[:ascii:]67777777777777777777777777)({-106}kkk^F----------"
+ "---------------------{13}A)f00000000sBAddddd{-66}kd!D'",
+ 2, 0 },
+ { "(Q ^])[^lf][:space:][:lowerprint:]\?",
+ 1, 0 },
+ { "[[^]\\S{152}W![:digit:][[^:space:(\?(]=pEhwY][:alnum:][:"
+ "digit):][:graph:]])QQIC9h-oowf[:xdigit:]{-52}{,190}"
+ "1111111111111111111fX{-189,226}W",
+ 0, 0 },
+ { "[^(\?!(\?<=)]).h[:as(\?>cii:])[:alnum:]$$$$$[:space:]3$$$$$$"
+ "$$$$$$$$$$$$$$$$$$$$$$$$$1",
+ 0, 0 },
+ { "[[$zQ================(\?<!=(\?>=========(\?====D[^))|i{}"
+ "\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?)][:s(pace:]])"
+ ")]",
+ 0, 0 },
+ { "[^{,-[15(\?#6}]Vwjjjjjjjj[jjjjjjjjjjjjjjjjjjS9999)]q]"
+ "rWWWWWWWWWWWWWWWW[:punct:]@@@@@@@@@@@@@@@@@@@@@@@@gO[:"
+ "blankcntrl:]>L[:ascii:]:::::::::::::::::::"
+ "x11uuuuuuuuuuuuuuuuuuuuuuuuuuuuu{-124,114}[:graph:]C#{tcg[:"
+ "xdigit:]gZZZZ[:lowerprint:]nA(_{{{{{{{{{{{{{{{{{{{{SS)\\D[:"
+ "alpha:]",
+ 1, 0 },
+ { "[^(\?())]!T\?[:asc[^ii:]E:4},,]I[^b(\?:n4(njj~+{\?'k{7}{189,"
+ "-194}{ig.[[[[[[(\?#[[[_bs6,JD`1(\?<!WBo]F+{d*VO22z2K1][:"
+ "xdigit:]))Suuuuuuuuuuu[^u{,117}\?YYYYYYYYYYYYYYYYYYYYYYYYB^]"
+ "|q]:eY1GGGGGGGGGGGGGGGGGGGGGGGGGGGGe\?)bU[:punct:]",
+ 0, 0 },
+ { "[\?UA(\?:]\?)[:xdigit:]A^mmmmmmmmmmmmmm>>>>>>>>>>>>>>>>>>>>>"
+ ">>>>>>>[^>>>(\?(>)){,-165}]",
+ 0, 0 },
+ { "([^[][^n(\?{[[p]#})|][^]L|66666666666[:graph:]][:graph:]2[:"
+ "xdigit:][:space:]9b})[:digit(\?imsximsx::]+PZ):{}|E)[:"
+ "xdigit[^:]|>]^[:alpha:]::::::::[:ascii:]````[:ascii:]:",
+ 1, 0 },
+ { "[:lowerprint(\?<!:])", 0, 0 },
+ { "[[^[]{-47}[:lowerprint:][:punct:]L[(\?::g(raph:]lY[:alnum:])"
+ "qWYU)}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}[c%$dp5[:alnum:]DDDDDDDD^"
+ "^%&{,-94}E]{-8,175}[:alpha:]-.^[:digi(t:]CCCC(CCCCCCCCC])."
+ "ax72)",
+ 1, 0 },
+ { "[[^($$$$$$$$$$$$$$$$$$[^$I((\?{\?(u)\"YuK "
+ "ZpOHq[!(\?>t|LQT(|)L[(:ascii:])",
+ 0, 0 },
+ { "[^[^([:graph:](QpPdyDQ`[:alpha:](.X[:digit:]wwwwwwwwwwwwww("
+ "\?imxims:wwwwwwwe(\?<!z)ONNN(\?#)[^])[:space:](KKKKKKKKK{"
+ "113,}327[:xdigit:]k)]CeeeeeeeeeeeeeeeeeMMMMMMMMMMMMMMMMM)[:"
+ "lowerprint:]]HHHHHHHHHHHHHHHHHHH]]]]]]]]]]]]]",
+ 1, 0 },
+ { "[Q(r(\?=)v]dm[:alnum:][:b(\?{lankcntrl:][:xdigit(\?=:])})P[:"
+ "graph:]bd/Rx){50}{-150,-172}",
+ 0, 0 },
+ { "[(\?(im(\?:sxims:))9]))L", 0, 0 },
+ { "[[^[(\?{^Z][^0[:alpha:]]\\XB*{-151}t})][:alnum:]]", 0, 0 },
+ { "[([(D\?/////////////////////.'yvYysU&5AU-]kV)*){,123}z]", 0,
+ 0 },
+ { "[:alnu(\?{m:][:a(\?=lpha:][:alpha:])n}))7[:ascii:][:xdigit:]"
+ "[:punct:]-",
+ 0, 0 },
+ { "[^[:graph:]IIIIIIIIIIIIIIIIIIIIIII][:sp(\?<!ace:])", 0, 0 },
+ { "[[[(\?=[[[cDD(\?<!D(\?:DDDDDDDDDDDD(\?<=DDD(DDDDDD(\?:"
+ "DDDDDDD(\?<=D(\?()])rvp{243,}D$<[:space:]([:lowerpr)int:])])"
+ "Ea{}U[:upperword:][:xdigit(\?#:]or}Z+34gD{/P NJ",
+ 1, 0 },
+ { "[^(,H>)*d2K0DNX5)T(].)[:digit:].", 0, 0 },
+ { "([:punct:(\?#])})JJJJJJJJ[:xdigit:]"
+ "PPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU.......................0hSk{"
+ ",89}[:xdigit:].[:xdigit:]Z",
+ 1, 0 },
+ { "(LGTTTTTTTTTTTTTTTTTTTTTTTTTT[:alpha:]){-106,113}[:punct:]d|"
+ "[:digit:]kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\?wP",
+ 1, 0 },
+ { "([^[^<N_-k\?{(\?#18}]i]::::::::::::::::::::::::::)1+LLLLn{}/"
+ "){-198}",
+ 1, 0 },
+ { "([[^(AAAAAAAAAA(\?(AAAAA)AAAAf).LzHHHHHHHHHHHHHHHHHHHHH(\?#"
+ "HHHHH|)[ZEEEEE(\?#EEEEEEEEE(\?<!EEEEEEEEsG)q[:punct:]{}][:"
+ "upperword:]D)[:space:][:digit:]+e[:ascii:]].i|JJJJJJJJ+n][:"
+ "xdigit:]Se)P[:lowerprint:]_______________________________.[:"
+ "punct:]pP{-172,86}iiiiiiiiiiiiiiiiiiiiiiiii){,-178}",
+ 1, 0 },
+ { "([\?=[[^,BDRRPZ{129}*D-[:punct:]]])([:upperword:]ud)\?][:"
+ "punct:]A",
+ -1, 0 },
+ { "(([(\?#((\?{\?=^])c-)C[:lowerprint:]xvkR}k\")"
+ "ccccccccccccccccccccNNNNNNN[:alp[ha:]{,93}vhlX:|A]2})nSw)]"
+ "N.",
+ 2, 0 },
+ { "()g/qzyiV(x3d|A0wllllll){162}[:space:]", 2, 0 },
+ { "qqqqqqqqqqqqqqqqqqqqvvvvvvvvvvvv8[:x(\?imsxmsx:digit:][:"
+ "alpha:]''''''''''''''''''''''''''')",
+ 0, 0 },
+ { "({,226}nf^W=vs$xK^=A=M#b,)V", 1, 0 },
+ { "(_T 2BC9N'cccccccccc-87EF#&^eQfDDDn._,m&c`tjAwR "
+ "#~A)[:(\?imsimx:alpha:])/yHYL6|{-40,47}",
+ 1, 0 },
+ { "[[^]{-8(4,138})z[:xdigit:]{180,}]", 1, 0 },
+ { "[([^T____________________(\?:__C(\?<=]-)])+[:ascii:])r[:"
+ "graph:].----------",
+ 0, 0 },
+ { "[f{}LLLL(LLp((((\?<!((((((((((((((({,56}]BR`{,52}){-22,}\?[:"
+ "space:]h>Sow",
+ 0, 0 },
+ { "{-179}^[:alpha:(\?!].a'5wacA3\\\\\\\\AAAAAAAA)~^]wC", 0, 0 },
+ { ">[:digit:]{,-212}+(`)LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL[:ascii:"
+ "][:digit:][:space:]",
+ 1, 0 },
+ { "[[^[[^RBW{,255(}(\?(\?>=(W)_]uu][:blankcntrl:])O)]]", 0, 0 },
+ { "(C_______________________________)2", 1, 0 },
+ { "([/ntf_a3].)", 1, 0 },
+ { "[:space:]+[(:upperword:],c7[:asci(\?<=i:]ggggggggggg)[:"
+ "ascii:]/1$$$$$$$$$$$$$$$$$$$$$$$$$$)",
+ 0, 0 },
+ { "Xq{109}~EEEEEEEE[:upper[^word:]lgB:X(h[:alpha:]B[:space:]].)"
+ "IkaH@3}}H'yK~\?[:upperw(\?#ord:(\?:]){=================[:"
+ "blankcntrl:])",
+ 1, 0 },
+ { "(([[^]]$3Xr^$%%%%%%%%%%%%%%%%%%%%%================U[:ascii:]"
+ ")X).FFFFFFFFFFgO[:punct:]oooooooooooooooooooBC[:blankcntrl:]"
+ "mmmmmmmmmmmmmmmmmmmm[:lowerprint:]rBM~<HAc#Sb&&&&&&&&&&&&&&&"
+ "&&&&&&&&&&&&&&Cy",
+ 2, 0 },
+ { "([([([^(\?:)D]-{M#H "
+ ">rERRRRRRR[^RRRRR(\?>RRRRR])[(\?=^)X]{207,}U])))Z[:"
+ "blankcntrl:]]yyyyyyyyyyyyyyyy\?",
+ 1, 0 },
+ { "[Q(\?{*[^(\?(\?!!])[:graph:]]})[:alnum:]iE)dGGGGGGG[^"
+ "GGGGGGGGGG[:xdigit:]w]",
+ 0, 0 },
+ { "[^Z(\?!6(\?(\?><=)[:graph:])]BBBBBBBBBBBBBBBB^)", 0, 0 },
+ { "[[^([^[^][[[[[[[(\?({[[(\?(\?imsxmsx(\?imsi[ms:::[[[[[[[[[})"
+ ")]$)){12,})|:::::::::::::::::::[:lowerprint:]{}{-96,-147}){"
+ "13,}`[:digit:]]\"^Ca%%%%%%%%%%%%%%%%%%%%%%%%%%"
+ "UUUUUUUUUUUUUUUUUU]]9",
+ 0, 0 },
+ { "[^(\?(\?(\?#!<=))JLBS\"zi)'''''''''''['''''''''''''"
+ "piiiiiiiiiiiii(\?<=iiii]])ZZZZZZZZZZZZZZZZZZ[:space:]",
+ 0, 0 },
+ { "({})[:punct:]", 1, 0 },
+ { "E9[:blankc(\?{ntrl:]})N", 0, 0 },
+ { "[:alph(\?#a:]){198,}sq\?X0B7", 0, 0 },
+ { "[^\\\\\\\\(\\\\\\[\\\\\\\\\\\\[(\?<(\?isximsx:={11(\?(9,}"
+ "\?0])]]))\?FN3M\?{-128,}Z444444)444fbLiVN8)",
+ 0, 0 },
+ { "[[^[^([[[[[[[[[(\?>[[[[[[[[[[[[[[[[[[[[[{53(\?<=,-175(\?>}"
+ "ggggggggggggggggg%))[:alnum:])[:punct:]"
+ "kkkkkkkkkkkkkkkkkkkkkkkkk)+"
+ "Soooooooooooooooooooooooooooooooo](WR+--)x36+llllllllllll{,"
+ "35}]Fqb^=F]KKKKKKaaaaa{,131}",
+ 1, 0 },
+ { "(g\"Ssqw<&{Cl{82,}Mdf|9cIlmCW{}[:digit:]4C{}[:alnum:]PP)", 1,
+ 0 },
+ { "OOOOOOOU[*evVIIIIIIIIIIIIIIIII(\?#(\?#IIII)]PP[:xdigit:]"
+ "2222222222222222[:xdigit:]Kx)p[:digit:]",
+ 0, 0 },
+ { "([[{248,16(\?=5(\?#}][:alpha:])|[:p(\?!unct:(\?(]", 1, 0 },
+ { "[pP((\?=S)(\?#)]$[:aln(\?(um:)]2\?)$GGGGGGGGGGGGGGGGG({-U:c)"
+ "{-61,}[:ascii:]{-202}G",
+ 1, 0 },
+ { "()$D[:alnum:]", 1, 0 },
+ { "[(\?#^]){}[:ascii:]", 0, 0 },
+ { "[uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu]FFFFFFFFFFFFFFFFFFFFFF&2e\?)"
+ "%oP'mc@z2b}n{<b4_Laz^0LLLLLLLLLLLLLLLLLLLLLLL,,,d",
+ 0, 0 },
+ { "{}(^________________''|$)RRRRRRRRRRRRRRRRRRR", 1, 0 },
+ { "(H)####################bbbbbbbbbbbbbbbbVSSSSSSSSSSS|"
+ "tdU\"goeAbPP{-248,81}",
+ 1, 0 },
+ { "[^[(\?ims(\?>xisx:)UHpP*n{}]{}fx14<7OEpE>n2150)"
+ "8888888888888888]^GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGS",
+ 0, 0 },
+ { "(d)+", 1, 0 },
+ { "[^.(\?(>)(\?=e)])al[:space:]x", 0, 0 },
+ { "[^256c(\?!]){-19,}", 0, 0 },
+ { "Q)", 0, 0 },
+ { "[^s\?\?(\?{\?\?\?(\?#\?(\?<!\?\?\?\?\?\?\?\?\?\?\?("
+ "\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?{}]F\?j(jjjjjjjjjjjjjjjjjjn)"
+ "kTI1f[{1|(\?<=^[^+[:digit:]{}^s^))})))T]{-17}{CCCCCCCCCCa{-"
+ "21,}{,-146}^uZQB]YuLu-|tUGRMz^^",
+ 1, 0 },
+ { "([^.{}.EE[EEEEEEEE(\?<=EEEEEEEEEEEEEEEU]]-@s))$", 1, 0 },
+ { "[^([((\?#[#])|a)])[cccccccccccccccc][:digit:]LLLLLLL[:alnum:"
+ "]}[P%vzl{}^]&",
+ 0, 0 },
+ { "({}[:space:]E)101+A{-35,11}", 1, 0 },
+ { "(va:7)u[:alpha:]", 1, 0 },
+ { "([^[[rrrrrrrrrr(\?:rrrrrrrrrr(\?<!rrrrrrrrry|D'*AH@a{}\?[:"
+ "space:][:alpha:]^]$ "
+ "{-225}[(\?(:as)(\?(>cii:])){-107,-139}6/"
+ "{^[:upperw(\?imsxmsx:ord:]{,-47} "
+ "]wuH#nAn)GGGGGGGGGGGGGGGGGr[)]T{91}lJ))[:lowerprint:][:"
+ "xdigit:][:lowerprint:])]*",
+ 1, 0 },
+ { "()[:space:]~!$[:alnum:]JJJJ[:ascii:]", 1, 0 },
+ { "[^(\?<=)-]()k", 1, 0 },
+ { "(()W){,8}ea", 2, 0 },
+ { "({,-56}5G&&&&rrrrrrrrrrrrrrrrrrrrrrrrrrk.8) hWJ,TM)0Yd-", 1,
+ 0 },
+ { "(Z-fddddddddddddddddddddddd)-{9}", 1, 0 },
+ { "[^<[(\?!:asc(\?:i(\?<!i:])F])[:alp(ha:]b))-}Wwx8B", 0, 0 },
+ { "[^[^[^([(\?{}(\?=)(\?())-CCCCCCCCCCC(\?=CCCCCCCC(CCCCC(\?:"
+ "CCCCCCCC(\?{l[(\?!:space:]})[:upperwor(\?:d:]{-27}[:al[^pha:"
+ "][:xdigit:]^f",
+ 0, 0 },
+ { "[[^]G@>2!+[:punct:(\?<!]{,189}6ZF[:blankcntrl:][:digit:]{,"
+ "214}){-115,-14}l[:upperword:]{101,}Z[:ascii:]Ld&02|c]<0~<bc",
+ 0, 0 },
+ { "(Q)[:digit:]x", 1, 0 },
+ { "hT[[:alnum:]\?]O[OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOxFF%^(\?(_"
+ "LN "
+ "8uXQT\"*/"
+ "L)+l)>qQ[^]e[:ascii:]PP()[:digit:]NQ8%6d=&2I{-62,-142}w]].e{"
+ "}*",
+ 1, 0 },
+ { "{,-219}xxxtEEEEEEEEEEEEEEEE[:pun(\?(ct:])qqq)"
+ "nnnnnnnnnnnnnnnnnnnnnnnnnnn",
+ 0, 0 },
+ { "[:di(\?>git:])W4", 0, 0 },
+ { "([^y])Fkvto$", 1, 0 },
+ { "[^($$$$$$(\?!$$$$$(\?{$$$$$$(\?<=$$$$$$$$$$$+===)[:alnum:]"
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM)Z]{}^[:blankcntrl:]--"
+ "xxxxxxxxxxxxxxx[^xxxxxxx)\?tVG\?{232,81}{121,}xn{,-226}})"
+ "tttttttttttttttttttttttmu(\?<!&&&&&&&&&&&&&&&&&&&&&&0b]z)$"
+ "87{,-192}{}{-242,}",
+ 0, 0 },
+ { "l[:dig(\?(it:]|s*)aA[:digit(\?<=:].^.))x[:digit:]", 0, 0 },
+ { "[:grap[^(\?#h:]').]Z", 0, 0 },
+ { "[:gra[^ph:]t[:digit:]222222222222(22222222222222222H "
+ "qM]pWZr[:ascii:]-hRb_.)Q{-228,-204}{}",
+ 1, 0 },
+ { "AAAAAAAAAAAAAAA(AA)YeX", 1, 0 },
+ { "(!dqqqF*^){(,-79}s!!!!!!!!!!!!)", 2, 0 },
+ { "[^(\?msxm(\?#sx:]|)ZHYup)j{95}0L:vXB#')d'DX\?m."
+ "T034\\\\\\\\\\\\\\\\\\\\\\y5rV{}S",
+ 0, 0 },
+ { "(W*O+yl([\?!P(\?:)I]${}{-195,-14}[:upperword:]{}[:xdi[^git:]"
+ "[:space:]X[:grap[^h:]~]zzzzzzzzzzzzzzzzzzzzzzzL)+)Y "
+ "b.-=jf{-216,}${/!}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|]",
+ 2, 0 },
+ { "[^\\\\\\\\\\(\?<=\\\\\\\\\\\\\\\\m]{-48,234}[:alpha:]s)", 0,
+ 0 },
+ { "[(\?{U}(\?<!)])LLLLLLLLLLLLLLsssssssssssssssssssssssssss[:"
+ "ascii:][:blankcntrl:]---------b",
+ 0, 0 },
+ { "[^[^[(\?#)(\?imsxims[x:)<<<<[<<<<<<<<<<(\?<!<<<<<<<([^\?(<<<"
+ "<<<<<<<z(\?(zu(\?<=~83}aZpIE)[:alnum:](\?imsximsx:(\?!jrE6("
+ "\?<!\?V(SzDU)000[000000000((\?=\?)=0])L|lOYuWXk",
+ 0, 0 },
+ { "$o[:dig(it:]nnnnnnnnnnnnnnn{-94}|G)[:alpha(\?!:] "
+ "{,-108}D=\?>[:digit:]S[:space:]t",
+ 0, 0 },
+ { "()n", 1, 0 },
+ { "[:upp(erword:]$)<}.vZM<lEY5Y*", 0, 0 },
+ { "[^([^\?>)rCD&{5(\?msxisx:7,}qqqqqqqqqqqqqqqqqq{31,}@w#W:(@("
+ "\?:zp$YYYYA[:alpha:]{1}A)*dZJ\"5OG|\?(\?#a])]|){-150}[:"
+ "xdigit:]",
+ 0, 0 },
+ { "[($)gwo{`\"]{-160,}"
+ "\\\\\\\\\\\\\\\\\\\\\\\\\\66666666666666888888888888",
+ -1, 1 },
+ { "((}DA+Rc000000000000000000)%vvvvvvvvvvvvvvvvvvvvv%C&emZ*[:"
+ "alnum:]#m/"
+ "D[:graph:][:blank[^cntrl:]E{,168})"
+ "kkkkkkkkkk000000000000000]",
+ 2, 0 },
+ { "[^[u*(\?#x01234)oxGGGGG(\?([GGGG)GGGGGGGGG]^U)!!CCCCBM`4QB^"
+ "XEN]{,-60}[:upperword:]G]",
+ 0, 0 },
+ { "(%)~t{S,K^MI3PMo)=b", 1, 0 },
+ { "[[[^]{}eU([:xdigit:]&&&&&&&&&&&&&&&&&)\"W|43[:alpha:][:"
+ "graph:]J8b[:blankcntrl:]gggggQ{,183}{,-254}\?[:ascii(:]{,"
+ "134}",
+ 1, 0 },
+ { "[[([^[^([^(\?=)1RRRRRRRRRRRRRRRRRRRRRR(\?:(\?(\?(\?!=#RRRRR("
+ "\?=RRRR(\?<[^!Ru)])]o[:[graph:[^]{,7})[:digit(\?::]{-215,}e["
+ ":space:]]",
+ 0, 0 },
+ { "({{{{{{{{{{{{{{{{{{KKKKKKKKKKKKKKKKKKKKKKKKKKKKBBBBBBBBBBBB)"
+ "[:space:]0[:alnum:]HcctQA",
+ 1, 0 },
+ { "[^(pP7(HsN[^g{186,-87}\?\?]EQ%u:-Y)+>>>>>>>>>>>>>>>>>>>>>pP]"
+ "[:alpha:]",
+ 0, 0 },
+ { "[(.{141}h|)((\?:\?=@Q} "
+ "ghcC{+*(R)D+][:lo(\?#werprint:]"
+ "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz))",
+ 0, 0 },
+ { "[^({}S)PPFl(])-216", 0, 0 },
+ { "[([[^(((([(\?#^[^[^\?4[(:[dig[^it(\?(:]{122,})y\?", 0, 0 },
+ { "[[2${188}u{1(4(\?(1,1(\?{98}e{&tbaoI]q)[:punct:])d}))"
+ "Nqffffffffffffffffffffffffffff[:ascii:]+]",
+ 0, 0 },
+ { "()K-", 1, 0 },
+ { "[[{2(2((\?(\?!()2})])[:alpha:]fVVVVVVVVV{-47}):::::::::::)"
+ "\?vwyyyyyyyyyyyyyyyyyyyyyyyyy-]{}",
+ 0, 0 },
+ { "ivcs)g", 0, 0 },
+ { "(hhhh[^hhhh(\?{h\?]})%%%%%%%%%%%%%%%)\"+38mbY:s9{/d# "
+ "zaNnbQb)b:*zpKI{-26,-189}",
+ 1, 0 },
+ { "S*(#)[:graph:]lllllllll&G)t", 1, 0 },
+ { "([^[(([\?=\?<!)]]___{-63,})]nt", 1, 0 },
+ { "[:b(lankcntrl:][:alpha:]*[:pu[^[nct:][:alpha:]A]$"
+ "aaaaaaaaaaaa*)A[:digit:]U][:alnum:]",
+ 0, 0 },
+ { "[^f[^p000{68(\?isxmx:,}(\?!vvvvvv)$)]PP#*{(})[:punct:]&&&&&&"
+ "&&&&&&&[:punct:]\?][:blankcntrl:]",
+ 1, 0 },
+ { "[^(((\?(\?(()))GGGGGGGGG{(\?!($)))((\?!)V^{228,145}))]{-229}"
+ "Qjjjjj[:punct:]R)",
+ 0, 0 },
+ { "[(Q[^((\?{(\?:]~z)})gE(.<){}|)Kuuuuu$*"
+ "222222222222222222222D]",
+ -1, 0 },
+ { "([^`(\?<=`````[^`````````M]\?)=L74A[:upperword:]]P", 1, 0 },
+ { "(({}[:space:]qv-T){,-192}{-45}{65}9\?X).d", 2, 0 },
+ { "_[(:upperword:]mU(P}qX>\?%)$Lwq[:alpha:]{-115,}============="
+ "==================={127,}",
+ 1, 0 },
+ { "e)", 0, 0 },
+ { "[{,2[5}Klen+D0'YX(\?<=|_H]I,Y\"*/<3sM[:digit:]])#.", 0, 0 },
+ { "[:(xdigit:]){[:digit(\?mxmsx::][:as(\?<=cii:]d!{135})#)pP[:"
+ "space:]Syyyyyyyyyyyyyyyyyyyy\"Gg8",
+ 0, 0 },
+ { "[(\?()])", 0, 0 },
+ { "[^([^[^[[^[:alpha:]SIus[^f<f]}}}}}}}}}}][:xdigit(\?=:]Z{-13}"
+ "*]_[]LLLL)]E[:alnum:]b$)]]]]]]]]]]]]]]]]]]]]]]]]][:"
+ "lowerprint:][:ascii:]{,40}{86,}"
+ "333333333999999999999999999999999999*"
+ "fffffffffffffffffffffffff99999999U9|[:digit:][:upperword:]"
+ "oowwwwwwww[wwwwwwwwww{195}[:xdigit:]]H{-73,153}R+zAz{}r/////"
+ "////////"
+ "{232,}kAoffffffffff[:blankcntrl:]xxxxxxxxxxxxxxx]KKKKKl0,[:"
+ "alpha:]|{,-165}Qc{96}CCCCCCCCCCCCCCCCCCCC/",
+ 0, 0 },
+ { "{}:V(7O-)[:ascii:][:graph:]PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP#",
+ 1, 0 },
+ { "[^(\?<[^=CC(CC$)]* c)BBBBBBBBBBBBBBBBBBBBBBB]z{-18,}",
+ 0, 0 },
+ { "[[qqqqqqqqqqq(\?(qq235|ttttttttttttttttttttttttttttt[[ttt<<<"
+ "<(\?{<<<<<<<<<<<<)<<<<<<<<p)/"
+ "S9(\?{OOOOOOO(\?<!OOOk)})]nIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIb]"
+ "Z})",
+ 0, 0 },
+ { "[^[^(\?>][^((\?<!C(\?!+(\?=)]^8)6nx).)){,-13}[:blankcntrl:]"
+ "\"(L{}){,29}nnnnn{-83}]l[:upperword:])",
+ 1, 0 },
+ { "[(ZZ\"#(\?#Nb(\?<!:U)oRRRR])Zei${Ec/)s", 0, 0 },
+ { "[^[^[(\?(t(\?:3```````)`````)|#CB)//////////////////////////"
+ "///"
+ "*!liB#|CCCCCCCCCCCCCC(\?=CCCCCCa7N]weTTTTTTTTTTTTTTTT1{}o\?{"
+ "}BBBBBBBBBBBBBBBBBBBBBBBB.])u{-218,126}.,[:space:]]",
+ 0, 0 },
+ { "[[([:alnum:])yyy(\?!yyyyyyyyyy(\?!yyyyyyyyyyyyyyyyyyy[:"
+ "graph:]I])Uw*X.^[:ascii:]{,-63}[:digit:]{-88})&&&&&&&&&&&&&&"
+ "]*",
+ 0, 0 },
+ { "[[[^K(\?=KKKKKKKKKKKK(\?:KKKKKKKKK[KKKKKK]]U[:digit:])]dd)({"
+ ",16})xy+Pu)JJJJJJJJJJJJJJJ[:space:][:ascii:][:upperword:]ql_"
+ "jywmt4B+]{-30,}^555555555Xza[:punct:]",
+ 1, 0 },
+ { "[[^^XXX(\?:XXX((XXXXXXXXXXXXXXXXXXXX)v)$N9$"
+ "r\"\"\"\"\"\"\"\"\"\"\"\"\"].{,239}$[:punct:]\"9999][:alpha:"
+ "]{}c){,55}s[:upperword:][:xdigit:]310",
+ 0, 0 },
+ { "[@([^I8oNl)]-{-203,-224}{-78,}KKKKKKKKc{-66}[:xdi(\?=git:]=="
+ "========){}f{-124,}[:upperword:][:lowerprint:]]{}--------l+",
+ 0, 0 },
+ { "[^]ozp+0(\?#\"[(\?()X]))[:blankcntrl:][^e{99,222}"
+ "JJJJJJJJJJJJJJJ3F]\?[:blankcntrl:]l$ot",
+ 0, 0 },
+ { "[[^[[((\?isximx:)2222222222(\?=22222[:graph:])+U)((\?{\?<=("
+ "\?()iYv8qc@#y)G])+}))FvnP\"7OZ-b273[:ascii:]Ak6*`S[:digit:]["
+ ":graph:]]{2}^G{79,}DDDDDbbbbbbbbbbbbbbbbbbbbbbbb(bbbbbbb)|"
+ "tP48y{wNJ_S hJbY]]dc",
+ 1, 0 },
+ { "[:alph(\?{a:]p1[:lowerprint:]}){163,}", 0, 0 },
+ { "W()", 1, 0 },
+ { "()``````````````````````````[:ascii:][:alnum:]{,26}[:graph:"
+ "]",
+ 1, 0 },
+ { "[:al(\?<!num:]|byyy,*)U5%u${190}-{-221,-33}"
+ "k7777777777777777777777777777777+eXXXXXXXXXXXXXXXXX[X(\?(XX)"
+ "XX)S'vEAa]*e",
+ -1, 0 },
+ { "[^(([R_AC[lE'{2(\?{28(]8LTt[]b[:punct:]]O)|2[:graph:][:"
+ "space:]}) "
+ "x3C[:alpha:])uI+dddddddddddddddddddddddd{-165,}"
+ "FFFFFFFFFFFFFFFFFFFFFFF)cccc*[:upperword:]]G{,-38}{24,}"
+ "555555555555555555555555555VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVZ["
+ ":blankcntrl:][:ascii:]",
+ 0, 0 },
+ { "[^QQQQQQQ(\?#QQ(QQQQQQ[:punct:][:space:]){(\?(\?:!}[:graph:]"
+ "t}}[^}}(}}}}}444444[^444444444444444444444]\?]G)E)L{,-103}{"
+ "84,}r$ii]-[:alp(\?<=ha:]S5G~9>n*)P<"
+ "3tttttttttttttttttttttttttt)n{}[:graph:]"
+ "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{,83}[:digit:])"
+ "0BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB[:alpha:]{-155,}{151,}",
+ 0, 0 },
+ { "Ue{,254}+f[:lowerp(\?<=rint:]U.fff)", 0, 0 },
+ { "QQQQQQQQQQQQQQQQQQQQQQQQAY<J)'MPi_u%#2doopqU7/"
+ "{103}[:graph:]e!7{GOr",
+ 0, 0 },
+ { "[^({,[^233}[^d)BBBBBBBBBBBBBBB=======(\?>===========[^=S|[^["
+ ":alpha:]G/]qqqqqqqqq{}[:xdigit:])..k",
+ 0, 0 },
+ { "[([^[[:space:]ffffff(\?=ff]M]))[:xdigit:]UbCI,CzalLU*y5I[:"
+ "digit:]r{-30,180}{-209,-45}Paf]",
+ 0, 0 },
+ { "[^[h(\?{hhhhhhhhhhhhhhhhhhhhh})]{,143}[:lowerprint:][:ascii:"
+ "((\?(\?=])[:asc)ii:])zp]",
+ 0, 0 },
+ { "[[(\?{]})]", 0, 0 },
+ { "[[1\"3m^,(\?<!2((\?!\?#t```````````````````````````)\?)|c^)"
+ "A^~]{61}W\\\\\\vvvvrrrrrrrrrrr[:digit(\?#:])]F[:upperword:]"
+ "dX\\\\",
+ 0, 0 },
+ { "([${144,}(\?<!)-RAk_F(\?imsxisx:=9]z/))", 1, 0 },
+ { "[[^[[[^([[^[^[^([[^([[Uiiiii#####(\?(\?{(\?<!#########(\?=##"
+ "###).^)(.|>2m[M/"
+ "2222222222222222222222222222(\?:22222222222(\?#22(\?:(\?="
+ "22222{,243}]x68+I/"
+ "K)11111111111]\\pP[:graph:]$[:space:]^{}A)[:xdigit:]-={>",
+ 0, 0 },
+ { "[(\?>[(^()Vty2vvvvvvvvvvvvvvvvz^])ZZZZZZZZZZZZZZZZZZZ-------"
+ "---------5\\dVLSp8UE2m+z3X/Sd",
+ 0, 0 },
+ { "[}}}}}}}}}}}}}}}}}}}(\?#}}(\?<=)|*C "
+ "]*29JW7O9mEB]pE_OoxN)[:alpha:]",
+ 0, 0 },
+ { "([^((\?<=\?)D{,200}.[(\?#:ascii:])[:space:].)[:alpha:]D|[:"
+ "graph:]{,-41}*LLUUUUUUUUUUUUU{-189,-131}]qHR<k2@P{27}<^e,ub%"
+ "\?/4){-243}+[:digit:]%*x9lA^",
+ 1, 0 },
+ { "([:alpha:]bT&+_)$Z{,212}x26`", 1, 0 },
+ { "[^([^(A{[^}g(\?()A9p#54b]-------------------------------)."
+ "wzD#=f\\)A)8a]]DNNNNNNNNNNNNNNNNNNNNNNNNNN",
+ 0, 0 },
+ { "(W000000000000000000000000000000)", 1, 0 },
+ { "www(wwwwwwwwwwwww)", 1, 0 },
+ { "()555555555555{18}i+[:alnum:]E {}U", 1, 0 },
+ { "SqbHoooooooooooo[^oooooo([^ooooooo])\\N[:xdigit:]]oooo`", 0,
+ 0 },
+ { "[999999999999999999uE{193,0}lx{7917}[:punct:]4&d]{221,}[:"
+ "digit:]{49,156}[:lowe(\?<=rprint:])[:space:]{-33}w+",
+ 0, 0 },
+ { "[^(\?{})<{220,-193}[(\?=:xdigit:]UUUUUUUUUUUUUUUUUUU'{-18}]"
+ ")",
+ 0, 0 },
+ { "b[(\?<=:upperw(\?{ord:][:digit:]})EEEEEEEEEEEEEEEEEEEEE/////"
+ "/////////////){177}C",
+ 0, 0 },
+ { "(^).[:alnum:][^[(\?=[(\?{[})DA5{)[[I~y&O\?9>])]][:"
+ "blankcntrl:]M[:alpha:]x9[:upperword:]|[:xdigit:]b",
+ 1, 0 },
+ { "()[:digit:][^[U}-]]{,206}V*WJ@R]\?", 1, 0 },
+ { "[^](\?#{}(\?[<=)yv)]r", 0, 0 },
+ { "({,-192}//////////////////////7!eW_0eoL){}", 1, 0 },
+ { "^[:punct:(]+)IIIIIIIII[:punct:]P$pP", 0, 0 },
+ { "[(\?=|U)^-]{-52,-72}[:digit:]*6666666666\?{{{", 0, 0 },
+ { "([^f(\?:+{1((\?=34,}]))^)s0bux7\?5`Bwr[:upperword:])Dy+", 1,
+ 0 },
+ { "AL{}:::::::::::::::::::::::::::::::{,(104}~@,Ysey@h).", 1,
+ 0 },
+ { "[^((.)))(\?()))))))))))))))))))))(\?msxims:))))))))))[)][:"
+ "upperword:][:alpha:])",
+ 0, 0 },
+ { "[^(()f])G^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^T{}N*nK[G]{,61}^^^^^"
+ "^^^]",
+ 0, 0 },
+ { "[(N::(\?<=[:digit:][:graph:][:space:]xB5[(:xdigit:]|Yv{}"
+ "HHHHHHHHHHHHHHHHHHHHHHHHd).[:g(\?<=raph:])[:digit:]<<)[:"
+ "digit:])[:space:]Q[:punct:]x7C]",
+ 0, 0 },
+ { "[^((\?(\?(())a)(\?!){})W)pP3333333333("
+ "33333333333333333333hhh]{})",
+ 0, 0 },
+ { "[^ [ "
+ "a*FFFFF[^FFFFFFFFFFF(\?<[^!FFFF(\?=FF])])L1]{,-52}{B-bxsPKg{"
+ ",8}[:digit:][:punct:][:upperword:]DD${,-131}",
+ 0, 0 },
+ { "($$$$$$$$$$$$$$$$$$$$$$$$$$$$$^pP),,,,,,,,,,,,,(,,,,,,,,,,,,"
+ ")QQQQQQQQQQQQQQQQQQQQQQQQ",
+ 2, 0 },
+ { "[:lowerprint:]|l{(,-54}C{}*-)IIIIIIIIIIIIIIIII", 1, 0 },
+ { "()+", 1, 0 },
+ { "[(([(\?{[:punct:]]|))[[[[[[[[[[})]WWWWWWWW&$$$$$$$[:graph:]",
+ 0, 0 },
+ { "[^(\?{}){(107[(^,}][:space:[]))^w,&aPPPPPP[^PPPPP{117,-213}"
+ "s\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?]]]222222[:d(\?("
+ "igit:]NNNNNN)NNNNNNNNNNNNN8)I",
+ 0, 0 },
+ { "[^(\?<!$)|TTTTTTTTTTTTTTTTTTTTTT(TTTT]a8)2<", 0, 0 },
+ { "([^[]%[^[^]-][:alpha:]37*:[:space:]]lQvu)[:xdigit:][:"
+ "blankcntrl:]",
+ 1, 0 },
+ { "[[Bl_>9C^:\?X_KK]2sw@hHZT!],uuuuuuut|lFW()''''''''''''''''''"
+ "'''[:graph:]<~v{-251}0[:digit:]C[{222,}]{,41}{}*g^UuS/"
+ "{-114}",
+ 1, 0 },
+ { "(D{,-79}[:gra(ph:(\?(]C[:ascii:]))I[tC.%tkllll[^"
+ "llllllllllllllll]&&&&&&)&&&&&&&&&&&&&&&&&&&&&&)]10435",
+ 1, 0 },
+ { "[:al(\?{[^num:]]})}x'[:(\?#xdigit:])"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKKKKKKKKKKKKKKKKKKKKKKKKKKKKTT"
+ "Tr*%{~f",
+ 0, 0 },
+ { "[ZQKEEEEEEEEEEEEEEEEE(\?<!]3|.~~~~~~~~~~~~~~303)"
+ "33333333333333333",
+ 0, 0 },
+ { "(-62([:ascii:]5555){-230,}<<<<<<SM[:punct:]{72}|E{160,})"
+ "Pfqba!{,-188}DS{ +2tRu\"0JG$",
+ 2, 0 },
+ { "([^(\?:(Ea00000000000000[:punct:][:graph:]{}]))[:xdigit:]{-"
+ "65}t){164,}",
+ 1, 0 },
+ { "[\?$$$$$$$$$$$$$$$$$$$$$$$$$F......(\?(.).q#R:j6%TTLCdtuM|8*"
+ "54<GHoqEh9FBW0:W]L0)o][:upperword:]",
+ 0, 0 },
+ { "[(\?>[:alnum:]W[:space:]]D)|L", 0, 0 },
+ { "(M(MM)[:alnum:]|[:lowerprint:]4)", 2, 0 },
+ { "[[^(\?:{}{2[2(\?>0,})]]]Etu)-)", 0, 0 },
+ { "([^[^^z[:graph:]]#{-144,96}[:punct:]!4LY//////////////////"
+ "SSSSSSSSSSSSSSSSSSSSSSSSS[[^:xdigit:]\?`-!L#p0{52}]%{-121,}["
+ ":graph:]]WqJ>$6UBg{,7}[:blankcntrl:])[:upperword:]y2wW!A[:"
+ "blankcntrl:]0CN\?",
+ 1, 0 },
+ { "[[^(\?:|+bII(IIIIIII(\?(\?>!)275SIIIIIIIIII(IIIIIII(\?="
+ "IIIIII[:graph:]|)`]S\?.}A)[:alnum:]Jgggggggggg{-150,}{-89,})"
+ "[:alpha:]Q)|07be5:j)]",
+ 0, 0 },
+ { "([(\?i(ms(\?=x-x(\?>:))C)]){})>eIqm~lFb[:upperword:][:"
+ "blankcntrl:]w=[:digit:][:graph:]",
+ 1, 0 },
+ { "([HHHHHHHHHHHHHHHHHHHHHHHHHH[^HHH("
+ "\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?!!!!!!!!!!!!!!!!!!"
+ "!!{23}]~J=[:ascii:]tttttttttttttttt])-216",
+ 1, 0 },
+ { "B{[^-32,246}{13(\?!0}q>GVQw*[:digit:][:punct:]."
+ "77777777777777777777`T(-t01odD]\?${}{-247}+gV{131})+[:"
+ "lowerprint:]m/z~d",
+ 0, 0 },
+ { "[t[$FV+(\?=E=[^])]-$U{-22[5,}{253,}08g]$[{}][:xdigit:][:"
+ "punct:]{-18}{-173,}]{,-191}V_|90",
+ 0, 0 },
+ { "()$", 1, 0 },
+ { "[^[^((((((((((((((W[(\?::blankcntrl:]&-JH]J){93}LLLLLLL|r{,"
+ "221}tY/172]-AS",
+ 0, 0 },
+ { "[^()(\?{qqqq(\?msimsx:qqqqqqqqqq3999999999999GGGGG|S*W%{,"
+ "128}][:xdigit:]AJt]}\"Zf!lRpr{>){,36}})",
+ 0, 0 },
+ { "[([]^]^)", 0, 0 },
+ { "([.(\?#){}[:alpha:]\?S{2}P%Gw]"
+ "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnYiq5)>i*r<",
+ 1, 0 },
+ { "[ggggggggggg$PPP:S "
+ "(:]N{239,}|A[:lowerprint:]vvvvvvvvvv[:lower(print:]{-184}({-"
+ "133,}+)[:punct:]P/Q.OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+ 1, 0 },
+ { "(RRRRRRR[^RRRRR[RRRRRRRRR])]", 1, 0 },
+ { "[(\?:^])D%", 0, 0 },
+ { "()[]#C[+[j]{,29}-]", 1, 0 },
+ { "(([(\?(((\?{\?!(\?=\?=#[Es*){02$r'}(\?:3pz)"
+ "uPPPPPPPPPPPPPPPP(\?(\?>:PPPP][:graph:][:ascii:]`.)[:punct:]"
+ "[:a(\?mxi:lnum:])r)$)[:xdigit:]$[:(\?=digit:])aa[^]a)\?])"
+ "sQQQQQQQQQQQQQQQQQQQQQQQQQQ^|$)-}))",
+ 2, 0 },
+ { "z@@@@@@@y${}[:(\?:upperword:]l\?{,144}-)", 0, 0 },
+ { "[:aln(\?:(\?>um:(\?imximsx:]){})FGGGGGGGGGG|-p){,105}", 0,
+ 0 },
+ { "[[{17}llllllllllllllll(\?:lllllllll{,(\?#-94}OUUUUUUU(\?#"
+ "UUUUUUUUUUUUUAA]p[:digit:]{-1(57,}5yyyyyyyyyyyyyyyyyyyyy[:"
+ "alnum:]v{-185}^^^^^^^^^^^^^)d[[[p)]))",
+ 1, 0 },
+ { "()|[:digit:].E2o", 1, 0 },
+ { "()3[:lowerprint:]", 1, 0 },
+ { "[(\?{(\?#(\?>SN}[^)z+r^t[:digit:]seP[:alnum:]$b1ZY[U(\?<!"
+ "U4IIIIIIIIIIIII(\?<=IIIIIIIIII]m)]))]4)",
+ 0, 0 },
+ { "{,74} qkk[^p]kbi6>{}000000000000000000000000000000$|)",
+ 0, 0 },
+ { "[:(\?=digit:])v{164}", 0, 0 },
+ { "[:graph:]h[:upper(\?(wo(\?{rd:)])00000[^000000000000})."
+ "4OEVf{,-46}]A",
+ 0, 0 },
+ { "[](((((((((((((((N{{{{{{{{{{{{{{{{,-1}e]a{-166,-44}", 0, 0 },
+ { "([[^[^[(^[]]YYYYYYYYYYY]D.cQ{}[:alpha:]ttttttt000000[^0000("
+ "\?<!0000000000000000N::::::::].][:alpha:]#5\?{}{-253,-193}]"
+ "\\[:ascii:]tS{,35}B)ffffffffffffffffffffffff))/",
+ 1, 0 },
+ { "(G)[:alpha:(\?#])W{-197,-220}w8", 1, 0 },
+ { "{-2[^00,(\?#-([84}ig+)]]l[:graph:][:graph:][:space:])"
+ "aaaaaaaaaaaaaaaaaaa{-208,}ea{,224}",
+ 0, 0 },
+ { "[^[W(\?<=[B[:xdigit:]{255,}FAAAAAAAAAAAAAAAAAAAPP])[:xdigit:"
+ "]+][:lowerprint:]${-195}",
+ 0, 0 },
+ { "[v{104,}BB].HHHHHHHHHHHH[:ascii:]"
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbb(btttttttttttttttttttttttttt){"
+ "180}",
+ 1, 0 },
+ { "[^(i[^iiiiiiiiiiiiiiiiii(ii)n])#######################]", 0,
+ 0 },
+ { "(([:space:])[:g(\?>raph:])[:punct:][:upperword:]LV\"t+t!)[:"
+ "ascii:][:lowerprint:]q",
+ 2, 0 },
+ { "[[[^([7(\?[<!)\\PP~D7L (\?imsimsx:(\?= "
+ "$GS26L3-J(\?()!)]]{-178}%$[:p(\?!unct:]))yyyyyyyyyyyyyy@w,["
+ "11!R86:)G*[(\?(:blankcntrl:]267$~L\?{-108}k[:alnum:]So\?Y/"
+ "eq]-|[:xdigit:]555555555555555555555555555)55555........W*O)"
+ ")][:alnum:]]I{,-126}[:lowerprint:]8\?[:xdigit:]u%wHc6\?:Pc.."
+ ".........................,,,,,,,,,,,,,,,,,,,,,,,,,,,]",
+ 0, 0 },
+ { "((3pPp))QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ", 2, 0 },
+ { "[[^]{-244[}(\?([^|W0E4]UUUUUUUUUUUUUU[:upper)word:][:space:]"
+ "{-57,})+L>R]]$PeFuufcBA`qr!!!!!!!!!!!!!!!!!!!!!!!!!",
+ 0, 0 },
+ { "[[(\?#F^(\?<!)|)fff(\?!fffffffffffffffff(\?{ffffff(\?:"
+ "ffffff[:alnum:])]]c.\?-}))",
+ 0, 0 },
+ { "[^[^((\?:)ww[wwww(\?>wwwww)3z/57z){34}]/(/////////////[^////"
+ "//////////////)]E%)L{-133}]*$]",
+ 1, 0 },
+ { "(!)GS[:ascii:][:punct:]{235}T'&-_h\"", 1, 0 },
+ { "(){}", 1, 0 },
+ { "[[^((\?!(\?<=)*QF[:alpha:])([^[^\?<!x60t(\?<!"
+ "UUUUUUUUUUUUUUUUUUUU)K&d{118}z7nM.G)````````````````````````"
+ "```E:(\?(){31,}){}]k]){,109}[:space:]]ZZ[:xdigit:]]{-68,}`{}"
+ "{}e\?[:alnum:]",
+ 0, 0 },
+ { "[^{223}.^,-qqqqqqqqq((\?!\?>qqqqqqqqqqqqqqqqqqqqqqqP6W0_'O)"
+ "Bur*'6&*t)]{65})+",
+ 0, 0 },
+ { "([(\?=)]wr$7f5ru){100,}[:xdigit:]y{}[:digit:]{}2n@P|9#mru~"
+ "97{-189,73}$a",
+ 1, 0 },
+ { "({-113,213}){-172,221}B[:ascii:]{,-48}", 1, 0 },
+ { "[^[[Xf`````((\?{(\?<=\?imsmsx:`````````(\?!`````````[```("
+ "\?mximsx:``(\?(&|o{xIaO][:)space:]3))\?])+)*<|@@@@@@@@@@@@@@"
+ "@@@@@@@@){-251,}{}]*[:graph:]1!azE\?|-120u*][:lowerprint:]}"
+ ")",
+ 0, 0 },
+ { "[[[^##(\?################(\?>(\?(##t)][:punct:])b))<<<<<<<<<"
+ "<<<<<<<<<<<<<<<<<[:alnum:]y "
+ ">u=l:rp8i3Ci#]46%NIO-W[:space:]IIIIIIIIIIIIIIIIII]W[:space:]"
+ "f]l{-253}",
+ 0, 0 },
+ { "[:graph:]L{-136,175}{[^}h(\?=t)Q]ooooooooo("
+ "ooooooooooooooooo_)[:space:]q\?",
+ 1, 0 },
+ { "()$.", 1, 0 },
+ { "[(\?<!^$.\?{197}B]$)", 0, 0 },
+ { "[:di(git:])[:low(erprint:])qqqqqqqqqqqqqqqq[:digit:]", 0,
+ 0 },
+ { "((zzzzzzzzzzzzAUUUU)l$]VD z~)n", 2, 0 },
+ { "([^[(\?<=^[]{}][.WWWW)044444444444(\?=44(\?{444(\?{("
+ "444444444444e{(\?=}}))..t]+[:(\?<!xdigit:]P]-N}))))|)",
+ 1, 0 },
+ { "\\ce[:(\?#asc(\?{ii:])})[:upperword:]`^", 0, 0 },
+ { "[:graph:(\?<=])[:alpha:]", 0, 0 },
+ { "([:upp(\?=erword:])pC)lp\?", 1, 0 },
+ { "(oooooooooooooo\?fN)-[:alpha:]{-213}[:alnum:]qHEu", 1, 0 },
+ { "[:punct:]TTTTTTTTTTTTTTTTTTT[:d(\?#igit:])[:alpha:]", 0, 0 },
+ { "([^[^[^J4(+++++++++++++++++++++SgDE(\?>\"y8].]::::::::::::::"
+ ":)pP5-]p)O{,199}xxxxxxxxxxxxxxxxxxxxxx[:ascii:]%",
+ 1, 0 },
+ { "([:alpha:]Fs)Z", 1, 0 },
+ { "[()]{209}[:alpha:]hhhhhhhhh(hhhhhhhhhhhhhhhhhhhhh)pP<<<<<<<<"
+ "<<<<<<<<<<<<<<<<<<<<<",
+ 1, 0 },
+ { "-{-8,}.[:(\?imsxx:ascii(\?<!:]{-231}aa*{}K^UQL\?)d\?[:"
+ "lowerprint:]W)q>D9'",
+ 0, 0 },
+ { "[#(\?msximsx:#########################-IIIIIIIIIIIIII(IIII("
+ "\?#IIIII((\?#[^III{})N.[(\?=:lowerprint:]))CwT,,,,,,,,,,,,,,"
+ ",,,,,,Sq]$CCCCCCCCCCCCCCCCCCCCCCCuuuuuuuu])))",
+ 0, 0 },
+ { "[:xdigit:][(\?#]){13}{,75}lllllllll", 0, 0 },
+ { "[c]QQQQQQQQ1+{-252[(\?#}33333])[:upperword:]", 0, 0 },
+ { "P@i #>>PF!@8G<[(\?:^P]-)D", 0, 0 },
+ { "uZZZZZZZZZZZZZZ[^ZZZZZl*-211{199}(\?!p])"
+ "EEEEEEEEEEEEEEEEEEEEEEEEEEED[:lowerp(\?msximsx:rint:])",
+ 0, 0 },
+ { "[(\?!^])021[:graph:]'", 0, 0 },
+ { "\\(\?>[(\?<=:ascii:]{}[:alpha:]d8}G))", 0, 0 },
+ { "[^[((\?!1)[^,a|]\?{,242}[:alnum:])X\"a", 0, 0 },
+ { "pP[((\?simx::a(\?!lnum:]vvvvvvvvvvvvvvvvvvvvvvvvv)|O0)[:"
+ "digit:]ooooooooooooooooooooo)"
+ "\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"",
+ 0, 0 },
+ { "_ L:8J-~ Y$[:uppe(rword:]{,-184}]{}6.A)", 0, 0 },
+ { "{,105}.(9]]{-12})N@0nOOE", 1, 0 },
+ { "HHHHHHHHHH[:xdigit:]uuuuuuuuuuuu{}E^X\\\\\\12601", -1, 1 },
+ { "( o)=\"OU7h{V>", 1, 0 },
+ { "[[:xdigit:])))))$[:xdigit:]+{152}{,-50}(c),,,,,,!!!!!!!!!!!!"
+ "!!(\?>!!!!!!!!!!!!!.[:digit:]i>\"O'i9])-175d_",
+ 0, 0 },
+ { "[([^[^[^([[Eeee[^eeeeeee(\?(\?<!(eeeeeeeeeeeeeeeeeef|]][:"
+ "alph()\?>(\?!(\?>a:]a{,166})/////////////////////"
+ "[:gr[^aph:])Gpu",
+ 0, 0 },
+ { "(7)NNNNNNNNNNN132", 1, 0 },
+ { "[([\?#^[]{QKm$v])][:alp[^ha:]]", 0, 0 },
+ { "(:{86})7{K|[:alpha:]{O", 1, 0 },
+ { "([Y(\?{[[^:alnum:][:alnum:][:digit:][:a(\?(lpha(\?(:].})", 1,
+ 0 },
+ { "[[({29,-30}([[^:digit:])Y]]J=~{,220}[:blankcntrl:])"
+ "0ooooooooooooooooooooooooooooooo[:punct:]&]",
+ 0, 0 },
+ { "[^1Dx32[:alnum:]]{[(\?::punct:]MMMMMMMMMM)12759", 0, 0 },
+ { "([[[]]*|(_])[:u(\?{pperword:]})", 2, 0 },
+ { "[:upper(\?(wo)rd:]){-16,250}", 0, 0 },
+ { "([^{194}i(\?({161)}PP\\S{}{,-14}]))z{208,225}BpPEt", 1, 0 },
+ { "[(\?m-ms:)}&!@29k0sUqzt9}<-x|A$!+G>>>>>>>>>>>>>>>>>>>>>>>>>>"
+ ">>>>>>CCCCCCCCCC-][[:space:]][:space:]El",
+ 0, 0 },
+ { "()[:digit:(\?isx(\?>ix:]K^WQQQQQQQQQQQQQQs)[:lowerprint:])",
+ 1, 0 },
+ { "[a|(\?imix:S(\?(SSSS)SS(\?>S)]W)8t[:ascii:]f$)[:alnum:]"
+ "111111111111111111111[^[:space:]x{12729}+'''''''''''''''']",
+ 0, 0 },
+ { "[^(\?!(\?(\?#=)a)[:punct:]=2)(){}$$$$$$$$$(\?ims(\?#-isx:$$$"
+ "$$$$$$$$$$$$$(\?#$$s)x{294b}##############################"
+ "slllll)]){,209}333333333333333333G:v2/K",
+ 0, 0 },
+ { "[^]ub(\?<=)vQ6(\?#Z\"3.)[:space:]u[[:digit:]]"
+ "7777777777777777U'{}sssssssssss",
+ 0, 0 },
+ { "(([(])`[:ascii:]b)", 2, 0 },
+ { "[[[^[^([^[^(\?=(\?imxisx:[[^w])", 0, 0 },
+ { "pppp(pppppppppp-{-175}Nb>k&)sssss{-190,-54}", 1, 0 },
+ { "()OJ@`'%[:(as(\?!cii(\?#:]))+pffffffffffffffffffffffffffff{,"
+ "162}[:ascii:]5)s-[:graph:]",
+ 1, 0 },
+ { "[(M{}Ux5{jaW/"
+ "{}[^u[:alpha:]s^{84,}PPb@Wt$(\?>nha<Yf41a)]{}[:lowerprint:])"
+ "*[:lowerprint:]][:upperword:]^1gS.^=pp{}"
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFF33333333333{}",
+ 0, 0 },
+ { ")\?L9~h4BQnNp F\\Q{}", 0, 0 },
+ { "($)[:upperwor(\?:d:])N[:alnum:]"
+ "bcccccccc5555555555555555555555555.N[:blankcntrl:]",
+ 1, 0 },
+ { "2222222222222222222ppppppppppppppppp[:lowerprint:]))[^B\\e{{"
+ "{{{f]6#+{,-104}{{{{{{{{{{{{{",
+ 0, 0 },
+ { "<[(\?>:al[^pha:]])\"O\"vN", 0, 0 },
+ { "[(\?>d8E@b.{(\?<=,-250}(\?=mx48[:punct:]^&)]nAeYY)W)-13272",
+ 0, 0 },
+ { "22222222222222222222222222///////////////////"
+ "[:digi(\?#t:]eM)[:lowerprint:][:alpha:][:alpha:]EEEEEEEEEEE",
+ 0, 0 },
+ { "[(\?={38,223})^\\\\\\\\\\\\\\\\L(\?:{,-50}3|)}r]aW\\x70U{-"
+ "110,}8LUf)w]4+oav",
+ 0, 0 },
+ { "G[:upperword:]v[:lowerprint:]-tu)j8CK", 0, 0 },
+ { "[([([^().(\?(\?><=c)'(\?<(='(\?<!''''''''(\?(\?<!!''''''''''"
+ "'(\?=''''''/"
+ "(|dHj(P>L\?q!G))|)(\?=n(\?(^tk)T-z$q!D|2<rc[^{,53})]jZy))))"
+ "6)[:bla)nkcntrl:])010])7pE`l[:space:]([:lowerprint:]"
+ "eXXXXXXXXXXXXXXXXXXXTTTrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr]+[:"
+ "alph(\?!a:]7)444444444444444444444444l{34,}]J{}"
+ "yyyyyyyyyyyyyyyyyyyyyyyyyyy)\?'z9~9s.mA",
+ 1, 0 },
+ { "().", 1, 0 },
+ { "{-205(,}[:al(ph(\?>[^a:]W,[4DLR[^^8THMtVv~KKw(\?>)pPF)].{-"
+ "245,}]))fffffffffd[:alpha:]zzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
+ 1, 0 },
+ { "[^[[^]{-[1(\?imximx:83,}{,182}][:graph:]]^])-bTO X0P", 0,
+ 0 },
+ { "[11111111111(\?#11111111]U[:asc([\?!ii:]{,37}+{-89}){-170,"
+ "218}{-21,})f[:xdigit:]]P.[:xdig(\?:it:]145)YYYYYY$S@:@@@@@@@"
+ "@@{-150,-109}",
+ 0, 0 },
+ { "{-40}<o][^D[(:graph:]]d).Q", 0, 0 },
+ { "()APPLn[:xdigit:]", 1, 0 },
+ { "[([^\?+++++++++++ [ (\?> (\?( (\?{ "
+ "(\?!]E{-29})pP)})ZpP",
+ 0, 0 },
+ { "(t|{}c[^z^\?(@YLD]bSSSSSSSSSSSSSSS)+{{{{{{{{{{{{{{{[:xdigit:"
+ "]n>1)WkF}7",
+ 1, 0 },
+ { "W22[0Q[^d-d{}PPPPPPPPPPPPPPP<^FZ(\?<=\"[U]Yo}9H'cYy]S[:"
+ "alnum:]^8wTDH)^u",
+ 0, 0 },
+ { "([^[(\?:(\?>((\?#$)(\?{^(\?>))///////////(\?>/"
+ "ggggggggggggggggg{1(\?!90,-13}\\D)Dyyyyyyyyyyyy(\?!y(\?<!"
+ "yyyyyyy)})]]$)[:xdigit:]|{}-)#a))nPpP[:lowerprint:]AA)V+q^[:"
+ "blankcntrl:]",
+ 1, 0 },
+ { "([^(\?!]))D{,97}", 1, 0 },
+ { "(c){,141}", 1, 0 },
+ { "nn[:s(\?<=pace:])[:upperword:]ooooooooooooooooooo*^[:space:]"
+ "`{-188,129}mmmmmmmmmmmmm^.",
+ 0, 0 },
+ { "[[G{(\?imsximsx:2(49}{,-46}r(\?(\?=#Gw]u))[:bl(\?>ankcntrl:]"
+ "))(^m+)zSiZ "
+ "F4[!]VV$E{-9,-100}''''('''''''''\?DEOOOOOOOOOOOO############"
+ "###[:space:])HHHH)[:digit:]'////////////",
+ 2, 0 },
+ { "[^*}(\?>)(\?:7Q=#+]KKKKKKKKKKKKKKKKKKKKKKKKKKKG)]]]]]]]]]]]]"
+ "]]]]]]]]]]]]]][:alpha:]-{}",
+ 0, 0 },
+ { "[n(\?<(\?#!nnnnnn55555{205,}!)[:alnum:]^]!!!!!!!!!!!!!!!!!!!"
+ "!!!![:punct:])[:x(\?(digit:]vr)|'n6W5 D&jk[:punct:]5)",
+ 0, 0 },
+ { "[^P(P{(\?i(msxisx:235,}))***])[:alpha:]^", 0, 0 },
+ { "[([t(\?<!(\?<!4])[:u(\?=pperword:]))-])}}}}}}}}}}}}}}}}}c{-"
+ "39,}[:digit:]$-",
+ 0, 0 },
+ { "([^)]{241}[:xdigit:][:upp(\?=erwo(\?(rd:]-xF5b{})q[:ascii:])"
+ "T4U{185}9999999999)()X&Ny[:alpha:]@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ "@@@@@@{69,}[:alnum:]x{d7f8}p-[:digit:]",
+ 2, 0 },
+ { "(f)(${,111}{25,}!\\d{,94}[:blankcntrl:]@[:space:][:ascii:])-"
+ "237{,232}DQVVVVVVVVVVVVVV)-",
+ 2, 0 },
+ { "PP[:g(\?!raph:]){}", 0, 0 },
+ { "([[^-][^4[:digit:]NNNNNNNNNNN]TVU:])[:ascii:]", 1, 0 },
+ { "(([^(\?[[^<=)][:graph:]+iiiiiiiiiiiiiiiiiiiiiiiiii0INFX[:"
+ "xdigi(\?(t:][:blankcntrl:]][:graph:]qM6A[:alpha:][:graph:])"
+ "1*]eFvvvvvvvvvv)v-)U))t{89}",
+ 2, 0 },
+ { "[^ZZZZZZZZZZZZZZZiiiiiiiiiiiii(iiiiiiiiiiiiiii{}))))))))))))"
+ "))))))]))))))))))))))))))))))))[:digit:]-",
+ 0, 0 },
+ { "ddddddddd+zzzzzzzzzzzz[:graph(:])ssssssM{-223}[:graph:]", 0,
+ 0 },
+ { "[:alph(\?>a:])x11{-144,45}.", 0, 0 },
+ { "[]{#y.^(\?{{}&&&&(\?:[^&&&&&&&&)[:punct:]n{190}OylBQ{(\?!-"
+ "73})2u',x(\?#Ds(\?#{})j(\?{-})})u0(((((((\?{(((([:alnum:])"
+ "MC})b=71TncyE>[:xdigit:]*\\f]{}]\"p#!8twZT\")[:punct:][:"
+ "space:]",
+ 0, 0 },
+ { "[^(Z6]8)|'@p8{}[:upperword:]MMMMMMMMMMMMMMMMMMMMMMMMMMMM{}"
+ "7c",
+ 0, 0 },
+ { "$0)@#vp,VcJ.Bdh", 0, 0 },
+ { "[[^(-])nnnn+s`[:alpha:][:blankcnt[^rl:][:upperword:]{-15,}]["
+ ":g(raph:]c]){,-177}6[:upperword:]##################{,-14}",
+ 0, 0 },
+ { "[[(5C{86(,}PPrrrrrrrrrrrrrrrrrrrrr{150,182})N{}LSC|)-[:"
+ "alnum:]{}KKKKKKKKKKKKKKKK<4=~7K3PPPPPPPPPPPPPPPPPPPPPPP[:"
+ "lowerprint:]]]",
+ -1, 0 },
+ { "([^(x{145b[5}^hfc.0)+]z@_&lA{-34,}])X\?", 1, 0 },
+ { "([(\?<=)(\?!])l)L", 1, 0 },
+ { "({-104,}DrPPDF4444444444444[:space:])[:space:]", 1, 0 },
+ { "())))", 1, 0 },
+ { "[[^((\?>\?(\?[{})q5v}r7t(P)xtffffffffffff))]{,-66}kdExX&-"
+ "SCeCzzzzzzzzzEc)E,\"^I]x{e629}|{}]",
+ 0, 0 },
+ { "[h[:punct:]p\\[\\\\(\?:\\\\[^\\\\)Eo#:C$u[^T/"
+ "ysA[*%nM:f]{,221}[:lowerprin[^t:]{]bx{f285}E]E[:alnum:]+]"
+ "1oe3B][:alp(ha:]]fh7}M$l)D{17}",
+ 0, 0 },
+ { "IIIIIIII[^IIIIIIX]-_S[:digit(\?#:])"
+ "33333333333333333333333333[:punct:]iiiiiiiiiiiiiiiiii",
+ 0, 0 },
+ { "[^[[:punct:](\?((\?:^ "
+ "#Q_po(\?=[:alpha:]{}z()(\?!======'wq$Q2)LLLLLLLLLLLLLLLe("
+ "C9gggggggggggggggggg[(\?<=:alnum:]()\?<!{-85,}W[[[[[[[[[[[[["
+ "[[[(\?{[[[[[[^)(]\?])|uuu[uuuuuuuuuuuuuuuuuu{,-20}p${}]MHI&"
+ "7s:\?$[:digit:]-:)_V`*{-52,}{250}$:ME9izF/"
+ "uP[:blankcntrl:]})''''''''''''''''''''''''''''')"
+ "CCCCCCCCCCCCCCCCCCCCCCCCdd[:ascii:][:lowerprint:]."
+ "Mcccccccccc2B{-230,}$[:digit:]",
+ 1, 0 },
+ { "()|mOAuK~P144[:space:]^9dddddddddddddddddddddddddddddd[:"
+ "blankcntrl:]",
+ 1, 0 },
+ { "[^[^[^.L[^-vEUl(\?>(\?=a!Ib1P]])])~~~~~~~]xE9", 0, 0 },
+ { "X()", 1, 0 },
+ { "[^()(\?#G(\?<!)(\?=^r])*,XXXXXXXXXXXXXXXXX@)444444444", 0,
+ 0 },
+ { "([[((\?<=({,-70})-[:xd(\?=igit:]{,138})", -1, 0 },
+ { "[(^]{62,67})", 0, 0 },
+ { "([((])[:space:]))", 1, 0 },
+ { "(a{(109,})[:alpha:]{,-121}{})]RRRRRRRRRRRRRRRRRRRRRRRR{}{"
+ "125,}ttttttttt{46,}`[:space:]",
+ 2, 0 },
+ { "[^[^([q[8]~.IPmiBSspP)]QpX[pT==8@lulANS]]{,-98}]", 0, 0 },
+ { "[^77777777777777777777777(\?>777777])", 0, 0 },
+ { "(),e<^X~{[:alpha:]{}G{70}", 1, 0 },
+ { "({-211,}'){}", 1, 0 },
+ { "[^(\?imsxsx:{}[*])cccccccccccccccccccccccccccccccc<z0W8]$",
+ 0, 0 },
+ { "(){2,89}$z", 1, 0 },
+ { "((050[^\"\"\"\"\"\"\"\"z]8|j{}{,-112}$).pP)qq1~hW}L", 2, 0 },
+ { "[[^[(+xx(\?<!xxxxxxxx(\?!xxxxxxxxxx(\?#(\?>[x))(\?:]r.]]]))["
+ ":graph(\?<=:])))",
+ 0, 0 },
+ { "[^([(\?#)(\?(\?(<=)l|\?(\?!])kkkkkkkkkkkkkkkkkkkkkkkkkk", 0,
+ 0 },
+ { "[:xdigit:]K(KKKKKKK)^3c.OOO{-240,-10}2{-97,-139}*{-34,}[:"
+ "xdigit:]",
+ 1, 0 },
+ { "[([^66666666F(\?>FFFFFFFFFFwpP)LLLLLDeDA&Am$l[:xdigit:]!T5#]"
+ "n[:alpha:]U*)))))))))))))PP]",
+ 0, 0 },
+ { "[[[:punct:]u^[:xdigit:]L(\?:[:xdigit:][[:graph:]PP{21}A[:"
+ "alpha:]8%I(M%b<eE~#C@r=uG~~~~~~~~~~~~~~~~~~~~~~~~~~~~+w]pP)"
+ "T]]$$$$$$$$$$$$$$${-121,}|l",
+ 0, 0 },
+ { "([(107{,-4(\?=}~[^D)])f]{,46}+ri<)", 1, 0 },
+ { "[(\?<=]{,208}+~)", 0, 0 },
+ { "[^444(\?<=4444444[:alnum:]&[,i]0)[:alpha:][:upperword:]", 0,
+ 0 },
+ { "[^([^(\?()*+)SS(\?>SSSSSSSSSSSSSSSSSSSSSS]]]]]]]]]]]]]]]]]]]"
+ "]]]]]]]]]]]{,-1}])[:blankcntrl:]============================"
+ "===[:punct:][:blankcntrl:]Z[:space:][:ascii:]$|$[:"
+ "blankcntrl:] JR.{,133}[:alpha:]$\?)<]",
+ -1, 0 },
+ { "(OL[:u[pperword(:][:s[^pace:].[:spac(e:],,,,]*])$)\?)", 1,
+ 0 },
+ { "(VI[:digit:][:alpha:]6)EG", 1, 0 },
+ { "({}){-2,-40}rrrrrrrrrrrrrrrrrrrrrrr[:punct:]", 1, 0 },
+ { "()q", 1, 0 },
+ { "[^([^[([^C|])]{,-56}[:xdigit:]{-144,}V])fYv{-[40,-58}$@@@@@@"
+ "@@@@@@@]|Y(-]-.]h-[:dig(it:])>>>dddddddddddddddddddddddddd{"
+ "101,}",
+ 1, 0 },
+ { "([P,{1(\?(\?(<=28,-218[^)}LoZX)])!!!!!!!!!!!!!!*[:blank(\?!"
+ "cntrl:]ed)\\\\\\\\\\\\\\\\\\\\[\\L\?][:graph:]:*Y{-108,120}"
+ "xCC)]",
+ 1, 0 },
+ { "(A[:space:]PP{185}a^!!!!!!lllllll)*db\?$Pfr", 1, 0 },
+ { "{-21,-118}kG[(\?{:xdigit:]})[:punct:]{69}"
+ "Qyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy5{}TTTTTTTTTTTTTTTTTTTTT",
+ 0, 0 },
+ { "[[^[P(\?<=P$X>0^d.[:punct:](\?#ccccccccccccccccccccccccc{}"
+ "3N000(\?>00000000000000000000000000000]f[:punct:]5)).R======"
+ "=========={,222}^wwwwwwww$)]-{} "
+ "]{,-22}CjP{242,}",
+ 0, 0 },
+ { "[(\?#^]{})", 0, 0 },
+ { "[^([[([([[([^[^(\?:(\?(\?(!)]\"))h>\"RRRRRRRRRRRRRRRR[^"
+ "RRRRR{68,-65}7Q(\?{]",
+ 0, 0 },
+ { "(P{}){175,}PP{}rttttttttttt", 1, 0 },
+ { "[:bla(\?{nkcntrl(\?#:]})))))))))))))))))))))))!!!!sR{})", 0,
+ 0 },
+ { " [:digit:]dAAAAAAAAAAAAA^[:ascii(:]55)^", 0, 0 },
+ { "($*)dZY", -1, 0 },
+ { "[:graph:][:lowerprint:]S[:gr(\?=aph:]{-128,}"
+ "666666666666666666666{}[:upperword:]|"
+ "nnnnnnnnnnnnnnnnnnnnnnnnnnB)c[:xdigit:]{-225,}{-4,}{-192,}"
+ "QQQQQQQQQQQQQQQ@@@@@@@@@@@@@@@@@@@@@@.",
+ 0, 0 },
+ { "([:digit:]s{44,}{}{-31,}c{,-130}pP){-241,}UeN", 1, 0 },
+ { "([^)((\?>\?#{}hK\"V2\?d][KKK(\?imsxim:KKKKKKKKKKKKKKKKKKKK[^"
+ "KKKKKKKKKWWWW[WWWWWWWWWWWWWWWWW)B])_l_3",
+ 1, 0 },
+ { "[(^[(\?!*){[^,91}].j]*]L)*c|[:alpha:]&", 0, 0 },
+ { "[^[[[^[777GGG(\?:W_U(\?imsxms:[:punct:]A]-)[:digit:][:"
+ "blankcntrl(\?(:]][:alnum:)])]WRRRRRRRRRRRRRRRRRRRRRRRRRRR]{"
+ "31,}[:xdigit:]][:xdigit:]))))))))))))))))))))))$[:xdigit:]",
+ 0, 0 },
+ { "[:ascii:]m*[:punct:]#[(\?<!:punct:][:alpha:]-,"
+ "7vyXeeeeeeeeeeeeeeeeeeeeeeeee^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
+ "^%%%%%%%%%%%%%%%%%%%%%%%%%%%%[:digit:]''''''''''''''''')",
+ 0, 0 },
+ { "([^*[(:punct:]9999999999999999999{147,}]j{,193}{171}Z-)){"
+ "208}0[:graph:]yDt",
+ 1, 0 },
+ { "(dw[[:alpha:]U]ttt[tttttttttttttttttttt]Q^171e)[:xdigit:]/",
+ 1, 0 },
+ { "[[^((\?#)Tqqqqqqqqqqqqqqqqqqqqqqqqq105++++++++++++++++++++++"
+ "++++b7V+7dit]])|D",
+ 0, 0 },
+ { "{}P7.Ajh[:xdigit:]^[:blankc((\?(\?<=nt[rl:]FFF)-]){}o|a[:"
+ "grap(\?!h:]))PsssssssssssssssssssssssssssssssN^{-60,}Kb",
+ 0, 0 },
+ { "[:alpha(\?(:]$!_+777777777777777777777777O)666)lll[^llllll[^"
+ "l{{{{{{{{{{{{{{{{{{{{{{|]{-217,}MoEl`7)^)LlU[:alph[a:]({-"
+ "241,27})]]{-212}{,249}n)X",
+ 1, 0 },
+ { "[U|ajP[:alnum:]n[(:digit:]]W)[:graph:]b[:xdigit:].P", 0, 0 },
+ { "(([:low(\?-imsx:erprint:]|{}[:ascii:][:gr(\?:aph:])>>>>>>>>>"
+ ">>>>{,-129}))\?{-226,}^P)R",
+ 2, 0 },
+ { "[^[[nnnnnnnnnn(\?=nnnn(\?!nnnnnnnnnnnn(\?#nnnnnn{,-38}N){"
+ "202,}]$[:alnum:])]t][:alnum:[]^=w){237}][:alpha:]-[:alpha:]+"
+ "e",
+ 0, 0 },
+ { "()[(\?(:digit):]+qc)O88888888{,151}aJ", 1, 0 },
+ { "([^([(\?!sv(\?=)d]{-200,})N))]Z{-73,15}", 1, 0 },
+ { "([\?\?\?\?|||||||||||(\?{||(\?=||||||||-}[))Ehhhhhhhhhhhhh{,"
+ "202}&TcfL((\?:>)((\?!\?>$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$8[:"
+ "alpha:]\\d])]C[:graph:]h*,\"\?u{|mU,a)[:blankcntrl:][:"
+ "lowerp(\?>rint:])PPnP+9.[:xdigit:]*PPjjjjjjjjjj~y<#*scf_\"^"
+ "e[:xdig(\?(i)t(:])~$y)^){-131,77}^L%",
+ 1, 0 },
+ { "[^[(((\?>)$}h9$B5+yhU/"
+ "Nqh$YYYYYYYYYYYYYYYYYYYYYShK)3WHw1vMMMMMMMMMMMMM(\?="
+ "MMMMMMMMMMMM[:alnum:]/"
+ ")dddddddddddd(dddddd\"e5zLW)+![:space:]+BHGHfAS]"
+ "\?IIIIIIIIIIIIIIII*&&&&&&&&&&&&&&&&&&)NNvwDteepjdm<<<<<<<<<<"
+ "<<<<<<<<<<<<<<<<<<<<${61,219}D][:digit:]0",
+ -1, 0 },
+ { "[:punct:][{177,(\?=234}]ix9*)", 0, 0 },
+ { "([^K{,3(\?<=4}]I)\?U)", 1, 0 },
+ { "[([^[[[^([([^[^(\?=])X", 0, 0 },
+ { "[:blankcntrl:(])qd_R\?{\?r[=\"[^[^6]vX8)a+{C%H84CK6Uy#E]sE{"
+ "208}",
+ 0, 0 },
+ { "PPPPPPPPPPPPPPPPPPPPPPPPPPnnnnnnnnnn()[:upperword:]us", 1,
+ 0 },
+ { "x{,46}[:graph:]LU{}CU)", 0, 0 },
+ { "()-t|[^W{}][:lo[^werprint:]{}]\?b5", 1, 0 },
+ { "()x5A", 1, 0 },
+ { "[([^]-217)]s{-47,135}0000000000000000000000000000000{,-108}",
+ 0, 0 },
+ { "[^((\?{[^L\?u]})f", 0, 0 },
+ { "()[[^^(\?{y(\?=VF_(\?<=]D}))]-= {46,})^5bIEQ{,-96}Z", 1, 0 },
+ { "([^{}f[:punct:]\"X%%%%%%%%%%%%%%%%%%%%]5{-194}A[:punct:]"
+ "mnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn+AAAAAAAAAA-)",
+ 1, 0 },
+ { "(CCCCCCCCCCCCCCCCCCCC{-230}352{-182,-68}O4{})", 1, 0 },
+ { "([^[^\?[:space:]$TTTTTTTTTTTTLLLLL[^LLLLLLLLLL[^({}{4,-179}]"
+ "]J] C]){}C{}{-224,})QQQQQQQQQQQQQQQQQ^",
+ 1, 0 },
+ { "([[:alnum:]].){-155,-82}dzI{55,}^", 1, 0 },
+ { "([[:alnum:](\?#{88,-178})[:graph:]NC\"pI[:punct:]rmWd5y^p+"
+ "gUP]YYYYYYYYYYYYYYYYYYYY~{,-62}{,200}{-109}{}+"
+ "333333333333333333333333333333{}p)^.hhhhhhhhhhhhhhh",
+ 1, 0 },
+ { "[000000(\?mmsx:00000000000000000000000)M]]]]2*`[^]QQQQQQQQ("
+ "\?<=QQQQQQQQQQQQQQQQQQQQQQQ])\"<h\?",
+ 0, 0 },
+ { "[^((<g(\?>5j[bbbbbbb(\?{bb)o{}3(\?imxisx:E]g})YYYYY[:"
+ "blankcntr(\?#l:].(()w264[:ascii:]^)[:ascii:]G)&(n "
+ "{^PGn[:xdigit:])nv_e|]{-103,30}",
+ 3, 0 },
+ { "[^(([(\?!{}@[^HCO[[^^D[|]{,-49}][:xdigit:]]c`4[:ascii(\?<!:]"
+ ")$66666666666)*)]PP$Z[:alpha:]{,-235}UK],(aT/"
+ "+6rbMqs60EloA)[:g(\?isx:raph:]!)]z$o{-24,}x1E[:blankcntrl:]"
+ "ZDFvk",
+ 1, 0 },
+ { "[:blank(\?=cntrl:]US@.!\"[:digit:]*E)$16182", 0, 0 },
+ { "[-{}x{3772[}][:(\?<=xdigit:][:u(\?#pperword:].W)aD)<pfN<b=C|"
+ "-{-38}EZdOP|!>ggggggggggggggg\\\\\\\\\\\\\\\\\\\\\\\\\\Ef[:"
+ "space:]\?][:ascii:]{21,}",
+ 0, 0 },
+ { "([:xdigit:]W[:u(pperword(\?::]jS "
+ "[:upperword:]*)[:alpha:]nnnnnnnnnnn))-148}SSu",
+ 1, 0 },
+ { "([^(\?!\?)[(:upperword:])Bx^x$~lCr6*)6", 1, 0 },
+ { "[{,-78}Y[:xdigit:][^s(\?>]P[:space:])]YYYYYYYYY[:punct:][:"
+ "alnum:][:blankcntrl:]",
+ 0, 0 },
+ { "([MMMMMM(\?(MMM)M(\?<=MMMMMMMMMMMMMMM[^M)]en][:punct:]-[:"
+ "alpha:]))Nr[:space:]",
+ 1, 0 },
+ { "~=1([^(\?=(\?:l){}])j{-44}{-18}[^u[:graph:]]{-187,}[:xdigit:"
+ "]w[:alpha:])",
+ 1, 0 },
+ { "[ccccc(\?>c(\?{cccc[ccccwetoCei+)w&-+{,-142}[:alpha:]"
+ "PP66io4(|zkA=],,,,,,,,,,,,,,,,,,,,,Lx5Cx{d2bb}]{188}U~~~~~~~"
+ "~~~~~~~~~~~~~~~~})",
+ 0, 0 },
+ { "Q|0\"[:d(\?:igit:]^{,-174})", 0, 0 },
+ { "[^[(\?>rh])]", 0, 0 },
+ { "[ees{{{{{{{{{{{{{{{{{bbbbbbb4`ml******(\?=****+])", 0, 0 },
+ { "((hdG[((\?<=:dig(it:])[^[:alpha:]$(\?sxi:)x{11390}[(\?{:"
+ "upperword:]~)i 8[:blankcn[trl:(])]+{,-183}Zqp",
+ 2, 0 },
+ { "Dd{D8`+DW={-[53,1(\?<=71}])", 0, 0 },
+ { "[:(\?(alpha:][:punct:])", 0, 0 },
+ { ".LLLLLLLLLLLLLLLLLLLLLLLLLLLL{}pP[:punct:]x0CZ{30,}!!!(!!!!!"
+ "!!!!!!!!!!!!!!!!!!!!==@77.%[:graph:]D)",
+ 1, 0 },
+ { "[^[^[[r(\?#]){-237,}RRRRRRRRRRRRRRRRRRRRRRRR[^Rll(\?!(\?{"
+ "lllll]",
+ 0, 0 },
+ { "()*ooooooooooooooooooooyyyyyyyyyyyyyyy", 1, 0 },
+ { "{,4(}D)JJJJJJJJJJJJJJJJJJJJJJJJJ", 1, 0 },
+ { "((b.D{}[:al[pha:]{64}]{})==========================[:alnum:]"
+ "h>77b)!Ab",
+ 2, 0 },
+ { "([^[^[^oooooooooooooooooooooo][:space:][:punct:]PeniKe*~$"
+ "g\?${>[:lowerprint:]w))))))))))))))){}yyyyyyyyyyyyyyyyyy]pP."
+ "|QhZ]{,190})sssssssssssssr+=[:blankcntrl:]"
+ "WWWWWWWWWWWWWWWWWWWWW",
+ 1, 0 },
+ { "([*(\?{})hhhhhhhhhhhhhhhh]G{,-170}QdErrrrrrrc-"
+ "jjjjjjjjjjjjjjjjjjjjn+{-130,-10})PpDS@Bee",
+ 1, 0 },
+ { "([:b(\?=lankcntrl:]))T[:alnum:]{-224}ywt", 1, 0 },
+ { "([633(\?<=333(\?<=3333333333(333333)^\?]aGA)[:digi(\?>(\?{t:"
+ "])$[[:space:][:xdigit:])|8T\?',_{171}{}{113}b\?5kAv0/"
+ "7{})`huh>xM]C8pYRz]s$Eu08)",
+ 1, 0 },
+ { "-(pP)[:alnum:]$^", 1, 0 },
+ { "[^x(\?{{17681}]P*)U(_t/8E_\"iN})3333333", 1, 0 },
+ { "(([^([[r(\?=[[^^*kx$][:alpha:]:::[:::::[^[^::::::::((\?{\?{:"
+ ":]).^p[:space:]}){52}{}]W{}fn",
+ 2, 0 },
+ { "[:(\?>punct:]Ef[:xdigit:]x{c07b}{-50}Z{129,}YL1T`\\A)x[:"
+ "punc(\?=t:]e[:xdigit:]2c6E46Y)+n ",
+ 0, 0 },
+ { "[^(\?!{,-79}[:punct:]'|}>,)][:blankcntrl:]{-118,-231}{-119,-"
+ "50}:XXXXXXXXXXXXXXXXX-~{}$txlB)3KFL",
+ 0, 0 },
+ { "[^(([^fccccccccccccccccccc(\?<!ccccgQeKMfKzz]X$$$$$$$$$$$$$$"
+ "$$$$$$$$$$$$$$$$$[:l(\?<=(\?<=owerprint:]))s{-97}{}))EUi${,-"
+ "132}'{79}---------{,-93}77777777777777777[:lowerprint:].:H)["
+ ":punct:]nnnnnncP\?s1:dGed{186}N@pppppppppppppppppppppP{-212,"
+ "-110}[:space:][:lowerprint:]$S}7{-112,164}-*.{-184,}"
+ "OOOOOOOOOO]f\?",
+ 0, 0 },
+ { "(([\?#(\?>)])qcU$Q7|82\?{})", 2, 0 },
+ { "[^yyyyyyyyyyyyyyyyyyyy(\?#yyyyyyyyyyya][:ascii:]\?)", 0, 0 },
+ { "(([((\?{)EEEE(\?<!EEEEE(\?:EEEEEE~)}){244,}"
+ "QQQQQQQQQQQQQQQQQQQ(\?>QQQQQQ(\?!QQQQQ][:digit:]\?))"
+ "99999999999999)[:digit:][:upperword:]b))PP{}{}",
+ 2, 0 },
+ { "(K(c=B))", 2, 0 },
+ { "(G`*s\?b[:g(raph:]))", 1, 0 },
+ { "[^[([[[*QQQQQQQQQQQQQQQQ(\?=(\?=QQQQQQ(\?<!"
+ "QQQQQQQQZddddddddd((\?{\?>ddddddddddc{22,}iiiiiiiii("
+ "iiiiiiiiiiiiiii(\?#iiiiiii[^i))\?\?\?\?\?\?]WWW)[:"
+ "lowerprint:])]{-60,202}+[:upperword:]f[:xdigit:][:alnum:]{,-"
+ "214})1~~~~~~~MMMMMMMMMMMMMMMMMM.",
+ 0, 0 },
+ { "({-102,})A.", 1, 0 },
+ { "[((((\?<!(\?[^>(\?#\?()))p\"JD.{}(\?>)))((\?{l(\?<=).'053][:"
+ "xdigit:]N+)})]WWWW%[:asc(\?{ii:]}))B[:alnum:]X){}s[:digit:]",
+ 0, 0 },
+ { "x7&{139}WWWWWWWWWWWWWW[:blankcntr[^(\?<!l:]-71]\"{-167}cqkI)"
+ "[:dig[^it:]{}{}[:digit:]*[:punct:]-[l11111111111111111(\?("
+ "111111111{175,-216}~[:alnum:]`+X1F)vCpWSp(\?>~[^n@f`````````"
+ "````)````````P])Y,N{}{}]{}pXF@)",
+ 0, 0 },
+ { "G[([(\?(^)$])P]^[:alnum:]){,-48}[:blankcntrl:]{}", 0, 0 },
+ { "[[^[^f(\?=f(\?<=fffffff[^fffffffff[^fffffffff(\?<=fff]){-"
+ "194,150}fx{e5a4}V",
+ 0, 0 },
+ { "9[:xdigit(\?{:]})", 0, 0 },
+ { "[^([[(\?>()$xxxxxxxxxxxxxx[xxxxxxxxxxxxxxxx((\?=aA)s13]])pp["
+ "(\?>pppppppppppppppp|{}){20,}]b)]{-179,183}{-204,}[:ascii:])"
+ "]-11111111{}{,132}qooooooooooooooooooo{}${}|9t",
+ 0, 0 },
+ { "([^[{}]\"[^6]*-{,-106}{}u]BR~8WG,U-)[:blankcntrl:]", 1, 0 },
+ { "[''''''''(''''''''''z])c", 0, 0 },
+ { "[^[(\?>])[:alnum:]r[:alnum:]+{,215}D]", 0, 0 },
+ { "([({,127}7Qr(\?:z)pPNev%}(\?msximsx:4(\?<!){}&.D5555(\?<="
+ "55555555555555555555i$[:xdigit:]){,-157}[:graph:]U[:punct:]"
+ "nn(\?=nnnnnnnnnnnn(\?>nn(\?:nnnnnnnn_U{}]E)):^"
+ "oooooooooooooooooooooooooooo)",
+ 1, 0 },
+ { "[^(\?#)(\?<!k2z]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]BW[:alnum:][:"
+ "graph:]{157}Y]s$C)[:graph:]{,-189}",
+ 0, 0 },
+ { "$+CCCCCCCCC[^CCCCCC(\?<=Ca=]r{-81}[:alpha:][:alpha:])E=", -1,
+ 0 },
+ { "[(((\?=\?{([^(\?<=)])>!(([:alnum:]{252}{}})ffffffffffffl){}"
+ "A2r\?~ImE\"[:punct:]){}[:digit:]",
+ 2, 0 },
+ { "([:blank[cntrl:]].t^P)", 1, 0 },
+ { "[^[(\?:X])|rrrrrrrrrrrrrrrrrrrrrrrrrr*P]Q", 0, 0 },
+ { "[[[^(\?{((\?<!))s})(\?<!A){14}(\?:L*+TTTTTTT]U{[^-12([\?!,}"
+ "\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?)Y`Y)L]|]]|"
+ "]",
+ 0, 0 },
+ { "hkXzf',]yP$+[:u(pperword:])", -1, 0 },
+ { "(#[:blankcnt(\?iximsx:rl:])$QQQQQQ{}[:digit:])\?A", 1, 0 },
+ { "(B{-34,})*{,106}", 1, 0 },
+ { "[(\?{:graph:]})", 0, 0 },
+ { "((){}{,63}[:punct:]^t[:space:])^17737", 2, 0 },
+ { "([^[SSSSSSSSS[SSSSSSSSSSSSSSS[([[[{38,}]Jn][:alpha:]])])$'",
+ 1, 0 },
+ { "[^({}{95})B{1(\?>15}]x{f779}ZZ,Wo)O[:alpha:][:lowerprint:]{"
+ "81,228}Q[:upperword:]",
+ 0, 0 },
+ { "[[^[^()n[[[[[[[[[[[[^[[[[[[[[[[(\?: G)(\?{K![^m) "
+ "j(\?:C|((\?:n*Xlaa908:n$m,))[:xdigit:]x(\?{{1a5cd}"
+ "pppppppppppppp(\?(pppp)p(pQ)))"
+ "ddddddddddddddddddddddddddddddd]q[:alnum:(\?{]Ga})\?})@[:"
+ "lowerprint:]{,169}[:blankcntrl:][:graph:]]n{-76,}|U\"{,-54}"
+ "t]I{}{-64,-232}]\?].\?{-111,227}) "
+ "@hFp\?j=H$Wbu<{,209}De{,145}{206}-})[:blankcntrl:]",
+ 0, 0 },
+ { "[^[^(LLLLLLLLLLLLLL[^L[L[:alpha:]3{,189}(\?#(\?>n){}^"
+ "EXXXXXXXXXXXXXXXXXXXXXXXXX]c*)^r=$WWWWWWWWWWWWW",
+ 0, 0 },
+ { ")w###################", 0, 0 },
+ { "{,121}[:d(\?(i)git:])E\?[:punct:]LLLLLLLLL[:ascii:]+", 0,
+ 0 },
+ { "([]]]]]]]]]]]]][:space:]Jrt3o.]b)pwwwwwwwwwwwQfm~", 1, 0 },
+ { "[+-{,-120}*(\?!()t*(\?(\?{>G)F)yd]V{}f<\?}){245}"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[:upperword:]",
+ 0, 0 },
+ { "(DDDDDDDDDDDDDDDDDDDDDDDDDDDDDc[:space:][:pu[^nct:]{-11,12}["
+ ":ascii:][:alpha:]{,155}P])",
+ 1, 0 },
+ { "()ggggggg{-136,-21}", 1, 0 },
+ { "([^((\?<=U\?)(\?=^^^^^^^^^^^[^^^^^^^^^^^^^///(\?#//[////////"
+ "////////////"
+ "(\?()#######b+]$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$^[:digit:])"
+ "\\U]Q8@}4d)\\U",
+ 1, 0 },
+ { "A[:graph(\?::])-mo=U[:upperword:]"
+ "ttttttttttttttttttttttttttt",
+ 0, 0 },
+ { "[^(((\?=\?im-m(sx:)c~~[^~~~~~~~~~~~~~(\?>~~~~~~~~~~~~~"
+ "SSSSSSSSSSSSSSSSSSSS]{51,}[:digit:]{,-179}N))kk["
+ "kkkkkkkkkkkkkkg$)[(\?::punct:]zWl)]|)*",
+ 0, 0 },
+ { "[((\?=()+A)][:graph:]x0B)[:graph:]", 0, 0 },
+ { "(nR%B[:blankcntrl:]C=|en-[:digit:]n[:graph:]HHHH[HH]D\?%[:"
+ "digit:]MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM.z(oF9zW8A7cfff(f))-["
+ ":blankcntrl:][:blankcntrl:]A[:digit:])D{,-243}",
+ 3, 0 },
+ { "([[()]]{,-251(})\?L)uw@", 2, 0 },
+ { "\"|{(,-144})A.ooooooooo(ooooooFFFFFFFFFFFFF\?)n{,-18}", 2,
+ 0 },
+ { "([^([(([[^([000000[0(0(\?!0(\?=0000000])45|E]", 1, 0 },
+ { "[B[[[[[[[[[[[|{}*oKqv%(\?<=wsQ{1pMeK1^6%nLNqi<@ge][:punct:]="
+ " M@* "
+ "D|NwL\\-"
+ "117\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"~"
+ "Qnd]h.O\"01x:[:alpha:]^){}D}\"",
+ 0, 0 },
+ { "([[RRRRRRRRRRRRRRRRRRRRRRRRRRRRxpSrx{7d79}*oJ2`Ft{n1,3g:1H@"
+ "bT$D "
+ "&[n/"
+ "Cg)=ld@Ir{Fk>*4*`(\?>````````````````````(\?:`````.........."
+ "...........]]{,246})7 \"F4[^F|/g)]+e`rw@{,-69}H)",
+ 1, 0 },
+ { "([(\?<=)X[:digit:]PP.[(\?#:((\?#\?#graph:])[:digit:][Q+)(N]["
+ ":alpha:]]f)[:graph:])+Elllllllllllllllll[:digit:]=)pP{uU-"
+ "20bzY|ZKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKt<c",
+ 1, 0 },
+ { "[^(([^$(\?:(\?#w)[(\?::punct:]]d{-149,}[:ascii:])[:"
+ "blankcntrl:]@@@@@[@@@@@@@@@@@@@@[:graph:][:xdigit:]O[:alpha:"
+ "]2$-[:graph:])[:lowerprint:]-\?#S[:blankcntrl:][:alnum:]){-"
+ "77,}]d[:digit:]N5v+Sqqqqqqq^% "
+ "-I4]*.)^[:alnum:]"
+ "JDfjMRU7ttttttttttttjjjjjjjjjjjjjjjjjjjjjjCCCCCCCCCCCCCCCCCC"
+ "CD{,21}{0,67}[:graph:]{,208}B",
+ -1, 0 },
+ { "(%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%[:ascii:])i{}[:lowerprint:]"
+ "epxxxxxxxxxxxxxx[:lowerprint:]r-",
+ 1, 0 },
+ { "([(^w(\?!)()])-s", 1, 0 },
+ { "[aIIIIIIIIIIIII(\?imsxims(\?=x:IIIIIIIm^NXXXXX(\?!("
+ "\?isximsx:XXXXXXXXXXXXXS0]F)z))+"
+ "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr{,-237})"
+ "ZZZZZZZZZZZZZZZZZZZZZZ",
+ 0, 0 },
+ { "(Z)[:alpha:]", 1, 0 },
+ { "U#Z(=)", 1, 0 },
+ { "([:lowerprint:][:punct:])1cVb*[:xdigit:]&&&&&&&&&&&&&&&&&&&&"
+ "&&&&O",
+ 1, 0 },
+ { "()~K`3/[^*h[]G6[:upperw(\?()ord:]w)[:punct:]]{}", 1, 0 },
+ { "[[[]V[:digit(\?>:])|l*KKKKKKKKKKKKKKKKK,,,,,,,[,,,s.{148,}"
+ "P33333][:lo(\?<!werprin(\?!t:]ZZZZZZZZZZZZZZZZZZZZZZZ]{,-"
+ "229}{-160,}){,-211}XPPP].{}z[:alnum:][:alpha:(\?=]t{166,}"
+ "uuuuu6]i*p(m))[:space:]E|S",
+ 1, 0 },
+ { "[^(h(\?(\?({#2})(\?(\?#>Q){,57}%[:digit:]"
+ "\?\?\?\?\?\?\?\?\?\?.[)]]d{)-49,}f)^O{,68})\?C",
+ 0, 0 },
+ { "(}u])18621", 1, 0 },
+ { "[:as(\?=cii:][^(\?=)(S-{.F-[:punct:]3-105^[:lowerprint:]"
+ "111111111111111111111111---)][:alnum:][:ascii:]JJJJJwHSk",
+ -1, 0 },
+ { "[^3>>>>>>-sZ^^^^(\?>]Y[:di(\?(\?imxim:#git:]{-158,-102}[:"
+ "punct:]{}{87,})))[:upperword:]",
+ 0, 0 },
+ { "[(\?<!^r]$W){}*[:alpha:].[:digit:]", 0, 0 },
+ { "[:ascii(\?::[^])X]-", 0, 0 },
+ { "[([^]Z)[:upperword:]N{}*[:graph:]*^", 0, 0 },
+ { "([[(\?#^[(:graph:]]){205,}[:gr(aph:]T%]^"
+ "MMMMMMMMMMMMMMMMMMMM){) <v\\[:digit:])",
+ 1, 0 },
+ { "[^Y.h~b(\?<=~P{(\?=169,65}\?[^\?\?\?\?\?\?\?\?\?["
+ "\?\?\?\?\?\?\?\?\?K\"s`[yT7oP[:alpha:]{})]zrrrrrrrrrrrrrr)]"
+ "KKKKKKKKKKKKKKK[:digit:]S][:lowerprint:][:digit:]",
+ 0, 0 },
+ { "(s)", 1, 0 },
+ { "[u(\?!uuuuuuuuuuuuuuuuuuuu[:digit:]{,48}[:graph:]WL[:alnum:]"
+ "]v=_)VN>{AjBBBBBBBBBBBBBBBBBBBBBBB[:upperword:]`'W)",
+ 0, 0 },
+ { "[^([[()DN1[^][|]\?]{-104,}])[:space:]][:lowerprint:]r[:"
+ "alpha:].DU",
+ 0, 0 },
+ { "[^((33333333333333333333333(\?<=3333333D))"
+ "kkkkkkkkkkkkkkkkkkkkkkk[k[:alpha:]])]X+",
+ 0, 0 },
+ { "[({,-17})[@e{220,(\?#41}])]]{-213,-225}", 0, 0 },
+ { "[[^(\?#[(\?:^[[(\?(^]))]])]vvvvvvvvvvvvvvvvvvvvv{,96}|m]{-"
+ "79,248}[:alpha:])",
+ 0, 0 },
+ { "([[(\?imsisx:^}$,-[:al(\?>num:]Xqqqqqqqqqqqq{-185,154}]b#+T)"
+ "{-241,})A{-27}[(\?<!:lowerprint:]X)[:punct:]ME-]+"
+ "BBBBBBBBBBBBBBBBa|{-40}M8mhgD 0HU]{16})",
+ -1, 0 },
+ { "[^(\?>([\?()(\?#))]--R1rk^UnP.[(\?!:digit:]])^)[:upperword:]"
+ "{}0000000000000000000000000000000~U{-139,-19}z<L-228",
+ 0, 0 },
+ { "()-:=3uE$[:alnum:]bP%{-210,}", 1, 0 },
+ { "(U)7777]]]]]]]]]]]]]]]]]]]]]]]]]]]]]c::AA[:alpha:]{,3}f1{"
+ "NzH@3lTf{}{",
+ 1, 0 },
+ { "[C{(\?>})RR(\?=R<]p'N~&.-})6]", 0, 0 },
+ { "[^\?[^(\?(lFt]).[^7Q-])kkkkkkkkkkkk]XTFy\"1Deiv!,'xVK", 0,
+ 0 },
+ { "[^$[^[:xdigit:](\?{*{245,99}h8v(\?!)]]u)Z[:punct:]})[:alnum:"
+ "]+|[:blankcntrl:]u{}[:lowerprint:]+bBJ4+k-v{-116}",
+ 0, 0 },
+ { "S)f{,180}[:graph:]&{12,244}", 0, 0 },
+ { "(([[(.()[^^{80(\?>(\?<=,235})ddddddddd[^ddddddddd(\?<=d.__B{"
+ "36}````````````````(\?:```(\?>```````,,,,,,,(\?:,,)P$U,[:"
+ "xdigit:])zzzzzzzzzzzzz]UUUU[uB]n<&[(:ascii:].][:alnum:])\?S]"
+ "{})d{138,}s9========[:lowerprint:]]OOOOOOOOOOOOOOO|"
+ "yyyyyyyyyyyyyyy$LZ[:lowerprint:]EEEEEEE[:ascii:][:punct:]"
+ "VpP^{-48}D){,46}x))2P))a[:lowerprint:]r",
+ 2, 0 },
+ { "[^(((\?<!):())PPPPPPPPPPPPPPP(\?=[PPPPPPP(\?{PPPPPPPP$)})"
+ "77777777777777777]{,-57}::::::::::::(::::::::::::::::)]g{89}"
+ "__________________[:xdigit:]l[:punct:])N",
+ 1, 0 },
+ { ":02-k\?p3I7aEhJ\\265-[:space:]pP[:space:]x0F[:alnum:]aM4[:"
+ "lowerprint:]sA@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
+ -1, 1 },
+ { "a[:upper(\?{word:]})X{-173,}-2F[:lowerprint:]", 0, 0 },
+ { "u,w<g*Q002S{,130}{239}[:lower(print:]cr{-165,}#$k<L/"
+ "&)[:blankcntrl:]aaaaaaaaaaaaaaaaaaaaaa[:ascii:]",
+ 0, 0 },
+ { "(xFA^{-161,93})U[:xdigit:]", 1, 0 },
+ { "[^(\?=]{})mE`", 0, 0 },
+ { "[[((\?(\?#:alnum:]])x6CS[:digit:]{-197,}.)N", 0, 0 },
+ { "[^(\?![])C*[:upp(erword:])-176]", 0, 0 },
+ { "[[^[[^[55555555555555555555555555(\?>555(\?<!555)S][]]A[:l("
+ "\?>owerp(rint:]])]*",
+ 0, 0 },
+ { "Au)khgzAfXIZoZ=g[:digit:]){,186}Upvf=x<]Tbd5Rq\?.", 0, 0 },
+ { "b{-176,}B^[:bla(\?(<!nkcntrl:]{-6,133}#B "
+ ":)<<<<<<<<<<<<<<<<<<<)[:alnum:]$}}}}}}}}}}}}}}}}}}}}}}}[:"
+ "xdigit:]tw",
+ 0, 0 },
+ { "(4IIIII(IIIIIIIIIIIIIIIII{})W{-152,-238}){,-56}^{-142,}", 2,
+ 0 },
+ { "[^([[(\?(\?(!)>>>>>>>>>>>>>(>>>>>>>>D)Ix{(1(\?imxmsx:762)c})"
+ ")A)[[[[[[[[[[[[[[5Rp]DDDDDDDDDDDDDDDDDDDD]Us+\\w[:digit:]{-"
+ "47}[:xdigit:][:blankcntrl:])ddddddddddddddd[^ddddddddddddd[:"
+ "digit:]|]]*{-165,-230}{-212}{53,}]\?",
+ 0, 0 },
+ { "[^[^]]|[:(\?:alnum:])}}}}}}}}}}}}}}}}}}}}", 0, 0 },
+ { "VVVVVVVVVVVVVVVVVVVVVVVVVVVV[:d(i(\?#git:])){{{{{{[:digit:]"
+ "ZfQ55555555{}Z",
+ 0, 0 },
+ { "[L][:blankcnt(\?((\?=rl:(\?=]){-35,[^}){)eJb>>>>>>>>>>>>>>>>"
+ ">>>>>>$ [:xdigit:]l0Tv2Tw2@C[:space:]Zc/{*)>]N3j~.dMBBBB",
+ 0, 0 },
+ { "[[^(\?>(([]))])[:graph:]]{65,}as#Q:lQ", 0, 0 },
+ { "[^[fPPUUUUUUUUUUU(\?#UUU[^UUUUUU(\?<="
+ "UUUUUUUUUGGGGGGGGGGGGGGGGGGG((\?{\?=GGGGGG.MK))+]+)&UxFW)"
+ "rwv\?@D.",
+ 0, 0 },
+ { "{-(60,})m", 1, 0 },
+ { "b[(])^w", 0, 0 },
+ { "[][^qVs(\?:(p])X)\?'", 0, 0 },
+ { "()8", 1, 0 },
+ { "(t[:punc[^t:(\?{][:blankcntrl:])})[^8\?]z*]", 1, 0 },
+ { "[:lowerprint:])[:graph:]lppppppppppppppppppppppppppppf", 0,
+ 0 },
+ { "[:alph(a:])[:ascii:]g +z-Bc-U{,%Gk", 0, 0 },
+ { "u[:graph:(\?=]*)W:::", 0, 0 },
+ { "([:alnum(:])l)", 1, 0 },
+ { "[[[}}}}}}}}(\?<!}}}}}}}+(\?{),,,,,,,,,,,,,,(\?!,,,,,,,,]"
+ "99999999999&R[:ascii:]ZZZZ-{-10,}{96}Ed*][:graph:])]}){}{}G{"
+ "-9,}",
+ 0, 0 },
+ { "([^[{}]]Z[[^:graph:]{-47}55555555555555555555555555555[:"
+ "ascii:]s]6,$:3qAew1Y)+)[:punct:]",
+ 1, 0 },
+ { "[[[[[([[[[[[[[[[[[[[[[[[[[[[[[8!1i]')", 0, 0 },
+ { "([((\?(\?#>)(\?{,)At]%M9FSq5)EB", 1, 0 },
+ { "(}````````````````(``{210,})[:(\?#space:]P[:digit:])PP.{-"
+ "227,}$pK~mm ImR|{,51}[:alnum:]<)[:alpha:]",
+ 2, 0 },
+ { "[^(\?<=])[:digit:]", 0, 0 },
+ { "[^'''''''{(\?:178,}e{,16}$QQQQQQQQQQQQQQQQQQQQQQQ$])", 0,
+ 0 },
+ { "[^(\?>@K*)(\?#d18]{78,}B)[:digit:]{-193,}=wg{,59}", 0, 0 },
+ { "[^.{156,}!(\?<=!!!!!!!!!!!!!!(\?{!(\?(!!!!!!!!!!!!!)})"
+ "TTTTTTTTTTTTTTTTTTTTTTTTTTTTT[^}}}}}}}}}}}})}}}}}}}}}}}}}]])"
+ "{}^L#%-{}FC",
+ 0, 0 },
+ { "(eeeee{-169,-100}-fa[:upperword:]N)$Nellllllllllllll", 1,
+ 0 },
+ { "[[(\?!())\?[(\?!:alnum:]e{,28}M])[:punct:]"
+ "CCCCCCCCCCCCCCCCCCCC]{-150,}{-167}",
+ 0, 0 },
+ { "[[@[@(\?#@[@]P]Z{')]{-186,117}]+)7f-", 0, 0 },
+ { "\\Q+kD}]AEM)u ", 0, 0 },
+ { "([(\?{(\?=:::::::::::::&){,210}]^})P{-31,}8[:space:]C[:"
+ "alnum:][:a(scii:]z|[:upperword:])[:alnum:][:graph:])zr~Zk",
+ 1, 0 },
+ { ".[:space:]e[:g(\?{(\?{raph:]})})@@@@@@@@@@@@@wb|~k", 0, 0 },
+ { "()ooooooooo\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"[:graph:]", 1,
+ 0 },
+ { "[^64h(\?(@Eyw][:xdi[git:]pP%%%%%u(uuu[:up[perword:]`8Utdh{)}"
+ "]]))lW[:punct:]W.hhhhhhhhhhhhhhhhhhhhhhhh'm<<}O8`ZXtG.$",
+ 1, 0 },
+ { "BPP[:digit:]bbbbbbbbbbb(bb)S+[:alnum:]", 1, 0 },
+ { "um.[:ascii((\?#\?!:])*)+KKKKKKKKKKKKKKKKKKKKKKKKKS.=<Bf", 0,
+ 0 },
+ { "", -1, 0 },
+ { "(()$[:lowerprint:][:s[pace:]2]bbbbbbbbbyoooooooooooooooooo*{"
+ "39,}$')qV`AcH>,eDl",
+ -1, 0 },
+ { "(()[^])e{-241,}", -1, 0 },
+ { "()[:alpha:]rliiiiiiii[:alnum:]Mb*QW9N.>\?{115,}&u*j", -1,
+ 0 },
+ { "()[]p", -1, 0 },
+ { "(I[^]pfL)$[:punct:]", -1, 0 },
+ { "([])>>>>>>>>>>[:alnum:]", -1, 0 },
+ { "([])O\\\\\\\\\\\\\\fffffffffffffffffffffff=s6jCZy/"
+ "b+ir2'*{151,}",
+ -1, 0 },
+ { "([])nnnnnnnnnnnnnnnnnnnnnnnnnn[:xdigit:]^N$f", -1, 0 },
+ { "([]M)[:lowerprint:]a(pg$Z[:punct:])77777777777.", -1, 0 },
+ { "([]XXXXXXXXXXXXXXXXXXXXXX-===========)", -1, 0 },
+ { "([]lkX{-224}[:blankcntrl:]$gPKIZlSC#F@XX "
+ "I'^}{234}yZm)uuuuuuuuuuuuuuuuuuuuuurS",
+ -1, 0 },
+ { "([^0kYkg9])IIIIIIIIIIIIIIIIIIIIII/"
+ "{(192,-118}l+FoSD6\?A)c[:xdigit:]`````````````````e-{-4,-"
+ "170}x{4620}Z[:upperword:]",
+ -1, 0 },
+ { "([^[^[^()(\?>){}B]XYF+#[:alpha:]{-85((,-55[^}t]n).{,-33}]]("
+ "bQJ!|O+{175,})RFh)Z+^.{137,}:VpP[:alpha:]-MceqVVkkkk("
+ "kkkkkkkkkkkkkkkkkk)"
+ "\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?{-"
+ "115,-67})``````````````````````````````",
+ -1, 0 },
+ { "([^]EzU[:alnum:]+^^^^^^^^^^^^^^^^^^^)[:xdigit:]HHHHHHHH$"
+ "66666666666666666666666666666666UUUUUUUUUUUUUUUUUUUUL{}iiii{"
+ "-76}X",
+ -1, 0 },
+ { "([^]~~~~~~~~~~{240,})]NOp", -1, 0 },
+ { "(sb)[:digit:]VVVVVVVVx{9569}52,|]", -1, 0 },
+ { "(x{19762}){}", -1, 0 },
+ { "-[:xdigit:][]", -1, 0 },
+ { "121|", -1, 0 },
+ { "141[:xdigit:][:lowerprint:]{24}{59,191}[:digit:]/", -1, 0 },
+ { "G[^],,,,,,,,,,,,,+\"DiX", -1, 0 },
+ { "Gm(ho9:\"8{-188,-200}Z[:blankcntrl:]{,171}"
+ "\?\?\?\?\?\?\?\?\?\?\?[:blankcntrl:]LLLLLLLLLLLLLLLLLLLLLLL{"
+ "}^[:graph:][:blankc(\?#ntrl:])w",
+ -1, 0 },
+ { "N\"\"\"\"\"\"\"-------------------------|[:alnum:]"
+ "AAAAAAAAAAAAAAAAAAAAf\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?",
+ -1, 0 },
+ { "U{-30,}^\?\?\?", -1, 0 },
+ { "W^*04rAY(Ee*>[^o3[]]_)", -1, 0 },
+ { "X[^]}*C[:alnum:]", -1, 0 },
+ { "[${,-3}]+^\?[|x8A|][:space:]'''''['''''"
+ "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJyl}.Y7G]",
+ -1, 0 },
+ { "[()&[&&&]\?\?["
+ "\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?"
+ "pg%k8ug`Wqk4|NR{h[CK5Ez=]jHpQw&`{:]{,91}D",
+ -1, 0 },
+ { "[(\?#(\?:)[)([\?>)(\?>(\?:[:alnum:])]G]{85}[^)w]N]gYrUs|",
+ -1, 0 },
+ { "[(\?<=)[:digit:]\?]{152,}VR|", -1, 0 },
+ { "[****(\?>**********(\?<!*******Q)Vr){[^25,}*:"
+ "FFFFFFFFFFFFFFFFFFFFFFFF(\?{FFFF(({}D]|",
+ -1, 0 },
+ { "[:ascii:]+{124,}:*]\?$-{92}D[:lowerprint:]``````````````````"
+ "```",
+ -1, 0 },
+ { "[:ascii:]\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?A<", -1, 0 },
+ { "[:blankcntrl:]p\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?$"
+ "\?TTTTTTTTTTTTTTTTT[:ascii:][:upperword:]",
+ -1, 0 },
+ { "[:punct:]{254}DDDDDDDDDDDDDDD@[:alpha:]Z\?\?-----R", -1, 0 },
+ { "[:upperword:]J\?\?nqCAdfyW5", -1, 0 },
+ { "[:upperword:]{-39}|", -1, 0 },
+ { "[:xdigit:]^\?", -1, 0 },
+ { "[Z*e ]NdmP\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?", -1, 0 },
+ { "[[:punct:]q]ex{15625}-", -1, 0 },
+ { "[[[^([^L((\?{b(\?=C\?]-134{,-207}[:ascii:]Hz}XIz}|", -1, 0 },
+ { "[[^V(\?:(\?<!(\?>))TTTTTTTTTTTTTTTTTTTTTTT)[:punct:][:digit:"
+ "]]GGGGGGGGGGGGGGGGGGGGG,]|.{-224}{96}{239,}1",
+ -1, 0 },
+ { "[[^^PP]{,-222}{182}{141}]zFD}-.", -1, 0 },
+ { "[] Hn&[:xdigit:][:upperword:]f", -1, 0 },
+ { "[]$.B", -1, 0 },
+ { "[]&&&&&&&&&&&&&&&&&&&&&&&", -1, 0 },
+ { "[]()[:xdigit:]er063{132,140}$", -1, 0 },
+ { "[]+1434", -1, 0 },
+ { "[]-", -1, 0 },
+ { "[]-#yyK", -1, 0 },
+ { "[]-(S$5)AxbdTKO[:alnum:]", -1, 0 },
+ { "[]2883", -1, 0 },
+ { "[]2dhd-[:alpha:]"
+ "sssssssssssssssss55555555555555555555555555555555Z[:punct:]",
+ -1, 0 },
+ { "[]4", -1, 0 },
+ { "[]44444444444444444G", -1, 0 },
+ { "[]\?", -1, 0 },
+ { "[]A", -1, 0 },
+ { "[]Gap8bc", -1, 0 },
+ { "[]OOOO", -1, 0 },
+ { "[]PP", -1, 0 },
+ { "[]QQ", -1, 0 },
+ { "[]WaFaGO,o", -1, 0 },
+ { "[]Z", -1, 0 },
+ { "[][:alpha:]|[:digit:]Ls$I-Ff~+xA3e", -1, 0 },
+ { "[][:ascii:]-218", -1, 0 },
+ { "[][:ascii:]N}}}}}}}}}}}}}}}-{137,}8682", -1, 0 },
+ { "[][:lowerprint:]Ur", -1, 0 },
+ { "[][:space:]15097", -1, 0 },
+ { "[][:xdigit:]", -1, 0 },
+ { "[]dpSSSSSSSS", -1, 0 },
+ { "[]e13768", -1, 0 },
+ { "[]gT", -1, 0 },
+ { "[]h", -1, 0 },
+ { "[]n", -1, 0 },
+ { "[]vvvvvvvvvvvvvvvvvvvvvvvvvv*[:xdigit:]", -1, 0 },
+ { "[]{,-212}1111111111111111111C3821", -1, 0 },
+ { "[]{-128,}hc", -1, 0 },
+ { "[]{-181,}&[:xdigit:].\?}}}}}}}}}}}}}}}}}}}}}}", -1, 0 },
+ { "[]{}F&}i`7|ZAH", -1, 0 },
+ { "[^(\?())u{196,}pP][r^ndddddddddddddddddddddd]{31,246}\?J",
+ -1, 0 },
+ { "[^.ii.1-S]lwwwwwwwwwwwwwwwwww[^wwwwwwwwwwwwww[:alnum:]DOpP+<"
+ "N][^]44{179}{-194,56}",
+ -1, 0 },
+ { "[^2[:alnum:]]\?t\?\?", -1, 0 },
+ { "[^[((\?{[^^<<<<(\?(\?<!{)})(\?<!]{,184}{-213}|", -1, 0 },
+ { "[^[^[]\?{89,}PPsvf{[:space:]]]vd{161,}", -1, 0 },
+ { "[^[^].]+{0}s", -1, 0 },
+ { "[^]${}", -1, 0 },
+ { "[^]([:punct:]),%[:xdigit:]w^0\?{-233}", -1, 0 },
+ { "[^]-", -1, 0 },
+ { "[^].^", -1, 0 },
+ { "[^]6743", -1, 0 },
+ { "[^]JD", -1, 0 },
+ { "[^]N=[:upperword:]zzzzzzzzzzzzzzzzz.", -1, 0 },
+ { "[^]OLz_6", -1, 0 },
+ { "[^]PP[:digit:]0eBEx=", -1, 0 },
+ { "[^]SHzuKp", -1, 0 },
+ { "[^][:upperword:]{111}-TpmXw", -1, 0 },
+ { "[^]^''''''''z{-73,}", -1, 0 },
+ { "[^]^{,141}e", -1, 0 },
+ { "[^]aaaaaaaaaaaaaaaaaaa{-98,43}", -1, 0 },
+ { "[^]f", -1, 0 },
+ { "[^]l", -1, 0 },
+ { "[^]n\"Wt", -1, 0 },
+ { "[^]pPZ\?q+m0LJ+", -1, 0 },
+ { "[^]p[:upperword:]L:", -1, 0 },
+ { "[^]q\?{,-18}-", -1, 0 },
+ { "[^]s[:space:(\?<=]$", -1, 0 },
+ { "[^]{,58}t", -1, 0 },
+ { "[^]{255,}JJJJJJJJJJJJJJJJJJJJJJJJJJ", -1, 0 },
+ { "[^]{45}", -1, 0 },
+ { "[^]{W", -1, 0 },
+ { "[^]{}{-22}", -1, 0 },
+ { "[^]{}{}{}[:xdigit:]+", -1, 0 },
+ { "[^]|9{,-108}{}.LVIJJJJJJJJJJJJJJJPP", -1, 0 },
+ { "[^{,-254}]|", -1, 0 },
+ { "[o(\?{(\?<=}[))f++++++++++++++++"
+ "777777777777777777777777yzPPs]"
+ "\?\?dRRRRRRRRRRRRRRRRRRRRRRRRRRRR&]>%fffffffffff",
+ -1, 0 },
+ { "aW|", -1, 0 },
+ { "cT{}[]C^r2``tm", -1, 0 },
+ { "kkkkkkkkkkkkkkkkkkkkkkk[:blankcntrl:]|{}3{26,}{151,}[:punct:"
+ "]JJJlH$gP%(2WUE%%%%%%%%%%%%%%%%%%%%a){ibf{}\?",
+ -1, 0 },
+ { "lZ\?\?\?\?\?\?\?\?\?\?\?-P2eZt[:punct:]", -1, 0 },
+ { "vF3qn[^]N.", -1, 0 },
+ { "wwwwwwwwwwwwww{-176,}275[^]>."
+ "UUUUUUUUUUUUUUUUUUUUeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee2$Yd",
+ -1, 0 },
+ { "{-197,223}bf]]]]]]]]]]\?&}/s\?\?~c", -1, 0 },
+ { "{-37,}EpP|", -1, 0 },
+ { "{}@]a[][:xdigit:]z{a", -1, 0 },
+ { "}02|", -1, 0 },
+ { "}}}}}}}}}(}}){}[llll]^N|", -1, 0 },
+ };
+ unsigned int i;
+ int r;
+
+ UNUSED(state);
+
+#ifdef HAVE_REGEX_H
+ /*
+ * Check if we get the expected response.
+ */
+ for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
+ regex_t preg;
+
+ memset(&preg, 0, sizeof(preg));
+ r = regcomp(&preg, tests[i].expression, REG_EXTENDED);
+ if (((r != 0 && tests[i].expect != -1) ||
+ (r == 0 && tests[i].expect == -1)) &&
+ !tests[i].exception)
+ {
+ } else if (r == 0 &&
+ preg.re_nsub != (unsigned int)tests[i].expect &&
+ !tests[i].exception)
+ {
+ tests[i].expect = preg.re_nsub;
+ }
+ if (r == 0) {
+ regfree(&preg);
+ }
+ }
+#endif /* ifdef HAVE_REGEX_H */
+
+ /*
+ * Check if we get the expected response.
+ */
+ for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
+ r = isc_regex_validate(tests[i].expression);
+ if (r != tests[i].expect) {
+ print_error("# %s -> %d expected %d\n",
+ tests[i].expression, r, tests[i].expect);
+ }
+ assert_int_equal(r, tests[i].expect);
+ }
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(regex_validate)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/result_test.c b/tests/isc/result_test.c
new file mode 100644
index 0000000..cec195b
--- /dev/null
+++ b/tests/isc/result_test.c
@@ -0,0 +1,64 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* convert result to identifier string */
+ISC_RUN_TEST_IMPL(isc_result_toid) {
+ const char *id;
+
+ UNUSED(state);
+
+ id = isc_result_toid(ISC_R_SUCCESS);
+ assert_string_equal("ISC_R_SUCCESS", id);
+
+ id = isc_result_toid(ISC_R_FAILURE);
+ assert_string_equal("ISC_R_FAILURE", id);
+}
+
+/* convert result to description string */
+ISC_RUN_TEST_IMPL(isc_result_totext) {
+ const char *str;
+
+ UNUSED(state);
+
+ str = isc_result_totext(ISC_R_SUCCESS);
+ assert_string_equal("success", str);
+
+ str = isc_result_totext(ISC_R_FAILURE);
+ assert_string_equal("failure", str);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_result_toid)
+ISC_TEST_ENTRY(isc_result_totext)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/safe_test.c b/tests/isc/safe_test.c
new file mode 100644
index 0000000..a3f01fe
--- /dev/null
+++ b/tests/isc/safe_test.c
@@ -0,0 +1,92 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/safe.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* test isc_safe_memequal() */
+ISC_RUN_TEST_IMPL(isc_safe_memequal) {
+ UNUSED(state);
+
+ assert_true(isc_safe_memequal("test", "test", 4));
+ assert_true(!isc_safe_memequal("test", "tesc", 4));
+ assert_true(
+ isc_safe_memequal("\x00\x00\x00\x00", "\x00\x00\x00\x00", 4));
+ assert_true(
+ !isc_safe_memequal("\x00\x00\x00\x00", "\x00\x00\x00\x01", 4));
+ assert_true(
+ !isc_safe_memequal("\x00\x00\x00\x02", "\x00\x00\x00\x00", 4));
+}
+
+/* test isc_safe_memwipe() */
+ISC_RUN_TEST_IMPL(isc_safe_memwipe) {
+ UNUSED(state);
+
+ /* These should pass. */
+ isc_safe_memwipe(NULL, 0);
+ isc_safe_memwipe((void *)-1, 0);
+
+ /*
+ * isc_safe_memwipe(ptr, size) should function same as
+ * memset(ptr, 0, size);
+ */
+ {
+ char buf1[4] = { 1, 2, 3, 4 };
+ char buf2[4] = { 1, 2, 3, 4 };
+
+ isc_safe_memwipe(buf1, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+
+ assert_int_equal(memcmp(buf1, buf2, sizeof(buf1)), 0);
+ }
+
+ /*
+ * Boundary test.
+ */
+ {
+ char buf1[4] = { 1, 2, 3, 4 };
+ char buf2[4] = { 1, 2, 3, 4 };
+
+ /*
+ * We wipe 3 elements on purpose, keeping the 4th in
+ * place.
+ */
+ isc_safe_memwipe(buf1, 3);
+ memset(buf2, 0, 3);
+
+ assert_int_equal(memcmp(buf1, buf2, sizeof(buf1)), 0);
+ }
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY(isc_safe_memequal)
+ISC_TEST_ENTRY(isc_safe_memwipe)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/siphash_test.c b/tests/isc/siphash_test.c
new file mode 100644
index 0000000..5e93980
--- /dev/null
+++ b/tests/isc/siphash_test.c
@@ -0,0 +1,170 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <sched.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/siphash.h>
+
+#include "siphash.c"
+
+#include <tests/isc.h>
+
+const uint8_t vectors_sip64[64][8] = {
+ { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72 },
+ { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74 },
+ { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d },
+ { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85 },
+ { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf },
+ { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18 },
+ { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb },
+ { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab },
+ { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93 },
+ { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e },
+ { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a },
+ { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4 },
+ { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75 },
+ { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14 },
+ { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7 },
+ { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1 },
+ { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f },
+ { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69 },
+ { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b },
+ { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb },
+ { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe },
+ { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0 },
+ { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93 },
+ { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8 },
+ { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8 },
+ { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc },
+ { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17 },
+ { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f },
+ { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde },
+ { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6 },
+ { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad },
+ { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32 },
+ { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71 },
+ { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7 },
+ { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12 },
+ { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15 },
+ { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31 },
+ { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02 },
+ { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca },
+ { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a },
+ { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e },
+ { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad },
+ { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18 },
+ { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4 },
+ { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9 },
+ { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9 },
+ { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb },
+ { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0 },
+ { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6 },
+ { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7 },
+ { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee },
+ { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1 },
+ { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a },
+ { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81 },
+ { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f },
+ { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24 },
+ { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7 },
+ { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea },
+ { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60 },
+ { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66 },
+ { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c },
+ { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f },
+ { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5 },
+ { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95 }
+};
+
+const uint8_t vectors_hsip32[64][4] = {
+ { 0xa9, 0x35, 0x9f, 0x5b }, { 0x27, 0x47, 0x5a, 0xb8 },
+ { 0xfa, 0x62, 0xa6, 0x03 }, { 0x8a, 0xfe, 0xe7, 0x04 },
+ { 0x2a, 0x6e, 0x46, 0x89 }, { 0xc5, 0xfa, 0xb6, 0x69 },
+ { 0x58, 0x63, 0xfc, 0x23 }, { 0x8b, 0xcf, 0x63, 0xc5 },
+ { 0xd0, 0xb8, 0x84, 0x8f }, { 0xf8, 0x06, 0xe7, 0x79 },
+ { 0x94, 0xb0, 0x79, 0x34 }, { 0x08, 0x08, 0x30, 0x50 },
+ { 0x57, 0xf0, 0x87, 0x2f }, { 0x77, 0xe6, 0x63, 0xff },
+ { 0xd6, 0xff, 0xf8, 0x7c }, { 0x74, 0xfe, 0x2b, 0x97 },
+ { 0xd9, 0xb5, 0xac, 0x84 }, { 0xc4, 0x74, 0x64, 0x5b },
+ { 0x46, 0x5b, 0x8d, 0x9b }, { 0x7b, 0xef, 0xe3, 0x87 },
+ { 0xe3, 0x4d, 0x10, 0x45 }, { 0x61, 0x3f, 0x62, 0xb3 },
+ { 0x70, 0xf3, 0x67, 0xfe }, { 0xe6, 0xad, 0xb8, 0xbd },
+ { 0x27, 0x40, 0x0c, 0x63 }, { 0x26, 0x78, 0x78, 0x75 },
+ { 0x4f, 0x56, 0x7b, 0x5f }, { 0x3a, 0xb0, 0xe6, 0x69 },
+ { 0xb0, 0x64, 0x40, 0x00 }, { 0xff, 0x67, 0x0f, 0xb4 },
+ { 0x50, 0x9e, 0x33, 0x8b }, { 0x5d, 0x58, 0x9f, 0x1a },
+ { 0xfe, 0xe7, 0x21, 0x12 }, { 0x33, 0x75, 0x32, 0x59 },
+ { 0x6a, 0x43, 0x4f, 0x8c }, { 0xfe, 0x28, 0xb7, 0x29 },
+ { 0xe7, 0x5c, 0xc6, 0xec }, { 0x69, 0x7e, 0x8d, 0x54 },
+ { 0x63, 0x68, 0x8b, 0x0f }, { 0x65, 0x0b, 0x62, 0xb4 },
+ { 0xb6, 0xbc, 0x18, 0x40 }, { 0x5d, 0x07, 0x45, 0x05 },
+ { 0x24, 0x42, 0xfd, 0x2e }, { 0x7b, 0xb7, 0x86, 0x3a },
+ { 0x77, 0x05, 0xd5, 0x48 }, { 0xd7, 0x52, 0x08, 0xb1 },
+ { 0xb6, 0xd4, 0x99, 0xc8 }, { 0x08, 0x92, 0x20, 0x2e },
+ { 0x69, 0xe1, 0x2c, 0xe3 }, { 0x8d, 0xb5, 0x80, 0xe5 },
+ { 0x36, 0x97, 0x64, 0xc6 }, { 0x01, 0x6e, 0x02, 0x04 },
+ { 0x3b, 0x85, 0xf3, 0xd4 }, { 0xfe, 0xdb, 0x66, 0xbe },
+ { 0x1e, 0x69, 0x2a, 0x3a }, { 0xc6, 0x89, 0x84, 0xc0 },
+ { 0xa5, 0xc5, 0xb9, 0x40 }, { 0x9b, 0xe9, 0xe8, 0x8c },
+ { 0x7d, 0xbc, 0x81, 0x40 }, { 0x7c, 0x07, 0x8e, 0xc5 },
+ { 0xd4, 0xe7, 0x6c, 0x73 }, { 0x42, 0x8f, 0xcb, 0xb9 },
+ { 0xbd, 0x83, 0x99, 0x7a }, { 0x59, 0xea, 0x4a, 0x74 }
+};
+
+ISC_RUN_TEST_IMPL(isc_siphash24) {
+ UNUSED(state);
+
+ uint8_t in[64], out[8], key[16];
+ for (size_t i = 0; i < ARRAY_SIZE(key); i++) {
+ key[i] = i;
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(in); i++) {
+ in[i] = i;
+ isc_siphash24(key, in, i, out);
+ assert_memory_equal(out, vectors_sip64[i], 8);
+ }
+}
+
+ISC_RUN_TEST_IMPL(isc_halfsiphash24) {
+ UNUSED(state);
+
+ uint8_t in[64], out[4], key[16];
+ for (size_t i = 0; i < ARRAY_SIZE(key); i++) {
+ key[i] = i;
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(in); i++) {
+ in[i] = i;
+ isc_halfsiphash24(key, in, i, out);
+ assert_memory_equal(out, vectors_hsip32[i], 4);
+ }
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_siphash24)
+ISC_TEST_ENTRY(isc_halfsiphash24)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/sockaddr_test.c b/tests/isc/sockaddr_test.c
new file mode 100644
index 0000000..c65ed76
--- /dev/null
+++ b/tests/isc/sockaddr_test.c
@@ -0,0 +1,149 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/netaddr.h>
+#include <isc/print.h>
+#include <isc/sockaddr.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* test sockaddr hash */
+ISC_RUN_TEST_IMPL(sockaddr_hash) {
+ isc_sockaddr_t addr;
+ struct in_addr in;
+ struct in6_addr in6;
+ unsigned int h1, h2, h3, h4;
+ int ret;
+
+ UNUSED(state);
+
+ in.s_addr = inet_addr("127.0.0.1");
+ isc_sockaddr_fromin(&addr, &in, 1);
+ h1 = isc_sockaddr_hash(&addr, true);
+ h2 = isc_sockaddr_hash(&addr, false);
+ assert_int_not_equal(h1, h2);
+
+ ret = inet_pton(AF_INET6, "::ffff:127.0.0.1", &in6);
+ assert_int_equal(ret, 1);
+ isc_sockaddr_fromin6(&addr, &in6, 1);
+ h3 = isc_sockaddr_hash(&addr, true);
+ h4 = isc_sockaddr_hash(&addr, false);
+ assert_int_equal(h1, h3);
+ assert_int_equal(h2, h4);
+}
+
+/* test isc_sockaddr_isnetzero() */
+ISC_RUN_TEST_IMPL(sockaddr_isnetzero) {
+ isc_sockaddr_t addr;
+ struct in_addr in;
+ struct in6_addr in6;
+ bool r;
+
+ size_t i;
+ struct {
+ const char *string;
+ bool expect;
+ } data4[] = {
+ { "0.0.0.0", true }, { "0.0.0.1", true },
+ { "0.0.1.0", true }, { "0.1.0.0", true },
+ { "1.0.0.0", false }, { "0.0.0.127", true },
+ { "0.0.0.255", true }, { "127.0.0.1", false },
+ { "255.255.255.255", false },
+ };
+ /*
+ * Mapped addresses are currently not netzero.
+ */
+ struct {
+ const char *string;
+ bool expect;
+ } data6[] = {
+ { "::ffff:0.0.0.0", false },
+ { "::ffff:0.0.0.1", false },
+ { "::ffff:0.0.0.127", false },
+ { "::ffff:0.0.0.255", false },
+ { "::ffff:127.0.0.1", false },
+ { "::ffff:255.255.255.255", false },
+ };
+
+ UNUSED(state);
+
+ for (i = 0; i < sizeof(data4) / sizeof(data4[0]); i++) {
+ in.s_addr = inet_addr(data4[i].string);
+ isc_sockaddr_fromin(&addr, &in, 1);
+ r = isc_sockaddr_isnetzero(&addr);
+ assert_int_equal(r, data4[i].expect);
+ }
+
+ for (i = 0; i < sizeof(data6) / sizeof(data6[0]); i++) {
+ int ret = inet_pton(AF_INET6, data6[i].string, &in6);
+ assert_int_equal(ret, 1);
+ isc_sockaddr_fromin6(&addr, &in6, 1);
+ r = isc_sockaddr_isnetzero(&addr);
+ assert_int_equal(r, data6[i].expect);
+ }
+}
+
+/*
+ * test that isc_sockaddr_eqaddrprefix() returns true when prefixes of a
+ * and b are equal, and false when they are not equal
+ */
+ISC_RUN_TEST_IMPL(sockaddr_eqaddrprefix) {
+ struct in_addr ina_a;
+ struct in_addr ina_b;
+ struct in_addr ina_c;
+ isc_sockaddr_t isa_a;
+ isc_sockaddr_t isa_b;
+ isc_sockaddr_t isa_c;
+
+ UNUSED(state);
+
+ assert_true(inet_pton(AF_INET, "194.100.32.87", &ina_a) >= 0);
+ assert_true(inet_pton(AF_INET, "194.100.32.80", &ina_b) >= 0);
+ assert_true(inet_pton(AF_INET, "194.101.32.87", &ina_c) >= 0);
+
+ isc_sockaddr_fromin(&isa_a, &ina_a, 0);
+ isc_sockaddr_fromin(&isa_b, &ina_b, 42);
+ isc_sockaddr_fromin(&isa_c, &ina_c, 0);
+
+ assert_true(isc_sockaddr_eqaddrprefix(&isa_a, &isa_b, 0));
+ assert_true(isc_sockaddr_eqaddrprefix(&isa_a, &isa_b, 29));
+ assert_true(isc_sockaddr_eqaddrprefix(&isa_a, &isa_c, 8));
+
+ assert_false(isc_sockaddr_eqaddrprefix(&isa_a, &isa_b, 30));
+ assert_false(isc_sockaddr_eqaddrprefix(&isa_a, &isa_b, 32));
+ assert_false(isc_sockaddr_eqaddrprefix(&isa_a, &isa_c, 16));
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(sockaddr_hash)
+ISC_TEST_ENTRY(sockaddr_isnetzero)
+ISC_TEST_ENTRY(sockaddr_eqaddrprefix)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/stats_test.c b/tests/isc/stats_test.c
new file mode 100644
index 0000000..a475323
--- /dev/null
+++ b/tests/isc/stats_test.c
@@ -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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/stats.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+/* test stats */
+ISC_RUN_TEST_IMPL(isc_stats_basic) {
+ isc_stats_t *stats = NULL;
+ isc_result_t result;
+
+ UNUSED(state);
+
+ result = isc_stats_create(mctx, &stats, 4);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_stats_ncounters(stats), 4);
+
+ /* Default all 0. */
+ for (int i = 0; i < isc_stats_ncounters(stats); i++) {
+ assert_int_equal(isc_stats_get_counter(stats, i), 0);
+ }
+
+ /* Test increment. */
+ for (int i = 0; i < isc_stats_ncounters(stats); i++) {
+ isc_stats_increment(stats, i);
+ assert_int_equal(isc_stats_get_counter(stats, i), 1);
+ isc_stats_increment(stats, i);
+ assert_int_equal(isc_stats_get_counter(stats, i), 2);
+ }
+
+ /* Test decrement. */
+ for (int i = 0; i < isc_stats_ncounters(stats); i++) {
+ isc_stats_decrement(stats, i);
+ assert_int_equal(isc_stats_get_counter(stats, i), 1);
+ isc_stats_decrement(stats, i);
+ assert_int_equal(isc_stats_get_counter(stats, i), 0);
+ }
+
+ /* Test set. */
+ for (int i = 0; i < isc_stats_ncounters(stats); i++) {
+ isc_stats_set(stats, i, i);
+ assert_int_equal(isc_stats_get_counter(stats, i), i);
+ }
+
+ /* Test update if greater. */
+ for (int i = 0; i < isc_stats_ncounters(stats); i++) {
+ isc_stats_update_if_greater(stats, i, i);
+ assert_int_equal(isc_stats_get_counter(stats, i), i);
+ isc_stats_update_if_greater(stats, i, i + 1);
+ assert_int_equal(isc_stats_get_counter(stats, i), i + 1);
+ }
+
+ /* Test resize. */
+ isc_stats_resize(&stats, 3);
+ assert_int_equal(isc_stats_ncounters(stats), 4);
+ isc_stats_resize(&stats, 4);
+ assert_int_equal(isc_stats_ncounters(stats), 4);
+ isc_stats_resize(&stats, 5);
+ assert_int_equal(isc_stats_ncounters(stats), 5);
+
+ /* Existing counters are retained */
+ for (int i = 0; i < isc_stats_ncounters(stats); i++) {
+ uint32_t expect = i + 1;
+ if (i == 4) {
+ expect = 0;
+ }
+ assert_int_equal(isc_stats_get_counter(stats, i), expect);
+ }
+
+ isc_stats_detach(&stats);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_stats_basic)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/symtab_test.c b/tests/isc/symtab_test.c
new file mode 100644
index 0000000..795a455
--- /dev/null
+++ b/tests/isc/symtab_test.c
@@ -0,0 +1,135 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/print.h>
+#include <isc/symtab.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+static void
+undefine(char *key, unsigned int type, isc_symvalue_t value, void *arg) {
+ UNUSED(arg);
+
+ assert_int_equal(type, 1);
+ isc_mem_free(mctx, key);
+ isc_mem_free(mctx, value.as_pointer);
+}
+
+/* test symbol table growth */
+ISC_RUN_TEST_IMPL(symtab_grow) {
+ isc_result_t result;
+ isc_symtab_t *st = NULL;
+ isc_symvalue_t value;
+ isc_symexists_t policy = isc_symexists_reject;
+ int i;
+
+ UNUSED(state);
+
+ result = isc_symtab_create(mctx, 3, undefine, NULL, false, &st);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(st);
+
+ /* Nothing should be in the table yet */
+
+ /*
+ * Put 1024 entries in the table (this should necessate
+ * regrowing the hash table several times
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16], *key;
+
+ snprintf(str, sizeof(str), "%04x", i);
+ key = isc_mem_strdup(mctx, str);
+ assert_non_null(key);
+ value.as_pointer = isc_mem_strdup(mctx, str);
+ assert_non_null(value.as_pointer);
+ result = isc_symtab_define(st, key, 1, value, policy);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS) {
+ undefine(key, 1, value, NULL);
+ }
+ }
+
+ /*
+ * Try to put them in again; this should fail
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16], *key;
+
+ snprintf(str, sizeof(str), "%04x", i);
+ key = isc_mem_strdup(mctx, str);
+ assert_non_null(key);
+ value.as_pointer = isc_mem_strdup(mctx, str);
+ assert_non_null(value.as_pointer);
+ result = isc_symtab_define(st, key, 1, value, policy);
+ assert_int_equal(result, ISC_R_EXISTS);
+ undefine(key, 1, value, NULL);
+ }
+
+ /*
+ * Retrieve them; this should succeed
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16];
+
+ snprintf(str, sizeof(str), "%04x", i);
+ result = isc_symtab_lookup(st, str, 0, &value);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_string_equal(str, (char *)value.as_pointer);
+ }
+
+ /*
+ * Undefine them
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16];
+
+ snprintf(str, sizeof(str), "%04x", i);
+ result = isc_symtab_undefine(st, str, 1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ /*
+ * Retrieve them again; this should fail
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16];
+
+ snprintf(str, sizeof(str), "%04x", i);
+ result = isc_symtab_lookup(st, str, 0, &value);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+ }
+
+ isc_symtab_destroy(&st);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(symtab_grow)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/task_test.c b/tests/isc/task_test.c
new file mode 100644
index 0000000..973ecc9
--- /dev/null
+++ b/tests/isc/task_test.c
@@ -0,0 +1,1408 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+
+#include <cmocka.h>
+
+#include <isc/atomic.h>
+#include <isc/cmocka.h>
+#include <isc/commandline.h>
+#include <isc/condition.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include "netmgr/uv-compat.h"
+
+#include <tests/isc.h>
+
+/* Set to true (or use -v option) for verbose output */
+static bool verbose = false;
+
+static isc_mutex_t lock;
+static isc_condition_t cv;
+
+atomic_int_fast32_t counter;
+static int active[10];
+static atomic_bool done;
+
+static int
+_setup(void **state) {
+ isc_mutex_init(&lock);
+ isc_condition_init(&cv);
+
+ workers = 0;
+ setup_managers(state);
+
+ return (0);
+}
+
+static int
+_setup2(void **state) {
+ isc_mutex_init(&lock);
+ isc_condition_init(&cv);
+
+ /* Two worker threads */
+ workers = 2;
+ setup_managers(state);
+
+ return (0);
+}
+
+static int
+_setup4(void **state) {
+ isc_mutex_init(&lock);
+ isc_condition_init(&cv);
+
+ /* Four worker threads */
+ workers = 4;
+ setup_managers(state);
+
+ return (0);
+}
+
+static int
+_teardown(void **state) {
+ teardown_managers(state);
+
+ isc_condition_destroy(&cv);
+ isc_mutex_destroy(&lock);
+
+ return (0);
+}
+
+static void
+set(isc_task_t *task, isc_event_t *event) {
+ atomic_int_fast32_t *value = (atomic_int_fast32_t *)event->ev_arg;
+
+ UNUSED(task);
+
+ isc_event_free(&event);
+ atomic_store(value, atomic_fetch_add(&counter, 1));
+}
+
+#include <isc/thread.h>
+
+static void
+set_and_drop(isc_task_t *task, isc_event_t *event) {
+ atomic_int_fast32_t *value = (atomic_int_fast32_t *)event->ev_arg;
+
+ UNUSED(task);
+
+ isc_event_free(&event);
+ LOCK(&lock);
+ atomic_store(value, atomic_fetch_add(&counter, 1));
+ UNLOCK(&lock);
+}
+
+/* Create a task */
+ISC_RUN_TEST_IMPL(create_task) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+
+ UNUSED(state);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_task_destroy(&task);
+ assert_null(task);
+}
+
+/* Process events */
+ISC_RUN_TEST_IMPL(all_events) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+ isc_event_t *event = NULL;
+ atomic_int_fast32_t a, b;
+ int i = 0;
+
+ UNUSED(state);
+
+ atomic_init(&counter, 1);
+ atomic_init(&a, 0);
+ atomic_init(&b, 0);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* First event */
+ event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST, set, &a,
+ sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&a), 0);
+ isc_task_send(task, &event);
+
+ event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST, set, &b,
+ sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&b), 0);
+ isc_task_send(task, &event);
+
+ while ((atomic_load(&a) == 0 || atomic_load(&b) == 0) && i++ < 5000) {
+ uv_sleep(1);
+ }
+
+ assert_int_not_equal(atomic_load(&a), 0);
+ assert_int_not_equal(atomic_load(&b), 0);
+
+ isc_task_destroy(&task);
+ assert_null(task);
+}
+
+/* Privileged events */
+ISC_RUN_TEST_IMPL(privileged_events) {
+ isc_result_t result;
+ isc_task_t *task1 = NULL, *task2 = NULL;
+ isc_event_t *event = NULL;
+ atomic_int_fast32_t a, b, c, d, e;
+ int i = 0;
+
+ UNUSED(state);
+
+ atomic_init(&counter, 1);
+ atomic_init(&a, -1);
+ atomic_init(&b, -1);
+ atomic_init(&c, -1);
+ atomic_init(&d, -1);
+ atomic_init(&e, -1);
+
+ /*
+ * Pause the net/task manager so we can fill up the work
+ * queue without things happening while we do it.
+ */
+ isc_nm_pause(netmgr);
+ isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_task_setname(task1, "privileged", NULL);
+ assert_false(isc_task_getprivilege(task1));
+ isc_task_setprivilege(task1, true);
+ assert_true(isc_task_getprivilege(task1));
+
+ result = isc_task_create(taskmgr, 0, &task2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_task_setname(task2, "normal", NULL);
+ assert_false(isc_task_getprivilege(task2));
+
+ /* First event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, set, &a,
+ sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&a), -1);
+ isc_task_send(task1, &event);
+
+ /* Second event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, set, &b,
+ sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&b), -1);
+ isc_task_send(task2, &event);
+
+ /* Third event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, set, &c,
+ sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&c), -1);
+ isc_task_send(task1, &event);
+
+ /* Fourth event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, set, &d,
+ sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&d), -1);
+ isc_task_send(task1, &event);
+
+ /* Fifth event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, set, &e,
+ sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&e), -1);
+ isc_task_send(task2, &event);
+
+ isc_nm_resume(netmgr);
+
+ /* We're waiting for *all* variables to be set */
+ while ((atomic_load(&a) < 0 || atomic_load(&b) < 0 ||
+ atomic_load(&c) < 0 || atomic_load(&d) < 0 ||
+ atomic_load(&e) < 0) &&
+ i++ < 5000)
+ {
+ isc_test_nap(1000);
+ }
+
+ /*
+ * We can't guarantee what order the events fire, but
+ * we do know the privileged tasks that set a, c, and d
+ * would have fired first.
+ */
+ assert_true(atomic_load(&a) <= 3);
+ assert_true(atomic_load(&c) <= 3);
+ assert_true(atomic_load(&d) <= 3);
+
+ /* ...and the non-privileged tasks that set b and e, last */
+ assert_true(atomic_load(&b) > 3);
+ assert_true(atomic_load(&e) > 3);
+
+ assert_int_equal(atomic_load(&counter), 6);
+
+ isc_task_setprivilege(task1, false);
+ assert_false(isc_task_getprivilege(task1));
+
+ isc_task_destroy(&task1);
+ assert_null(task1);
+ isc_task_destroy(&task2);
+ assert_null(task2);
+}
+
+/*
+ * Edge case: this tests that the task manager behaves as expected when
+ * we explicitly set it into normal mode *while* running privileged.
+ */
+ISC_RUN_TEST_IMPL(privilege_drop) {
+ isc_result_t result;
+ isc_task_t *task1 = NULL, *task2 = NULL;
+ isc_event_t *event = NULL;
+ atomic_int_fast32_t a, b, c, d, e; /* non valid states */
+ int i = 0;
+
+ UNUSED(state);
+
+ atomic_init(&counter, 1);
+ atomic_init(&a, -1);
+ atomic_init(&b, -1);
+ atomic_init(&c, -1);
+ atomic_init(&d, -1);
+ atomic_init(&e, -1);
+
+ /*
+ * Pause the net/task manager so we can fill up the work queue
+ * without things happening while we do it.
+ */
+ isc_nm_pause(netmgr);
+ isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_task_setname(task1, "privileged", NULL);
+ assert_false(isc_task_getprivilege(task1));
+ isc_task_setprivilege(task1, true);
+ assert_true(isc_task_getprivilege(task1));
+
+ result = isc_task_create(taskmgr, 0, &task2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_task_setname(task2, "normal", NULL);
+ assert_false(isc_task_getprivilege(task2));
+
+ /* First event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set_and_drop, &a, sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&a), -1);
+ isc_task_send(task1, &event);
+
+ /* Second event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set_and_drop, &b, sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&b), -1);
+ isc_task_send(task2, &event);
+
+ /* Third event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set_and_drop, &c, sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&c), -1);
+ isc_task_send(task1, &event);
+
+ /* Fourth event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set_and_drop, &d, sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&d), -1);
+ isc_task_send(task1, &event);
+
+ /* Fifth event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set_and_drop, &e, sizeof(isc_event_t));
+ assert_non_null(event);
+
+ assert_int_equal(atomic_load(&e), -1);
+ isc_task_send(task2, &event);
+
+ isc_nm_resume(netmgr);
+
+ /* We're waiting for all variables to be set. */
+ while ((atomic_load(&a) == -1 || atomic_load(&b) == -1 ||
+ atomic_load(&c) == -1 || atomic_load(&d) == -1 ||
+ atomic_load(&e) == -1) &&
+ i++ < 5000)
+ {
+ isc_test_nap(1000);
+ }
+
+ /*
+ * We need to check that all privilege mode events were fired
+ * in privileged mode, and non privileged in non-privileged.
+ */
+ assert_true(atomic_load(&a) <= 3);
+ assert_true(atomic_load(&c) <= 3);
+ assert_true(atomic_load(&d) <= 3);
+
+ /* ...and neither of the non-privileged tasks did... */
+ assert_true(atomic_load(&b) > 3);
+ assert_true(atomic_load(&e) > 3);
+
+ /* ...but all five of them did run. */
+ assert_int_equal(atomic_load(&counter), 6);
+
+ isc_task_destroy(&task1);
+ assert_null(task1);
+ isc_task_destroy(&task2);
+ assert_null(task2);
+}
+
+/*
+ * Basic task functions:
+ */
+static void
+basic_cb(isc_task_t *task, isc_event_t *event) {
+ int i, j;
+
+ UNUSED(task);
+
+ j = 0;
+ for (i = 0; i < 1000000; i++) {
+ j += 100;
+ }
+
+ UNUSED(j);
+
+ if (verbose) {
+ print_message("# task %s\n", (char *)event->ev_arg);
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+basic_shutdown(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ if (verbose) {
+ print_message("# shutdown %s\n", (char *)event->ev_arg);
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+basic_tick(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ if (verbose) {
+ print_message("# %s\n", (char *)event->ev_arg);
+ }
+
+ isc_event_free(&event);
+}
+
+static char one[] = "1";
+static char two[] = "2";
+static char three[] = "3";
+static char four[] = "4";
+static char tick[] = "tick";
+static char tock[] = "tock";
+
+ISC_RUN_TEST_IMPL(basic) {
+ isc_result_t result;
+ isc_task_t *task1 = NULL;
+ isc_task_t *task2 = NULL;
+ isc_task_t *task3 = NULL;
+ isc_task_t *task4 = NULL;
+ isc_event_t *event = NULL;
+ isc_timer_t *ti1 = NULL;
+ isc_timer_t *ti2 = NULL;
+ isc_time_t absolute;
+ isc_interval_t interval;
+ char *testarray[] = { one, one, one, one, one, one, one, one,
+ one, two, three, four, two, three, four, NULL };
+ int i;
+
+ UNUSED(state);
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_task_create(taskmgr, 0, &task2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_task_create(taskmgr, 0, &task3);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_task_create(taskmgr, 0, &task4);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task1, basic_shutdown, one);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_task_onshutdown(task2, basic_shutdown, two);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_task_onshutdown(task3, basic_shutdown, three);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ result = isc_task_onshutdown(task4, basic_shutdown, four);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_time_settoepoch(&absolute);
+ isc_interval_set(&interval, 1, 0);
+ result = isc_timer_create(timermgr, isc_timertype_ticker, &absolute,
+ &interval, task1, basic_tick, tick, &ti1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ ti2 = NULL;
+ isc_time_settoepoch(&absolute);
+ isc_interval_set(&interval, 1, 0);
+ result = isc_timer_create(timermgr, isc_timertype_ticker, &absolute,
+ &interval, task2, basic_tick, tock, &ti2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ sleep(2);
+
+ for (i = 0; testarray[i] != NULL; i++) {
+ /*
+ * 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, basic_cb,
+ testarray[i], sizeof(*event));
+ assert_non_null(event);
+ isc_task_send(task1, &event);
+ }
+
+ (void)isc_task_purge(task3, NULL, 0, 0);
+
+ isc_task_detach(&task1);
+ isc_task_detach(&task2);
+ isc_task_detach(&task3);
+ isc_task_detach(&task4);
+
+ sleep(10);
+ isc_timer_destroy(&ti1);
+ isc_timer_destroy(&ti2);
+}
+
+/*
+ * Exclusive mode test:
+ * When one task enters exclusive mode, all other active
+ * tasks complete first.
+ */
+static int
+spin(int n) {
+ int i;
+ int r = 0;
+ for (i = 0; i < n; i++) {
+ r += i;
+ if (r > 1000000) {
+ r = 0;
+ }
+ }
+ return (r);
+}
+
+static void
+exclusive_cb(isc_task_t *task, isc_event_t *event) {
+ int taskno = *(int *)(event->ev_arg);
+
+ if (verbose) {
+ print_message("# task enter %d\n", taskno);
+ }
+
+ /* task chosen from the middle of the range */
+ if (taskno == 6) {
+ isc_result_t result;
+ int i;
+
+ result = isc_task_beginexclusive(task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (i = 0; i < 10; i++) {
+ assert_int_equal(active[i], 0);
+ }
+
+ isc_task_endexclusive(task);
+ atomic_store(&done, true);
+ } else {
+ active[taskno]++;
+ (void)spin(10000000);
+ active[taskno]--;
+ }
+
+ if (verbose) {
+ print_message("# task exit %d\n", taskno);
+ }
+
+ if (atomic_load(&done)) {
+ isc_mem_put(event->ev_destroy_arg, event->ev_arg, sizeof(int));
+ isc_event_free(&event);
+ atomic_fetch_sub(&counter, 1);
+ } else {
+ isc_task_send(task, &event);
+ }
+}
+
+ISC_RUN_TEST_IMPL(task_exclusive) {
+ isc_task_t *tasks[10];
+ isc_result_t result;
+ int i;
+
+ UNUSED(state);
+
+ atomic_init(&counter, 0);
+
+ for (i = 0; i < 10; i++) {
+ isc_event_t *event = NULL;
+ int *v;
+
+ tasks[i] = NULL;
+
+ if (i == 6) {
+ /* task chosen from the middle of the range */
+ result = isc_task_create_bound(taskmgr, 0, &tasks[i],
+ 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_taskmgr_setexcltask(taskmgr, tasks[6]);
+ } else {
+ result = isc_task_create(taskmgr, 0, &tasks[i]);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ v = isc_mem_get(mctx, sizeof *v);
+ assert_non_null(v);
+
+ *v = i;
+
+ event = isc_event_allocate(mctx, NULL, 1, exclusive_cb, v,
+ sizeof(*event));
+ assert_non_null(event);
+
+ isc_task_send(tasks[i], &event);
+ atomic_fetch_add(&counter, 1);
+ }
+
+ for (i = 0; i < 10; i++) {
+ isc_task_detach(&tasks[i]);
+ }
+
+ while (atomic_load(&counter) > 0) {
+ uv_sleep(1);
+ }
+}
+
+/*
+ * Max tasks test:
+ * The task system can create and execute many tasks. Tests with 10000.
+ */
+static void
+maxtask_shutdown(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ if (event->ev_arg != NULL) {
+ isc_task_destroy((isc_task_t **)&event->ev_arg);
+ } else {
+ LOCK(&lock);
+ atomic_store(&done, true);
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+maxtask_cb(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+
+ if (event->ev_arg != NULL) {
+ isc_task_t *newtask = NULL;
+
+ event->ev_arg = (void *)(((uintptr_t)event->ev_arg) - 1);
+
+ /*
+ * Create a new task and forward the message.
+ */
+ result = isc_task_create(taskmgr, 0, &newtask);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(newtask, maxtask_shutdown,
+ (void *)task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_task_send(newtask, &event);
+ } else if (task != NULL) {
+ isc_task_destroy(&task);
+ isc_event_free(&event);
+ }
+}
+
+ISC_RUN_TEST_IMPL(manytasks) {
+ isc_event_t *event = NULL;
+ uintptr_t ntasks = 10000;
+
+ UNUSED(state);
+
+ if (verbose) {
+ print_message("# Testing with %lu tasks\n",
+ (unsigned long)ntasks);
+ }
+
+ atomic_init(&done, false);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, maxtask_cb,
+ (void *)ntasks, sizeof(*event));
+ assert_non_null(event);
+
+ LOCK(&lock);
+ maxtask_cb(NULL, event);
+ while (!atomic_load(&done)) {
+ WAIT(&cv, &lock);
+ }
+ UNLOCK(&lock);
+}
+
+/*
+ * Shutdown test:
+ * When isc_task_shutdown() is called, shutdown events are posted
+ * in LIFO order.
+ */
+
+static int nevents = 0;
+static int nsdevents = 0;
+static int senders[4];
+atomic_bool ready, all_done;
+
+static void
+sd_sde1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ assert_int_equal(nevents, 256);
+ assert_int_equal(nsdevents, 1);
+ ++nsdevents;
+
+ if (verbose) {
+ print_message("# shutdown 1\n");
+ }
+
+ isc_event_free(&event);
+
+ atomic_store(&all_done, true);
+}
+
+static void
+sd_sde2(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ assert_int_equal(nevents, 256);
+ assert_int_equal(nsdevents, 0);
+ ++nsdevents;
+
+ if (verbose) {
+ print_message("# shutdown 2\n");
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+sd_event1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ while (!atomic_load(&ready)) {
+ WAIT(&cv, &lock);
+ }
+ UNLOCK(&lock);
+
+ if (verbose) {
+ print_message("# event 1\n");
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+sd_event2(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ ++nevents;
+
+ if (verbose) {
+ print_message("# event 2\n");
+ }
+
+ isc_event_free(&event);
+}
+
+ISC_RUN_TEST_IMPL(task_shutdown) {
+ isc_result_t result;
+ isc_eventtype_t event_type;
+ isc_event_t *event = NULL;
+ isc_task_t *task = NULL;
+ int i;
+
+ UNUSED(state);
+
+ nevents = nsdevents = 0;
+ event_type = 3;
+ atomic_init(&ready, false);
+ atomic_init(&all_done, false);
+
+ LOCK(&lock);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * This event causes the task to wait on cv.
+ */
+ event = isc_event_allocate(mctx, &senders[1], event_type, sd_event1,
+ NULL, sizeof(*event));
+ assert_non_null(event);
+ isc_task_send(task, &event);
+
+ /*
+ * Now we fill up the task's event queue with some events.
+ */
+ for (i = 0; i < 256; ++i) {
+ event = isc_event_allocate(mctx, &senders[1], event_type,
+ sd_event2, NULL, sizeof(*event));
+ assert_non_null(event);
+ isc_task_send(task, &event);
+ }
+
+ /*
+ * Now we register two shutdown events.
+ */
+ result = isc_task_onshutdown(task, sd_sde1, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task, sd_sde2, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_task_shutdown(task);
+ isc_task_detach(&task);
+
+ /*
+ * Now we free the task by signaling cv.
+ */
+ atomic_store(&ready, true);
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
+ while (!atomic_load(&all_done)) {
+ isc_test_nap(1000);
+ }
+
+ assert_int_equal(nsdevents, 2);
+}
+
+/*
+ * Post-shutdown test:
+ * After isc_task_shutdown() has been called, any call to
+ * isc_task_onshutdown() will return ISC_R_SHUTTINGDOWN.
+ */
+static void
+psd_event1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+
+ while (!atomic_load(&done)) {
+ WAIT(&cv, &lock);
+ }
+
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+psd_sde(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ isc_event_free(&event);
+}
+
+ISC_RUN_TEST_IMPL(post_shutdown) {
+ isc_result_t result;
+ isc_eventtype_t event_type;
+ isc_event_t *event;
+ isc_task_t *task;
+
+ UNUSED(state);
+
+ atomic_init(&done, false);
+ event_type = 4;
+
+ isc_condition_init(&cv);
+
+ LOCK(&lock);
+
+ task = NULL;
+ result = isc_task_create(taskmgr, 0, &task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * This event causes the task to wait on cv.
+ */
+ event = isc_event_allocate(mctx, &senders[1], event_type, psd_event1,
+ NULL, sizeof(*event));
+ assert_non_null(event);
+ isc_task_send(task, &event);
+
+ isc_task_shutdown(task);
+
+ result = isc_task_onshutdown(task, psd_sde, NULL);
+ assert_int_equal(result, ISC_R_SHUTTINGDOWN);
+
+ /*
+ * Release the task.
+ */
+ atomic_store(&done, true);
+
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
+ isc_task_detach(&task);
+}
+
+/*
+ * Helper for the purge tests below:
+ */
+
+#define SENDERCNT 3
+#define TYPECNT 4
+#define TAGCNT 5
+#define NEVENTS (SENDERCNT * TYPECNT * TAGCNT)
+
+static bool testrange;
+static void *purge_sender;
+static isc_eventtype_t purge_type_first;
+static isc_eventtype_t purge_type_last;
+static void *purge_tag;
+static int eventcnt;
+
+atomic_bool started;
+
+static void
+pg_event1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ while (!atomic_load(&started)) {
+ WAIT(&cv, &lock);
+ }
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+pg_event2(isc_task_t *task, isc_event_t *event) {
+ bool sender_match = false;
+ bool type_match = false;
+ bool tag_match = false;
+
+ UNUSED(task);
+
+ if ((purge_sender == NULL) || (purge_sender == event->ev_sender)) {
+ sender_match = true;
+ }
+
+ if (testrange) {
+ if ((purge_type_first <= event->ev_type) &&
+ (event->ev_type <= purge_type_last))
+ {
+ type_match = true;
+ }
+ } else {
+ if (purge_type_first == event->ev_type) {
+ type_match = true;
+ }
+ }
+
+ if ((purge_tag == NULL) || (purge_tag == event->ev_tag)) {
+ tag_match = true;
+ }
+
+ if (sender_match && type_match && tag_match) {
+ if ((event->ev_attributes & ISC_EVENTATTR_NOPURGE) != 0) {
+ if (verbose) {
+ print_message("# event %p,%d,%p "
+ "matched but was not "
+ "purgeable\n",
+ event->ev_sender,
+ (int)event->ev_type,
+ event->ev_tag);
+ }
+ ++eventcnt;
+ } else if (verbose) {
+ print_message("# event %p,%d,%p not purged\n",
+ event->ev_sender, (int)event->ev_type,
+ event->ev_tag);
+ }
+ } else {
+ ++eventcnt;
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+pg_sde(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ atomic_store(&done, true);
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+test_purge(int sender, int type, int tag, int exp_purged) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+ isc_event_t *eventtab[NEVENTS];
+ isc_event_t *event = NULL;
+ isc_interval_t interval;
+ isc_time_t now;
+ int sender_cnt, type_cnt, tag_cnt, event_cnt, i;
+ int purged = 0;
+
+ atomic_init(&started, false);
+ atomic_init(&done, false);
+ eventcnt = 0;
+
+ isc_condition_init(&cv);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task, pg_sde, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Block the task on cv.
+ */
+ event = isc_event_allocate(mctx, (void *)1, 9999, pg_event1, NULL,
+ sizeof(*event));
+
+ assert_non_null(event);
+ isc_task_send(task, &event);
+
+ /*
+ * Fill the task's queue with some messages with varying
+ * sender, type, tag, and purgeable attribute values.
+ */
+ event_cnt = 0;
+ for (sender_cnt = 0; sender_cnt < SENDERCNT; ++sender_cnt) {
+ for (type_cnt = 0; type_cnt < TYPECNT; ++type_cnt) {
+ for (tag_cnt = 0; tag_cnt < TAGCNT; ++tag_cnt) {
+ eventtab[event_cnt] = isc_event_allocate(
+ mctx, &senders[sender + sender_cnt],
+ (isc_eventtype_t)(type + type_cnt),
+ pg_event2, NULL, sizeof(*event));
+
+ assert_non_null(eventtab[event_cnt]);
+
+ eventtab[event_cnt]->ev_tag =
+ (void *)((uintptr_t)tag + tag_cnt);
+
+ /*
+ * Mark events as non-purgeable if
+ * sender, type and tag are all
+ * odd-numbered. (There should be 4
+ * of these out of 60 events total.)
+ */
+ if (((sender_cnt % 2) != 0) &&
+ ((type_cnt % 2) != 0) &&
+ ((tag_cnt % 2) != 0))
+ {
+ eventtab[event_cnt]->ev_attributes |=
+ ISC_EVENTATTR_NOPURGE;
+ }
+ ++event_cnt;
+ }
+ }
+ }
+
+ for (i = 0; i < event_cnt; ++i) {
+ isc_task_send(task, &eventtab[i]);
+ }
+
+ if (testrange) {
+ /*
+ * We're testing isc_task_purgerange.
+ */
+ purged = isc_task_purgerange(
+ task, purge_sender, (isc_eventtype_t)purge_type_first,
+ (isc_eventtype_t)purge_type_last, purge_tag);
+ assert_int_equal(purged, exp_purged);
+ } else {
+ /*
+ * We're testing isc_task_purge.
+ */
+ if (verbose) {
+ print_message("# purge events %p,%u,%p\n", purge_sender,
+ purge_type_first, purge_tag);
+ }
+ purged = isc_task_purge(task, purge_sender,
+ (isc_eventtype_t)purge_type_first,
+ purge_tag);
+ if (verbose) {
+ print_message("# purged %d expected %d\n", purged,
+ exp_purged);
+ }
+
+ assert_int_equal(purged, exp_purged);
+ }
+
+ /*
+ * Unblock the task, allowing event processing.
+ */
+ LOCK(&lock);
+ atomic_store(&started, true);
+ SIGNAL(&cv);
+
+ isc_task_shutdown(task);
+
+ isc_interval_set(&interval, 5, 0);
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (!atomic_load(&done)) {
+ result = isc_time_nowplusinterval(&now, &interval);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ WAITUNTIL(&cv, &lock, &now);
+ }
+
+ UNLOCK(&lock);
+
+ isc_task_detach(&task);
+
+ assert_int_equal(eventcnt, event_cnt - exp_purged);
+}
+
+/*
+ * Purge test:
+ * A call to isc_task_purge(task, sender, type, tag) purges all events of
+ * type 'type' and with tag 'tag' not marked as unpurgeable from sender
+ * from the task's " queue and returns the number of events purged.
+ */
+ISC_RUN_TEST_IMPL(purge) {
+ UNUSED(state);
+
+ /* Try purging on a specific sender. */
+ if (verbose) {
+ print_message("# testing purge on 2,4,8 expecting 1\n");
+ }
+ purge_sender = &senders[2];
+ purge_type_first = 4;
+ purge_type_last = 4;
+ purge_tag = (void *)8;
+ testrange = false;
+ test_purge(1, 4, 7, 1);
+
+ /* Try purging on all senders. */
+ if (verbose) {
+ print_message("# testing purge on 0,4,8 expecting 3\n");
+ }
+ purge_sender = NULL;
+ purge_type_first = 4;
+ purge_type_last = 4;
+ purge_tag = (void *)8;
+ testrange = false;
+ test_purge(1, 4, 7, 3);
+
+ /* Try purging on all senders, specified type, all tags. */
+ if (verbose) {
+ print_message("# testing purge on 0,4,0 expecting 15\n");
+ }
+ purge_sender = NULL;
+ purge_type_first = 4;
+ purge_type_last = 4;
+ purge_tag = NULL;
+ testrange = false;
+ test_purge(1, 4, 7, 15);
+
+ /* Try purging on a specified tag, no such type. */
+ if (verbose) {
+ print_message("# testing purge on 0,99,8 expecting 0\n");
+ }
+ purge_sender = NULL;
+ purge_type_first = 99;
+ purge_type_last = 99;
+ purge_tag = (void *)8;
+ testrange = false;
+ test_purge(1, 4, 7, 0);
+
+ /* Try purging on specified sender, type, all tags. */
+ if (verbose) {
+ print_message("# testing purge on 3,5,0 expecting 5\n");
+ }
+ purge_sender = &senders[3];
+ purge_type_first = 5;
+ purge_type_last = 5;
+ purge_tag = NULL;
+ testrange = false;
+ test_purge(1, 4, 7, 5);
+}
+
+/*
+ * Purge range test:
+ * A call to isc_event_purgerange(task, sender, first, last, tag) purges
+ * all events not marked unpurgeable from sender 'sender' and of type within
+ * the range 'first' to 'last' inclusive from the task's event queue and
+ * returns the number of tasks purged.
+ */
+
+ISC_RUN_TEST_IMPL(purgerange) {
+ UNUSED(state);
+
+ /* Now let's try some ranges. */
+ /* testing purgerange on 2,4-5,8 expecting 1 */
+ purge_sender = &senders[2];
+ purge_type_first = 4;
+ purge_type_last = 5;
+ purge_tag = (void *)8;
+ testrange = true;
+ test_purge(1, 4, 7, 1);
+
+ /* Try purging on all senders. */
+ if (verbose) {
+ print_message("# testing purge on 0,4-5,8 expecting 5\n");
+ }
+ purge_sender = NULL;
+ purge_type_first = 4;
+ purge_type_last = 5;
+ purge_tag = (void *)8;
+ testrange = true;
+ test_purge(1, 4, 7, 5);
+
+ /* Try purging on all senders, specified type, all tags. */
+ if (verbose) {
+ print_message("# testing purge on 0,5-6,0 expecting 28\n");
+ }
+ purge_sender = NULL;
+ purge_type_first = 5;
+ purge_type_last = 6;
+ purge_tag = NULL;
+ testrange = true;
+ test_purge(1, 4, 7, 28);
+
+ /* Try purging on a specified tag, no such type. */
+ if (verbose) {
+ print_message("# testing purge on 0,99-101,8 expecting 0\n");
+ }
+ purge_sender = NULL;
+ purge_type_first = 99;
+ purge_type_last = 101;
+ purge_tag = (void *)8;
+ testrange = true;
+ test_purge(1, 4, 7, 0);
+
+ /* Try purging on specified sender, type, all tags. */
+ if (verbose) {
+ print_message("# testing purge on 3,5-6,0 expecting 10\n");
+ }
+ purge_sender = &senders[3];
+ purge_type_first = 5;
+ purge_type_last = 6;
+ purge_tag = NULL;
+ testrange = true;
+ test_purge(1, 4, 7, 10);
+}
+
+/*
+ * Helpers for purge event tests
+ */
+static void
+pge_event1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ while (!atomic_load(&started)) {
+ WAIT(&cv, &lock);
+ }
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+pge_event2(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ ++eventcnt;
+ isc_event_free(&event);
+}
+
+static void
+pge_sde(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ atomic_store(&done, true);
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+try_purgeevent(bool purgeable) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+ bool purged;
+ isc_event_t *event1 = NULL;
+ isc_event_t *event2 = NULL;
+ isc_event_t *event2_clone = NULL;
+ isc_time_t now;
+ isc_interval_t interval;
+
+ atomic_init(&started, false);
+ atomic_init(&done, false);
+ eventcnt = 0;
+
+ isc_condition_init(&cv);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task, pge_sde, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Block the task on cv.
+ */
+ event1 = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)1,
+ pge_event1, NULL, sizeof(*event1));
+ assert_non_null(event1);
+ isc_task_send(task, &event1);
+
+ event2 = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)1,
+ pge_event2, NULL, sizeof(*event2));
+ assert_non_null(event2);
+
+ event2_clone = event2;
+
+ if (purgeable) {
+ event2->ev_attributes &= ~ISC_EVENTATTR_NOPURGE;
+ } else {
+ event2->ev_attributes |= ISC_EVENTATTR_NOPURGE;
+ }
+
+ isc_task_send(task, &event2);
+
+ purged = isc_task_purgeevent(task, event2_clone);
+ assert_int_equal(purgeable, purged);
+
+ /*
+ * Unblock the task, allowing event processing.
+ */
+ LOCK(&lock);
+ atomic_store(&started, true);
+ SIGNAL(&cv);
+
+ isc_task_shutdown(task);
+
+ isc_interval_set(&interval, 5, 0);
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (!atomic_load(&done)) {
+ result = isc_time_nowplusinterval(&now, &interval);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ WAITUNTIL(&cv, &lock, &now);
+ }
+ UNLOCK(&lock);
+
+ isc_task_detach(&task);
+
+ assert_int_equal(eventcnt, (purgeable ? 0 : 1));
+}
+
+/*
+ * Purge event test:
+ * When the event is marked as purgeable, a call to
+ * isc_task_purgeevent(task, event) purges the event 'event' from the
+ * task's queue and returns true.
+ */
+
+ISC_RUN_TEST_IMPL(purgeevent) {
+ UNUSED(state);
+
+ try_purgeevent(true);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(manytasks, _setup4, _teardown)
+ISC_TEST_ENTRY_CUSTOM(all_events, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(basic, _setup2, _teardown)
+ISC_TEST_ENTRY_CUSTOM(create_task, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(post_shutdown, _setup2, _teardown)
+ISC_TEST_ENTRY_CUSTOM(privilege_drop, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(privileged_events, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(purge, _setup2, _teardown)
+ISC_TEST_ENTRY_CUSTOM(purgeevent, _setup2, _teardown)
+ISC_TEST_ENTRY_CUSTOM(task_shutdown, _setup4, _teardown)
+ISC_TEST_ENTRY_CUSTOM(task_exclusive, _setup4, _teardown)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/taskpool_test.c b/tests/isc/taskpool_test.c
new file mode 100644
index 0000000..a92e0ad
--- /dev/null
+++ b/tests/isc/taskpool_test.c
@@ -0,0 +1,164 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/task.h>
+#include <isc/taskpool.h>
+#include <isc/util.h>
+
+#include <tests/isc.h>
+
+#define TASK_MAGIC ISC_MAGIC('T', 'A', 'S', 'K')
+#define VALID_TASK(t) ISC_MAGIC_VALID(t, TASK_MAGIC)
+
+/* Create a taskpool */
+ISC_RUN_TEST_IMPL(create_pool) {
+ isc_result_t result;
+ isc_taskpool_t *pool = NULL;
+
+ UNUSED(state);
+
+ result = isc_taskpool_create(taskmgr, mctx, 8, 2, false, &pool);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_taskpool_size(pool), 8);
+
+ isc_taskpool_destroy(&pool);
+ assert_null(pool);
+}
+
+/* Resize a taskpool */
+ISC_RUN_TEST_IMPL(expand_pool) {
+ isc_result_t result;
+ isc_taskpool_t *pool1 = NULL, *pool2 = NULL, *hold = NULL;
+
+ UNUSED(state);
+
+ result = isc_taskpool_create(taskmgr, mctx, 10, 2, false, &pool1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_taskpool_size(pool1), 10);
+
+ /* resizing to a smaller size should have no effect */
+ hold = pool1;
+ result = isc_taskpool_expand(&pool1, 5, false, &pool2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_taskpool_size(pool2), 10);
+ assert_ptr_equal(pool2, hold);
+ assert_null(pool1);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to the same size should have no effect */
+ hold = pool1;
+ result = isc_taskpool_expand(&pool1, 10, false, &pool2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_taskpool_size(pool2), 10);
+ assert_ptr_equal(pool2, hold);
+ assert_null(pool1);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to larger size should make a new pool */
+ hold = pool1;
+ result = isc_taskpool_expand(&pool1, 20, false, &pool2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_taskpool_size(pool2), 20);
+ assert_ptr_not_equal(pool2, hold);
+ assert_null(pool1);
+
+ isc_taskpool_destroy(&pool2);
+ assert_null(pool2);
+}
+
+/* Get tasks */
+ISC_RUN_TEST_IMPL(get_tasks) {
+ isc_result_t result;
+ isc_taskpool_t *pool = NULL;
+ isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
+
+ UNUSED(state);
+
+ result = isc_taskpool_create(taskmgr, mctx, 2, 2, false, &pool);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_taskpool_size(pool), 2);
+
+ /* two tasks in pool; make sure we can access them more than twice */
+ isc_taskpool_gettask(pool, &task1);
+ assert_true(VALID_TASK(task1));
+
+ isc_taskpool_gettask(pool, &task2);
+ assert_true(VALID_TASK(task2));
+
+ isc_taskpool_gettask(pool, &task3);
+ assert_true(VALID_TASK(task3));
+
+ isc_task_destroy(&task1);
+ isc_task_destroy(&task2);
+ isc_task_destroy(&task3);
+
+ isc_taskpool_destroy(&pool);
+ assert_null(pool);
+}
+
+/* Set privileges */
+ISC_RUN_TEST_IMPL(set_privilege) {
+ isc_result_t result;
+ isc_taskpool_t *pool = NULL;
+ isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
+
+ UNUSED(state);
+
+ result = isc_taskpool_create(taskmgr, mctx, 2, 2, true, &pool);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_taskpool_size(pool), 2);
+
+ isc_taskpool_gettask(pool, &task1);
+ isc_taskpool_gettask(pool, &task2);
+ isc_taskpool_gettask(pool, &task3);
+
+ assert_true(VALID_TASK(task1));
+ assert_true(VALID_TASK(task2));
+ assert_true(VALID_TASK(task3));
+
+ assert_true(isc_task_getprivilege(task1));
+ assert_true(isc_task_getprivilege(task2));
+ assert_true(isc_task_getprivilege(task3));
+
+ isc_task_destroy(&task1);
+ isc_task_destroy(&task2);
+ isc_task_destroy(&task3);
+
+ isc_taskpool_destroy(&pool);
+ assert_null(pool);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(create_pool, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(expand_pool, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(get_tasks, setup_managers, teardown_managers)
+ISC_TEST_ENTRY_CUSTOM(set_privilege, setup_managers, teardown_managers)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/testdata/file/keep b/tests/isc/testdata/file/keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/isc/testdata/file/keep
diff --git a/tests/isc/time_test.c b/tests/isc/time_test.c
new file mode 100644
index 0000000..6b0f329
--- /dev/null
+++ b/tests/isc/time_test.c
@@ -0,0 +1,418 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/result.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include "time.c"
+
+#include <tests/isc.h>
+
+#define MAX_NS (NS_PER_SEC - 1)
+
+struct time_vectors {
+ isc_time_t a;
+ isc_interval_t b;
+ isc_time_t r;
+ isc_result_t result;
+};
+
+const struct time_vectors vectors_add[8] = {
+ { { 0, 0 }, { 0, 0 }, { 0, 0 }, ISC_R_SUCCESS },
+ { { 0, MAX_NS }, { 0, MAX_NS }, { 1, MAX_NS - 1 }, ISC_R_SUCCESS },
+ { { 0, NS_PER_SEC / 2 },
+ { 0, NS_PER_SEC / 2 },
+ { 1, 0 },
+ ISC_R_SUCCESS },
+ { { UINT_MAX, MAX_NS }, { 0, 0 }, { UINT_MAX, MAX_NS }, ISC_R_SUCCESS },
+ { { UINT_MAX, 0 }, { 0, MAX_NS }, { UINT_MAX, MAX_NS }, ISC_R_SUCCESS },
+ { { UINT_MAX, 0 }, { 1, 0 }, { 0, 0 }, ISC_R_RANGE },
+ { { UINT_MAX, MAX_NS }, { 0, 1 }, { 0, 0 }, ISC_R_RANGE },
+ { { UINT_MAX / 2 + 1, NS_PER_SEC / 2 },
+ { UINT_MAX / 2, NS_PER_SEC / 2 },
+ { 0, 0 },
+ ISC_R_RANGE },
+};
+
+const struct time_vectors vectors_sub[7] = {
+ { { 0, 0 }, { 0, 0 }, { 0, 0 }, ISC_R_SUCCESS },
+ { { 1, 0 }, { 0, MAX_NS }, { 0, 1 }, ISC_R_SUCCESS },
+ { { 1, NS_PER_SEC / 2 },
+ { 0, MAX_NS },
+ { 0, NS_PER_SEC / 2 + 1 },
+ ISC_R_SUCCESS },
+ { { UINT_MAX, MAX_NS }, { UINT_MAX, 0 }, { 0, MAX_NS }, ISC_R_SUCCESS },
+ { { 0, 0 }, { 1, 0 }, { 0, 0 }, ISC_R_RANGE },
+ { { 0, 0 }, { 0, MAX_NS }, { 0, 0 }, ISC_R_RANGE },
+};
+
+ISC_RUN_TEST_IMPL(isc_time_add_test) {
+ UNUSED(state);
+
+ for (size_t i = 0; i < ARRAY_SIZE(vectors_add); i++) {
+ isc_time_t r = { UINT_MAX, UINT_MAX };
+ isc_result_t result = isc_time_add(&(vectors_add[i].a),
+ &(vectors_add[i].b), &r);
+ assert_int_equal(result, vectors_add[i].result);
+ if (result != ISC_R_SUCCESS) {
+ continue;
+ }
+
+ assert_int_equal(r.seconds, vectors_add[i].r.seconds);
+ assert_int_equal(r.nanoseconds, vectors_add[i].r.nanoseconds);
+ }
+
+ expect_assert_failure((void)isc_time_add(&(isc_time_t){ 0, MAX_NS + 1 },
+ &(isc_interval_t){ 0, 0 },
+ &(isc_time_t){ 0, 0 }));
+ expect_assert_failure((void)isc_time_add(
+ &(isc_time_t){ 0, 0 }, &(isc_interval_t){ 0, MAX_NS + 1 },
+ &(isc_time_t){ 0, 0 }));
+
+ expect_assert_failure((void)isc_time_add((isc_time_t *)NULL,
+ &(isc_interval_t){ 0, 0 },
+ &(isc_time_t){ 0, 0 }));
+ expect_assert_failure((void)isc_time_add(&(isc_time_t){ 0, 0 },
+ (isc_interval_t *)NULL,
+ &(isc_time_t){ 0, 0 }));
+ expect_assert_failure((void)isc_time_add(
+ &(isc_time_t){ 0, 0 }, &(isc_interval_t){ 0, 0 }, NULL));
+}
+
+ISC_RUN_TEST_IMPL(isc_time_sub_test) {
+ UNUSED(state);
+
+ for (size_t i = 0; i < ARRAY_SIZE(vectors_sub); i++) {
+ isc_time_t r = { UINT_MAX, UINT_MAX };
+ isc_result_t result = isc_time_subtract(
+ &(vectors_sub[i].a), &(vectors_sub[i].b), &r);
+ assert_int_equal(result, vectors_sub[i].result);
+ if (result != ISC_R_SUCCESS) {
+ continue;
+ }
+ assert_int_equal(r.seconds, vectors_sub[i].r.seconds);
+ assert_int_equal(r.nanoseconds, vectors_sub[i].r.nanoseconds);
+ }
+
+ expect_assert_failure((void)isc_time_subtract(
+ &(isc_time_t){ 0, MAX_NS + 1 }, &(isc_interval_t){ 0, 0 },
+ &(isc_time_t){ 0, 0 }));
+ expect_assert_failure((void)isc_time_subtract(
+ &(isc_time_t){ 0, 0 }, &(isc_interval_t){ 0, MAX_NS + 1 },
+ &(isc_time_t){ 0, 0 }));
+
+ expect_assert_failure((void)isc_time_subtract((isc_time_t *)NULL,
+ &(isc_interval_t){ 0, 0 },
+ &(isc_time_t){ 0, 0 }));
+ expect_assert_failure((void)isc_time_subtract(&(isc_time_t){ 0, 0 },
+ (isc_interval_t *)NULL,
+ &(isc_time_t){ 0, 0 }));
+ expect_assert_failure((void)isc_time_subtract(
+ &(isc_time_t){ 0, 0 }, &(isc_interval_t){ 0, 0 }, NULL));
+}
+
+/* parse http time stamp */
+
+ISC_RUN_TEST_IMPL(isc_time_parsehttptimestamp_test) {
+ isc_result_t result;
+ isc_time_t t, x;
+ char buf[ISC_FORMATHTTPTIMESTAMP_SIZE];
+
+ UNUSED(state);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ result = isc_time_now(&t);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_time_formathttptimestamp(&t, buf, sizeof(buf));
+ result = isc_time_parsehttptimestamp(buf, &x);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(isc_time_seconds(&t), isc_time_seconds(&x));
+}
+
+/* print UTC in ISO8601 */
+
+ISC_RUN_TEST_IMPL(isc_time_formatISO8601_test) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ UNUSED(state);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ result = isc_time_now(&t);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* check formatting: yyyy-mm-ddThh:mm:ssZ */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601(&t, buf, sizeof(buf));
+ assert_int_equal(strlen(buf), 20);
+ assert_int_equal(buf[4], '-');
+ assert_int_equal(buf[7], '-');
+ assert_int_equal(buf[10], 'T');
+ assert_int_equal(buf[13], ':');
+ assert_int_equal(buf[16], ':');
+ assert_int_equal(buf[19], 'Z');
+
+ /* check time conversion correctness */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_settoepoch(&t);
+ isc_time_formatISO8601(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "1970-01-01T00:00:00Z");
+
+ memset(buf, 'X', sizeof(buf));
+ isc_time_set(&t, 1450000000, 123000000);
+ isc_time_formatISO8601(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "2015-12-13T09:46:40Z");
+}
+
+/* print UTC in ISO8601 with milliseconds */
+
+ISC_RUN_TEST_IMPL(isc_time_formatISO8601ms_test) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ UNUSED(state);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ result = isc_time_now(&t);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* check formatting: yyyy-mm-ddThh:mm:ss.sssZ */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601ms(&t, buf, sizeof(buf));
+ assert_int_equal(strlen(buf), 24);
+ assert_int_equal(buf[4], '-');
+ assert_int_equal(buf[7], '-');
+ assert_int_equal(buf[10], 'T');
+ assert_int_equal(buf[13], ':');
+ assert_int_equal(buf[16], ':');
+ assert_int_equal(buf[19], '.');
+ assert_int_equal(buf[23], 'Z');
+
+ /* check time conversion correctness */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_settoepoch(&t);
+ isc_time_formatISO8601ms(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "1970-01-01T00:00:00.000Z");
+
+ memset(buf, 'X', sizeof(buf));
+ isc_time_set(&t, 1450000000, 123000000);
+ isc_time_formatISO8601ms(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "2015-12-13T09:46:40.123Z");
+}
+
+/* print UTC in ISO8601 with microseconds */
+
+ISC_RUN_TEST_IMPL(isc_time_formatISO8601us_test) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ UNUSED(state);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ result = isc_time_now_hires(&t);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* check formatting: yyyy-mm-ddThh:mm:ss.ssssssZ */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601us(&t, buf, sizeof(buf));
+ assert_int_equal(strlen(buf), 27);
+ assert_int_equal(buf[4], '-');
+ assert_int_equal(buf[7], '-');
+ assert_int_equal(buf[10], 'T');
+ assert_int_equal(buf[13], ':');
+ assert_int_equal(buf[16], ':');
+ assert_int_equal(buf[19], '.');
+ assert_int_equal(buf[26], 'Z');
+
+ /* check time conversion correctness */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_settoepoch(&t);
+ isc_time_formatISO8601us(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "1970-01-01T00:00:00.000000Z");
+
+ memset(buf, 'X', sizeof(buf));
+ isc_time_set(&t, 1450000000, 123456000);
+ isc_time_formatISO8601us(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "2015-12-13T09:46:40.123456Z");
+}
+
+/* print local time in ISO8601 */
+
+ISC_RUN_TEST_IMPL(isc_time_formatISO8601L_test) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ UNUSED(state);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ result = isc_time_now(&t);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* check formatting: yyyy-mm-ddThh:mm:ss */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601L(&t, buf, sizeof(buf));
+ assert_int_equal(strlen(buf), 19);
+ assert_int_equal(buf[4], '-');
+ assert_int_equal(buf[7], '-');
+ assert_int_equal(buf[10], 'T');
+ assert_int_equal(buf[13], ':');
+ assert_int_equal(buf[16], ':');
+
+ /* check time conversion correctness */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_settoepoch(&t);
+ isc_time_formatISO8601L(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "1969-12-31T16:00:00");
+
+ memset(buf, 'X', sizeof(buf));
+ isc_time_set(&t, 1450000000, 123000000);
+ isc_time_formatISO8601L(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "2015-12-13T01:46:40");
+}
+
+/* print local time in ISO8601 with milliseconds */
+
+ISC_RUN_TEST_IMPL(isc_time_formatISO8601Lms_test) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ UNUSED(state);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ result = isc_time_now(&t);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* check formatting: yyyy-mm-ddThh:mm:ss.sss */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601Lms(&t, buf, sizeof(buf));
+ assert_int_equal(strlen(buf), 23);
+ assert_int_equal(buf[4], '-');
+ assert_int_equal(buf[7], '-');
+ assert_int_equal(buf[10], 'T');
+ assert_int_equal(buf[13], ':');
+ assert_int_equal(buf[16], ':');
+ assert_int_equal(buf[19], '.');
+
+ /* check time conversion correctness */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_settoepoch(&t);
+ isc_time_formatISO8601Lms(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "1969-12-31T16:00:00.000");
+
+ memset(buf, 'X', sizeof(buf));
+ isc_time_set(&t, 1450000000, 123000000);
+ isc_time_formatISO8601Lms(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "2015-12-13T01:46:40.123");
+}
+
+/* print local time in ISO8601 with microseconds */
+
+ISC_RUN_TEST_IMPL(isc_time_formatISO8601Lus_test) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ UNUSED(state);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ result = isc_time_now_hires(&t);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* check formatting: yyyy-mm-ddThh:mm:ss.ssssss */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatISO8601Lus(&t, buf, sizeof(buf));
+ assert_int_equal(strlen(buf), 26);
+ assert_int_equal(buf[4], '-');
+ assert_int_equal(buf[7], '-');
+ assert_int_equal(buf[10], 'T');
+ assert_int_equal(buf[13], ':');
+ assert_int_equal(buf[16], ':');
+ assert_int_equal(buf[19], '.');
+
+ /* check time conversion correctness */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_settoepoch(&t);
+ isc_time_formatISO8601Lus(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "1969-12-31T16:00:00.000000");
+
+ memset(buf, 'X', sizeof(buf));
+ isc_time_set(&t, 1450000000, 123456000);
+ isc_time_formatISO8601Lus(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "2015-12-13T01:46:40.123456");
+}
+
+/* print UTC time as yyyymmddhhmmsssss */
+
+ISC_RUN_TEST_IMPL(isc_time_formatshorttimestamp_test) {
+ isc_result_t result;
+ isc_time_t t;
+ char buf[64];
+
+ UNUSED(state);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ result = isc_time_now(&t);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /* check formatting: yyyymmddhhmmsssss */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_formatshorttimestamp(&t, buf, sizeof(buf));
+ assert_int_equal(strlen(buf), 17);
+
+ /* check time conversion correctness */
+ memset(buf, 'X', sizeof(buf));
+ isc_time_settoepoch(&t);
+ isc_time_formatshorttimestamp(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "19700101000000000");
+
+ memset(buf, 'X', sizeof(buf));
+ isc_time_set(&t, 1450000000, 123000000);
+ isc_time_formatshorttimestamp(&t, buf, sizeof(buf));
+ assert_string_equal(buf, "20151213094640123");
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(isc_time_add_test)
+ISC_TEST_ENTRY(isc_time_sub_test)
+ISC_TEST_ENTRY(isc_time_parsehttptimestamp_test)
+ISC_TEST_ENTRY(isc_time_formatISO8601_test)
+ISC_TEST_ENTRY(isc_time_formatISO8601ms_test)
+ISC_TEST_ENTRY(isc_time_formatISO8601us_test)
+ISC_TEST_ENTRY(isc_time_formatISO8601L_test)
+ISC_TEST_ENTRY(isc_time_formatISO8601Lms_test)
+ISC_TEST_ENTRY(isc_time_formatISO8601Lus_test)
+ISC_TEST_ENTRY(isc_time_formatshorttimestamp_test)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/timer_test.c b/tests/isc/timer_test.c
new file mode 100644
index 0000000..644018a
--- /dev/null
+++ b/tests/isc/timer_test.c
@@ -0,0 +1,599 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/atomic.h>
+#include <isc/commandline.h>
+#include <isc/condition.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include "netmgr/uv-compat.h"
+#include "timer.c"
+
+#include <tests/isc.h>
+
+/* Set to true (or use -v option) for verbose output */
+static bool verbose = false;
+
+#define FUDGE_SECONDS 0 /* in absence of clock_getres() */
+#define FUDGE_NANOSECONDS 500000000 /* in absence of clock_getres() */
+
+static isc_timer_t *timer = NULL;
+static isc_condition_t cv;
+static isc_mutex_t mx;
+static isc_time_t endtime;
+static isc_mutex_t lasttime_mx;
+static isc_time_t lasttime;
+static int seconds;
+static int nanoseconds;
+static atomic_int_fast32_t eventcnt;
+static atomic_uint_fast32_t errcnt;
+static int nevents;
+
+static int
+_setup(void **state) {
+ atomic_init(&errcnt, ISC_R_SUCCESS);
+
+ setup_managers(state);
+
+ return (0);
+}
+
+static int
+_teardown(void **state) {
+ teardown_managers(state);
+
+ return (0);
+}
+
+static void
+test_shutdown(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+
+ UNUSED(task);
+
+ /*
+ * Signal shutdown processing complete.
+ */
+ result = isc_mutex_lock(&mx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_condition_signal(&cv);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_mutex_unlock(&mx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_event_free(&event);
+}
+
+static void
+setup_test(isc_timertype_t timertype, isc_time_t *expires,
+ isc_interval_t *interval,
+ void (*action)(isc_task_t *, isc_event_t *)) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+ isc_time_settoepoch(&endtime);
+ atomic_init(&eventcnt, 0);
+
+ isc_mutex_init(&mx);
+ isc_mutex_init(&lasttime_mx);
+
+ isc_condition_init(&cv);
+
+ atomic_store(&errcnt, ISC_R_SUCCESS);
+
+ LOCK(&mx);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task, test_shutdown, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_mutex_lock(&lasttime_mx);
+ result = isc_time_now(&lasttime);
+ isc_mutex_unlock(&lasttime_mx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_timer_create(timermgr, timertype, expires, interval, task,
+ action, (void *)timertype, &timer);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (atomic_load(&eventcnt) != nevents) {
+ result = isc_condition_wait(&cv, &mx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ UNLOCK(&mx);
+
+ assert_int_equal(atomic_load(&errcnt), ISC_R_SUCCESS);
+
+ isc_task_detach(&task);
+ isc_mutex_destroy(&mx);
+ isc_mutex_destroy(&lasttime_mx);
+ (void)isc_condition_destroy(&cv);
+}
+
+static void
+set_global_error(isc_result_t result) {
+ (void)atomic_compare_exchange_strong(
+ &errcnt, &(uint_fast32_t){ ISC_R_SUCCESS }, result);
+}
+
+static void
+subthread_assert_true(bool expected, const char *file, unsigned int line) {
+ if (!expected) {
+ printf("# %s:%u subthread_assert_true\n", file, line);
+ set_global_error(ISC_R_UNEXPECTED);
+ }
+}
+#define subthread_assert_true(expected) \
+ subthread_assert_true(expected, __FILE__, __LINE__)
+
+static void
+subthread_assert_int_equal(int observed, int expected, const char *file,
+ unsigned int line) {
+ if (observed != expected) {
+ printf("# %s:%u subthread_assert_int_equal(%d != %d)\n", file,
+ line, observed, expected);
+ set_global_error(ISC_R_UNEXPECTED);
+ }
+}
+#define subthread_assert_int_equal(observed, expected) \
+ subthread_assert_int_equal(observed, expected, __FILE__, __LINE__)
+
+static void
+subthread_assert_result_equal(isc_result_t result, isc_result_t expected,
+ const char *file, unsigned int line) {
+ if (result != expected) {
+ printf("# %s:%u subthread_assert_result_equal(%u != %u)\n",
+ file, line, (unsigned int)result,
+ (unsigned int)expected);
+ set_global_error(result);
+ }
+}
+#define subthread_assert_result_equal(observed, expected) \
+ subthread_assert_result_equal(observed, expected, __FILE__, __LINE__)
+
+static void
+ticktock(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ isc_time_t now;
+ isc_time_t base;
+ isc_time_t ulim;
+ isc_time_t llim;
+ isc_interval_t interval;
+ isc_eventtype_t expected_event_type;
+
+ int tick = atomic_fetch_add(&eventcnt, 1);
+
+ if (verbose) {
+ print_message("# tick %d\n", tick);
+ }
+
+ expected_event_type = ISC_TIMEREVENT_LIFE;
+ if ((uintptr_t)event->ev_arg == isc_timertype_ticker) {
+ expected_event_type = ISC_TIMEREVENT_TICK;
+ }
+
+ if (event->ev_type != expected_event_type) {
+ print_error("# expected event type %u, got %u\n",
+ expected_event_type, event->ev_type);
+ }
+
+ result = isc_time_now(&now);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ isc_mutex_lock(&lasttime_mx);
+ result = isc_time_add(&lasttime, &interval, &base);
+ isc_mutex_unlock(&lasttime_mx);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, FUDGE_SECONDS, FUDGE_NANOSECONDS);
+ result = isc_time_add(&base, &interval, &ulim);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ result = isc_time_subtract(&base, &interval, &llim);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ subthread_assert_true(isc_time_compare(&llim, &now) <= 0);
+ subthread_assert_true(isc_time_compare(&ulim, &now) >= 0);
+
+ isc_interval_set(&interval, 0, 0);
+ isc_mutex_lock(&lasttime_mx);
+ result = isc_time_add(&now, &interval, &lasttime);
+ isc_mutex_unlock(&lasttime_mx);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ isc_event_free(&event);
+
+ if (atomic_load(&eventcnt) == nevents) {
+ result = isc_time_now(&endtime);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+ isc_timer_destroy(&timer);
+ isc_task_shutdown(task);
+ }
+}
+
+/*
+ * Individual unit tests
+ */
+
+/* timer type ticker */
+ISC_RUN_TEST_IMPL(ticker) {
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(state);
+
+ nevents = 12;
+ seconds = 0;
+ nanoseconds = 500000000;
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ isc_time_settoepoch(&expires);
+
+ setup_test(isc_timertype_ticker, &expires, &interval, ticktock);
+}
+
+/* timer type once reaches lifetime */
+ISC_RUN_TEST_IMPL(once_life) {
+ isc_result_t result;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(state);
+
+ nevents = 1;
+ seconds = 1;
+ nanoseconds = 100000000;
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ result = isc_time_nowplusinterval(&expires, &interval);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, 0, 0);
+
+ setup_test(isc_timertype_once, &expires, &interval, ticktock);
+}
+
+static void
+test_idle(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ isc_time_t now;
+ isc_time_t base;
+ isc_time_t ulim;
+ isc_time_t llim;
+ isc_interval_t interval;
+
+ int tick = atomic_fetch_add(&eventcnt, 1);
+
+ if (verbose) {
+ print_message("# tick %d\n", tick);
+ }
+
+ result = isc_time_now(&now);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ isc_mutex_lock(&lasttime_mx);
+ result = isc_time_add(&lasttime, &interval, &base);
+ isc_mutex_unlock(&lasttime_mx);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, FUDGE_SECONDS, FUDGE_NANOSECONDS);
+ result = isc_time_add(&base, &interval, &ulim);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ result = isc_time_subtract(&base, &interval, &llim);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ subthread_assert_true(isc_time_compare(&llim, &now) <= 0);
+ subthread_assert_true(isc_time_compare(&ulim, &now) >= 0);
+
+ isc_interval_set(&interval, 0, 0);
+ isc_mutex_lock(&lasttime_mx);
+ isc_time_add(&now, &interval, &lasttime);
+ isc_mutex_unlock(&lasttime_mx);
+
+ subthread_assert_int_equal(event->ev_type, ISC_TIMEREVENT_IDLE);
+
+ isc_event_free(&event);
+
+ isc_timer_destroy(&timer);
+ isc_task_shutdown(task);
+}
+
+/* timer type once idles out */
+ISC_RUN_TEST_IMPL(once_idle) {
+ isc_result_t result;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(state);
+
+ nevents = 1;
+ seconds = 1;
+ nanoseconds = 200000000;
+
+ isc_interval_set(&interval, seconds + 1, nanoseconds);
+ result = isc_time_nowplusinterval(&expires, &interval);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+
+ setup_test(isc_timertype_once, &expires, &interval, test_idle);
+}
+
+/* timer reset */
+static void
+test_reset(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ isc_time_t now;
+ isc_time_t base;
+ isc_time_t ulim;
+ isc_time_t llim;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ int tick = atomic_fetch_add(&eventcnt, 1);
+
+ if (verbose) {
+ print_message("# tick %d\n", tick);
+ }
+
+ /*
+ * Check expired time.
+ */
+
+ result = isc_time_now(&now);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ isc_mutex_lock(&lasttime_mx);
+ result = isc_time_add(&lasttime, &interval, &base);
+ isc_mutex_unlock(&lasttime_mx);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, FUDGE_SECONDS, FUDGE_NANOSECONDS);
+ result = isc_time_add(&base, &interval, &ulim);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ result = isc_time_subtract(&base, &interval, &llim);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ subthread_assert_true(isc_time_compare(&llim, &now) <= 0);
+ subthread_assert_true(isc_time_compare(&ulim, &now) >= 0);
+
+ isc_interval_set(&interval, 0, 0);
+ isc_mutex_lock(&lasttime_mx);
+ isc_time_add(&now, &interval, &lasttime);
+ isc_mutex_unlock(&lasttime_mx);
+
+ int _eventcnt = atomic_load(&eventcnt);
+
+ if (_eventcnt < 3) {
+ subthread_assert_int_equal(event->ev_type, ISC_TIMEREVENT_TICK);
+
+ if (_eventcnt == 2) {
+ isc_interval_set(&interval, seconds, nanoseconds);
+ result = isc_time_nowplusinterval(&expires, &interval);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, 0, 0);
+ result = isc_timer_reset(timer, isc_timertype_once,
+ &expires, &interval, false);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+ }
+
+ isc_event_free(&event);
+ } else {
+ subthread_assert_int_equal(event->ev_type, ISC_TIMEREVENT_LIFE);
+
+ isc_event_free(&event);
+ isc_timer_destroy(&timer);
+ isc_task_shutdown(task);
+ }
+}
+
+ISC_RUN_TEST_IMPL(reset) {
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(state);
+
+ nevents = 3;
+ seconds = 0;
+ nanoseconds = 750000000;
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ isc_time_settoepoch(&expires);
+
+ setup_test(isc_timertype_ticker, &expires, &interval, test_reset);
+}
+
+static atomic_bool startflag;
+static atomic_bool shutdownflag;
+static isc_timer_t *tickertimer = NULL;
+static isc_timer_t *oncetimer = NULL;
+static isc_task_t *task1 = NULL;
+static isc_task_t *task2 = NULL;
+
+/*
+ * task1 blocks on mx while events accumulate
+ * in its queue, until signaled by task2.
+ */
+
+static void
+tick_event(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(task);
+
+ if (!atomic_load(&startflag)) {
+ if (verbose) {
+ print_message("# tick_event %d\n", -1);
+ }
+ isc_event_free(&event);
+ return;
+ }
+
+ int tick = atomic_fetch_add(&eventcnt, 1);
+ if (verbose) {
+ print_message("# tick_event %d\n", tick);
+ }
+
+ /*
+ * On the first tick, purge all remaining tick events
+ * and then shut down the task.
+ */
+ if (tick == 0) {
+ isc_time_settoepoch(&expires);
+ isc_interval_set(&interval, seconds, 0);
+ result = isc_timer_reset(tickertimer, isc_timertype_ticker,
+ &expires, &interval, true);
+ subthread_assert_result_equal(result, ISC_R_SUCCESS);
+
+ isc_task_shutdown(task);
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+once_event(isc_task_t *task, isc_event_t *event) {
+ if (verbose) {
+ print_message("# once_event\n");
+ }
+
+ /*
+ * Allow task1 to start processing events.
+ */
+ atomic_store(&startflag, true);
+
+ isc_event_free(&event);
+ isc_task_shutdown(task);
+}
+
+static void
+shutdown_purge(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+ UNUSED(event);
+
+ if (verbose) {
+ print_message("# shutdown_event\n");
+ }
+
+ /*
+ * Signal shutdown processing complete.
+ */
+ atomic_store(&shutdownflag, 1);
+
+ isc_event_free(&event);
+}
+
+/* timer events purged */
+ISC_RUN_TEST_IMPL(purge) {
+ isc_result_t result;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(state);
+
+ atomic_init(&startflag, 0);
+ atomic_init(&shutdownflag, 0);
+ atomic_init(&eventcnt, 0);
+ seconds = 1;
+ nanoseconds = 0;
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task1, shutdown_purge, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_time_settoepoch(&expires);
+ isc_interval_set(&interval, seconds, 0);
+
+ tickertimer = NULL;
+ result = isc_timer_create(timermgr, isc_timertype_ticker, &expires,
+ &interval, task1, tick_event, NULL,
+ &tickertimer);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ oncetimer = NULL;
+
+ isc_interval_set(&interval, (seconds * 2) + 1, 0);
+ result = isc_time_nowplusinterval(&expires, &interval);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, 0, 0);
+ result = isc_timer_create(timermgr, isc_timertype_once, &expires,
+ &interval, task2, once_event, NULL,
+ &oncetimer);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (!atomic_load(&shutdownflag)) {
+ uv_sleep(1);
+ }
+
+ assert_int_equal(atomic_load(&errcnt), ISC_R_SUCCESS);
+
+ assert_int_equal(atomic_load(&eventcnt), 1);
+
+ isc_timer_destroy(&tickertimer);
+ isc_timer_destroy(&oncetimer);
+ isc_task_destroy(&task1);
+ isc_task_destroy(&task2);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(ticker, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(once_life, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(once_idle, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(reset, _setup, _teardown)
+ISC_TEST_ENTRY_CUSTOM(purge, _setup, _teardown)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/isc/uv_wrap.h b/tests/isc/uv_wrap.h
new file mode 100644
index 0000000..5c557b8
--- /dev/null
+++ b/tests/isc/uv_wrap.h
@@ -0,0 +1,327 @@
+/*
+ * 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
+
+#if HAVE_CMOCKA
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <uv.h>
+
+#include <isc/atomic.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include "../netmgr/uv-compat.h"
+
+/* uv_udp_t */
+
+int
+__wrap_uv_udp_open(uv_udp_t *handle, uv_os_sock_t sock);
+int
+__wrap_uv_udp_bind(uv_udp_t *handle, const struct sockaddr *addr,
+ unsigned int flags);
+#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
+int
+__wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr);
+int
+__wrap_uv_udp_getpeername(const uv_udp_t *handle, struct sockaddr *name,
+ int *namelen);
+#endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
+int
+__wrap_uv_udp_getsockname(const uv_udp_t *handle, struct sockaddr *name,
+ int *namelen);
+int
+__wrap_uv_udp_send(uv_udp_send_t *req, uv_udp_t *handle, const uv_buf_t bufs[],
+ unsigned int nbufs, const struct sockaddr *addr,
+ uv_udp_send_cb send_cb);
+int
+__wrap_uv_udp_recv_start(uv_udp_t *handle, uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb);
+int
+__wrap_uv_udp_recv_stop(uv_udp_t *handle);
+
+/* uv_tcp_t */
+int
+__wrap_uv_tcp_open(uv_tcp_t *handle, uv_os_sock_t sock);
+int
+__wrap_uv_tcp_bind(uv_tcp_t *handle, const struct sockaddr *addr,
+ unsigned int flags);
+int
+__wrap_uv_tcp_getsockname(const uv_tcp_t *handle, struct sockaddr *name,
+ int *namelen);
+int
+__wrap_uv_tcp_getpeername(const uv_tcp_t *handle, struct sockaddr *name,
+ int *namelen);
+int
+__wrap_uv_tcp_connect(uv_connect_t *req, uv_tcp_t *handle,
+ const struct sockaddr *addr, uv_connect_cb cb);
+
+/* uv_stream_t */
+int
+__wrap_uv_listen(uv_stream_t *stream, int backlog, uv_connection_cb cb);
+int
+__wrap_uv_accept(uv_stream_t *server, uv_stream_t *client);
+
+/* uv_handle_t */
+int
+__wrap_uv_send_buffer_size(uv_handle_t *handle, int *value);
+int
+__wrap_uv_recv_buffer_size(uv_handle_t *handle, int *value);
+int
+__wrap_uv_fileno(const uv_handle_t *handle, uv_os_fd_t *fd);
+
+/* uv_timer_t */
+/* FIXME */
+/*
+ * uv_timer_init
+ * uv_timer_start
+ */
+
+static atomic_int __state_uv_udp_open = 0;
+
+int
+__wrap_uv_udp_open(uv_udp_t *handle, uv_os_sock_t sock) {
+ if (atomic_load(&__state_uv_udp_open) == 0) {
+ return (uv_udp_open(handle, sock));
+ }
+ return (atomic_load(&__state_uv_udp_open));
+}
+
+static atomic_int __state_uv_udp_bind = 0;
+
+int
+__wrap_uv_udp_bind(uv_udp_t *handle, const struct sockaddr *addr,
+ unsigned int flags) {
+ if (atomic_load(&__state_uv_udp_bind) == 0) {
+ return (uv_udp_bind(handle, addr, flags));
+ }
+ return (atomic_load(&__state_uv_udp_bind));
+}
+
+static atomic_int __state_uv_udp_connect __attribute__((unused)) = 0;
+
+#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
+int
+__wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
+ if (atomic_load(&__state_uv_udp_connect) == 0) {
+ return (uv_udp_connect(handle, addr));
+ }
+ return (atomic_load(&__state_uv_udp_connect));
+}
+#endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
+
+static atomic_int __state_uv_udp_getpeername __attribute__((unused)) = 0;
+
+#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
+int
+__wrap_uv_udp_getpeername(const uv_udp_t *handle, struct sockaddr *name,
+ int *namelen) {
+ if (atomic_load(&__state_uv_udp_getpeername) == 0) {
+ return (uv_udp_getpeername(handle, name, namelen));
+ }
+ return (atomic_load(&__state_uv_udp_getpeername));
+}
+#endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
+
+static atomic_int __state_uv_udp_getsockname = 0;
+int
+__wrap_uv_udp_getsockname(const uv_udp_t *handle, struct sockaddr *name,
+ int *namelen) {
+ if (atomic_load(&__state_uv_udp_getsockname) == 0) {
+ return (uv_udp_getsockname(handle, name, namelen));
+ }
+ return (atomic_load(&__state_uv_udp_getsockname));
+}
+
+static atomic_int __state_uv_udp_send = 0;
+int
+__wrap_uv_udp_send(uv_udp_send_t *req, uv_udp_t *handle, const uv_buf_t bufs[],
+ unsigned int nbufs, const struct sockaddr *addr,
+ uv_udp_send_cb send_cb) {
+ if (atomic_load(&__state_uv_udp_send) == 0) {
+ return (uv_udp_send(req, handle, bufs, nbufs, addr, send_cb));
+ }
+ return (atomic_load(&__state_uv_udp_send));
+}
+
+static atomic_int __state_uv_udp_recv_start = 0;
+int
+__wrap_uv_udp_recv_start(uv_udp_t *handle, uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ if (atomic_load(&__state_uv_udp_recv_start) == 0) {
+ return (uv_udp_recv_start(handle, alloc_cb, recv_cb));
+ }
+ return (atomic_load(&__state_uv_udp_recv_start));
+}
+
+static atomic_int __state_uv_udp_recv_stop = 0;
+int
+__wrap_uv_udp_recv_stop(uv_udp_t *handle) {
+ if (atomic_load(&__state_uv_udp_recv_stop) == 0) {
+ return (uv_udp_recv_stop(handle));
+ }
+ return (atomic_load(&__state_uv_udp_recv_stop));
+}
+
+static atomic_int __state_uv_tcp_open = 0;
+int
+__wrap_uv_tcp_open(uv_tcp_t *handle, uv_os_sock_t sock) {
+ if (atomic_load(&__state_uv_tcp_open) == 0) {
+ return (uv_tcp_open(handle, sock));
+ }
+ return (atomic_load(&__state_uv_tcp_open));
+}
+
+static atomic_int __state_uv_tcp_bind = 0;
+int
+__wrap_uv_tcp_bind(uv_tcp_t *handle, const struct sockaddr *addr,
+ unsigned int flags) {
+ if (atomic_load(&__state_uv_tcp_bind) == 0) {
+ return (uv_tcp_bind(handle, addr, flags));
+ }
+ return (atomic_load(&__state_uv_tcp_bind));
+}
+
+static atomic_int __state_uv_tcp_getsockname = 0;
+int
+__wrap_uv_tcp_getsockname(const uv_tcp_t *handle, struct sockaddr *name,
+ int *namelen) {
+ if (atomic_load(&__state_uv_tcp_getsockname) == 0) {
+ return (uv_tcp_getsockname(handle, name, namelen));
+ }
+ return (atomic_load(&__state_uv_tcp_getsockname));
+}
+
+static atomic_int __state_uv_tcp_getpeername = 0;
+int
+__wrap_uv_tcp_getpeername(const uv_tcp_t *handle, struct sockaddr *name,
+ int *namelen) {
+ if (atomic_load(&__state_uv_tcp_getpeername) == 0) {
+ return (uv_tcp_getpeername(handle, name, namelen));
+ }
+ return (atomic_load(&__state_uv_tcp_getpeername));
+}
+
+static atomic_int __state_uv_tcp_connect = 0;
+int
+__wrap_uv_tcp_connect(uv_connect_t *req, uv_tcp_t *handle,
+ const struct sockaddr *addr, uv_connect_cb cb) {
+ if (atomic_load(&__state_uv_tcp_connect) == 0) {
+ return (uv_tcp_connect(req, handle, addr, cb));
+ }
+ return (atomic_load(&__state_uv_tcp_connect));
+}
+
+static atomic_int __state_uv_listen = 0;
+int
+__wrap_uv_listen(uv_stream_t *stream, int backlog, uv_connection_cb cb) {
+ if (atomic_load(&__state_uv_listen) == 0) {
+ return (uv_listen(stream, backlog, cb));
+ }
+ return (atomic_load(&__state_uv_listen));
+}
+
+static atomic_int __state_uv_accept = 0;
+int
+__wrap_uv_accept(uv_stream_t *server, uv_stream_t *client) {
+ if (atomic_load(&__state_uv_accept) == 0) {
+ return (uv_accept(server, client));
+ }
+ return (atomic_load(&__state_uv_accept));
+}
+
+static atomic_int __state_uv_send_buffer_size = 0;
+int
+__wrap_uv_send_buffer_size(uv_handle_t *handle, int *value) {
+ if (atomic_load(&__state_uv_send_buffer_size) == 0) {
+ return (uv_send_buffer_size(handle, value));
+ }
+ return (atomic_load(&__state_uv_send_buffer_size));
+}
+
+static atomic_int __state_uv_recv_buffer_size = 0;
+int
+__wrap_uv_recv_buffer_size(uv_handle_t *handle, int *value) {
+ if (atomic_load(&__state_uv_recv_buffer_size) == 0) {
+ return (uv_recv_buffer_size(handle, value));
+ }
+ return (atomic_load(&__state_uv_recv_buffer_size));
+}
+
+static atomic_int __state_uv_fileno = 0;
+int
+__wrap_uv_fileno(const uv_handle_t *handle, uv_os_fd_t *fd) {
+ if (atomic_load(&__state_uv_fileno) == 0) {
+ return (uv_fileno(handle, fd));
+ }
+ return (atomic_load(&__state_uv_fileno));
+}
+
+#define uv_udp_open(...) __wrap_uv_udp_open(__VA_ARGS__)
+#define uv_udp_bind(...) __wrap_uv_udp_bind(__VA_ARGS__)
+#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
+#define uv_udp_connect(...) __wrap_uv_udp_connect(__VA_ARGS__)
+#define uv_udp_getpeername(...) __wrap_uv_udp_getpeername(__VA_ARGS__)
+#endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
+#define uv_udp_getsockname(...) __wrap_uv_udp_getsockname(__VA_ARGS__)
+#define uv_udp_send(...) __wrap_uv_udp_send(__VA_ARGS__)
+#define uv_udp_recv_start(...) __wrap_uv_udp_recv_start(__VA_ARGS__)
+#define uv_udp_recv_stop(...) __wrap_uv_udp_recv_stop(__VA_ARGS__)
+
+#define uv_tcp_open(...) __wrap_uv_tcp_open(__VA_ARGS__)
+#define uv_tcp_bind(...) __wrap_uv_tcp_bind(__VA_ARGS__)
+#define uv_tcp_getsockname(...) __wrap_uv_tcp_getsockname(__VA_ARGS__)
+#define uv_tcp_getpeername(...) __wrap_uv_tcp_getpeername(__VA_ARGS__)
+#define uv_tcp_connect(...) __wrap_uv_tcp_connect(__VA_ARGS__)
+
+#define uv_listen(...) __wrap_uv_listen(__VA_ARGS__)
+#define uv_accept(...) __wrap_uv_accept(__VA_ARGS__)
+
+#define uv_send_buffer_size(...) __wrap_uv_send_buffer_size(__VA_ARGS__)
+#define uv_recv_buffer_size(...) __wrap_uv_recv_buffer_size(__VA_ARGS__)
+#define uv_fileno(...) __wrap_uv_fileno(__VA_ARGS__)
+
+#define RESET_RETURN \
+ { \
+ atomic_store(&__state_uv_udp_open, 0); \
+ atomic_store(&__state_uv_udp_bind, 0); \
+ atomic_store(&__state_uv_udp_connect, 0); \
+ atomic_store(&__state_uv_udp_getpeername, 0); \
+ atomic_store(&__state_uv_udp_getsockname, 0); \
+ atomic_store(&__state_uv_udp_send, 0); \
+ atomic_store(&__state_uv_udp_recv_start, 0); \
+ atomic_store(&__state_uv_udp_recv_stop, 0); \
+ atomic_store(&__state_uv_tcp_open, 0); \
+ atomic_store(&__state_uv_tcp_bind, 0); \
+ atomic_store(&__state_uv_tcp_getpeername, 0); \
+ atomic_store(&__state_uv_tcp_getsockname, 0); \
+ atomic_store(&__state_uv_tcp_connect, 0); \
+ atomic_store(&__state_uv_listen, 0); \
+ atomic_store(&__state_uv_accept, 0); \
+ atomic_store(&__state_uv_send_buffer_size, 0); \
+ atomic_store(&__state_uv_recv_buffer_size, 0); \
+ atomic_store(&__state_uv_fileno, 0); \
+ }
+
+#define WILL_RETURN(func, value) atomic_store(&__state_##func, value)
+
+#endif /* HAVE_CMOCKA */
diff --git a/tests/isccfg/Makefile.am b/tests/isccfg/Makefile.am
new file mode 100644
index 0000000..5a6fb03
--- /dev/null
+++ b/tests/isccfg/Makefile.am
@@ -0,0 +1,20 @@
+include $(top_srcdir)/Makefile.top
+
+AM_CPPFLAGS += \
+ $(LIBISC_CFLAGS) \
+ $(LIBDNS_CFLAGS) \
+ $(LIBISCCFG_CFLAGS) \
+ $(LIBUV_CFLAGS) \
+ -I$(top_srcdir)/lib/isc
+
+LDADD += \
+ $(LIBISC_LIBS) \
+ $(LIBDNS_LIBS) \
+ $(LIBISCCFG_LIBS) \
+ $(LIBUV_LIBS)
+
+check_PROGRAMS = \
+ duration_test \
+ parser_test
+
+include $(top_srcdir)/Makefile.tests
diff --git a/tests/isccfg/Makefile.in b/tests/isccfg/Makefile.in
new file mode 100644
index 0000000..712138a
--- /dev/null
+++ b/tests/isccfg/Makefile.in
@@ -0,0 +1,1174 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HOST_MACOS_TRUE@am__append_1 = \
+@HOST_MACOS_TRUE@ -Wl,-flat_namespace
+
+check_PROGRAMS = duration_test$(EXEEXT) parser_test$(EXEEXT)
+subdir = tests/isccfg
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4/ax_jemalloc.m4 \
+ $(top_srcdir)/m4/ax_lib_lmdb.m4 \
+ $(top_srcdir)/m4/ax_perl_module.m4 \
+ $(top_srcdir)/m4/ax_posix_shell.m4 \
+ $(top_srcdir)/m4/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_python_module.m4 \
+ $(top_srcdir)/m4/ax_restore_flags.m4 \
+ $(top_srcdir)/m4/ax_save_flags.m4 $(top_srcdir)/m4/ax_tls.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+duration_test_SOURCES = duration_test.c
+duration_test_OBJECTS = duration_test.$(OBJEXT)
+duration_test_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+duration_test_DEPENDENCIES = $(LIBISC_LIBS) $(LIBDNS_LIBS) \
+ $(LIBISCCFG_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+parser_test_SOURCES = parser_test.c
+parser_test_OBJECTS = parser_test.$(OBJEXT)
+parser_test_LDADD = $(LDADD)
+parser_test_DEPENDENCIES = $(LIBISC_LIBS) $(LIBDNS_LIBS) \
+ $(LIBISCCFG_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/duration_test.Po \
+ ./$(DEPDIR)/parser_test.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = duration_test.c parser_test.c
+DIST_SOURCES = duration_test.c parser_test.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = test-recursive unit-recursive \
+ doc-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/Makefile.tests \
+ $(top_srcdir)/Makefile.top $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CMOCKA_CFLAGS = @CMOCKA_CFLAGS@
+CMOCKA_LIBS = @CMOCKA_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURL = @CURL@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEVELOPER_MODE = @DEVELOPER_MODE@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FSTRM_CAPTURE = @FSTRM_CAPTURE@
+FUZZ_LDFLAGS = @FUZZ_LDFLAGS@
+FUZZ_LOG_COMPILER = @FUZZ_LOG_COMPILER@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@
+JEMALLOC_LIBS = @JEMALLOC_LIBS@
+JSON_C_CFLAGS = @JSON_C_CFLAGS@
+JSON_C_LIBS = @JSON_C_LIBS@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_CONFIG = @KRB5_CONFIG@
+KRB5_LIBS = @KRB5_LIBS@
+LATEXMK = @LATEXMK@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBNGHTTP2_CFLAGS = @LIBNGHTTP2_CFLAGS@
+LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUV_CFLAGS = @LIBUV_CFLAGS@
+LIBUV_LIBS = @LIBUV_LIBS@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIPO = @LIPO@
+LMDB_CFLAGS = @LMDB_CFLAGS@
+LMDB_LIBS = @LMDB_LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAXMINDDB_CFLAGS = @MAXMINDDB_CFLAGS@
+MAXMINDDB_LIBS = @MAXMINDDB_LIBS@
+MAXMINDDB_PREFIX = @MAXMINDDB_PREFIX@
+MKDIR_P = @MKDIR_P@
+NC = @NC@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTEST = @PYTEST@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+READLINE_CFLAGS = @READLINE_CFLAGS@
+READLINE_LIBS = @READLINE_LIBS@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINX_BUILD = @SPHINX_BUILD@
+STD_CFLAGS = @STD_CFLAGS@
+STD_CPPFLAGS = @STD_CPPFLAGS@
+STD_LDFLAGS = @STD_LDFLAGS@
+STRIP = @STRIP@
+TEST_CFLAGS = @TEST_CFLAGS@
+VERSION = @VERSION@
+XELATEX = @XELATEX@
+XSLTPROC = @XSLTPROC@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
+AM_CFLAGS = $(STD_CFLAGS) -I$(top_srcdir)/tests/include $(TEST_CFLAGS)
+AM_CPPFLAGS = $(STD_CPPFLAGS) -include $(top_builddir)/config.h \
+ -I$(srcdir)/include $(LIBISC_CFLAGS) $(LIBDNS_CFLAGS) \
+ $(LIBISCCFG_CFLAGS) $(LIBUV_CFLAGS) -I$(top_srcdir)/lib/isc \
+ $(CMOCKA_CFLAGS) -DNAMED_PLUGINDIR=\"$(pkglibdir)\" \
+ -DTESTS_DIR=\"$(abs_srcdir)\"
+AM_LDFLAGS = $(STD_LDFLAGS) $(am__append_1)
+LDADD = $(LIBISC_LIBS) $(LIBDNS_LIBS) $(LIBISCCFG_LIBS) $(LIBUV_LIBS) \
+ $(top_builddir)/tests/libtest/libtest.la $(CMOCKA_LIBS)
+LIBISC_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib/isc/include \
+ -I$(top_builddir)/lib/isc/include
+
+LIBISC_LIBS = $(top_builddir)/lib/isc/libisc.la
+LIBDNS_CFLAGS = \
+ -I$(top_srcdir)/lib/dns/include \
+ -I$(top_builddir)/lib/dns/include
+
+LIBDNS_LIBS = \
+ $(top_builddir)/lib/dns/libdns.la
+
+LIBNS_CFLAGS = \
+ -I$(top_srcdir)/lib/ns/include
+
+LIBNS_LIBS = \
+ $(top_builddir)/lib/ns/libns.la
+
+LIBIRS_CFLAGS = \
+ -I$(top_srcdir)/lib/irs/include
+
+LIBIRS_LIBS = \
+ $(top_builddir)/lib/irs/libirs.la
+
+LIBISCCFG_CFLAGS = \
+ -I$(top_srcdir)/lib/isccfg/include
+
+LIBISCCFG_LIBS = \
+ $(top_builddir)/lib/isccfg/libisccfg.la
+
+LIBISCCC_CFLAGS = \
+ -I$(top_srcdir)/lib/isccc/include/
+
+LIBISCCC_LIBS = \
+ $(top_builddir)/lib/isccc/libisccc.la
+
+LIBBIND9_CFLAGS = \
+ -I$(top_srcdir)/lib/bind9/include
+
+LIBBIND9_LIBS = \
+ $(top_builddir)/lib/bind9/libbind9.la
+
+@HAVE_CMOCKA_TRUE@TESTS = $(check_PROGRAMS)
+LOG_COMPILER = $(top_builddir)/tests/unit-test-driver.sh
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/isccfg/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tests/isccfg/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+duration_test$(EXEEXT): $(duration_test_OBJECTS) $(duration_test_DEPENDENCIES) $(EXTRA_duration_test_DEPENDENCIES)
+ @rm -f duration_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(duration_test_OBJECTS) $(duration_test_LDADD) $(LIBS)
+
+parser_test$(EXEEXT): $(parser_test_OBJECTS) $(parser_test_DEPENDENCIES) $(EXTRA_parser_test_DEPENDENCIES)
+ @rm -f parser_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(parser_test_OBJECTS) $(parser_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/duration_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+test-local:
+unit-local:
+doc-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS: $(check_PROGRAMS)
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+duration_test.log: duration_test$(EXEEXT)
+ @p='duration_test$(EXEEXT)'; \
+ b='duration_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser_test.log: parser_test$(EXEEXT)
+ @p='parser_test$(EXEEXT)'; \
+ b='parser_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/duration_test.Po
+ -rm -f ./$(DEPDIR)/parser_test.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+doc: doc-am
+
+doc-am: doc-local
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/duration_test.Po
+ -rm -f ./$(DEPDIR)/parser_test.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+test: test-am
+
+test-am: test-local
+
+uninstall-am:
+
+unit: unit-am
+
+unit-am: unit-local
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-checkPROGRAMS clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir \
+ doc-am doc-local dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am recheck tags tags-am test-am test-local \
+ uninstall uninstall-am unit-am unit-local
+
+.PRECIOUS: Makefile
+
+
+unit-local: check
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/isccfg/duration_test.c b/tests/isccfg/duration_test.c
new file mode 100644
index 0000000..32028a5
--- /dev/null
+++ b/tests/isccfg/duration_test.c
@@ -0,0 +1,244 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <isccfg/cfg.h>
+#include <isccfg/grammar.h>
+#include <isccfg/namedconf.h>
+
+#include <tests/isc.h>
+
+isc_log_t *lctx = NULL;
+static isc_logcategory_t categories[] = { { "", 0 },
+ { "client", 0 },
+ { "network", 0 },
+ { "update", 0 },
+ { "queries", 0 },
+ { "unmatched", 0 },
+ { "update-security", 0 },
+ { "query-errors", 0 },
+ { NULL, 0 } };
+
+ISC_SETUP_TEST_IMPL(group) {
+ 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_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);
+ result = isc_log_usechannel(logconfig, "stderr", NULL, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+ISC_TEARDOWN_TEST_IMPL(group) {
+ if (lctx == NULL) {
+ return (-1);
+ }
+
+ isc_log_setcontext(NULL);
+ isc_log_destroy(&lctx);
+
+ return (0);
+}
+
+struct duration_conf {
+ const char *string;
+ uint32_t time;
+ const char *out;
+};
+typedef struct duration_conf duration_conf_t;
+
+static void
+output(void *closure, const char *text, int textlen) {
+ int r;
+
+ REQUIRE(textlen >= 0 && textlen < CFG_DURATION_MAXLEN);
+
+ r = snprintf(closure, CFG_DURATION_MAXLEN, "%s", text);
+ INSIST(r == textlen);
+}
+
+/* test cfg_obj_asduration() and cfg_print_duration() */
+ISC_RUN_TEST_IMPL(duration) {
+ isc_result_t result;
+ /*
+ * When 'out' is NULL, the printed result is expected to be the same as
+ * the input 'string', compared by ignoring the case of the characters.
+ */
+ duration_conf_t durations[] = {
+ { .string = "unlimited", .time = 0 },
+ { .string = "PT0S", .time = 0 },
+ { .string = "PT42S", .time = 42 },
+ { .string = "PT10m", .time = 600 },
+ { .string = "PT10m4S", .time = 604 },
+ { .string = "PT3600S", .time = 3600 },
+ { .string = "pT2H", .time = 7200 },
+ { .string = "Pt2H3S", .time = 7203 },
+ { .string = "PT2h1m3s", .time = 7263 },
+ { .string = "p7d", .time = 604800 },
+ { .string = "P7DT2h", .time = 612000 },
+ { .string = "P2W", .time = 1209600 },
+ { .string = "P3M", .time = 8035200 },
+ { .string = "P3MT10M", .time = 8035800 },
+ { .string = "p5y", .time = 157680000 },
+ { .string = "P5YT2H", .time = 157687200 },
+ { .string = "P1Y1M1DT1H1M1S", .time = 34304461 },
+ { .string = "P99Y399M999DT3999H9999M2911754S",
+ .time = UINT32_MAX - 1 },
+ { .string = "P99Y399M999DT3999H9999M2911755S",
+ .time = UINT32_MAX },
+ { .string = "P4294967295Y4294967295M4294967295D"
+ "T4294967295H4294967295M4294967295S",
+ .time = UINT32_MAX },
+ { .string = "PT4294967294S", .time = UINT32_MAX - 1 },
+ { .string = "PT4294967295S", .time = UINT32_MAX },
+ { .string = "0", .time = 0 },
+ { .string = "30", .time = 30 },
+ { .string = "42s", .time = 42, .out = "42" },
+ { .string = "10m", .time = 600, .out = "600" },
+ { .string = "2H", .time = 7200, .out = "7200" },
+ { .string = "7d", .time = 604800, .out = "604800" },
+ { .string = "2w", .time = 1209600, .out = "1209600" },
+ { 0 }, /* Indicates that the remaining durations are invalid. */
+ { .string = "PT4Y" },
+ { .string = "P-4Y2M" },
+ { .string = "P5H1M30S" },
+ { .string = "P7Y4W" },
+ { .string = "X7Y4M" },
+ { .string = "T7H4M" },
+ { .string = "1Y6M" },
+ { .string = "PT4294967296S" },
+ { .string = "PT99999999999S" },
+ { .string = "P99999999999Y99999999999M99999999999D"
+ "T99999999999H99999999999M99999999999S" },
+ };
+ isc_buffer_t buf1;
+ cfg_parser_t *p1 = NULL;
+ cfg_obj_t *c1 = NULL;
+ bool must_fail = false;
+
+ for (size_t i = 0; i < ARRAY_SIZE(durations); i++) {
+ const cfg_listelt_t *element;
+ const cfg_obj_t *kasps = NULL;
+ const char cfg_tpl[] =
+ "dnssec-policy \"dp\"\n"
+ "{\nkeys {csk lifetime %s algorithm rsasha256;};\n};\n";
+ char conf[sizeof(cfg_tpl) + CFG_DURATION_MAXLEN] = { 0 };
+ char out[CFG_DURATION_MAXLEN] = { 0 };
+ cfg_printer_t pctx = { .f = output, .closure = out };
+
+ if (durations[i].string == NULL) {
+ must_fail = true;
+ continue;
+ }
+
+ snprintf(&conf[0], sizeof(conf), cfg_tpl, durations[i].string);
+
+ isc_buffer_init(&buf1, conf, strlen(conf) - 1);
+ isc_buffer_add(&buf1, strlen(conf) - 1);
+
+ /* Parse with default line numbering */
+ result = cfg_parser_create(mctx, lctx, &p1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = cfg_parse_buffer(p1, &buf1, "text1", 0,
+ &cfg_type_namedconf, 0, &c1);
+ if (must_fail) {
+ assert_int_equal(result, DNS_R_BADTTL);
+ cfg_parser_destroy(&p1);
+ continue;
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ (void)cfg_map_get(c1, "dnssec-policy", &kasps);
+ assert_non_null(kasps);
+ for (element = cfg_list_first(kasps); element != NULL;
+ element = cfg_list_next(element))
+ {
+ const cfg_listelt_t *key_element;
+ const cfg_obj_t *lifetime = NULL;
+ const cfg_obj_t *keys = NULL;
+ const cfg_obj_t *key = NULL;
+ const cfg_obj_t *kopts = NULL;
+ cfg_obj_t *kconf = cfg_listelt_value(element);
+ int cmp;
+
+ assert_non_null(kconf);
+
+ kopts = cfg_tuple_get(kconf, "options");
+ result = cfg_map_get(kopts, "keys", &keys);
+
+ key_element = cfg_list_first(keys);
+ assert_non_null(key_element);
+
+ key = cfg_listelt_value(key_element);
+ assert_non_null(key);
+
+ lifetime = cfg_tuple_get(key, "lifetime");
+ assert_non_null(lifetime);
+
+ assert_int_equal(durations[i].time,
+ cfg_obj_asduration(lifetime));
+
+ cfg_print_duration_or_unlimited(&pctx, lifetime);
+ cmp = strncasecmp(durations[i].out != NULL
+ ? durations[i].out
+ : durations[i].string,
+ out, strlen(durations[i].string));
+ assert_int_equal(cmp, 0);
+ }
+
+ cfg_obj_destroy(p1, &c1);
+ cfg_parser_destroy(&p1);
+ }
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(duration)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN_CUSTOM(setup_test_group, teardown_test_group)
diff --git a/tests/isccfg/parser_test.c b/tests/isccfg/parser_test.c
new file mode 100644
index 0000000..89a3ba4
--- /dev/null
+++ b/tests/isccfg/parser_test.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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <isccfg/cfg.h>
+#include <isccfg/grammar.h>
+#include <isccfg/namedconf.h>
+
+#include <tests/isc.h>
+
+isc_log_t *lctx = NULL;
+static isc_logcategory_t categories[] = { { "", 0 },
+ { "client", 0 },
+ { "network", 0 },
+ { "update", 0 },
+ { "queries", 0 },
+ { "unmatched", 0 },
+ { "update-security", 0 },
+ { "query-errors", 0 },
+ { NULL, 0 } };
+
+ISC_SETUP_TEST_IMPL(group) {
+ 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_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);
+ result = isc_log_usechannel(logconfig, "stderr", NULL, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+ISC_TEARDOWN_TEST_IMPL(group) {
+ if (lctx == NULL) {
+ return (-1);
+ }
+
+ isc_log_setcontext(NULL);
+ isc_log_destroy(&lctx);
+
+ return (0);
+}
+
+/* mimic calling nzf_append() */
+static void
+append(void *arg, const char *str, int len) {
+ char *buf = arg;
+ size_t l = strlen(buf);
+ snprintf(buf + l, 1024 - l, "%.*s", len, str);
+}
+
+ISC_RUN_TEST_IMPL(addzoneconf) {
+ isc_result_t result;
+ isc_buffer_t b;
+ cfg_parser_t *p = NULL;
+ const char *tests[] = {
+ "zone \"test4.baz\" { type primary; file \"e.db\"; };",
+ "zone \"test/.baz\" { type primary; file \"e.db\"; };",
+ "zone \"test\\\".baz\" { type primary; file \"e.db\"; };",
+ "zone \"test\\.baz\" { type primary; file \"e.db\"; };",
+ "zone \"test\\\\.baz\" { type primary; file \"e.db\"; };",
+ "zone \"test\\032.baz\" { type primary; file \"e.db\"; };",
+ "zone \"test\\010.baz\" { type primary; file \"e.db\"; };"
+ };
+ char buf[1024];
+
+ /* Parse with default line numbering */
+ result = cfg_parser_create(mctx, lctx, &p);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
+ cfg_obj_t *conf = NULL;
+ const cfg_obj_t *obj = NULL, *zlist = NULL;
+
+ isc_buffer_constinit(&b, tests[i], strlen(tests[i]));
+ isc_buffer_add(&b, strlen(tests[i]));
+
+ result = cfg_parse_buffer(p, &b, "text1", 0,
+ &cfg_type_namedconf, 0, &conf);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Mimic calling nzf_append() from bin/named/server.c
+ * and check that the output matches the input.
+ */
+ result = cfg_map_get(conf, "zone", &zlist);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ obj = cfg_listelt_value(cfg_list_first(zlist));
+ assert_ptr_not_equal(obj, NULL);
+
+ strlcpy(buf, "zone ", sizeof(buf));
+ cfg_printx(obj, CFG_PRINTER_ONELINE, append, buf);
+ strlcat(buf, ";", sizeof(buf));
+ assert_string_equal(tests[i], buf);
+
+ cfg_obj_destroy(p, &conf);
+ cfg_parser_reset(p);
+ }
+
+ cfg_parser_destroy(&p);
+}
+
+/* test cfg_parse_buffer() */
+ISC_RUN_TEST_IMPL(parse_buffer) {
+ isc_result_t result;
+ unsigned char text[] = "options\n{\nrecursion yes;\n};\n";
+ isc_buffer_t buf1, buf2;
+ cfg_parser_t *p1 = NULL, *p2 = NULL;
+ cfg_obj_t *c1 = NULL, *c2 = NULL;
+
+ isc_buffer_init(&buf1, &text[0], sizeof(text) - 1);
+ isc_buffer_add(&buf1, sizeof(text) - 1);
+
+ /* Parse with default line numbering */
+ result = cfg_parser_create(mctx, lctx, &p1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = cfg_parse_buffer(p1, &buf1, "text1", 0, &cfg_type_namedconf, 0,
+ &c1);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(p1->line, 5);
+
+ isc_buffer_init(&buf2, &text[0], sizeof(text) - 1);
+ isc_buffer_add(&buf2, sizeof(text) - 1);
+
+ /* Parse with changed line number */
+ result = cfg_parser_create(mctx, lctx, &p2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = cfg_parse_buffer(p2, &buf2, "text2", 100, &cfg_type_namedconf,
+ 0, &c2);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(p2->line, 104);
+
+ cfg_obj_destroy(p1, &c1);
+ cfg_obj_destroy(p2, &c2);
+
+ cfg_parser_destroy(&p1);
+ cfg_parser_destroy(&p2);
+}
+
+/* test cfg_map_firstclause() */
+ISC_RUN_TEST_IMPL(cfg_map_firstclause) {
+ const char *name = NULL;
+ const void *clauses = NULL;
+ unsigned int idx;
+
+ name = cfg_map_firstclause(&cfg_type_zoneopts, &clauses, &idx);
+ assert_non_null(name);
+ assert_non_null(clauses);
+ assert_int_equal(idx, 0);
+}
+
+/* test cfg_map_nextclause() */
+ISC_RUN_TEST_IMPL(cfg_map_nextclause) {
+ const char *name = NULL;
+ const void *clauses = NULL;
+ unsigned int idx;
+
+ name = cfg_map_firstclause(&cfg_type_zoneopts, &clauses, &idx);
+ assert_non_null(name);
+ assert_non_null(clauses);
+ assert_int_equal(idx, ISC_R_SUCCESS);
+
+ do {
+ name = cfg_map_nextclause(&cfg_type_zoneopts, &clauses, &idx);
+ if (name != NULL) {
+ assert_non_null(clauses);
+ } else {
+ assert_null(clauses);
+ assert_int_equal(idx, 0);
+ }
+ } while (name != NULL);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY(addzoneconf)
+ISC_TEST_ENTRY(parse_buffer)
+ISC_TEST_ENTRY(cfg_map_firstclause)
+ISC_TEST_ENTRY(cfg_map_nextclause)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN_CUSTOM(setup_test_group, teardown_test_group)
diff --git a/tests/libtest/Makefile.am b/tests/libtest/Makefile.am
new file mode 100644
index 0000000..6bd4b80
--- /dev/null
+++ b/tests/libtest/Makefile.am
@@ -0,0 +1,25 @@
+include $(top_srcdir)/Makefile.top
+
+AM_CPPFLAGS += \
+ $(LIBISC_CFLAGS) \
+ $(LIBDNS_CFLAGS) \
+ $(LIBNS_CFLAGS) \
+ $(LIBUV_CFLAGS) \
+ -I$(top_srcdir)/lib/isc
+
+LDADD += \
+ $(LIBISC_LIBS) \
+ $(LIBDNS_LIBS) \
+ $(LIBNS_LIBS)
+
+check_LTLIBRARIES = libtest.la
+
+libtest_la_SOURCES = \
+ ../include/tests/dns.h \
+ ../include/tests/isc.h \
+ ../include/tests/ns.h \
+ dns.c \
+ isc.c \
+ ns.c
+
+include $(top_srcdir)/Makefile.tests
diff --git a/tests/libtest/Makefile.in b/tests/libtest/Makefile.in
new file mode 100644
index 0000000..8e89774
--- /dev/null
+++ b/tests/libtest/Makefile.in
@@ -0,0 +1,1157 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HOST_MACOS_TRUE@am__append_1 = \
+@HOST_MACOS_TRUE@ -Wl,-flat_namespace
+
+TESTS =
+subdir = tests/libtest
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4/ax_jemalloc.m4 \
+ $(top_srcdir)/m4/ax_lib_lmdb.m4 \
+ $(top_srcdir)/m4/ax_perl_module.m4 \
+ $(top_srcdir)/m4/ax_posix_shell.m4 \
+ $(top_srcdir)/m4/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_python_module.m4 \
+ $(top_srcdir)/m4/ax_restore_flags.m4 \
+ $(top_srcdir)/m4/ax_save_flags.m4 $(top_srcdir)/m4/ax_tls.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+libtest_la_LIBADD =
+am_libtest_la_OBJECTS = dns.lo isc.lo ns.lo
+libtest_la_OBJECTS = $(am_libtest_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/dns.Plo ./$(DEPDIR)/isc.Plo \
+ ./$(DEPDIR)/ns.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libtest_la_SOURCES)
+DIST_SOURCES = $(libtest_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = test-recursive unit-recursive \
+ doc-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/Makefile.tests \
+ $(top_srcdir)/Makefile.top $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CMOCKA_CFLAGS = @CMOCKA_CFLAGS@
+CMOCKA_LIBS = @CMOCKA_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURL = @CURL@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEVELOPER_MODE = @DEVELOPER_MODE@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FSTRM_CAPTURE = @FSTRM_CAPTURE@
+FUZZ_LDFLAGS = @FUZZ_LDFLAGS@
+FUZZ_LOG_COMPILER = @FUZZ_LOG_COMPILER@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@
+JEMALLOC_LIBS = @JEMALLOC_LIBS@
+JSON_C_CFLAGS = @JSON_C_CFLAGS@
+JSON_C_LIBS = @JSON_C_LIBS@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_CONFIG = @KRB5_CONFIG@
+KRB5_LIBS = @KRB5_LIBS@
+LATEXMK = @LATEXMK@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBNGHTTP2_CFLAGS = @LIBNGHTTP2_CFLAGS@
+LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUV_CFLAGS = @LIBUV_CFLAGS@
+LIBUV_LIBS = @LIBUV_LIBS@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIPO = @LIPO@
+LMDB_CFLAGS = @LMDB_CFLAGS@
+LMDB_LIBS = @LMDB_LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAXMINDDB_CFLAGS = @MAXMINDDB_CFLAGS@
+MAXMINDDB_LIBS = @MAXMINDDB_LIBS@
+MAXMINDDB_PREFIX = @MAXMINDDB_PREFIX@
+MKDIR_P = @MKDIR_P@
+NC = @NC@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTEST = @PYTEST@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+READLINE_CFLAGS = @READLINE_CFLAGS@
+READLINE_LIBS = @READLINE_LIBS@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINX_BUILD = @SPHINX_BUILD@
+STD_CFLAGS = @STD_CFLAGS@
+STD_CPPFLAGS = @STD_CPPFLAGS@
+STD_LDFLAGS = @STD_LDFLAGS@
+STRIP = @STRIP@
+TEST_CFLAGS = @TEST_CFLAGS@
+VERSION = @VERSION@
+XELATEX = @XELATEX@
+XSLTPROC = @XSLTPROC@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
+AM_CFLAGS = $(STD_CFLAGS) -I$(top_srcdir)/tests/include $(TEST_CFLAGS)
+AM_CPPFLAGS = $(STD_CPPFLAGS) -include $(top_builddir)/config.h \
+ -I$(srcdir)/include $(LIBISC_CFLAGS) $(LIBDNS_CFLAGS) \
+ $(LIBNS_CFLAGS) $(LIBUV_CFLAGS) -I$(top_srcdir)/lib/isc \
+ $(CMOCKA_CFLAGS) -DNAMED_PLUGINDIR=\"$(pkglibdir)\" \
+ -DTESTS_DIR=\"$(abs_srcdir)\"
+AM_LDFLAGS = $(STD_LDFLAGS) $(am__append_1)
+LDADD = $(LIBISC_LIBS) $(LIBDNS_LIBS) $(LIBNS_LIBS) \
+ $(top_builddir)/tests/libtest/libtest.la $(CMOCKA_LIBS)
+LIBISC_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib/isc/include \
+ -I$(top_builddir)/lib/isc/include
+
+LIBISC_LIBS = $(top_builddir)/lib/isc/libisc.la
+LIBDNS_CFLAGS = \
+ -I$(top_srcdir)/lib/dns/include \
+ -I$(top_builddir)/lib/dns/include
+
+LIBDNS_LIBS = \
+ $(top_builddir)/lib/dns/libdns.la
+
+LIBNS_CFLAGS = \
+ -I$(top_srcdir)/lib/ns/include
+
+LIBNS_LIBS = \
+ $(top_builddir)/lib/ns/libns.la
+
+LIBIRS_CFLAGS = \
+ -I$(top_srcdir)/lib/irs/include
+
+LIBIRS_LIBS = \
+ $(top_builddir)/lib/irs/libirs.la
+
+LIBISCCFG_CFLAGS = \
+ -I$(top_srcdir)/lib/isccfg/include
+
+LIBISCCFG_LIBS = \
+ $(top_builddir)/lib/isccfg/libisccfg.la
+
+LIBISCCC_CFLAGS = \
+ -I$(top_srcdir)/lib/isccc/include/
+
+LIBISCCC_LIBS = \
+ $(top_builddir)/lib/isccc/libisccc.la
+
+LIBBIND9_CFLAGS = \
+ -I$(top_srcdir)/lib/bind9/include
+
+LIBBIND9_LIBS = \
+ $(top_builddir)/lib/bind9/libbind9.la
+
+check_LTLIBRARIES = libtest.la
+libtest_la_SOURCES = \
+ ../include/tests/dns.h \
+ ../include/tests/isc.h \
+ ../include/tests/ns.h \
+ dns.c \
+ isc.c \
+ ns.c
+
+LOG_COMPILER = $(top_builddir)/tests/unit-test-driver.sh
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/libtest/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tests/libtest/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkLTLIBRARIES:
+ -test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES)
+ @list='$(check_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libtest.la: $(libtest_la_OBJECTS) $(libtest_la_DEPENDENCIES) $(EXTRA_libtest_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libtest_la_OBJECTS) $(libtest_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ns.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+test-local:
+unit-local:
+doc-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS: $(check_LTLIBRARIES)
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_LTLIBRARIES)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkLTLIBRARIES clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/dns.Plo
+ -rm -f ./$(DEPDIR)/isc.Plo
+ -rm -f ./$(DEPDIR)/ns.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+doc: doc-am
+
+doc-am: doc-local
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/dns.Plo
+ -rm -f ./$(DEPDIR)/isc.Plo
+ -rm -f ./$(DEPDIR)/ns.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+test: test-am
+
+test-am: test-local
+
+uninstall-am:
+
+unit: unit-am
+
+unit-am: unit-local
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-checkLTLIBRARIES clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir doc-am doc-local dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ recheck tags tags-am test-am test-local uninstall uninstall-am \
+ unit-am unit-local
+
+.PRECIOUS: Makefile
+
+
+unit-local: check
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/libtest/dns.c b/tests/libtest/dns.c
new file mode 100644
index 0000000..ae3748f
--- /dev/null
+++ b/tests/libtest/dns.c
@@ -0,0 +1,501 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/buffer.h>
+#include <isc/file.h>
+#include <isc/hash.h>
+#include <isc/hex.h>
+#include <isc/lex.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/netmgr.h>
+#include <isc/os.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/callbacks.h>
+#include <dns/db.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/name.h>
+#include <dns/view.h>
+#include <dns/zone.h>
+
+#include <tests/dns.h>
+
+dns_zonemgr_t *zonemgr = NULL;
+
+/*
+ * Create a view.
+ */
+isc_result_t
+dns_test_makeview(const char *name, bool with_cache, dns_view_t **viewp) {
+ isc_result_t result;
+ dns_view_t *view = NULL;
+ dns_cache_t *cache = NULL;
+
+ result = dns_view_create(mctx, dns_rdataclass_in, name, &view);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ if (with_cache) {
+ result = dns_cache_create(mctx, mctx, taskmgr, timermgr,
+ dns_rdataclass_in, "", "rbt", 0, NULL,
+ &cache);
+ if (result != ISC_R_SUCCESS) {
+ dns_view_detach(&view);
+ return (result);
+ }
+
+ dns_view_setcache(view, cache, false);
+ /*
+ * Reference count for "cache" is now at 2, so decrement it in
+ * order for the cache to be automatically freed when "view"
+ * gets freed.
+ */
+ dns_cache_detach(&cache);
+ }
+
+ *viewp = view;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
+ bool createview) {
+ dns_fixedname_t fixed_origin;
+ dns_zone_t *zone = NULL;
+ isc_result_t result;
+ dns_name_t *origin;
+
+ REQUIRE(view == NULL || !createview);
+
+ /*
+ * Create the zone structure.
+ */
+ result = dns_zone_create(&zone, mctx);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ /*
+ * Set zone type and origin.
+ */
+ dns_zone_settype(zone, dns_zone_primary);
+ origin = dns_fixedname_initname(&fixed_origin);
+ result = dns_name_fromstring(origin, name, 0, NULL);
+ if (result != ISC_R_SUCCESS) {
+ goto detach_zone;
+ }
+ result = dns_zone_setorigin(zone, origin);
+ if (result != ISC_R_SUCCESS) {
+ goto detach_zone;
+ }
+
+ /*
+ * If requested, create a view.
+ */
+ if (createview) {
+ result = dns_test_makeview("view", false, &view);
+ if (result != ISC_R_SUCCESS) {
+ goto detach_zone;
+ }
+ }
+
+ /*
+ * If a view was passed as an argument or created above, attach the
+ * created zone to it. Otherwise, set the zone's class to IN.
+ */
+ if (view != NULL) {
+ dns_zone_setview(zone, view);
+ dns_zone_setclass(zone, view->rdclass);
+ dns_view_addzone(view, zone);
+ } else {
+ dns_zone_setclass(zone, dns_rdataclass_in);
+ }
+
+ *zonep = zone;
+
+ return (ISC_R_SUCCESS);
+
+detach_zone:
+ dns_zone_detach(&zone);
+
+ return (result);
+}
+
+isc_result_t
+dns_test_setupzonemgr(void) {
+ isc_result_t result;
+ REQUIRE(zonemgr == NULL);
+
+ result = dns_zonemgr_create(mctx, taskmgr, timermgr, netmgr, &zonemgr);
+ return (result);
+}
+
+isc_result_t
+dns_test_managezone(dns_zone_t *zone) {
+ isc_result_t result;
+ REQUIRE(zonemgr != NULL);
+
+ result = dns_zonemgr_setsize(zonemgr, 1);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ result = dns_zonemgr_managezone(zonemgr, zone);
+ return (result);
+}
+
+void
+dns_test_releasezone(dns_zone_t *zone) {
+ REQUIRE(zonemgr != NULL);
+ dns_zonemgr_releasezone(zonemgr, zone);
+}
+
+void
+dns_test_closezonemgr(void) {
+ REQUIRE(zonemgr != NULL);
+
+ dns_zonemgr_shutdown(zonemgr);
+ dns_zonemgr_detach(&zonemgr);
+}
+
+/*
+ * Sleep for 'usec' microseconds.
+ */
+void
+dns_test_nap(uint32_t usec) {
+ struct timespec ts;
+
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ nanosleep(&ts, NULL);
+}
+
+isc_result_t
+dns_test_loaddb(dns_db_t **db, dns_dbtype_t dbtype, const char *origin,
+ const char *testfile) {
+ 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, dbtype, dns_rdataclass_in, 0,
+ NULL, db);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ result = dns_db_load(*db, testfile, dns_masterformat_text, 0);
+ return (result);
+}
+
+static int
+fromhex(char c) {
+ if (c >= '0' && c <= '9') {
+ return (c - '0');
+ } else if (c >= 'a' && c <= 'f') {
+ return (c - 'a' + 10);
+ } else if (c >= 'A' && c <= 'F') {
+ return (c - 'A' + 10);
+ }
+
+ printf("bad input format: %02x\n", c);
+ exit(3);
+}
+
+/*
+ * Format contents of given memory region as a hex string, using the buffer
+ * of length 'buflen' pointed to by 'buf'. 'buflen' must be at least three
+ * times 'len'. Always returns 'buf'.
+ */
+char *
+dns_test_tohex(const unsigned char *data, size_t len, char *buf,
+ size_t buflen) {
+ isc_constregion_t source = { .base = data, .length = len };
+ isc_buffer_t target;
+ isc_result_t result;
+
+ memset(buf, 0, buflen);
+ isc_buffer_init(&target, buf, buflen);
+ result = isc_hex_totext((isc_region_t *)&source, 1, " ", &target);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ return (buf);
+}
+
+isc_result_t
+dns_test_getdata(const char *file, unsigned char *buf, size_t bufsiz,
+ size_t *sizep) {
+ isc_result_t result;
+ unsigned char *bp;
+ char *rp, *wp;
+ char s[BUFSIZ];
+ size_t len, i;
+ FILE *f = NULL;
+ int n;
+
+ result = isc_stdio_open(file, "r", &f);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ bp = buf;
+ while (fgets(s, sizeof(s), f) != NULL) {
+ rp = s;
+ wp = s;
+ len = 0;
+ while (*rp != '\0') {
+ if (*rp == '#') {
+ break;
+ }
+ if (*rp != ' ' && *rp != '\t' && *rp != '\r' &&
+ *rp != '\n')
+ {
+ *wp++ = *rp;
+ len++;
+ }
+ rp++;
+ }
+ if (len == 0U) {
+ continue;
+ }
+ if (len % 2 != 0U) {
+ result = ISC_R_UNEXPECTEDEND;
+ break;
+ }
+ if (len > bufsiz * 2) {
+ result = ISC_R_NOSPACE;
+ break;
+ }
+ rp = s;
+ for (i = 0; i < len; i += 2) {
+ n = fromhex(*rp++);
+ n *= 16;
+ n += fromhex(*rp++);
+ *bp++ = n;
+ }
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ *sizep = bp - buf;
+ }
+
+ isc_stdio_close(f);
+ return (result);
+}
+
+static void
+nullmsg(dns_rdatacallbacks_t *cb, const char *fmt, ...) {
+ UNUSED(cb);
+ UNUSED(fmt);
+}
+
+isc_result_t
+dns_test_rdatafromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t rdtype, unsigned char *dst,
+ size_t dstlen, const char *src, bool warnings) {
+ dns_rdatacallbacks_t callbacks;
+ isc_buffer_t source, target;
+ isc_lex_t *lex = NULL;
+ isc_lexspecials_t specials = { 0 };
+ isc_result_t result;
+ size_t length;
+
+ REQUIRE(rdata != NULL);
+ REQUIRE(DNS_RDATA_INITIALIZED(rdata));
+ REQUIRE(dst != NULL);
+ REQUIRE(src != NULL);
+
+ /*
+ * Set up source to hold the input string.
+ */
+ length = strlen(src);
+ isc_buffer_constinit(&source, src, length);
+ isc_buffer_add(&source, length);
+
+ /*
+ * Create a lexer as one is required by dns_rdata_fromtext().
+ */
+ result = isc_lex_create(mctx, 64, &lex);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ /*
+ * Set characters which will be treated as valid multi-line RDATA
+ * delimiters while reading the source string. These should match
+ * specials from lib/dns/master.c.
+ */
+ specials[0] = 1;
+ specials['('] = 1;
+ specials[')'] = 1;
+ specials['"'] = 1;
+ isc_lex_setspecials(lex, specials);
+
+ /*
+ * Expect DNS masterfile comments.
+ */
+ isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
+
+ /*
+ * Point lexer at source.
+ */
+ result = isc_lex_openbuffer(lex, &source);
+ if (result != ISC_R_SUCCESS) {
+ goto destroy_lexer;
+ }
+
+ /*
+ * Set up target for storing uncompressed wire form of provided RDATA.
+ */
+ isc_buffer_init(&target, dst, dstlen);
+
+ /*
+ * Set up callbacks so warnings and errors are not printed.
+ */
+ if (!warnings) {
+ dns_rdatacallbacks_init(&callbacks);
+ callbacks.warn = callbacks.error = nullmsg;
+ }
+
+ /*
+ * Parse input string, determining result.
+ */
+ result = dns_rdata_fromtext(rdata, rdclass, rdtype, lex, dns_rootname,
+ 0, mctx, &target, &callbacks);
+
+destroy_lexer:
+ isc_lex_destroy(&lex);
+
+ return (result);
+}
+
+void
+dns_test_namefromstring(const char *namestr, dns_fixedname_t *fname) {
+ size_t length;
+ isc_buffer_t *b = NULL;
+ isc_result_t result;
+ dns_name_t *name;
+
+ length = strlen(namestr);
+
+ name = dns_fixedname_initname(fname);
+
+ isc_buffer_allocate(mctx, &b, length);
+
+ isc_buffer_putmem(b, (const unsigned char *)namestr, length);
+ result = dns_name_fromtext(name, b, dns_rootname, 0, NULL);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_free(&b);
+}
+
+isc_result_t
+dns_test_difffromchanges(dns_diff_t *diff, const zonechange_t *changes,
+ bool warnings) {
+ isc_result_t result = ISC_R_SUCCESS;
+ unsigned char rdata_buf[1024];
+ dns_difftuple_t *tuple = NULL;
+ isc_consttextregion_t region;
+ dns_rdatatype_t rdatatype;
+ dns_fixedname_t fixedname;
+ dns_rdata_t rdata;
+ dns_name_t *name;
+ size_t i;
+
+ REQUIRE(diff != NULL);
+ REQUIRE(changes != NULL);
+
+ dns_diff_init(mctx, diff);
+
+ for (i = 0; changes[i].owner != NULL; i++) {
+ /*
+ * Parse owner name.
+ */
+ name = dns_fixedname_initname(&fixedname);
+ result = dns_name_fromstring(name, changes[i].owner, 0, mctx);
+ if (result != ISC_R_SUCCESS) {
+ break;
+ }
+
+ /*
+ * Parse RDATA type.
+ */
+ region.base = changes[i].type;
+ region.length = strlen(changes[i].type);
+ result = dns_rdatatype_fromtext(&rdatatype,
+ (isc_textregion_t *)&region);
+ if (result != ISC_R_SUCCESS) {
+ break;
+ }
+
+ /*
+ * Parse RDATA.
+ */
+ dns_rdata_init(&rdata);
+ result = dns_test_rdatafromstring(
+ &rdata, dns_rdataclass_in, rdatatype, rdata_buf,
+ sizeof(rdata_buf), changes[i].rdata, warnings);
+ if (result != ISC_R_SUCCESS) {
+ break;
+ }
+
+ /*
+ * Create a diff tuple for the parsed change and append it to
+ * the diff.
+ */
+ result = dns_difftuple_create(mctx, changes[i].op, name,
+ changes[i].ttl, &rdata, &tuple);
+ if (result != ISC_R_SUCCESS) {
+ break;
+ }
+ dns_diff_append(diff, &tuple);
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ dns_diff_clear(diff);
+ }
+
+ return (result);
+}
diff --git a/tests/libtest/isc.c b/tests/libtest/isc.c
new file mode 100644
index 0000000..970a4b1
--- /dev/null
+++ b/tests/libtest/isc.c
@@ -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.
+ */
+
+/*! \file */
+
+#include <inttypes.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/os.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include "netmgr_p.h"
+#include "task_p.h"
+#include "timer_p.h"
+
+#include <tests/isc.h>
+
+isc_mem_t *mctx = NULL;
+isc_taskmgr_t *taskmgr = NULL;
+isc_timermgr_t *timermgr = NULL;
+isc_nm_t *netmgr = NULL;
+unsigned int workers = 0;
+isc_task_t *maintask = NULL;
+
+int
+setup_managers(void **state) {
+ isc_result_t result;
+
+ UNUSED(state);
+
+ REQUIRE(mctx != NULL);
+
+ if (workers == 0) {
+ char *env_workers = getenv("ISC_TASK_WORKERS");
+ if (env_workers != NULL) {
+ workers = atoi(env_workers);
+ } else {
+ workers = isc_os_ncpus();
+ }
+ INSIST(workers > 0);
+ }
+
+ result = isc_managers_create(mctx, workers, 0, &netmgr, &taskmgr,
+ &timermgr);
+ if (result != ISC_R_SUCCESS) {
+ return (-1);
+ }
+
+ result = isc_task_create_bound(taskmgr, 0, &maintask, 0);
+ if (result != ISC_R_SUCCESS) {
+ return (-1);
+ }
+
+ isc_taskmgr_setexcltask(taskmgr, maintask);
+
+ return (0);
+}
+
+int
+teardown_managers(void **state) {
+ UNUSED(state);
+
+ isc_task_detach(&maintask);
+ isc_managers_destroy(&netmgr, &taskmgr, &timermgr);
+
+ return (0);
+}
diff --git a/tests/libtest/ns.c b/tests/libtest/ns.c
new file mode 100644
index 0000000..4a53ad8
--- /dev/null
+++ b/tests/libtest/ns.c
@@ -0,0 +1,669 @@
+/*
+ * 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 <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/buffer.h>
+#include <isc/file.h>
+#include <isc/hash.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/netmgr.h>
+#include <isc/os.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/resource.h>
+#include <isc/result.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/cache.h>
+#include <dns/db.h>
+#include <dns/dispatch.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/name.h>
+#include <dns/view.h>
+#include <dns/zone.h>
+
+#include <ns/client.h>
+#include <ns/hooks.h>
+#include <ns/interfacemgr.h>
+#include <ns/server.h>
+
+#include <tests/ns.h>
+
+dns_dispatchmgr_t *dispatchmgr = NULL;
+ns_clientmgr_t *clientmgr = NULL;
+ns_interfacemgr_t *interfacemgr = NULL;
+ns_server_t *sctx = NULL;
+bool debug_mem_record = true;
+
+static isc_result_t
+matchview(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
+ dns_message_t *message, dns_aclenv_t *env, isc_result_t *sigresultp,
+ dns_view_t **viewp) {
+ UNUSED(srcaddr);
+ UNUSED(destaddr);
+ UNUSED(message);
+ UNUSED(env);
+ UNUSED(sigresultp);
+ UNUSED(viewp);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+int
+setup_server(void **state) {
+ isc_result_t result;
+ ns_listenlist_t *listenon = NULL;
+ in_port_t port = 5300 + isc_random8();
+
+ setup_managers(state);
+
+ ns_server_create(mctx, matchview, &sctx);
+
+ result = dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr);
+ if (result != ISC_R_SUCCESS) {
+ return (-1);
+ }
+
+ result = ns_interfacemgr_create(mctx, sctx, taskmgr, timermgr, netmgr,
+ dispatchmgr, maintask, NULL, workers,
+ false, &interfacemgr);
+ if (result != ISC_R_SUCCESS) {
+ return (-1);
+ }
+
+ result = ns_listenlist_default(mctx, port, true, AF_INET, &listenon);
+ if (result != ISC_R_SUCCESS) {
+ return (-1);
+ }
+
+ ns_interfacemgr_setlistenon4(interfacemgr, listenon);
+ ns_listenlist_detach(&listenon);
+
+ clientmgr = ns_interfacemgr_getclientmgr(interfacemgr);
+
+ return (0);
+}
+
+int
+teardown_server(void **state) {
+ if (interfacemgr != NULL) {
+ ns_interfacemgr_shutdown(interfacemgr);
+ ns_interfacemgr_detach(&interfacemgr);
+ }
+
+ if (dispatchmgr != NULL) {
+ dns_dispatchmgr_detach(&dispatchmgr);
+ }
+
+ if (sctx != NULL) {
+ ns_server_detach(&sctx);
+ }
+
+ teardown_managers(state);
+ return (0);
+}
+
+static dns_zone_t *served_zone = NULL;
+
+/*
+ * We don't want to use netmgr-based client accounting, we need to emulate it.
+ */
+atomic_uint_fast32_t client_refs[32];
+atomic_uintptr_t client_addrs[32];
+
+void
+isc__nmhandle_attach(isc_nmhandle_t *source, isc_nmhandle_t **targetp FLARG) {
+ ns_client_t *client = (ns_client_t *)source;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ if (atomic_load(&client_addrs[i]) == (uintptr_t)client) {
+ break;
+ }
+ }
+ INSIST(i < 32);
+ INSIST(atomic_load(&client_refs[i]) > 0);
+
+ atomic_fetch_add(&client_refs[i], 1);
+
+ *targetp = source;
+ return;
+}
+
+void
+isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG) {
+ isc_nmhandle_t *handle = *handlep;
+ ns_client_t *client = (ns_client_t *)handle;
+ int i;
+
+ *handlep = NULL;
+
+ for (i = 0; i < 32; i++) {
+ if (atomic_load(&client_addrs[i]) == (uintptr_t)client) {
+ break;
+ }
+ }
+ INSIST(i < 32);
+
+ if (atomic_fetch_sub(&client_refs[i], 1) == 1) {
+ dns_view_detach(&client->view);
+ client->state = 4;
+ ns__client_reset_cb(client);
+ ns__client_put_cb(client);
+ isc_mem_put(mctx, client, sizeof(ns_client_t));
+ atomic_store(&client_addrs[i], (uintptr_t)NULL);
+ }
+
+ return;
+}
+
+isc_result_t
+ns_test_serve_zone(const char *zonename, const char *filename,
+ dns_view_t *view) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+
+ /*
+ * Prepare zone structure for further processing.
+ */
+ result = dns_test_makezone(zonename, &served_zone, view, false);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ /*
+ * Start zone manager.
+ */
+ result = dns_test_setupzonemgr();
+ if (result != ISC_R_SUCCESS) {
+ goto free_zone;
+ }
+
+ /*
+ * Add the zone to the zone manager.
+ */
+ result = dns_test_managezone(served_zone);
+ if (result != ISC_R_SUCCESS) {
+ goto close_zonemgr;
+ }
+
+ view->nocookieudp = 512;
+
+ /*
+ * Set path to the master file for the zone and then load it.
+ */
+ dns_zone_setfile(served_zone, filename, dns_masterformat_text,
+ &dns_master_style_default);
+ result = dns_zone_load(served_zone, false);
+ if (result != ISC_R_SUCCESS) {
+ goto release_zone;
+ }
+
+ /*
+ * The zone should now be loaded; test it.
+ */
+ result = dns_zone_getdb(served_zone, &db);
+ if (result != ISC_R_SUCCESS) {
+ goto release_zone;
+ }
+ if (db != NULL) {
+ dns_db_detach(&db);
+ }
+
+ return (ISC_R_SUCCESS);
+
+release_zone:
+ dns_test_releasezone(served_zone);
+close_zonemgr:
+ dns_test_closezonemgr();
+free_zone:
+ dns_zone_detach(&served_zone);
+
+ return (result);
+}
+
+void
+ns_test_cleanup_zone(void) {
+ dns_test_releasezone(served_zone);
+ dns_test_closezonemgr();
+
+ dns_zone_detach(&served_zone);
+}
+
+isc_result_t
+ns_test_getclient(ns_interface_t *ifp0, bool tcp, ns_client_t **clientp) {
+ isc_result_t result;
+ ns_client_t *client = isc_mem_get(mctx, sizeof(ns_client_t));
+ int i;
+
+ UNUSED(ifp0);
+ UNUSED(tcp);
+
+ result = ns__client_setup(client, clientmgr, true);
+
+ for (i = 0; i < 32; i++) {
+ if (atomic_load(&client_addrs[i]) == (uintptr_t)NULL ||
+ atomic_load(&client_addrs[i]) == (uintptr_t)client)
+ {
+ break;
+ }
+ }
+ REQUIRE(i < 32);
+
+ atomic_store(&client_refs[i], 2);
+ atomic_store(&client_addrs[i], (uintptr_t)client);
+ client->handle = (isc_nmhandle_t *)client; /* Hack */
+ *clientp = client;
+
+ return (result);
+}
+
+/*%
+ * Synthesize a DNS message based on supplied QNAME, QTYPE and flags, then
+ * parse it and store the results in client->message.
+ */
+static isc_result_t
+attach_query_msg_to_client(ns_client_t *client, const char *qnamestr,
+ dns_rdatatype_t qtype, unsigned int qflags) {
+ dns_rdataset_t *qrdataset = NULL;
+ dns_message_t *message = NULL;
+ unsigned char query[65536];
+ dns_name_t *qname = NULL;
+ isc_buffer_t querybuf;
+ dns_compress_t cctx;
+ isc_result_t result;
+
+ REQUIRE(client != NULL);
+ REQUIRE(qnamestr != NULL);
+
+ /*
+ * Create a new DNS message holding a query.
+ */
+ dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message);
+
+ /*
+ * Set query ID to a random value.
+ */
+ message->id = isc_random16();
+
+ /*
+ * Set query flags as requested by the caller.
+ */
+ message->flags = qflags;
+
+ /*
+ * Allocate structures required to construct the query.
+ */
+ result = dns_message_gettemprdataset(message, &qrdataset);
+ if (result != ISC_R_SUCCESS) {
+ goto destroy_message;
+ }
+ result = dns_message_gettempname(message, &qname);
+ if (result != ISC_R_SUCCESS) {
+ goto put_rdataset;
+ }
+
+ /*
+ * Convert "qnamestr" to a DNS name, create a question rdataset of
+ * class IN and type "qtype", link the two and add the result to the
+ * QUESTION section of the query.
+ */
+ result = dns_name_fromstring(qname, qnamestr, 0, mctx);
+ if (result != ISC_R_SUCCESS) {
+ goto put_name;
+ }
+ dns_rdataset_makequestion(qrdataset, dns_rdataclass_in, qtype);
+ ISC_LIST_APPEND(qname->list, qrdataset, link);
+ dns_message_addname(message, qname, DNS_SECTION_QUESTION);
+
+ /*
+ * Render the query.
+ */
+ dns_compress_init(&cctx, -1, mctx);
+ isc_buffer_init(&querybuf, query, sizeof(query));
+ result = dns_message_renderbegin(message, &cctx, &querybuf);
+ if (result != ISC_R_SUCCESS) {
+ goto destroy_message;
+ }
+ result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
+ if (result != ISC_R_SUCCESS) {
+ goto destroy_message;
+ }
+ result = dns_message_renderend(message);
+ if (result != ISC_R_SUCCESS) {
+ goto destroy_message;
+ }
+ dns_compress_invalidate(&cctx);
+
+ /*
+ * Destroy the created message as it was rendered into "querybuf" and
+ * the latter is all we are going to need from now on.
+ */
+ dns_message_detach(&message);
+
+ /*
+ * Parse the rendered query, storing results in client->message.
+ */
+ isc_buffer_first(&querybuf);
+ return (dns_message_parse(client->message, &querybuf, 0));
+
+put_name:
+ dns_message_puttempname(message, &qname);
+put_rdataset:
+ dns_message_puttemprdataset(message, &qrdataset);
+destroy_message:
+ dns_message_detach(&message);
+
+ return (result);
+}
+
+/*%
+ * A hook action which stores the query context pointed to by "arg" at
+ * "data". Causes execution to be interrupted at hook insertion
+ * point.
+ */
+static ns_hookresult_t
+extract_qctx(void *arg, void *data, isc_result_t *resultp) {
+ query_ctx_t **qctxp;
+ query_ctx_t *qctx;
+
+ REQUIRE(arg != NULL);
+ REQUIRE(data != NULL);
+ REQUIRE(resultp != NULL);
+
+ /*
+ * qctx is a stack variable in lib/ns/query.c. Its contents need to be
+ * duplicated or otherwise they will become invalidated once the stack
+ * gets unwound.
+ */
+ qctx = isc_mem_get(mctx, sizeof(*qctx));
+ if (qctx != NULL) {
+ memmove(qctx, (query_ctx_t *)arg, sizeof(*qctx));
+ }
+
+ qctxp = (query_ctx_t **)data;
+ /*
+ * If memory allocation failed, the supplied pointer will simply be set
+ * to NULL. We rely on the user of this hook to react properly.
+ */
+ *qctxp = qctx;
+ *resultp = ISC_R_UNSET;
+
+ return (NS_HOOK_RETURN);
+}
+
+/*%
+ * Initialize a query context for "client" and store it in "qctxp".
+ *
+ * Requires:
+ *
+ * \li "client->message" to hold a parsed DNS query.
+ */
+static isc_result_t
+create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) {
+ ns_hooktable_t *saved_hook_table = NULL, *query_hooks = NULL;
+ const ns_hook_t hook = {
+ .action = extract_qctx,
+ .action_data = qctxp,
+ };
+
+ REQUIRE(client != NULL);
+ REQUIRE(qctxp != NULL);
+ REQUIRE(*qctxp == NULL);
+
+ /*
+ * Call ns_query_start() to initialize a query context for given
+ * client, but first hook into query_setup() so that we can just
+ * extract an initialized query context, without kicking off any
+ * further processing. Make sure we do not overwrite any previously
+ * set hooks.
+ */
+
+ ns_hooktable_create(mctx, &query_hooks);
+ ns_hook_add(query_hooks, mctx, NS_QUERY_SETUP, &hook);
+
+ saved_hook_table = ns__hook_table;
+ ns__hook_table = query_hooks;
+
+ ns_query_start(client, client->handle);
+
+ ns__hook_table = saved_hook_table;
+ ns_hooktable_free(mctx, (void **)&query_hooks);
+
+ isc_nmhandle_detach(&client->reqhandle);
+
+ if (*qctxp == NULL) {
+ return (ISC_R_NOMEMORY);
+ } else {
+ return (ISC_R_SUCCESS);
+ }
+}
+
+isc_result_t
+ns_test_qctx_create(const ns_test_qctx_create_params_t *params,
+ query_ctx_t **qctxp) {
+ ns_client_t *client = NULL;
+ isc_result_t result;
+ isc_nmhandle_t *handle = NULL;
+
+ REQUIRE(params != NULL);
+ REQUIRE(params->qname != NULL);
+ REQUIRE(qctxp != NULL);
+ REQUIRE(*qctxp == NULL);
+
+ /*
+ * Allocate and initialize a client structure.
+ */
+ result = ns_test_getclient(NULL, false, &client);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+ TIME_NOW(&client->tnow);
+
+ /*
+ * Every client needs to belong to a view.
+ */
+ result = dns_test_makeview("view", params->with_cache, &client->view);
+ if (result != ISC_R_SUCCESS) {
+ goto detach_client;
+ }
+
+ /*
+ * Synthesize a DNS query using given QNAME, QTYPE and flags, storing
+ * it in client->message.
+ */
+ result = attach_query_msg_to_client(client, params->qname,
+ params->qtype, params->qflags);
+ if (result != ISC_R_SUCCESS) {
+ goto detach_view;
+ }
+
+ /*
+ * Allow recursion for the client. As NS_CLIENTATTR_RA normally gets
+ * set in ns__client_request(), i.e. earlier than the unit tests hook
+ * into the call chain, just set it manually.
+ */
+ client->attributes |= NS_CLIENTATTR_RA;
+
+ /*
+ * Create a query context for a client sending the previously
+ * synthesized query.
+ */
+ result = create_qctx_for_client(client, qctxp);
+ if (result != ISC_R_SUCCESS) {
+ goto detach_query;
+ }
+
+ /*
+ * The reference count for "client" is now at 2, so we need to
+ * decrement it in order for it to drop to zero when "qctx" gets
+ * destroyed.
+ */
+ handle = client->handle;
+ isc_nmhandle_detach(&handle);
+
+ return (ISC_R_SUCCESS);
+
+detach_query:
+ dns_message_detach(&client->message);
+detach_view:
+ dns_view_detach(&client->view);
+detach_client:
+ isc_nmhandle_detach(&client->handle);
+
+ return (result);
+}
+
+void
+ns_test_qctx_destroy(query_ctx_t **qctxp) {
+ query_ctx_t *qctx;
+
+ REQUIRE(qctxp != NULL);
+ REQUIRE(*qctxp != NULL);
+
+ qctx = *qctxp;
+ *qctxp = NULL;
+
+ if (qctx->zone != NULL) {
+ dns_zone_detach(&qctx->zone);
+ }
+ if (qctx->db != NULL) {
+ dns_db_detach(&qctx->db);
+ }
+ if (qctx->client != NULL) {
+ isc_nmhandle_detach(&qctx->client->handle);
+ }
+
+ isc_mem_put(mctx, qctx, sizeof(*qctx));
+}
+
+ns_hookresult_t
+ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp) {
+ UNUSED(arg);
+ UNUSED(data);
+
+ *resultp = ISC_R_UNSET;
+
+ return (NS_HOOK_RETURN);
+}
+
+isc_result_t
+ns_test_loaddb(dns_db_t **db, dns_dbtype_t dbtype, const char *origin,
+ const char *testfile) {
+ 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, dbtype, dns_rdataclass_in, 0,
+ NULL, db);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ result = dns_db_load(*db, testfile, dns_masterformat_text, 0);
+ return (result);
+}
+
+static int
+fromhex(char c) {
+ if (c >= '0' && c <= '9') {
+ return (c - '0');
+ } else if (c >= 'a' && c <= 'f') {
+ return (c - 'a' + 10);
+ } else if (c >= 'A' && c <= 'F') {
+ return (c - 'A' + 10);
+ }
+
+ printf("bad input format: %02x\n", c);
+ exit(3);
+}
+
+isc_result_t
+ns_test_getdata(const char *file, unsigned char *buf, size_t bufsiz,
+ size_t *sizep) {
+ isc_result_t result;
+ unsigned char *bp;
+ char *rp, *wp;
+ char s[BUFSIZ];
+ size_t len, i;
+ FILE *f = NULL;
+ int n;
+
+ result = isc_stdio_open(file, "r", &f);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ bp = buf;
+ while (fgets(s, sizeof(s), f) != NULL) {
+ rp = s;
+ wp = s;
+ len = 0;
+ while (*rp != '\0') {
+ if (*rp == '#') {
+ break;
+ }
+ if (*rp != ' ' && *rp != '\t' && *rp != '\r' &&
+ *rp != '\n')
+ {
+ *wp++ = *rp;
+ len++;
+ }
+ rp++;
+ }
+ if (len == 0U) {
+ continue;
+ }
+ if (len % 2 != 0U) {
+ CHECK(ISC_R_UNEXPECTEDEND);
+ }
+ if (len > bufsiz * 2) {
+ CHECK(ISC_R_NOSPACE);
+ }
+ rp = s;
+ for (i = 0; i < len; i += 2) {
+ n = fromhex(*rp++);
+ n *= 16;
+ n += fromhex(*rp++);
+ *bp++ = n;
+ }
+ }
+
+ *sizep = bp - buf;
+
+ result = ISC_R_SUCCESS;
+
+cleanup:
+ isc_stdio_close(f);
+ return (result);
+}
diff --git a/tests/ns/Makefile.am b/tests/ns/Makefile.am
new file mode 100644
index 0000000..33f91d8
--- /dev/null
+++ b/tests/ns/Makefile.am
@@ -0,0 +1,25 @@
+include $(top_srcdir)/Makefile.top
+
+AM_CPPFLAGS += \
+ $(LIBISC_CFLAGS) \
+ $(LIBDNS_CFLAGS) \
+ $(LIBNS_CFLAGS) \
+ $(LIBUV_CFLAGS) \
+ -I$(top_srcdir)/lib/isc \
+ -I$(top_srcdir)/lib/dns
+
+LDADD += \
+ $(LIBISC_LIBS) \
+ $(LIBDNS_LIBS) \
+ $(LIBNS_LIBS) \
+ $(LIBUV_LIBS)
+
+check_PROGRAMS = \
+ listenlist_test \
+ notify_test \
+ plugin_test \
+ query_test
+
+EXTRA_DIST = testdata
+
+include $(top_srcdir)/Makefile.tests
diff --git a/tests/ns/Makefile.in b/tests/ns/Makefile.in
new file mode 100644
index 0000000..efa0cc9
--- /dev/null
+++ b/tests/ns/Makefile.in
@@ -0,0 +1,1219 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HOST_MACOS_TRUE@am__append_1 = \
+@HOST_MACOS_TRUE@ -Wl,-flat_namespace
+
+check_PROGRAMS = listenlist_test$(EXEEXT) notify_test$(EXEEXT) \
+ plugin_test$(EXEEXT) query_test$(EXEEXT)
+subdir = tests/ns
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4/ax_jemalloc.m4 \
+ $(top_srcdir)/m4/ax_lib_lmdb.m4 \
+ $(top_srcdir)/m4/ax_perl_module.m4 \
+ $(top_srcdir)/m4/ax_posix_shell.m4 \
+ $(top_srcdir)/m4/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_python_module.m4 \
+ $(top_srcdir)/m4/ax_restore_flags.m4 \
+ $(top_srcdir)/m4/ax_save_flags.m4 $(top_srcdir)/m4/ax_tls.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+listenlist_test_SOURCES = listenlist_test.c
+listenlist_test_OBJECTS = listenlist_test.$(OBJEXT)
+listenlist_test_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+listenlist_test_DEPENDENCIES = $(LIBISC_LIBS) $(LIBDNS_LIBS) \
+ $(LIBNS_LIBS) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+notify_test_SOURCES = notify_test.c
+notify_test_OBJECTS = notify_test.$(OBJEXT)
+notify_test_LDADD = $(LDADD)
+notify_test_DEPENDENCIES = $(LIBISC_LIBS) $(LIBDNS_LIBS) $(LIBNS_LIBS) \
+ $(am__DEPENDENCIES_1) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+plugin_test_SOURCES = plugin_test.c
+plugin_test_OBJECTS = plugin_test.$(OBJEXT)
+plugin_test_LDADD = $(LDADD)
+plugin_test_DEPENDENCIES = $(LIBISC_LIBS) $(LIBDNS_LIBS) $(LIBNS_LIBS) \
+ $(am__DEPENDENCIES_1) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+query_test_SOURCES = query_test.c
+query_test_OBJECTS = query_test.$(OBJEXT)
+query_test_LDADD = $(LDADD)
+query_test_DEPENDENCIES = $(LIBISC_LIBS) $(LIBDNS_LIBS) $(LIBNS_LIBS) \
+ $(am__DEPENDENCIES_1) $(top_builddir)/tests/libtest/libtest.la \
+ $(am__DEPENDENCIES_1)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/listenlist_test.Po \
+ ./$(DEPDIR)/notify_test.Po ./$(DEPDIR)/plugin_test.Po \
+ ./$(DEPDIR)/query_test.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = listenlist_test.c notify_test.c plugin_test.c query_test.c
+DIST_SOURCES = listenlist_test.c notify_test.c plugin_test.c \
+ query_test.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = test-recursive unit-recursive \
+ doc-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/Makefile.tests \
+ $(top_srcdir)/Makefile.top $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CMOCKA_CFLAGS = @CMOCKA_CFLAGS@
+CMOCKA_LIBS = @CMOCKA_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURL = @CURL@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEVELOPER_MODE = @DEVELOPER_MODE@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FSTRM_CAPTURE = @FSTRM_CAPTURE@
+FUZZ_LDFLAGS = @FUZZ_LDFLAGS@
+FUZZ_LOG_COMPILER = @FUZZ_LOG_COMPILER@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@
+JEMALLOC_LIBS = @JEMALLOC_LIBS@
+JSON_C_CFLAGS = @JSON_C_CFLAGS@
+JSON_C_LIBS = @JSON_C_LIBS@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_CONFIG = @KRB5_CONFIG@
+KRB5_LIBS = @KRB5_LIBS@
+LATEXMK = @LATEXMK@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBNGHTTP2_CFLAGS = @LIBNGHTTP2_CFLAGS@
+LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUV_CFLAGS = @LIBUV_CFLAGS@
+LIBUV_LIBS = @LIBUV_LIBS@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIPO = @LIPO@
+LMDB_CFLAGS = @LMDB_CFLAGS@
+LMDB_LIBS = @LMDB_LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAXMINDDB_CFLAGS = @MAXMINDDB_CFLAGS@
+MAXMINDDB_LIBS = @MAXMINDDB_LIBS@
+MAXMINDDB_PREFIX = @MAXMINDDB_PREFIX@
+MKDIR_P = @MKDIR_P@
+NC = @NC@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTEST = @PYTEST@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+READLINE_CFLAGS = @READLINE_CFLAGS@
+READLINE_LIBS = @READLINE_LIBS@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINX_BUILD = @SPHINX_BUILD@
+STD_CFLAGS = @STD_CFLAGS@
+STD_CPPFLAGS = @STD_CPPFLAGS@
+STD_LDFLAGS = @STD_LDFLAGS@
+STRIP = @STRIP@
+TEST_CFLAGS = @TEST_CFLAGS@
+VERSION = @VERSION@
+XELATEX = @XELATEX@
+XSLTPROC = @XSLTPROC@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
+AM_CFLAGS = $(STD_CFLAGS) -I$(top_srcdir)/tests/include $(TEST_CFLAGS)
+AM_CPPFLAGS = $(STD_CPPFLAGS) -include $(top_builddir)/config.h \
+ -I$(srcdir)/include $(LIBISC_CFLAGS) $(LIBDNS_CFLAGS) \
+ $(LIBNS_CFLAGS) $(LIBUV_CFLAGS) -I$(top_srcdir)/lib/isc \
+ -I$(top_srcdir)/lib/dns $(CMOCKA_CFLAGS) \
+ -DNAMED_PLUGINDIR=\"$(pkglibdir)\" \
+ -DTESTS_DIR=\"$(abs_srcdir)\"
+AM_LDFLAGS = $(STD_LDFLAGS) $(am__append_1)
+LDADD = $(LIBISC_LIBS) $(LIBDNS_LIBS) $(LIBNS_LIBS) $(LIBUV_LIBS) \
+ $(top_builddir)/tests/libtest/libtest.la $(CMOCKA_LIBS)
+LIBISC_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib/isc/include \
+ -I$(top_builddir)/lib/isc/include
+
+LIBISC_LIBS = $(top_builddir)/lib/isc/libisc.la
+LIBDNS_CFLAGS = \
+ -I$(top_srcdir)/lib/dns/include \
+ -I$(top_builddir)/lib/dns/include
+
+LIBDNS_LIBS = \
+ $(top_builddir)/lib/dns/libdns.la
+
+LIBNS_CFLAGS = \
+ -I$(top_srcdir)/lib/ns/include
+
+LIBNS_LIBS = \
+ $(top_builddir)/lib/ns/libns.la
+
+LIBIRS_CFLAGS = \
+ -I$(top_srcdir)/lib/irs/include
+
+LIBIRS_LIBS = \
+ $(top_builddir)/lib/irs/libirs.la
+
+LIBISCCFG_CFLAGS = \
+ -I$(top_srcdir)/lib/isccfg/include
+
+LIBISCCFG_LIBS = \
+ $(top_builddir)/lib/isccfg/libisccfg.la
+
+LIBISCCC_CFLAGS = \
+ -I$(top_srcdir)/lib/isccc/include/
+
+LIBISCCC_LIBS = \
+ $(top_builddir)/lib/isccc/libisccc.la
+
+LIBBIND9_CFLAGS = \
+ -I$(top_srcdir)/lib/bind9/include
+
+LIBBIND9_LIBS = \
+ $(top_builddir)/lib/bind9/libbind9.la
+
+EXTRA_DIST = testdata
+@HAVE_CMOCKA_TRUE@TESTS = $(check_PROGRAMS)
+LOG_COMPILER = $(top_builddir)/tests/unit-test-driver.sh
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/ns/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tests/ns/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/Makefile.top $(top_srcdir)/Makefile.tests $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+listenlist_test$(EXEEXT): $(listenlist_test_OBJECTS) $(listenlist_test_DEPENDENCIES) $(EXTRA_listenlist_test_DEPENDENCIES)
+ @rm -f listenlist_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(listenlist_test_OBJECTS) $(listenlist_test_LDADD) $(LIBS)
+
+notify_test$(EXEEXT): $(notify_test_OBJECTS) $(notify_test_DEPENDENCIES) $(EXTRA_notify_test_DEPENDENCIES)
+ @rm -f notify_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(notify_test_OBJECTS) $(notify_test_LDADD) $(LIBS)
+
+plugin_test$(EXEEXT): $(plugin_test_OBJECTS) $(plugin_test_DEPENDENCIES) $(EXTRA_plugin_test_DEPENDENCIES)
+ @rm -f plugin_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(plugin_test_OBJECTS) $(plugin_test_LDADD) $(LIBS)
+
+query_test$(EXEEXT): $(query_test_OBJECTS) $(query_test_DEPENDENCIES) $(EXTRA_query_test_DEPENDENCIES)
+ @rm -f query_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(query_test_OBJECTS) $(query_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listenlist_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notify_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query_test.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+test-local:
+unit-local:
+doc-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS: $(check_PROGRAMS)
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+listenlist_test.log: listenlist_test$(EXEEXT)
+ @p='listenlist_test$(EXEEXT)'; \
+ b='listenlist_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+notify_test.log: notify_test$(EXEEXT)
+ @p='notify_test$(EXEEXT)'; \
+ b='notify_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+plugin_test.log: plugin_test$(EXEEXT)
+ @p='plugin_test$(EXEEXT)'; \
+ b='plugin_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+query_test.log: query_test$(EXEEXT)
+ @p='query_test$(EXEEXT)'; \
+ b='query_test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/listenlist_test.Po
+ -rm -f ./$(DEPDIR)/notify_test.Po
+ -rm -f ./$(DEPDIR)/plugin_test.Po
+ -rm -f ./$(DEPDIR)/query_test.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+doc: doc-am
+
+doc-am: doc-local
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/listenlist_test.Po
+ -rm -f ./$(DEPDIR)/notify_test.Po
+ -rm -f ./$(DEPDIR)/plugin_test.Po
+ -rm -f ./$(DEPDIR)/query_test.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+test: test-am
+
+test-am: test-local
+
+uninstall-am:
+
+unit: unit-am
+
+unit-am: unit-local
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-checkPROGRAMS clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir \
+ doc-am doc-local dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am recheck tags tags-am test-am test-local \
+ uninstall uninstall-am unit-am unit-local
+
+.PRECIOUS: Makefile
+
+
+unit-local: check
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/ns/listenlist_test.c b/tests/ns/listenlist_test.c
new file mode 100644
index 0000000..53d5783
--- /dev/null
+++ b/tests/ns/listenlist_test.c
@@ -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.
+ */
+
+#include <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/list.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/util.h>
+
+#include <dns/acl.h>
+
+#include <ns/listenlist.h>
+
+#include <tests/ns.h>
+
+static int
+_setup(void **state) {
+ isc__nm_force_tid(0);
+
+ setup_managers(state);
+
+ return (0);
+}
+
+static int
+_teardown(void **state) {
+ isc__nm_force_tid(-1);
+
+ teardown_managers(state);
+
+ return (0);
+}
+
+/* test that ns_listenlist_default() works */
+ISC_RUN_TEST_IMPL(ns_listenlist_default) {
+ isc_result_t result;
+ in_port_t port = 5300 + isc_random8();
+ ns_listenlist_t *list = NULL;
+ ns_listenelt_t *elt;
+ int count;
+
+ UNUSED(state);
+
+ result = ns_listenlist_default(mctx, port, false, AF_INET, &list);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_non_null(list);
+
+ assert_false(ISC_LIST_EMPTY(list->elts));
+
+ count = 0;
+ elt = ISC_LIST_HEAD(list->elts);
+ while (elt != NULL) {
+ ns_listenelt_t *next = ISC_LIST_NEXT(elt, link);
+ dns_acl_t *acl = NULL;
+
+ dns_acl_attach(elt->acl, &acl);
+ ISC_LIST_UNLINK(list->elts, elt, link);
+ ns_listenelt_destroy(elt);
+ elt = next;
+
+ assert_true(dns_acl_isnone(acl));
+ dns_acl_detach(&acl);
+ count++;
+ }
+
+ assert_true(ISC_LIST_EMPTY(list->elts));
+ assert_int_equal(count, 1);
+
+ ns_listenlist_detach(&list);
+
+ result = ns_listenlist_default(mctx, port, true, AF_INET, &list);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_false(ISC_LIST_EMPTY(list->elts));
+
+ /* This time just use ns_listenlist_detach() to destroy elements */
+ count = 0;
+ elt = ISC_LIST_HEAD(list->elts);
+ while (elt != NULL) {
+ ns_listenelt_t *next = ISC_LIST_NEXT(elt, link);
+ assert_true(dns_acl_isany(elt->acl));
+ elt = next;
+ count++;
+ }
+
+ assert_int_equal(count, 1);
+
+ ns_listenlist_detach(&list);
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(ns_listenlist_default, _setup, _teardown)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/ns/notify_test.c b/tests/ns/notify_test.c
new file mode 100644
index 0000000..1b962e3
--- /dev/null
+++ b/tests/ns/notify_test.c
@@ -0,0 +1,141 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/event.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include <dns/acl.h>
+#include <dns/rcode.h>
+#include <dns/view.h>
+
+#include <ns/client.h>
+#include <ns/notify.h>
+
+#include <tests/dns.h>
+#include <tests/ns.h>
+
+static int
+setup_test(void **state) {
+ isc__nm_force_tid(0);
+ return (setup_server(state));
+}
+
+static int
+teardown_test(void **state) {
+ isc__nm_force_tid(-1);
+ return (teardown_server(state));
+}
+
+static void
+check_response(isc_buffer_t *buf) {
+ isc_result_t result;
+ dns_message_t *message = NULL;
+ char rcodebuf[20];
+ isc_buffer_t b;
+
+ dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &message);
+
+ result = dns_message_parse(message, buf, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ isc_buffer_init(&b, rcodebuf, sizeof(rcodebuf));
+ result = dns_rcode_totext(message->rcode, &b);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ assert_int_equal(message->rcode, dns_rcode_noerror);
+
+ dns_message_detach(&message);
+}
+
+/* test ns_notify_start() */
+ISC_RUN_TEST_IMPL(ns_notify_start) {
+ isc_result_t result;
+ ns_client_t *client = NULL;
+ isc_nmhandle_t *handle = NULL;
+ dns_message_t *nmsg = NULL;
+ unsigned char ndata[4096];
+ isc_buffer_t nbuf;
+ size_t nsize;
+
+ UNUSED(state);
+
+ result = ns_test_getclient(NULL, false, &client);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = dns_test_makeview("view", false, &client->view);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = ns_test_serve_zone("example.com",
+ TESTS_DIR "/testdata/notify/zone1.db",
+ client->view);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Create a NOTIFY message by parsing a file in testdata.
+ * (XXX: use better message mocking method when available.)
+ */
+
+ result = ns_test_getdata(TESTS_DIR "/testdata/notify/notify1.msg",
+ ndata, sizeof(ndata), &nsize);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ isc_buffer_init(&nbuf, ndata, nsize);
+ isc_buffer_add(&nbuf, nsize);
+
+ dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &nmsg);
+
+ result = dns_message_parse(nmsg, &nbuf, 0);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ /*
+ * Set up client object with this message and test the NOTIFY
+ * handler.
+ */
+ if (client->message != NULL) {
+ dns_message_detach(&client->message);
+ }
+ client->message = nmsg;
+ nmsg = NULL;
+ client->sendcb = check_response;
+ ns_notify_start(client, client->handle);
+
+ /*
+ * Clean up
+ */
+ ns_test_cleanup_zone();
+
+ handle = client->handle;
+ isc_nmhandle_detach(&client->handle);
+ isc_nmhandle_detach(&handle);
+}
+
+ISC_TEST_LIST_START
+ISC_TEST_ENTRY_CUSTOM(ns_notify_start, setup_test, teardown_test)
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/ns/plugin_test.c b/tests/ns/plugin_test.c
new file mode 100644
index 0000000..24d021e
--- /dev/null
+++ b/tests/ns/plugin_test.c
@@ -0,0 +1,166 @@
+/*
+ * 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 <inttypes.h>
+#include <limits.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/attributes.h>
+#include <isc/dir.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+noreturn void
+_fail(const char *const file, const int line);
+
+#include <ns/hooks.h>
+
+#include <tests/ns.h>
+
+/*%
+ * Structure containing parameters for run_full_path_test().
+ */
+typedef struct {
+ const ns_test_id_t id; /* libns test identifier */
+ const char *input; /* source string - plugin name or path
+ * */
+ size_t output_size; /* size of target char array to
+ * allocate */
+ isc_result_t result; /* expected return value */
+ const char *output; /* expected output string */
+} ns_plugin_expandpath_test_params_t;
+
+/*%
+ * Perform a single ns_plugin_expandpath() check using given parameters.
+ */
+static void
+run_full_path_test(const ns_plugin_expandpath_test_params_t *test,
+ void **state) {
+ char **target = (char **)state;
+ isc_result_t result;
+
+ REQUIRE(test != NULL);
+ REQUIRE(test->id.description != NULL);
+ REQUIRE(test->input != NULL);
+ REQUIRE(test->result != ISC_R_SUCCESS || test->output != NULL);
+
+ /*
+ * Prepare a target buffer of given size. Store it in 'state' so that
+ * it can get cleaned up by _teardown() if the test fails.
+ */
+ *target = isc_mem_allocate(mctx, test->output_size);
+
+ /*
+ * Call ns_plugin_expandpath().
+ */
+ result = ns_plugin_expandpath(test->input, *target, test->output_size);
+
+ /*
+ * Check return value.
+ */
+ if (result != test->result) {
+ fail_msg("# test \"%s\" on line %d: "
+ "expected result %d (%s), got %d (%s)",
+ test->id.description, test->id.lineno, test->result,
+ isc_result_totext(test->result), result,
+ isc_result_totext(result));
+ }
+
+ /*
+ * Check output string if return value indicates success.
+ */
+ if (result == ISC_R_SUCCESS && strcmp(*target, test->output) != 0) {
+ fail_msg("# test \"%s\" on line %d: "
+ "expected output \"%s\", got \"%s\"",
+ test->id.description, test->id.lineno, test->output,
+ *target);
+ }
+
+ isc_mem_free(mctx, *target);
+}
+
+/* test ns_plugin_expandpath() */
+ISC_RUN_TEST_IMPL(ns_plugin_expandpath) {
+ size_t i;
+
+ const ns_plugin_expandpath_test_params_t tests[] = {
+ {
+ NS_TEST_ID("correct use with an absolute path"),
+ .input = "/usr/lib/named/foo.so",
+ .output_size = PATH_MAX,
+ .result = ISC_R_SUCCESS,
+ .output = "/usr/lib/named/foo.so",
+ },
+ {
+ NS_TEST_ID("correct use with a relative path"),
+ .input = "../../foo.so",
+ .output_size = PATH_MAX,
+ .result = ISC_R_SUCCESS,
+ .output = "../../foo.so",
+ },
+ {
+ NS_TEST_ID("correct use with a filename"),
+ .input = "foo.so",
+ .output_size = PATH_MAX,
+ .result = ISC_R_SUCCESS,
+ .output = NAMED_PLUGINDIR "/foo.so",
+ },
+ {
+ NS_TEST_ID("no space at all in target buffer"),
+ .input = "/usr/lib/named/foo.so",
+ .output_size = 0,
+ .result = ISC_R_NOSPACE,
+ },
+ {
+ NS_TEST_ID("target buffer too small to fit input"),
+ .input = "/usr/lib/named/foo.so",
+ .output_size = 1,
+ .result = ISC_R_NOSPACE,
+ },
+ {
+ NS_TEST_ID("target buffer too small to fit NULL byte"),
+ .input = "/foo.so",
+ .output_size = 7,
+ .result = ISC_R_NOSPACE,
+ },
+ {
+ NS_TEST_ID("target buffer too small to fit full path"),
+ .input = "foo.so",
+ .output_size = 7,
+ .result = ISC_R_NOSPACE,
+ },
+ };
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ run_full_path_test(&tests[i], state);
+ }
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(ns_plugin_expandpath, setup_managers, teardown_managers)
+
+ISC_TEST_LIST_END
+
+ISC_TEST_MAIN
diff --git a/tests/ns/query_test.c b/tests/ns/query_test.c
new file mode 100644
index 0000000..5bea01a
--- /dev/null
+++ b/tests/ns/query_test.c
@@ -0,0 +1,1500 @@
+/*
+ * 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 <inttypes.h>
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/quota.h>
+#include <isc/util.h>
+
+#include <dns/badcache.h>
+#include <dns/view.h>
+#include <dns/zone.h>
+
+#include <ns/client.h>
+#include <ns/events.h>
+#include <ns/hooks.h>
+#include <ns/query.h>
+#include <ns/server.h>
+#include <ns/stats.h>
+
+#include <tests/ns.h>
+
+static int
+setup_test(void **state) {
+ isc__nm_force_tid(0);
+ setup_server(state);
+ return (0);
+}
+
+static int
+teardown_test(void **state) {
+ isc__nm_force_tid(-1);
+ teardown_server(state);
+ return (0);
+}
+
+/* can be used for client->sendcb to avoid disruption on sending a response */
+static void
+send_noop(isc_buffer_t *buffer) {
+ UNUSED(buffer);
+}
+
+/*****
+***** ns__query_sfcache() tests
+*****/
+
+/*%
+ * Structure containing parameters for ns__query_sfcache_test().
+ */
+typedef struct {
+ const ns_test_id_t id; /* libns test identifier */
+ unsigned int qflags; /* query flags */
+ bool cache_entry_present; /* whether a SERVFAIL
+ * cache entry
+ * matching the query
+ * should be
+ * present */
+ uint32_t cache_entry_flags; /* NS_FAILCACHE_* flags to
+ * set for
+ * the SERVFAIL cache entry
+ * */
+ bool servfail_expected; /* whether a cached
+ * SERVFAIL is
+ * expected to be returned
+ * */
+} ns__query_sfcache_test_params_t;
+
+/*%
+ * Perform a single ns__query_sfcache() check using given parameters.
+ */
+static void
+run_sfcache_test(const ns__query_sfcache_test_params_t *test) {
+ ns_hooktable_t *query_hooks = NULL;
+ query_ctx_t *qctx = NULL;
+ isc_result_t result;
+ const ns_hook_t hook = {
+ .action = ns_test_hook_catch_call,
+ };
+
+ REQUIRE(test != NULL);
+ REQUIRE(test->id.description != NULL);
+ REQUIRE(test->cache_entry_present || test->cache_entry_flags == 0);
+
+ /*
+ * Interrupt execution if ns_query_done() is called.
+ */
+
+ ns_hooktable_create(mctx, &query_hooks);
+ ns_hook_add(query_hooks, mctx, NS_QUERY_DONE_BEGIN, &hook);
+ ns__hook_table = query_hooks;
+
+ /*
+ * Construct a query context for a ./NS query with given flags.
+ */
+ {
+ const ns_test_qctx_create_params_t qctx_params = {
+ .qname = ".",
+ .qtype = dns_rdatatype_ns,
+ .qflags = test->qflags,
+ .with_cache = true,
+ };
+
+ result = ns_test_qctx_create(&qctx_params, &qctx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ /*
+ * If this test wants a SERVFAIL cache entry matching the query to
+ * exist, create it.
+ */
+ if (test->cache_entry_present) {
+ isc_interval_t hour;
+ isc_time_t expire;
+
+ isc_interval_set(&hour, 3600, 0);
+ result = isc_time_nowplusinterval(&expire, &hour);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ dns_badcache_add(qctx->client->view->failcache, dns_rootname,
+ dns_rdatatype_ns, true,
+ test->cache_entry_flags, &expire);
+ }
+
+ /*
+ * Check whether ns__query_sfcache() behaves as expected.
+ */
+ ns__query_sfcache(qctx);
+
+ if (test->servfail_expected) {
+ if (qctx->result != DNS_R_SERVFAIL) {
+ fail_msg("# test \"%s\" on line %d: "
+ "expected SERVFAIL, got %s",
+ test->id.description, test->id.lineno,
+ isc_result_totext(qctx->result));
+ }
+ } else {
+ if (qctx->result != ISC_R_SUCCESS) {
+ fail_msg("# test \"%s\" on line %d: "
+ "expected success, got %s",
+ test->id.description, test->id.lineno,
+ isc_result_totext(qctx->result));
+ }
+ }
+
+ /*
+ * Clean up.
+ */
+ ns_test_qctx_destroy(&qctx);
+ ns_hooktable_free(mctx, (void **)&query_hooks);
+}
+
+/* test ns__query_sfcache() */
+ISC_RUN_TEST_IMPL(ns_query_sfcache) {
+ size_t i;
+
+ const ns__query_sfcache_test_params_t tests[] = {
+ /*
+ * Sanity check for an empty SERVFAIL cache.
+ */
+ {
+ NS_TEST_ID("query: RD=1, CD=0; cache: empty"),
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .cache_entry_present = false,
+ .servfail_expected = false,
+ },
+ /*
+ * Query: RD=1, CD=0. Cache entry: CD=0. Should SERVFAIL.
+ */
+ {
+ NS_TEST_ID("query: RD=1, CD=0; cache: CD=0"),
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .cache_entry_present = true,
+ .cache_entry_flags = 0,
+ .servfail_expected = true,
+ },
+ /*
+ * Query: RD=1, CD=1. Cache entry: CD=0. Should not SERVFAIL:
+ * failed validation should not influence CD=1 queries.
+ */
+ {
+ NS_TEST_ID("query: RD=1, CD=1; cache: CD=0"),
+ .qflags = DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_CD,
+ .cache_entry_present = true,
+ .cache_entry_flags = 0,
+ .servfail_expected = false,
+ },
+ /*
+ * Query: RD=1, CD=1. Cache entry: CD=1. Should SERVFAIL:
+ * SERVFAIL responses elicited by CD=1 queries can be
+ * "replayed" for other CD=1 queries during the lifetime of the
+ * SERVFAIL cache entry.
+ */
+ {
+ NS_TEST_ID("query: RD=1, CD=1; cache: CD=1"),
+ .qflags = DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_CD,
+ .cache_entry_present = true,
+ .cache_entry_flags = NS_FAILCACHE_CD,
+ .servfail_expected = true,
+ },
+ /*
+ * Query: RD=1, CD=0. Cache entry: CD=1. Should SERVFAIL: if
+ * a CD=1 query elicited a SERVFAIL, a CD=0 query for the same
+ * QNAME and QTYPE will SERVFAIL as well.
+ */
+ {
+ NS_TEST_ID("query: RD=1, CD=0; cache: CD=1"),
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .cache_entry_present = true,
+ .cache_entry_flags = NS_FAILCACHE_CD,
+ .servfail_expected = true,
+ },
+ /*
+ * Query: RD=0, CD=0. Cache entry: CD=0. Should not SERVFAIL
+ * despite a matching entry being present as the SERVFAIL cache
+ * should not be consulted for non-recursive queries.
+ */
+ {
+ NS_TEST_ID("query: RD=0, CD=0; cache: CD=0"),
+ .qflags = 0,
+ .cache_entry_present = true,
+ .cache_entry_flags = 0,
+ .servfail_expected = false,
+ },
+ };
+
+ UNUSED(state);
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ run_sfcache_test(&tests[i]);
+ }
+}
+
+/*****
+***** ns__query_start() tests
+*****/
+
+/*%
+ * Structure containing parameters for ns__query_start_test().
+ */
+typedef struct {
+ const ns_test_id_t id; /* libns test identifier */
+ const char *qname; /* QNAME */
+ dns_rdatatype_t qtype; /* QTYPE */
+ unsigned int qflags; /* query flags */
+ bool disable_name_checks; /* if set to true, owner
+ * name
+ * checks will
+ * be disabled for the
+ * view created
+ * */
+ bool recursive_service; /* if set to true, the view
+ * created will
+ * have a cache
+ * database
+ * attached */
+ const char *auth_zone_origin; /* origin name of the zone
+ * the
+ * created view will be
+ * authoritative for */
+ const char *auth_zone_path; /* path to load the
+ * authoritative
+ * zone from */
+ enum { /* expected result: */
+ NS__QUERY_START_R_INVALID,
+ NS__QUERY_START_R_REFUSE, /* query should be REFUSED */
+ NS__QUERY_START_R_CACHE, /* query should be answered from
+ * cache */
+ NS__QUERY_START_R_AUTH, /* query should be answered using
+ * authoritative data */
+ } expected_result;
+} ns__query_start_test_params_t;
+
+/*%
+ * Perform a single ns__query_start() check using given parameters.
+ */
+static void
+run_start_test(const ns__query_start_test_params_t *test) {
+ ns_hooktable_t *query_hooks = NULL;
+ query_ctx_t *qctx = NULL;
+ isc_result_t result;
+ const ns_hook_t hook = {
+ .action = ns_test_hook_catch_call,
+ };
+
+ REQUIRE(test != NULL);
+ REQUIRE(test->id.description != NULL);
+ REQUIRE((test->auth_zone_origin == NULL &&
+ test->auth_zone_path == NULL) ||
+ (test->auth_zone_origin != NULL &&
+ test->auth_zone_path != NULL));
+
+ /*
+ * Interrupt execution if query_lookup() or ns_query_done() is called.
+ */
+
+ ns_hooktable_create(mctx, &query_hooks);
+ ns_hook_add(query_hooks, mctx, NS_QUERY_LOOKUP_BEGIN, &hook);
+ ns_hook_add(query_hooks, mctx, NS_QUERY_DONE_BEGIN, &hook);
+ ns__hook_table = query_hooks;
+
+ /*
+ * Construct a query context using the supplied parameters.
+ */
+ {
+ const ns_test_qctx_create_params_t qctx_params = {
+ .qname = test->qname,
+ .qtype = test->qtype,
+ .qflags = test->qflags,
+ .with_cache = test->recursive_service,
+ };
+ result = ns_test_qctx_create(&qctx_params, &qctx);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ /*
+ * Enable view->checknames by default, disable if requested.
+ */
+ qctx->client->view->checknames = !test->disable_name_checks;
+
+ /*
+ * Load zone from file and attach it to the client's view, if
+ * requested.
+ */
+ if (test->auth_zone_path != NULL) {
+ result = ns_test_serve_zone(test->auth_zone_origin,
+ test->auth_zone_path,
+ qctx->client->view);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
+
+ /*
+ * Check whether ns__query_start() behaves as expected.
+ */
+ ns__query_start(qctx);
+
+ switch (test->expected_result) {
+ case NS__QUERY_START_R_REFUSE:
+ if (qctx->result != DNS_R_REFUSED) {
+ fail_msg("# test \"%s\" on line %d: "
+ "expected REFUSED, got %s",
+ test->id.description, test->id.lineno,
+ isc_result_totext(qctx->result));
+ }
+ if (qctx->zone != NULL) {
+ fail_msg("# test \"%s\" on line %d: "
+ "no zone was expected to be attached to "
+ "query context, but some was",
+ test->id.description, test->id.lineno);
+ }
+ if (qctx->db != NULL) {
+ fail_msg("# test \"%s\" on line %d: "
+ "no database was expected to be attached to "
+ "query context, but some was",
+ test->id.description, test->id.lineno);
+ }
+ break;
+ case NS__QUERY_START_R_CACHE:
+ if (qctx->result != ISC_R_SUCCESS) {
+ fail_msg("# test \"%s\" on line %d: "
+ "expected success, got %s",
+ test->id.description, test->id.lineno,
+ isc_result_totext(qctx->result));
+ }
+ if (qctx->zone != NULL) {
+ fail_msg("# test \"%s\" on line %d: "
+ "no zone was expected to be attached to "
+ "query context, but some was",
+ test->id.description, test->id.lineno);
+ }
+ if (qctx->db == NULL || qctx->db != qctx->client->view->cachedb)
+ {
+ fail_msg("# test \"%s\" on line %d: "
+ "cache database was expected to be "
+ "attached to query context, but it was not",
+ test->id.description, test->id.lineno);
+ }
+ break;
+ case NS__QUERY_START_R_AUTH:
+ if (qctx->result != ISC_R_SUCCESS) {
+ fail_msg("# test \"%s\" on line %d: "
+ "expected success, got %s",
+ test->id.description, test->id.lineno,
+ isc_result_totext(qctx->result));
+ }
+ if (qctx->zone == NULL) {
+ fail_msg("# test \"%s\" on line %d: "
+ "a zone was expected to be attached to query "
+ "context, but it was not",
+ test->id.description, test->id.lineno);
+ }
+ if (qctx->db == qctx->client->view->cachedb) {
+ fail_msg("# test \"%s\" on line %d: "
+ "cache database was not expected to be "
+ "attached to query context, but it is",
+ test->id.description, test->id.lineno);
+ }
+ break;
+ case NS__QUERY_START_R_INVALID:
+ fail_msg("# test \"%s\" on line %d has no expected result set",
+ test->id.description, test->id.lineno);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ /*
+ * Clean up.
+ */
+ if (test->auth_zone_path != NULL) {
+ ns_test_cleanup_zone();
+ }
+ ns_test_qctx_destroy(&qctx);
+ ns_hooktable_free(mctx, (void **)&query_hooks);
+}
+
+/* test ns__query_start() */
+ISC_RUN_TEST_IMPL(ns_query_start) {
+ size_t i;
+
+ const ns__query_start_test_params_t tests[] = {
+ /*
+ * Recursive foo/A query to a server without recursive service
+ * and no zones configured. Query should be REFUSED.
+ */
+ {
+ NS_TEST_ID("foo/A, no cache, no auth"),
+ .qname = "foo",
+ .qtype = dns_rdatatype_a,
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .recursive_service = false,
+ .expected_result = NS__QUERY_START_R_REFUSE,
+ },
+ /*
+ * Recursive foo/A query to a server with recursive service and
+ * no zones configured. Query should be answered from cache.
+ */
+ {
+ NS_TEST_ID("foo/A, cache, no auth"),
+ .qname = "foo",
+ .qtype = dns_rdatatype_a,
+ .recursive_service = true,
+ .expected_result = NS__QUERY_START_R_CACHE,
+ },
+ /*
+ * Recursive foo/A query to a server with recursive service and
+ * zone "foo" configured. Query should be answered from
+ * authoritative data.
+ */
+ {
+ NS_TEST_ID("foo/A, RD=1, cache, auth for foo"),
+ .qname = "foo",
+ .qtype = dns_rdatatype_a,
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .recursive_service = true,
+ .auth_zone_origin = "foo",
+ .auth_zone_path = TESTS_DIR "/testdata/query/foo.db",
+ .expected_result = NS__QUERY_START_R_AUTH,
+ },
+ /*
+ * Recursive bar/A query to a server without recursive service
+ * and zone "foo" configured. Query should be REFUSED.
+ */
+ {
+ NS_TEST_ID("bar/A, RD=1, no cache, auth for foo"),
+ .qname = "bar",
+ .qtype = dns_rdatatype_a,
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .recursive_service = false,
+ .auth_zone_origin = "foo",
+ .auth_zone_path = TESTS_DIR "/testdata/query/foo.db",
+ .expected_result = NS__QUERY_START_R_REFUSE,
+ },
+ /*
+ * Recursive bar/A query to a server with recursive service and
+ * zone "foo" configured. Query should be answered from
+ * cache.
+ */
+ {
+ NS_TEST_ID("bar/A, RD=1, cache, auth for foo"),
+ .qname = "bar",
+ .qtype = dns_rdatatype_a,
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .recursive_service = true,
+ .auth_zone_origin = "foo",
+ .auth_zone_path = TESTS_DIR "/testdata/query/foo.db",
+ .expected_result = NS__QUERY_START_R_CACHE,
+ },
+ /*
+ * Recursive bar.foo/DS query to a server with recursive
+ * service and zone "foo" configured. Query should be answered
+ * from authoritative data.
+ */
+ {
+ NS_TEST_ID("bar.foo/DS, RD=1, cache, auth for foo"),
+ .qname = "bar.foo",
+ .qtype = dns_rdatatype_ds,
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .recursive_service = true,
+ .auth_zone_origin = "foo",
+ .auth_zone_path = TESTS_DIR "/testdata/query/foo.db",
+ .expected_result = NS__QUERY_START_R_AUTH,
+ },
+ /*
+ * Non-recursive bar.foo/DS query to a server with recursive
+ * service and zone "foo" configured. Query should be answered
+ * from authoritative data.
+ */
+ {
+ NS_TEST_ID("bar.foo/DS, RD=0, cache, auth for foo"),
+ .qname = "bar.foo",
+ .qtype = dns_rdatatype_ds,
+ .qflags = 0,
+ .recursive_service = true,
+ .auth_zone_origin = "foo",
+ .auth_zone_path = TESTS_DIR "/testdata/query/foo.db",
+ .expected_result = NS__QUERY_START_R_AUTH,
+ },
+ /*
+ * Recursive foo/DS query to a server with recursive service
+ * and zone "foo" configured. Query should be answered from
+ * cache.
+ */
+ {
+ NS_TEST_ID("foo/DS, RD=1, cache, auth for foo"),
+ .qname = "foo",
+ .qtype = dns_rdatatype_ds,
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .recursive_service = true,
+ .auth_zone_origin = "foo",
+ .auth_zone_path = TESTS_DIR "/testdata/query/foo.db",
+ .expected_result = NS__QUERY_START_R_CACHE,
+ },
+ /*
+ * Non-recursive foo/DS query to a server with recursive
+ * service and zone "foo" configured. Query should be answered
+ * from authoritative data.
+ */
+ {
+ NS_TEST_ID("foo/DS, RD=0, cache, auth for foo"),
+ .qname = "foo",
+ .qtype = dns_rdatatype_ds,
+ .qflags = 0,
+ .recursive_service = true,
+ .auth_zone_origin = "foo",
+ .auth_zone_path = TESTS_DIR "/testdata/query/foo.db",
+ .expected_result = NS__QUERY_START_R_AUTH,
+ },
+ /*
+ * Recursive _foo/A query to a server with recursive service,
+ * no zones configured and owner name checks disabled. Query
+ * should be answered from cache.
+ */
+ {
+ NS_TEST_ID("_foo/A, cache, no auth, name checks off"),
+ .qname = "_foo",
+ .qtype = dns_rdatatype_a,
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .disable_name_checks = true,
+ .recursive_service = true,
+ .expected_result = NS__QUERY_START_R_CACHE,
+ },
+ /*
+ * Recursive _foo/A query to a server with recursive service,
+ * no zones configured and owner name checks enabled. Query
+ * should be REFUSED.
+ */
+ {
+ NS_TEST_ID("_foo/A, cache, no auth, name checks on"),
+ .qname = "_foo",
+ .qtype = dns_rdatatype_a,
+ .qflags = DNS_MESSAGEFLAG_RD,
+ .disable_name_checks = false,
+ .recursive_service = true,
+ .expected_result = NS__QUERY_START_R_REFUSE,
+ },
+ };
+
+ UNUSED(state);
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ run_start_test(&tests[i]);
+ }
+}
+
+/*****
+***** tests for ns_query_hookasync().
+*****/
+
+/*%
+ * Structure containing parameters for ns__query_hookasync_test().
+ */
+typedef struct {
+ const ns_test_id_t id; /* libns test identifier */
+ ns_hookpoint_t hookpoint; /* hook point specified for resume */
+ ns_hookpoint_t hookpoint2; /* expected hook point used after resume */
+ ns_hook_action_t action; /* action for the hook point */
+ isc_result_t start_result; /* result of 'runasync' */
+ bool quota_ok; /* true if recursion quota should be okay */
+ bool do_cancel; /* true if query should be canceled
+ * in test */
+} ns__query_hookasync_test_params_t;
+
+/* Data structure passed from tests to hooks */
+typedef struct hookasync_data {
+ bool async; /* true if in a hook-triggered
+ * asynchronous process */
+ bool canceled; /* true if the query has been canceled */
+ isc_result_t start_result; /* result of 'runasync' */
+ ns_hook_resevent_t *rev; /* resume event sent on completion */
+ query_ctx_t qctx; /* shallow copy of qctx passed to hook */
+ ns_hookpoint_t hookpoint; /* specifies where to resume */
+ ns_hookpoint_t lasthookpoint; /* remember the last hook point called */
+} hookasync_data_t;
+
+/*
+ * 'destroy' callback of hook recursion ctx.
+ * The dynamically allocated context will be freed here, thereby proving
+ * this is actually called; otherwise tests would fail due to memory leak.
+ */
+static void
+destroy_hookactx(ns_hookasync_t **ctxp) {
+ ns_hookasync_t *ctx = *ctxp;
+
+ *ctxp = NULL;
+ isc_mem_putanddetach(&ctx->mctx, ctx, sizeof(*ctx));
+}
+
+/* 'cancel' callback of hook recursion ctx. */
+static void
+cancel_hookactx(ns_hookasync_t *ctx) {
+ /* Mark the hook data so the test can confirm this is called. */
+ ((hookasync_data_t *)ctx->private)->canceled = true;
+}
+
+/* 'runasync' callback passed to ns_query_hookasync */
+static isc_result_t
+test_hookasync(query_ctx_t *qctx, isc_mem_t *memctx, void *arg,
+ isc_task_t *task, isc_taskaction_t action, void *evarg,
+ ns_hookasync_t **ctxp) {
+ hookasync_data_t *asdata = arg;
+ ns_hookasync_t *ctx = NULL;
+ ns_hook_resevent_t *rev = NULL;
+
+ if (asdata->start_result != ISC_R_SUCCESS) {
+ return (asdata->start_result);
+ }
+
+ ctx = isc_mem_get(memctx, sizeof(*ctx));
+ rev = (ns_hook_resevent_t *)isc_event_allocate(
+ memctx, task, NS_EVENT_HOOKASYNCDONE, action, evarg,
+ sizeof(*rev));
+
+ rev->hookpoint = asdata->hookpoint;
+ rev->origresult = DNS_R_NXDOMAIN;
+ rev->saved_qctx = qctx;
+ rev->ctx = ctx;
+ asdata->rev = rev;
+
+ *ctx = (ns_hookasync_t){ .private = asdata };
+ isc_mem_attach(memctx, &ctx->mctx);
+ ctx->destroy = destroy_hookactx;
+ ctx->cancel = cancel_hookactx;
+
+ *ctxp = ctx;
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Main logic for hook actions.
+ * 'hookpoint' should identify the point that calls the hook. It will be
+ * remembered in the hook data, so that the test can confirm which hook point
+ * was last used.
+ */
+static ns_hookresult_t
+hook_async_common(void *arg, void *data, isc_result_t *resultp,
+ ns_hookpoint_t hookpoint) {
+ query_ctx_t *qctx = arg;
+ hookasync_data_t *asdata = data;
+ isc_result_t result;
+
+ asdata->qctx = *qctx; /* remember passed ctx for inspection */
+ asdata->lasthookpoint = hookpoint; /* ditto */
+
+ if (!asdata->async) {
+ /* Initial call to the hook; start recursion */
+ result = ns_query_hookasync(qctx, test_hookasync, asdata);
+ if (result == ISC_R_SUCCESS) {
+ asdata->async = true;
+ }
+ } else {
+ /*
+ * Resume from the completion of async event.
+ * fetchhandle should have been detached so that we can start
+ * another async event or DNS recursive resolution.
+ */
+ INSIST(qctx->client->fetchhandle == NULL);
+ asdata->async = false;
+ switch (hookpoint) {
+ case NS_QUERY_GOT_ANSWER_BEGIN:
+ case NS_QUERY_NODATA_BEGIN:
+ case NS_QUERY_NXDOMAIN_BEGIN:
+ case NS_QUERY_NCACHE_BEGIN:
+ INSIST(*resultp == DNS_R_NXDOMAIN);
+ break;
+ default:;
+ }
+ }
+
+ *resultp = ISC_R_UNSET;
+ return (NS_HOOK_RETURN);
+}
+
+static ns_hookresult_t
+hook_async_query_setup(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_SETUP));
+}
+
+static ns_hookresult_t
+hook_async_query_start_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_START_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_lookup_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_LOOKUP_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_resume_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_RESUME_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_got_answer_begin(void *arg, void *data,
+ isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp,
+ NS_QUERY_GOT_ANSWER_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_respond_any_begin(void *arg, void *data,
+ isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp,
+ NS_QUERY_RESPOND_ANY_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_addanswer_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp,
+ NS_QUERY_ADDANSWER_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_notfound_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_NOTFOUND_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_prep_delegation_begin(void *arg, void *data,
+ isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp,
+ NS_QUERY_PREP_DELEGATION_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_zone_delegation_begin(void *arg, void *data,
+ isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp,
+ NS_QUERY_ZONE_DELEGATION_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_delegation_begin(void *arg, void *data,
+ isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp,
+ NS_QUERY_DELEGATION_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_delegation_recurse_begin(void *arg, void *data,
+ isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp,
+ NS_QUERY_DELEGATION_RECURSE_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_nodata_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_NODATA_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_nxdomain_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_NXDOMAIN_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_ncache_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_NCACHE_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_cname_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_CNAME_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_dname_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_DNAME_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_respond_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_RESPOND_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_response_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp,
+ NS_QUERY_PREP_RESPONSE_BEGIN));
+}
+
+static ns_hookresult_t
+hook_async_query_done_begin(void *arg, void *data, isc_result_t *resultp) {
+ return (hook_async_common(arg, data, resultp, NS_QUERY_DONE_BEGIN));
+}
+
+/*
+ * hook on destroying actx. Can't be used for async event, but we use this
+ * to remember the qctx at that point.
+ */
+static ns_hookresult_t
+ns_test_qctx_destroy_hook(void *arg, void *data, isc_result_t *resultp) {
+ query_ctx_t *qctx = arg;
+ hookasync_data_t *asdata = data;
+
+ asdata->qctx = *qctx; /* remember passed ctx for inspection */
+ *resultp = ISC_R_UNSET;
+ return (NS_HOOK_CONTINUE);
+}
+
+static void
+run_hookasync_test(const ns__query_hookasync_test_params_t *test) {
+ query_ctx_t *qctx = NULL;
+ isc_result_t result;
+ hookasync_data_t asdata = {
+ .async = false,
+ .canceled = false,
+ .start_result = test->start_result,
+ .hookpoint = test->hookpoint,
+ };
+ const ns_hook_t testhook = {
+ .action = test->action,
+ .action_data = &asdata,
+ };
+ const ns_hook_t destroyhook = {
+ .action = ns_test_qctx_destroy_hook,
+ .action_data = &asdata,
+ };
+ isc_quota_t *quota = NULL;
+ isc_statscounter_t srvfail_cnt;
+ bool expect_servfail = false;
+
+ /*
+ * Prepare hooks. We always begin with ns__query_start for simplicity.
+ * Its action will specify various different resume points (unusual
+ * in practice, but that's fine for the testing purpose).
+ */
+ ns__hook_table = NULL;
+ ns_hooktable_create(mctx, &ns__hook_table);
+ ns_hook_add(ns__hook_table, mctx, NS_QUERY_START_BEGIN, &testhook);
+ if (test->hookpoint2 != NS_QUERY_START_BEGIN) {
+ /*
+ * unless testing START_BEGIN itself, specify the hook for the
+ * expected resume point, too.
+ */
+ ns_hook_add(ns__hook_table, mctx, test->hookpoint2, &testhook);
+ }
+ ns_hook_add(ns__hook_table, mctx, NS_QUERY_QCTX_DESTROYED,
+ &destroyhook);
+
+ {
+ const ns_test_qctx_create_params_t qctx_params = {
+ .qname = "test.example.com",
+ .qtype = dns_rdatatype_aaaa,
+ };
+ result = ns_test_qctx_create(&qctx_params, &qctx);
+ INSIST(result == ISC_R_SUCCESS);
+ qctx->client->sendcb = send_noop;
+ }
+
+ /*
+ * Set recursion quota to the lowest possible value, then make it full
+ * if we want to exercise a quota failure case.
+ */
+ isc_quota_max(&sctx->recursionquota, 1);
+ if (!test->quota_ok) {
+ result = isc_quota_attach(&sctx->recursionquota, &quota);
+ INSIST(result == ISC_R_SUCCESS);
+ }
+
+ /* Remember SERVFAIL counter */
+ srvfail_cnt = ns_stats_get_counter(qctx->client->sctx->nsstats,
+ ns_statscounter_servfail);
+
+ /*
+ * If the query has been canceled, or async event didn't succeed,
+ * SERVFAIL will have to be sent. In this case we need to have
+ * 'reqhandle' attach to the client's handle as it's detached in
+ * query_error.
+ */
+ if (test->start_result != ISC_R_SUCCESS || !test->quota_ok ||
+ test->do_cancel)
+ {
+ expect_servfail = true;
+ isc_nmhandle_attach(qctx->client->handle,
+ &qctx->client->reqhandle);
+ }
+
+ /*
+ * Emulate query handling from query_start.
+ * Specified hook should be called.
+ */
+ qctx->client->state = NS_CLIENTSTATE_WORKING;
+ result = ns__query_start(qctx);
+ INSIST(result == ISC_R_UNSET);
+
+ /*
+ * hook-triggered async event should be happening unless it hits
+ * recursion quota limit or 'runasync' callback fails.
+ */
+ INSIST(asdata.async ==
+ (test->quota_ok && test->start_result == ISC_R_SUCCESS));
+
+ /*
+ * Emulate cancel if so specified.
+ * The cancel callback should be called.
+ */
+ if (test->do_cancel) {
+ ns_query_cancel(qctx->client);
+ }
+ INSIST(asdata.canceled == test->do_cancel);
+
+ /* If async event has started, manually invoke the 'done' event. */
+ if (asdata.async) {
+ qctx->client->now = 0; /* set to sentinel before resume */
+ asdata.rev->ev_action(asdata.rev->ev_sender,
+ (isc_event_t *)asdata.rev);
+
+ /* Confirm necessary cleanup has been performed. */
+ INSIST(qctx->client->query.hookactx == NULL);
+ INSIST(qctx->client->state == NS_CLIENTSTATE_WORKING);
+ INSIST(qctx->client->recursionquota == NULL);
+ INSIST(ns_stats_get_counter(qctx->client->sctx->nsstats,
+ ns_statscounter_recursclients) ==
+ 0);
+ INSIST(!ISC_LINK_LINKED(qctx->client, rlink));
+ if (!test->do_cancel) {
+ /*
+ * In the normal case the client's timestamp is updated
+ * and the query handling has been resumed from the
+ * expected point.
+ */
+ INSIST(qctx->client->now != 0);
+ INSIST(asdata.lasthookpoint == test->hookpoint2);
+ }
+ } else {
+ INSIST(qctx->client->query.hookactx == NULL);
+ }
+
+ /*
+ * Confirm SERVFAIL has been sent if it was expected.
+ * Also, the last-generated qctx should have detach_client being true.
+ */
+ if (expect_servfail) {
+ INSIST(ns_stats_get_counter(qctx->client->sctx->nsstats,
+ ns_statscounter_servfail) ==
+ srvfail_cnt + 1);
+ if (test->do_cancel) {
+ /* qctx was created on resume and copied in hook */
+ INSIST(asdata.qctx.detach_client);
+ } else {
+ INSIST(qctx->detach_client);
+ }
+ }
+
+ /*
+ * Cleanup. Note that we've kept 'qctx' until now; otherwise
+ * qctx->client may have been invalidated while we still need it.
+ */
+ ns_test_qctx_destroy(&qctx);
+ ns_hooktable_free(mctx, (void **)&ns__hook_table);
+ if (quota != NULL) {
+ isc_quota_detach(&quota);
+ }
+}
+
+ISC_RUN_TEST_IMPL(ns_query_hookasync) {
+ size_t i;
+
+ UNUSED(state);
+
+ const ns__query_hookasync_test_params_t tests[] = {
+ {
+ NS_TEST_ID("normal case"),
+ NS_QUERY_START_BEGIN,
+ NS_QUERY_START_BEGIN,
+ hook_async_query_start_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("quota fail"),
+ NS_QUERY_START_BEGIN,
+ NS_QUERY_START_BEGIN,
+ hook_async_query_start_begin,
+ ISC_R_SUCCESS,
+ false,
+ false,
+ },
+ {
+ NS_TEST_ID("start fail"),
+ NS_QUERY_START_BEGIN,
+ NS_QUERY_START_BEGIN,
+ hook_async_query_start_begin,
+ ISC_R_FAILURE,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("query cancel"),
+ NS_QUERY_START_BEGIN,
+ NS_QUERY_START_BEGIN,
+ hook_async_query_start_begin,
+ ISC_R_SUCCESS,
+ true,
+ true,
+ },
+ /*
+ * The rest of the test case just confirms supported hookpoints
+ * with the same test logic.
+ */
+ {
+ NS_TEST_ID("async from setup"),
+ NS_QUERY_SETUP,
+ NS_QUERY_SETUP,
+ hook_async_query_setup,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from lookup"),
+ NS_QUERY_LOOKUP_BEGIN,
+ NS_QUERY_LOOKUP_BEGIN,
+ hook_async_query_lookup_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from resume"),
+ NS_QUERY_RESUME_BEGIN,
+ NS_QUERY_RESUME_BEGIN,
+ hook_async_query_resume_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from resume restored"),
+ NS_QUERY_RESUME_RESTORED,
+ NS_QUERY_RESUME_BEGIN,
+ hook_async_query_resume_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from gotanswer"),
+ NS_QUERY_GOT_ANSWER_BEGIN,
+ NS_QUERY_GOT_ANSWER_BEGIN,
+ hook_async_query_got_answer_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from respond any"),
+ NS_QUERY_RESPOND_ANY_BEGIN,
+ NS_QUERY_RESPOND_ANY_BEGIN,
+ hook_async_query_respond_any_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from add answer"),
+ NS_QUERY_ADDANSWER_BEGIN,
+ NS_QUERY_ADDANSWER_BEGIN,
+ hook_async_query_addanswer_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from notfound"),
+ NS_QUERY_NOTFOUND_BEGIN,
+ NS_QUERY_NOTFOUND_BEGIN,
+ hook_async_query_notfound_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from prep delegation"),
+ NS_QUERY_PREP_DELEGATION_BEGIN,
+ NS_QUERY_PREP_DELEGATION_BEGIN,
+ hook_async_query_prep_delegation_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from zone delegation"),
+ NS_QUERY_ZONE_DELEGATION_BEGIN,
+ NS_QUERY_ZONE_DELEGATION_BEGIN,
+ hook_async_query_zone_delegation_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from delegation"),
+ NS_QUERY_DELEGATION_BEGIN,
+ NS_QUERY_DELEGATION_BEGIN,
+ hook_async_query_delegation_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from async delegation"),
+ NS_QUERY_DELEGATION_RECURSE_BEGIN,
+ NS_QUERY_DELEGATION_RECURSE_BEGIN,
+ hook_async_query_delegation_recurse_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from nodata"),
+ NS_QUERY_NODATA_BEGIN,
+ NS_QUERY_NODATA_BEGIN,
+ hook_async_query_nodata_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from nxdomain"),
+ NS_QUERY_NXDOMAIN_BEGIN,
+ NS_QUERY_NXDOMAIN_BEGIN,
+ hook_async_query_nxdomain_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from ncache"),
+ NS_QUERY_NCACHE_BEGIN,
+ NS_QUERY_NCACHE_BEGIN,
+ hook_async_query_ncache_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from CNAME"),
+ NS_QUERY_CNAME_BEGIN,
+ NS_QUERY_CNAME_BEGIN,
+ hook_async_query_cname_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from DNAME"),
+ NS_QUERY_DNAME_BEGIN,
+ NS_QUERY_DNAME_BEGIN,
+ hook_async_query_dname_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from prep response"),
+ NS_QUERY_PREP_RESPONSE_BEGIN,
+ NS_QUERY_PREP_RESPONSE_BEGIN,
+ hook_async_query_response_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from respond"),
+ NS_QUERY_RESPOND_BEGIN,
+ NS_QUERY_RESPOND_BEGIN,
+ hook_async_query_respond_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from done begin"),
+ NS_QUERY_DONE_BEGIN,
+ NS_QUERY_DONE_BEGIN,
+ hook_async_query_done_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ {
+ NS_TEST_ID("async from done send"),
+ NS_QUERY_DONE_SEND,
+ NS_QUERY_DONE_BEGIN,
+ hook_async_query_done_begin,
+ ISC_R_SUCCESS,
+ true,
+ false,
+ },
+ };
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ run_hookasync_test(&tests[i]);
+ }
+}
+
+/*****
+***** tests for higher level ("e2e") behavior of ns_query_hookasync().
+***** It exercises overall behavior for some selected cases, while
+***** ns__query_hookasync_test exercises implementation details for a
+***** simple scenario and for all supported hook points.
+*****/
+
+/*%
+ * Structure containing parameters for ns__query_hookasync_e2e_test().
+ */
+typedef struct {
+ const ns_test_id_t id; /* libns test identifier */
+ const char *qname; /* QNAME */
+ ns_hookpoint_t hookpoint; /* hook point specified for resume */
+ isc_result_t start_result; /* result of 'runasync' */
+ bool do_cancel; /* true if query should be canceled
+ * in test */
+ dns_rcode_t expected_rcode;
+} ns__query_hookasync_e2e_test_params_t;
+
+/* data structure passed from tests to hooks */
+typedef struct hookasync_e2e_data {
+ bool async; /* true if in a hook-triggered
+ * asynchronous process */
+ ns_hook_resevent_t *rev; /* resume event sent on completion */
+ ns_hookpoint_t hookpoint; /* specifies where to resume */
+ isc_result_t start_result; /* result of 'runasync' */
+ dns_rcode_t expected_rcode;
+ bool done; /* if SEND_DONE hook is called */
+} hookasync_e2e_data_t;
+
+/* Cancel callback. Just need to be defined, it doesn't have to do anything. */
+static void
+cancel_e2ehookactx(ns_hookasync_t *ctx) {
+ UNUSED(ctx);
+}
+
+/* 'runasync' callback passed to ns_query_hookasync */
+static isc_result_t
+test_hookasync_e2e(query_ctx_t *qctx, isc_mem_t *memctx, void *arg,
+ isc_task_t *task, isc_taskaction_t action, void *evarg,
+ ns_hookasync_t **ctxp) {
+ ns_hookasync_t *ctx = NULL;
+ ns_hook_resevent_t *rev = NULL;
+ hookasync_e2e_data_t *asdata = arg;
+
+ if (asdata->start_result != ISC_R_SUCCESS) {
+ return (asdata->start_result);
+ }
+
+ ctx = isc_mem_get(memctx, sizeof(*ctx));
+ rev = (ns_hook_resevent_t *)isc_event_allocate(
+ memctx, task, NS_EVENT_HOOKASYNCDONE, action, evarg,
+ sizeof(*rev));
+
+ rev->hookpoint = asdata->hookpoint;
+ rev->saved_qctx = qctx;
+ rev->ctx = ctx;
+ asdata->rev = rev;
+
+ *ctx = (ns_hookasync_t){ .private = asdata };
+ isc_mem_attach(memctx, &ctx->mctx);
+ ctx->destroy = destroy_hookactx;
+ ctx->cancel = cancel_e2ehookactx;
+
+ *ctxp = ctx;
+ return (ISC_R_SUCCESS);
+}
+
+static ns_hookresult_t
+hook_async_e2e(void *arg, void *data, isc_result_t *resultp) {
+ query_ctx_t *qctx = arg;
+ hookasync_e2e_data_t *asdata = data;
+ isc_result_t result;
+
+ if (!asdata->async) {
+ /* Initial call to the hook; start async event */
+ result = ns_query_hookasync(qctx, test_hookasync_e2e, asdata);
+ if (result != ISC_R_SUCCESS) {
+ *resultp = result;
+ return (NS_HOOK_RETURN);
+ }
+
+ asdata->async = true;
+ asdata->rev->origresult = *resultp; /* save it for resume */
+ *resultp = ISC_R_UNSET;
+ return (NS_HOOK_RETURN);
+ } else {
+ /* Resume from the completion of async event */
+ asdata->async = false;
+ /* Don't touch 'resultp' */
+ return (NS_HOOK_CONTINUE);
+ }
+}
+
+/*
+ * Check whether the final response has expected the RCODE according to
+ * the test scenario.
+ */
+static ns_hookresult_t
+hook_donesend(void *arg, void *data, isc_result_t *resultp) {
+ query_ctx_t *qctx = arg;
+ hookasync_e2e_data_t *asdata = data;
+
+ INSIST(qctx->client->message->rcode == asdata->expected_rcode);
+ asdata->done = true; /* Let the test know this hook is called */
+ *resultp = ISC_R_UNSET;
+ return (NS_HOOK_CONTINUE);
+}
+
+static void
+run_hookasync_e2e_test(const ns__query_hookasync_e2e_test_params_t *test) {
+ query_ctx_t *qctx = NULL;
+ isc_result_t result;
+ hookasync_e2e_data_t asdata = {
+ .async = false,
+ .hookpoint = test->hookpoint,
+ .start_result = test->start_result,
+ .expected_rcode = test->expected_rcode,
+ .done = false,
+ };
+ const ns_hook_t donesend_hook = {
+ .action = hook_donesend,
+ .action_data = &asdata,
+ };
+ const ns_hook_t hook = {
+ .action = hook_async_e2e,
+ .action_data = &asdata,
+ };
+ const ns_test_qctx_create_params_t qctx_params = {
+ .qname = test->qname,
+ .qtype = dns_rdatatype_a,
+ .with_cache = true,
+ };
+
+ ns__hook_table = NULL;
+ ns_hooktable_create(mctx, &ns__hook_table);
+ ns_hook_add(ns__hook_table, mctx, test->hookpoint, &hook);
+ ns_hook_add(ns__hook_table, mctx, NS_QUERY_DONE_SEND, &donesend_hook);
+
+ result = ns_test_qctx_create(&qctx_params, &qctx);
+ INSIST(result == ISC_R_SUCCESS);
+
+ isc_sockaddr_any(&qctx->client->peeraddr); /* for sortlist */
+ qctx->client->sendcb = send_noop;
+
+ /* Load a zone. it should have ns.foo/A */
+ result = ns_test_serve_zone("foo", TESTS_DIR "/testdata/query/foo.db",
+ qctx->client->view);
+ INSIST(result == ISC_R_SUCCESS);
+
+ /*
+ * We expect to have a response sent all cases, so we need to
+ * setup reqhandle (which will be detached on the send).
+ */
+ isc_nmhandle_attach(qctx->client->handle, &qctx->client->reqhandle);
+
+ /* Handle the query. hook-based async event will be triggered. */
+ qctx->client->state = NS_CLIENTSTATE_WORKING;
+ ns__query_start(qctx);
+
+ /* If specified cancel the query at this point. */
+ if (test->do_cancel) {
+ ns_query_cancel(qctx->client);
+ }
+
+ if (test->start_result == ISC_R_SUCCESS) {
+ /*
+ * If async event has started, manually invoke the done event.
+ */
+ INSIST(asdata.async);
+ asdata.rev->ev_action(asdata.rev->ev_sender,
+ (isc_event_t *)asdata.rev);
+
+ /*
+ * Usually 'async' is reset to false on the 2nd call to
+ * the hook. But the hook isn't called if the query is
+ * canceled.
+ */
+ INSIST(asdata.done == !test->do_cancel);
+ INSIST(asdata.async == test->do_cancel);
+ } else {
+ INSIST(!asdata.async);
+ }
+
+ /* Cleanup */
+ ns_test_qctx_destroy(&qctx);
+ ns_test_cleanup_zone();
+ ns_hooktable_free(mctx, (void **)&ns__hook_table);
+}
+
+ISC_RUN_TEST_IMPL(ns_query_hookasync_e2e) {
+ UNUSED(state);
+
+ const ns__query_hookasync_e2e_test_params_t tests[] = {
+ {
+ NS_TEST_ID("positive answer"),
+ "ns.foo",
+ NS_QUERY_GOT_ANSWER_BEGIN,
+ ISC_R_SUCCESS,
+ false,
+ dns_rcode_noerror,
+ },
+ {
+ NS_TEST_ID("NXDOMAIN"),
+ "notexist.foo",
+ NS_QUERY_NXDOMAIN_BEGIN,
+ ISC_R_SUCCESS,
+ false,
+ dns_rcode_nxdomain,
+ },
+ {
+ NS_TEST_ID("async fail"),
+ "ns.foo",
+ NS_QUERY_DONE_BEGIN,
+ ISC_R_FAILURE,
+ false,
+ -1,
+ },
+ {
+ NS_TEST_ID("cancel query"),
+ "ns.foo",
+ NS_QUERY_DONE_BEGIN,
+ ISC_R_SUCCESS,
+ true,
+ -1,
+ },
+ };
+
+ for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ run_hookasync_e2e_test(&tests[i]);
+ }
+}
+
+ISC_TEST_LIST_START
+
+ISC_TEST_ENTRY_CUSTOM(ns_query_sfcache, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(ns_query_start, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(ns_query_hookasync, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(ns_query_hookasync_e2e, setup_test, teardown_test)
+
+ISC_TEST_LIST_END
+ISC_TEST_MAIN
diff --git a/tests/ns/testdata/notify/notify1.msg b/tests/ns/testdata/notify/notify1.msg
new file mode 100644
index 0000000..a84193b
--- /dev/null
+++ b/tests/ns/testdata/notify/notify1.msg
@@ -0,0 +1,3 @@
+# notify for example.com
+10 a6 10 10 00 01 00 00 00 00 00 00 07 65 78 61
+6d 70 6c 65 03 63 6f 6d 00 00 06 00 01
diff --git a/tests/ns/testdata/notify/zone1.db b/tests/ns/testdata/notify/zone1.db
new file mode 100644
index 0000000..b218d6d
--- /dev/null
+++ b/tests/ns/testdata/notify/zone1.db
@@ -0,0 +1,26 @@
+; 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 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+ in ns ns.example.com.
+ in ns ns2.example.com.
+ in ns ns3.example.com.
+ns in a 10.0.0.1
+ns2 in a 10.0.0.2
+ns3 in a 10.0.0.3
+
+a in a 1.2.3.4
diff --git a/tests/ns/testdata/query/foo.db b/tests/ns/testdata/query/foo.db
new file mode 100644
index 0000000..5fb2c42
--- /dev/null
+++ b/tests/ns/testdata/query/foo.db
@@ -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.
+
+$TTL 3600
+@ IN SOA localhost. postmaster.localhost. (
+ 1 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+ IN NS ns
+ns IN A 127.0.0.1
diff --git a/tests/unit-test-driver.sh.in b/tests/unit-test-driver.sh.in
new file mode 100644
index 0000000..9a60db1
--- /dev/null
+++ b/tests/unit-test-driver.sh.in
@@ -0,0 +1,60 @@
+#!/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.
+
+TOP_BUILDDIR=@abs_top_builddir@
+TOP_SRCDIR=@abs_top_srcdir@
+
+if [ -z "${1}" ]; then
+ echo "Usage: ${0} test_program" >&2
+ exit 1
+fi
+
+TEST_PROGRAM="${1}"
+TIMEOUT=300
+
+"${TEST_PROGRAM}" &
+TEST_PROGRAM_PID=${!}
+STATUS=124
+while [ ${TIMEOUT} -gt 0 ]; do
+ if ! kill -0 "${TEST_PROGRAM_PID}" 2>/dev/null; then
+ wait "${TEST_PROGRAM_PID}"
+ STATUS=${?}
+ break
+ fi
+ sleep 1
+ TIMEOUT=$((TIMEOUT - 1))
+done
+if [ ${TIMEOUT} -eq 0 ]; then
+ echo "PID ${TEST_PROGRAM_PID} exceeded run time limit, sending SIGABRT" >&2
+ kill -ABRT "${TEST_PROGRAM_PID}" 2>/dev/null
+fi
+
+TEST_PROGRAM_NAME=$(basename "${TEST_PROGRAM}")
+TEST_PROGRAM_WORK_DIR=$(dirname "${TEST_PROGRAM}")
+find "${TEST_PROGRAM_WORK_DIR}" -name 'core*' -or -name '*.core' | while read -r CORE_DUMP; do
+ BINARY=$(gdb --batch --core="${CORE_DUMP}" 2>/dev/null | sed -n "s/^Core was generated by \`\(.*\)'\.\$/\1/p")
+ if ! echo "${BINARY}" | grep -q "${TEST_PROGRAM_NAME}\$"; then
+ continue
+ fi
+ echo "I:${TEST_PROGRAM_NAME}:Core dump found: ${CORE_DUMP}"
+ echo "D:${TEST_PROGRAM_NAME}:backtrace from ${CORE_DUMP} start"
+ "${TOP_BUILDDIR}/libtool" --mode=execute gdb \
+ --batch \
+ --command="${TOP_SRCDIR}/bin/tests/system/run.gdb" \
+ --core="${CORE_DUMP}" \
+ -- \
+ "${BINARY}"
+ echo "D:${TEST_PROGRAM_NAME}:backtrace from ${CORE_DUMP} end"
+done
+
+exit ${STATUS}