diff options
Diffstat (limited to 'bin/tests/optional')
31 files changed, 7447 insertions, 0 deletions
diff --git a/bin/tests/optional/Kchild.example.+005+33180.key b/bin/tests/optional/Kchild.example.+005+33180.key new file mode 100644 index 0000000..ab92a6a --- /dev/null +++ b/bin/tests/optional/Kchild.example.+005+33180.key @@ -0,0 +1,5 @@ +; This is a zone-signing key, keyid 33180, for child.example. +; Created: 20181025104746 (Thu Oct 25 12:47:46 2018) +; Publish: 20181025104746 (Thu Oct 25 12:47:46 2018) +; Activate: 20181025104746 (Thu Oct 25 12:47:46 2018) +child.example. IN DNSKEY 256 3 5 AwEAAb9eatC8ASzDnRApcZuxyBrvJRANRQjCXQ1FWK+8vEyXV5NIE9Km hKIV2wbq2tLBPfjNQz4BTJ9RmDINf1RayDlt6L+IQV1JCaDaMjd1zU3n SQK18Y7fMu0ww4AMKOnoVRbkIxa3zlA0chImXcfPE0q2AvKBYLzPfkPO cfplAuRkLcGUxdADCipNzCOakpcd5gfm9Sa2HlaXcw3gyI1WcE8= diff --git a/bin/tests/optional/Kchild.example.+005+33180.private b/bin/tests/optional/Kchild.example.+005+33180.private new file mode 100644 index 0000000..83a50df --- /dev/null +++ b/bin/tests/optional/Kchild.example.+005+33180.private @@ -0,0 +1,13 @@ +Private-key-format: v1.3 +Algorithm: 5 (RSASHA1) +Modulus: v15q0LwBLMOdEClxm7HIGu8lEA1FCMJdDUVYr7y8TJdXk0gT0qaEohXbBura0sE9+M1DPgFMn1GYMg1/VFrIOW3ov4hBXUkJoNoyN3XNTedJArXxjt8y7TDDgAwo6ehVFuQjFrfOUDRyEiZdx88TSrYC8oFgvM9+Q85x+mUC5GQtwZTF0AMKKk3MI5qSlx3mB+b1JrYeVpdzDeDIjVZwTw== +PublicExponent: AQAB +PrivateExponent: WDsn9GU6BXGLENCK2MX3BLQN2oDDu24hiOTYJu5VwtpkPjuVKCIuNKzu9xmBGnqOIBBDWGsw8KOmEC247yOL/S53iRdBS8lI7yiqznc52RhlmrdPKXbNpVnPwil8wocw+oQYa7uvdPYxI2Yy3B/tRgUxlxSlc/LW/dr0BX2L7qr/aeOBeGSRUlCpc7tYU9a2RUaLpVxF6SlqicCpC91MAQ== +Prime1: 466f+JL66Bl4qYnkj0s9+1N3pYmdcM9Ja1AN66X4VLslA9Cm1JEaC5V9HOptfcXUk0XYEVnKeKM2lIQnvcLG0yuQHIa+pGi7P8vgQfdaRUE= +Prime2: 1yuUkTVRSbUWeUreEcHgeeBBJ61UshX7t07gnGgIr3artGdo2CVEb5//+2Mvj5bgjCQBvjBbmHNZrR0jKDRBTIGtqbBerOuhEN4AXdAEgY8= +Exponent1: KzUXbJ/P973ltR7S/hKEV66WVRbRhvf/cdsGWULs5n+BXcD59/r1W19qF9OxJZ4mYjBt+ZT1pIEsuXB+7jcJbkelGJTFlwO9DTVOgJZFTkE= +Exponent2: FTPsLertGbBIiKdB/sn2Dsx0Xy6LXAkihsu1AnSV9oRhIyPVhwcVGVLQ7Lq3YxThB648pbsqK3miapamcj3D+YAF1uTUT4Hgm0LlEll/OC0= +Coefficient: Vulw9kmmjKc+wmOukLdzheoA2hNPDVtgiynfzHybyXdqvapCoK+ZVmNFzjO0M41ATcpvya3iX0bekMQqYnBhLURNZUIyqz2nGskOjV8I5Jg= +Created: 20181025104746 +Publish: 20181025104746 +Activate: 20181025104746 diff --git a/bin/tests/optional/Makefile.in b/bin/tests/optional/Makefile.in new file mode 100644 index 0000000..29e026f --- /dev/null +++ b/bin/tests/optional/Makefile.in @@ -0,0 +1,254 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \ + ${OPENSSL_CFLAGS} @DST_GSSAPI_INC@ + +CDEFINES = @USE_GSSAPI@ + +CWARNINGS = +BACKTRACECFLAGS = @BACKTRACECFLAGS@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ + +DNSLIBS = ../../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +ISCLIBS = ../../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCCFGLIBS = ../../../lib/isccfg/libisccfg.@A@ + +DNSDEPLIBS = ../../../lib/dns/libdns.@A@ +ISCDEPLIBS = ../../../lib/isc/libisc.@A@ +ISCDEPNOSYMLIBS = ../../../lib/isc/libisc-nosymtbl.@A@ +ISCCFGDEPLIBS = ../../../lib/isccfg/libisccfg.@A@ + +LIBS = @LIBS@ + +SUBDIRS = + +# These programs are not built by default, but only when +# configured with --enable-developer or built explicitly with +# "make all_tests" + +TARGETS = @XTARGETS@ +XTARGETS = adb_test@EXEEXT@ \ + byaddr_test@EXEEXT@ \ + backtrace_test@EXEEXT@ \ + backtrace_test_nosymtbl@EXEEXT@ \ + byname_test@EXEEXT@ \ + db_test@EXEEXT@ \ + gsstest@EXEEXT@ \ + fsaccess_test@EXEEXT@ \ + inter_test@EXEEXT@ \ + lex_test@EXEEXT@ \ + lfsr_test@EXEEXT@ \ + log_test@EXEEXT@ \ + master_test@EXEEXT@ \ + mempool_test@EXEEXT@ \ + name_test@EXEEXT@ \ + nsecify@EXEEXT@ \ + ratelimiter_test@EXEEXT@ \ + rbt_test@EXEEXT@ \ + rwlock_test@EXEEXT@ \ + serial_test@EXEEXT@ \ + shutdown_test@EXEEXT@ \ + sig0_test@EXEEXT@ \ + sock_test@EXEEXT@ \ + sym_test@EXEEXT@ \ + task_test@EXEEXT@ \ + timer_test@EXEEXT@ \ + zone_test@EXEEXT@ + +SRCS = ${XSRCS} +XSRCS = adb_test.c \ + byaddr_test.c \ + backtrace_test.c \ + byname_test.c \ + db_test.c \ + fsaccess_test.c \ + gsstest.c \ + inter_test.c \ + lex_test.c \ + lfsr_test.c \ + log_test.c \ + master_test.c \ + mempool_test.c \ + name_test.c \ + nsecify.c \ + ratelimiter_test.c \ + rbt_test.c \ + rwlock_test.c \ + serial_test.c \ + shutdown_test.c \ + sig0_test.c \ + sock_test.c \ + sym_test.c \ + task_test.c \ + timer_test.c \ + zone_test.c + +@BIND9_MAKE_RULES@ + +# disable optimization for backtrace test to get the expected result +BTTEST_CFLAGS = ${BACKTRACECFLAGS} ${EXT_CFLAGS} ${ALL_CPPFLAGS} -g \ + ${ALWAYS_WARNINGS} ${STD_CWARNINGS} ${CWARNINGS} ${PTHREAD_CFLAGS} + +all_tests: ${XTARGETS} + +adb_test@EXEEXT@: adb_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ adb_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +backtrace_test_nosymtbl@EXEEXT@: ${srcdir}/backtrace_test.c ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} -o $@ \ + ${srcdir}/backtrace_test.c ${ISCLIBS} ${LIBS} + +backtrace_test@EXEEXT@: ${srcdir}/backtrace_test.c backtrace_test_nosymtbl@EXEEXT@ + #first step: create a first symbol table + rm -f symtbl.c + if test X${MKSYMTBL_PROGRAM} != X; then \ + ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \ + backtrace_test_nosymtbl@EXEEXT@; else \ + cp ${top_srcdir}/lib/isc/backtrace-emptytbl.c symtbl.c; fi + #second step: build a binary with the first symbol table + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} \ + -o $@0 ${srcdir}/backtrace_test.c symtbl.c \ + ${ISCNOSYMLIBS} ${LIBS} + rm -f symtbl.c + #third step: create a second symbol table + if test X${MKSYMTBL_PROGRAM} != X; then \ + ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl $@0; else \ + cp ${top_srcdir}/lib/isc/backtrace-emptytbl.c symtbl.c; fi + #fourth step: build the final binary + rm -f $@0 + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} \ + -o $@ ${srcdir}/backtrace_test.c symtbl.c ${ISCNOSYMLIBS} ${LIBS} + rm -f symtbl.c + +nsecify@EXEEXT@: nsecify.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ nsecify.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +byaddr_test@EXEEXT@: byaddr_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byaddr_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +byname_test@EXEEXT@: byname_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byname_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +lex_test@EXEEXT@: lex_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lex_test.@O@ \ + ${ISCLIBS} ${LIBS} + +lfsr_test@EXEEXT@: lfsr_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lfsr_test.@O@ \ + ${ISCLIBS} ${LIBS} + +log_test@EXEEXT@: log_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ log_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +name_test@EXEEXT@: name_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ name_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +entropy_test@EXEEXT@: entropy_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy_test.@O@ \ + ${ISCLIBS} ${LIBS} + +entropy2_test@EXEEXT@: entropy2_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy2_test.@O@ \ + ${ISCLIBS} ${LIBS} + +sock_test@EXEEXT@: sock_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sock_test.@O@ \ + ${ISCLIBS} ${LIBS} + +sym_test@EXEEXT@: sym_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sym_test.@O@ \ + ${ISCLIBS} ${LIBS} + +task_test@EXEEXT@: task_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ task_test.@O@ \ + ${ISCLIBS} ${LIBS} + +shutdown_test@EXEEXT@: shutdown_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ shutdown_test.@O@ \ + ${ISCLIBS} ${LIBS} + +timer_test@EXEEXT@: timer_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ timer_test.@O@ \ + ${ISCLIBS} ${LIBS} + +ratelimiter_test@EXEEXT@: ratelimiter_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ratelimiter_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +rbt_test@EXEEXT@: rbt_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rbt_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +rwlock_test@EXEEXT@: rwlock_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rwlock_test.@O@ \ + ${ISCLIBS} ${LIBS} + +master_test@EXEEXT@: master_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ master_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +db_test@EXEEXT@: db_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ db_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +mempool_test@EXEEXT@: mempool_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ mempool_test.@O@ \ + ${ISCLIBS} ${LIBS} + +serial_test@EXEEXT@: serial_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ serial_test.@O@ \ + ${ISCLIBS} ${LIBS} + +zone_test@EXEEXT@: zone_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zone_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +fsaccess_test@EXEEXT@: fsaccess_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ fsaccess_test.@O@ \ + ${ISCLIBS} ${LIBS} + +inter_test@EXEEXT@: inter_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ inter_test.@O@ \ + ${ISCLIBS} ${LIBS} + +sig0_test@EXEEXT@: sig0_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sig0_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} + +gsstest@EXEEXT@: gsstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} \ + -o $@ gsstest.@O@ ${DNSLIBS} ${ISCLIBS} ${LIBS} + +clean distclean:: + rm -f ${TARGETS} ${XTARGETS} + rm -f backtrace_test_symtbl.c + +check: test + +test: + @for dir in $(TESTDIRS) ;\ + do \ + ( cd $$dir; $(MAKE) test ) ;\ + done diff --git a/bin/tests/optional/adb_test.c b/bin/tests/optional/adb_test.c new file mode 100644 index 0000000..7e9e4ca --- /dev/null +++ b/bin/tests/optional/adb_test.c @@ -0,0 +1,410 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <isc/app.h> +#include <isc/buffer.h> +#include <isc/hash.h> +#include <isc/managers.h> +#include <isc/print.h> +#include <isc/socket.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +#include <dns/adb.h> +#include <dns/cache.h> +#include <dns/db.h> +#include <dns/dispatch.h> +#include <dns/log.h> +#include <dns/result.h> +#include <dns/rootns.h> + +typedef struct client client_t; +struct client { + dns_name_t name; + const char *target; + ISC_LINK(client_t) link; + dns_adbfind_t *find; +}; + +static isc_mem_t *mctx = NULL; +static isc_mempool_t *cmp = NULL; +static isc_log_t *lctx = NULL; +static isc_logconfig_t *lcfg = NULL; +static isc_nm_t *netmgr = NULL; +static isc_taskmgr_t *taskmgr = NULL; +static isc_socketmgr_t *socketmgr = NULL; +static isc_timermgr_t *timermgr = NULL; +static dns_dispatchmgr_t *dispatchmgr = NULL; +static isc_task_t *t1 = NULL, *t2 = NULL; +static dns_view_t *view = NULL; +static dns_db_t *rootdb = NULL; +static ISC_LIST(client_t) clients; +static isc_mutex_t client_lock; +static isc_stdtime_t now; +static dns_adb_t *adb = NULL; + +static void +check_result(isc_result_t result, const char *format, ...) + ISC_FORMAT_PRINTF(2, 3); + +static void +check_result(isc_result_t result, const char *format, ...) { + va_list args; + + if (result == ISC_R_SUCCESS) { + return; + } + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, ": %s\n", isc_result_totext(result)); + exit(1); +} + +static client_t * +new_client(void) { + client_t *client; + + client = isc_mempool_get(cmp); + INSIST(client != NULL); + dns_name_init(&client->name, NULL); + ISC_LINK_INIT(client, link); + client->find = NULL; + + return (client); +} + +static void +free_client(client_t **c) { + client_t *client; + + INSIST(c != NULL); + client = *c; + *c = NULL; + INSIST(client != NULL); + dns_name_free(&client->name, mctx); + INSIST(!ISC_LINK_LINKED(client, link)); + INSIST(client->find == NULL); + + isc_mempool_put(cmp, client); +} + +static void +CLOCK(void) { + RUNTIME_CHECK(isc_mutex_lock(&client_lock) == ISC_R_SUCCESS); +} + +static void +CUNLOCK(void) { + RUNTIME_CHECK(isc_mutex_unlock(&client_lock) == ISC_R_SUCCESS); +} + +static void +lookup_callback(isc_task_t *task, isc_event_t *ev) { + client_t *client; + + client = ev->ev_arg; + INSIST(client->find == ev->ev_sender); + + printf("NAME %s:\n\tTask %p got event %p type %08x from %p, client " + "%p\n\terr4: %s err6: %s\n", + client->target, task, ev, ev->ev_type, client->find, client, + isc_result_totext(client->find->result_v4), + isc_result_totext(client->find->result_v6)); + + isc_event_free(&ev); + ev = NULL; + + CLOCK(); + + dns_adb_dumpfind(client->find, stderr); + dns_adb_destroyfind(&client->find); + + ISC_LIST_UNLINK(clients, client, link); + free_client(&client); + + CUNLOCK(); +} + +static void +create_managers(void) { + isc_result_t result; + + result = isc_managers_create(mctx, 5, 0, &netmgr, &taskmgr); + check_result(result, "isc_managers_create"); + + result = isc_timermgr_create(mctx, &timermgr); + check_result(result, "isc_timermgr_create"); + + result = isc_socketmgr_create(mctx, &socketmgr); + check_result(result, "isc_socketmgr_create"); + + result = dns_dispatchmgr_create(mctx, &dispatchmgr); + check_result(result, "dns_dispatchmgr_create"); +} + +static void +create_view(void) { + dns_cache_t *cache = NULL; + isc_result_t result; + + /* + * View. + */ + result = dns_view_create(mctx, dns_rdataclass_in, "_default", &view); + check_result(result, "dns_view_create"); + + /* + * Cache. + */ + result = dns_cache_create(mctx, mctx, taskmgr, timermgr, + dns_rdataclass_in, "", "rbt", 0, NULL, + &cache); + check_result(result, "dns_cache_create"); + dns_view_setcache(view, cache, false); + dns_cache_detach(&cache); + + { + unsigned int attrs; + isc_sockaddr_t any4, any6; + dns_dispatch_t *disp4 = NULL; + dns_dispatch_t *disp6 = NULL; + + isc_sockaddr_any(&any4); + isc_sockaddr_any6(&any6); + + attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any4, 512, 6, 1024, + 17, 19, attrs, attrs, + &disp4) == ISC_R_SUCCESS); + INSIST(disp4 != NULL); + + attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any6, 512, 6, 1024, + 17, 19, attrs, attrs, + &disp6) == ISC_R_SUCCESS); + INSIST(disp6 != NULL); + + RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1, + socketmgr, timermgr, 0, + dispatchmgr, disp4, + disp6) == ISC_R_SUCCESS); + } + + rootdb = NULL; + result = dns_rootns_create(mctx, dns_rdataclass_in, NULL, &rootdb); + check_result(result, "dns_rootns_create()"); + dns_view_sethints(view, rootdb); + dns_db_detach(&rootdb); + + dns_view_freeze(view); +} + +static void +lookup(const char *target) { + dns_name_t name; + unsigned char namedata[256]; + client_t *client; + isc_buffer_t t, namebuf; + isc_result_t result; + unsigned int options; + + INSIST(target != NULL); + + client = new_client(); + isc_buffer_constinit(&t, target, strlen(target)); + isc_buffer_add(&t, strlen(target)); + isc_buffer_init(&namebuf, namedata, sizeof(namedata)); + dns_name_init(&name, NULL); + result = dns_name_fromtext(&name, &t, dns_rootname, 0, &namebuf); + check_result(result, "dns_name_fromtext %s", target); + + dns_name_dup(&name, mctx, &client->name); + + options = 0; + options |= DNS_ADBFIND_INET; + options |= DNS_ADBFIND_INET6; + options |= DNS_ADBFIND_WANTEVENT; + options |= DNS_ADBFIND_HINTOK; + options |= DNS_ADBFIND_GLUEOK; + result = dns_adb_createfind( + adb, t2, lookup_callback, client, &client->name, dns_rootname, + 0, options, now, NULL, view->dstport, 0, NULL, &client->find); + if (result != ISC_R_SUCCESS) { + printf("DNS_ADB_CREATEFIND -> %s\n", dns_result_totext(result)); + } + dns_adb_dumpfind(client->find, stderr); + + if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) { + client->target = target; + ISC_LIST_APPEND(clients, client, link); + } else { + printf("NAME %s: err4 %s, err6 %s\n", target, + isc_result_totext(client->find->result_v4), + isc_result_totext(client->find->result_v6)); + + dns_adb_destroyfind(&client->find); + free_client(&client); + } +} + +int +main(int argc, char **argv) { + isc_result_t result; + isc_logdestination_t destination; + + UNUSED(argc); + UNUSED(argv); + + dns_result_register(); + result = isc_app_start(); + check_result(result, "isc_app_start()"); + + isc_stdtime_get(&now); + + isc_mutex_init(&client_lock); + + ISC_LIST_INIT(clients); + + /* + * EVERYTHING needs a memory context. + */ + isc_mem_create(&mctx); + + cmp = NULL; + isc_mempool_create(mctx, sizeof(client_t), &cmp); + isc_mempool_setname(cmp, "adb test clients"); + + isc_log_create(mctx, &lctx, &lcfg); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + /* + * Create and install the default channel. + */ + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, ISC_LOG_PRINTTIME); + + result = isc_log_usechannel(lcfg, "_default", NULL, NULL); + check_result(result, "isc_log_usechannel()"); + + /* + * Set the initial debug level. + */ + isc_log_setdebuglevel(lctx, 2); + + create_managers(); + + result = isc_task_create(taskmgr, 0, &t1); + check_result(result, "isc_task_create t1"); + result = isc_task_create(taskmgr, 0, &t2); + check_result(result, "isc_task_create t2"); + + printf("task 1 = %p\n", t1); + printf("task 2 = %p\n", t2); + + create_view(); + RUNTIME_CHECK(view != NULL); + + adb = view->adb; + + /* + * Lock the entire client list here. This will cause all events + * for found names to block as well. + */ + CLOCK(); + lookup("f.root-servers.net."); /* Should be in hints */ + lookup("www.iengines.com"); /* should fetch */ + lookup("www.isc.org"); /* should fetch */ + lookup("www.flame.org"); /* should fetch */ + lookup("kechara.flame.org."); /* should fetch */ + lookup("moghedien.flame.org."); /* should fetch */ + lookup("mailrelay.flame.org."); /* should fetch */ + lookup("ipv4v6.flame.org."); /* should fetch */ + lookup("nonexistent.flame.org."); /* should fail to be found */ + lookup("foobar.badns.flame.org."); /* should fail utterly (NS) */ + lookup("i.root-servers.net."); /* Should be in hints */ + lookup("www.firstcard.com."); + lookup("dns04.flame.org."); + CUNLOCK(); + + sleep(10); + + dns_adb_dump(adb, stderr); + + sleep(10); + + CLOCK(); + lookup("f.root-servers.net."); /* Should be in hints */ + lookup("www.iengines.com"); /* should fetch */ + lookup("www.isc.org"); /* should fetch */ + lookup("www.flame.org"); /* should fetch */ + lookup("kechara.flame.org."); /* should fetch */ + lookup("moghedien.flame.org."); /* should fetch */ + lookup("mailrelay.flame.org."); /* should fetch */ + lookup("ipv4v6.flame.org."); /* should fetch */ + lookup("nonexistent.flame.org."); /* should fail to be found */ + lookup("foobar.badns.flame.org."); /* should fail utterly (NS) */ + lookup("i.root-servers.net."); /* Should be in hints */ + CUNLOCK(); + + sleep(20); + + dns_adb_dump(adb, stderr); + + isc_task_detach(&t1); + isc_task_detach(&t2); + + isc_mem_stats(mctx, stdout); + dns_adb_dump(adb, stderr); + + isc_app_run(); + + dns_adb_dump(adb, stderr); + + dns_view_detach(&view); + adb = NULL; + + fprintf(stderr, "Destroying socket manager\n"); + isc_socketmgr_destroy(&socketmgr); + fprintf(stderr, "Destroying timer manager\n"); + isc_timermgr_destroy(&timermgr); + + fprintf(stderr, "Destroying task and network managers\n"); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_log_destroy(&lctx); + + isc_mempool_destroy(&cmp); + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/backtrace_test.c b/bin/tests/optional/backtrace_test.c new file mode 100644 index 0000000..2aa7979 --- /dev/null +++ b/bin/tests/optional/backtrace_test.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdio.h> +#include <string.h> + +#include <isc/backtrace.h> +#include <isc/print.h> +#include <isc/result.h> + +const char *expected_symbols[] = { "func3", "func2", "func1", "main" }; + +static int +func3() { + void *tracebuf[16]; + int i, nframes; + int error = 0; + const char *fname; + isc_result_t result; + unsigned long offset; + + result = isc_backtrace_gettrace(tracebuf, 16, &nframes); + if (result != ISC_R_SUCCESS) { + printf("isc_backtrace_gettrace failed: %s\n", + isc_result_totext(result)); + return (1); + } + + if (nframes < 4) { + error++; + } + + for (i = 0; i < 4 && i < nframes; i++) { + fname = NULL; + result = isc_backtrace_getsymbol(tracebuf[i], &fname, &offset); + if (result != ISC_R_SUCCESS) { + error++; + continue; + } + if (strcmp(fname, expected_symbols[i]) != 0) { + error++; + } + } + + if (error) { + printf("Unexpected result:\n"); + printf(" # of frames: %d (expected: at least 4)\n", nframes); + printf(" symbols:\n"); + for (i = 0; i < nframes; i++) { + fname = NULL; + result = isc_backtrace_getsymbol(tracebuf[i], &fname, + &offset); + if (result == ISC_R_SUCCESS) { + printf(" [%d] %s\n", i, fname); + } else { + printf(" [%d] %p getsymbol failed: %s\n", i, + tracebuf[i], isc_result_totext(result)); + } + } + } + + return (error); +} + +static int +func2() { + return (func3()); +} + +static int +func1() { + return (func2()); +} + +int +main() { + return (func1()); +} diff --git a/bin/tests/optional/byaddr_test.c b/bin/tests/optional/byaddr_test.c new file mode 100644 index 0000000..7e24cfe --- /dev/null +++ b/bin/tests/optional/byaddr_test.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file + */ + +#include <stdbool.h> +#include <stdlib.h> + +#include <isc/app.h> +#include <isc/commandline.h> +#include <isc/managers.h> +#include <isc/mem.h> +#include <isc/netaddr.h> +#include <isc/print.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +#include <dns/byaddr.h> +#include <dns/cache.h> +#include <dns/dispatch.h> +#include <dns/events.h> +#include <dns/forward.h> +#include <dns/resolver.h> +#include <dns/result.h> +#include <dns/view.h> + +static void +done(isc_task_t *task, isc_event_t *event) { + dns_byaddrevent_t *bevent; + dns_byaddr_t *byaddr; + dns_name_t *name; + + REQUIRE(event->ev_type == DNS_EVENT_BYADDRDONE); + bevent = (dns_byaddrevent_t *)event; + + UNUSED(task); + + printf("byaddr event result = %s\n", isc_result_totext(bevent->result)); + + if (bevent->result == ISC_R_SUCCESS) { + for (name = ISC_LIST_HEAD(bevent->names); name != NULL; + name = ISC_LIST_NEXT(name, link)) + { + char text[DNS_NAME_FORMATSIZE]; + dns_name_format(name, text, sizeof(text)); + printf("%s\n", text); + } + } + + byaddr = event->ev_sender; + dns_byaddr_destroy(&byaddr); + isc_event_free(&event); + + isc_app_shutdown(); +} + +int +main(int argc, char *argv[]) { + isc_mem_t *mctx = NULL; + bool verbose = false; + unsigned int workers = 2; + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_task_t *task = NULL; + isc_timermgr_t *timermgr = NULL; + dns_view_t *view = NULL; + int ch; + isc_socketmgr_t *socketmgr = NULL; + dns_dispatchmgr_t *dispatchmgr = NULL; + isc_netaddr_t na; + dns_byaddr_t *byaddr = NULL; + isc_result_t result; + unsigned int options = 0; + dns_cache_t *cache; + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + + dns_result_register(); + + isc_mem_create(&mctx); + + while ((ch = isc_commandline_parse(argc, argv, "nvw:")) != -1) { + switch (ch) { + case 'n': + /* + * We only try nibbles, so do nothing for this option. + */ + break; + case 'v': + verbose = true; + break; + case 'w': + workers = (unsigned int)atoi(isc_commandline_argument); + break; + } + } + + if (verbose) { + printf("%u workers\n", workers); + printf("IPv4: %s\n", isc_result_totext(isc_net_probeipv4())); + printf("IPv6: %s\n", isc_result_totext(isc_net_probeipv6())); + } + + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS); + isc_task_setname(task, "byaddr", NULL); + + RUNTIME_CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr) == + ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(dns_cache_create(mctx, mctx, taskmgr, timermgr, + dns_rdataclass_in, "", "rbt", 0, NULL, + &cache) == ISC_R_SUCCESS); + + RUNTIME_CHECK(dns_view_create(mctx, dns_rdataclass_in, "default", + &view) == ISC_R_SUCCESS); + + { + unsigned int attrs; + dns_dispatch_t *disp4 = NULL; + dns_dispatch_t *disp6 = NULL; + + if (isc_net_probeipv4() == ISC_R_SUCCESS) { + isc_sockaddr_t any4; + + isc_sockaddr_any(&any4); + + attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK( + dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any4, 512, 6, + 1024, 17, 19, attrs, attrs, + &disp4) == ISC_R_SUCCESS); + INSIST(disp4 != NULL); + } + + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + isc_sockaddr_t any6; + + isc_sockaddr_any6(&any6); + + attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK( + dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any6, 512, 6, + 1024, 17, 19, attrs, attrs, + &disp6) == ISC_R_SUCCESS); + INSIST(disp6 != NULL); + } + + RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1, + socketmgr, timermgr, 0, + dispatchmgr, disp4, + disp6) == ISC_R_SUCCESS); + + if (disp4 != NULL) { + dns_dispatch_detach(&disp4); + } + if (disp6 != NULL) { + dns_dispatch_detach(&disp6); + } + } + + { + struct in_addr ina; + isc_sockaddr_t sa; + isc_sockaddrlist_t sal; + + ISC_LIST_INIT(sal); + ina.s_addr = inet_addr("127.0.0.1"); + isc_sockaddr_fromin(&sa, &ina, 53); + ISC_LIST_APPEND(sal, &sa, link); + + RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname, + &sal, dns_fwdpolicy_only) == + ISC_R_SUCCESS); + } + + dns_view_setcache(view, cache, false); + dns_view_freeze(view); + + dns_cache_detach(&cache); + + printf("address = %s\n", argv[isc_commandline_index]); + na.family = AF_INET; + if (inet_pton(AF_INET, argv[isc_commandline_index], + (char *)&na.type.in) != 1) + { + na.family = AF_INET6; + if (inet_pton(AF_INET6, argv[isc_commandline_index], + (char *)&na.type.in6) != 1) + { + printf("unknown address format\n"); + exit(1); + } + } + + result = dns_byaddr_create(mctx, &na, view, options, task, done, NULL, + &byaddr); + if (result != ISC_R_SUCCESS) { + printf("dns_byaddr_create() returned %s\n", + isc_result_totext(result)); + RUNTIME_CHECK(0); + } + + (void)isc_app_run(); + + /* + * XXXRTH if we get a control-C before we get to isc_app_run(), + * we're in trouble (because we might try to destroy things before + * they've been created. + */ + + dns_view_detach(&view); + + isc_task_shutdown(task); + isc_task_detach(&task); + + dns_dispatchmgr_destroy(&dispatchmgr); + + isc_managers_destroy(&netmgr, &taskmgr); + + isc_socketmgr_destroy(&socketmgr); + isc_timermgr_destroy(&timermgr); + + if (verbose) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/byname_test.c b/bin/tests/optional/byname_test.c new file mode 100644 index 0000000..fa76973 --- /dev/null +++ b/bin/tests/optional/byname_test.c @@ -0,0 +1,350 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include <isc/app.h> +#include <isc/commandline.h> +#include <isc/hash.h> +#include <isc/managers.h> +#include <isc/netaddr.h> +#include <isc/print.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +#include <dns/adb.h> +#include <dns/cache.h> +#include <dns/dispatch.h> +#include <dns/events.h> +#include <dns/forward.h> +#include <dns/log.h> +#include <dns/resolver.h> +#include <dns/result.h> + +static isc_mem_t *mctx = NULL; +static isc_nm_t *netmgr = NULL; +static isc_taskmgr_t *taskmgr = NULL; +static dns_view_t *view = NULL; +static dns_adbfind_t *find = NULL; +static isc_task_t *task = NULL; +static dns_fixedname_t fixed; +static dns_fixedname_t target; +static isc_log_t *lctx = NULL; +static isc_logconfig_t *lcfg = NULL; +static unsigned int level = 0; + +static void +adb_callback(isc_task_t *task, isc_event_t *event); + +static void +log_init(void) { + isc_logdestination_t destination; + unsigned int flags; + + /* + * Setup a logging context. + */ + isc_log_create(mctx, &lctx, &lcfg); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + /* + * Create and install the default channel. + */ + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + flags = ISC_LOG_PRINTTIME; + isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, flags); + + RUNTIME_CHECK(isc_log_usechannel(lcfg, "_default", NULL, NULL) == + ISC_R_SUCCESS); + isc_log_setdebuglevel(lctx, level); +} + +static void +print_addresses(dns_adbfind_t *adbfind) { + dns_adbaddrinfo_t *address; + + for (address = ISC_LIST_HEAD(adbfind->list); address != NULL; + address = ISC_LIST_NEXT(address, publink)) + { + isc_netaddr_t netaddr; + char text[ISC_NETADDR_FORMATSIZE]; + isc_netaddr_fromsockaddr(&netaddr, &address->sockaddr); + isc_netaddr_format(&netaddr, text, sizeof(text)); + printf("%s\n", text); + } +} + +static void +print_name(dns_name_t *name) { + char text[DNS_NAME_FORMATSIZE]; + + dns_name_format(name, text, sizeof(text)); + printf("%s\n", text); +} + +static void +do_find(bool want_event) { + isc_result_t result; + bool done = false; + unsigned int options; + + options = DNS_ADBFIND_INET | DNS_ADBFIND_INET6; + if (want_event) { + options |= DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT; + } + dns_fixedname_init(&target); + result = dns_adb_createfind(view->adb, task, adb_callback, NULL, + dns_fixedname_name(&fixed), dns_rootname, 0, + options, 0, dns_fixedname_name(&target), 0, + 0, NULL, &find); + if (result == ISC_R_SUCCESS) { + if (!ISC_LIST_EMPTY(find->list)) { + /* + * We have at least some of the addresses for the + * name. + */ + INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0); + print_addresses(find); + done = true; + } else { + /* + * We don't know any of the addresses for this + * name. + */ + if ((find->options & DNS_ADBFIND_WANTEVENT) == 0) { + /* + * And ADB isn't going to send us any events + * either. This query loses. + */ + done = true; + } + /* + * If the DNS_ADBFIND_WANTEVENT flag was set, we'll + * get an event when something happens. + */ + } + } else if (result == DNS_R_ALIAS) { + print_name(dns_fixedname_name(&target)); + done = true; + } else { + printf("dns_adb_createfind() returned %s\n", + isc_result_totext(result)); + done = true; + } + + if (done) { + if (find != NULL) { + dns_adb_destroyfind(&find); + } + isc_app_shutdown(); + } +} + +static void +adb_callback(isc_task_t *etask, isc_event_t *event) { + unsigned int type = event->ev_type; + + REQUIRE(etask == task); + + isc_event_free(&event); + dns_adb_destroyfind(&find); + + if (type == DNS_EVENT_ADBMOREADDRESSES) { + do_find(false); + } else if (type == DNS_EVENT_ADBNOMOREADDRESSES) { + printf("no more addresses\n"); + isc_app_shutdown(); + } else { + printf("unexpected ADB event type %u\n", type); + isc_app_shutdown(); + } +} + +static void +run(isc_task_t *xtask, isc_event_t *event) { + UNUSED(xtask); + do_find(true); + isc_event_free(&event); +} + +int +main(int argc, char *argv[]) { + bool verbose = false; + unsigned int workers = 2; + isc_timermgr_t *timermgr = NULL; + int ch; + isc_socketmgr_t *socketmgr = NULL; + dns_dispatchmgr_t *dispatchmgr = NULL; + dns_cache_t *cache = NULL; + isc_buffer_t b; + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + + dns_result_register(); + + isc_mem_create(&mctx); + + while ((ch = isc_commandline_parse(argc, argv, "d:vw:")) != -1) { + switch (ch) { + case 'd': + level = (unsigned int)atoi(isc_commandline_argument); + break; + case 'v': + verbose = true; + break; + case 'w': + workers = (unsigned int)atoi(isc_commandline_argument); + break; + } + } + + log_init(); + + if (verbose) { + printf("%u workers\n", workers); + printf("IPv4: %s\n", isc_result_totext(isc_net_probeipv4())); + printf("IPv6: %s\n", isc_result_totext(isc_net_probeipv6())); + } + + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS); + isc_task_setname(task, "byname", NULL); + + RUNTIME_CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr) == + ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(dns_cache_create(mctx, mctx, taskmgr, timermgr, + dns_rdataclass_in, "", "rbt", 0, NULL, + &cache) == ISC_R_SUCCESS); + + RUNTIME_CHECK(dns_view_create(mctx, dns_rdataclass_in, "default", + &view) == ISC_R_SUCCESS); + + { + unsigned int attrs; + dns_dispatch_t *disp4 = NULL; + dns_dispatch_t *disp6 = NULL; + + if (isc_net_probeipv4() == ISC_R_SUCCESS) { + isc_sockaddr_t any4; + isc_sockaddr_any(&any4); + + attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK( + dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any4, 512, 6, + 1024, 17, 19, attrs, attrs, + &disp4) == ISC_R_SUCCESS); + INSIST(disp4 != NULL); + } + + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + isc_sockaddr_t any6; + + isc_sockaddr_any6(&any6); + + attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP; + RUNTIME_CHECK( + dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &any6, 512, 6, + 1024, 17, 19, attrs, attrs, + &disp6) == ISC_R_SUCCESS); + INSIST(disp6 != NULL); + } + + RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1, + socketmgr, timermgr, 0, + dispatchmgr, disp4, + disp6) == ISC_R_SUCCESS); + + if (disp4 != NULL) { + dns_dispatch_detach(&disp4); + } + if (disp6 != NULL) { + dns_dispatch_detach(&disp6); + } + } + + { + struct in_addr ina; + isc_sockaddr_t sa; + isc_sockaddrlist_t sal; + + ISC_LIST_INIT(sal); + ina.s_addr = inet_addr("127.0.0.1"); + isc_sockaddr_fromin(&sa, &ina, 53); + ISC_LIST_APPEND(sal, &sa, link); + + REQUIRE(DNS_VIEW_VALID(view)); + RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname, + &sal, dns_fwdpolicy_only) == + ISC_R_SUCCESS); + } + + dns_view_setcache(view, cache, false); + dns_view_freeze(view); + + dns_cache_detach(&cache); + + printf("name = %s\n", argv[isc_commandline_index]); + isc_buffer_init(&b, argv[isc_commandline_index], + strlen(argv[isc_commandline_index])); + isc_buffer_add(&b, strlen(argv[isc_commandline_index])); + dns_fixedname_init(&fixed); + dns_fixedname_init(&target); + RUNTIME_CHECK(dns_name_fromtext(dns_fixedname_name(&fixed), &b, + dns_rootname, 0, + NULL) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_app_onrun(mctx, task, run, NULL) == ISC_R_SUCCESS); + + (void)isc_app_run(); + + dns_view_detach(&view); + isc_task_shutdown(task); + isc_task_detach(&task); + + dns_dispatchmgr_destroy(&dispatchmgr); + + isc_managers_destroy(&netmgr, &taskmgr); + + isc_socketmgr_destroy(&socketmgr); + isc_timermgr_destroy(&timermgr); + + isc_log_destroy(&lctx); + + if (verbose) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/db_test.c b/bin/tests/optional/db_test.c new file mode 100644 index 0000000..05bd748 --- /dev/null +++ b/bin/tests/optional/db_test.c @@ -0,0 +1,983 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file + */ + +#include <inttypes.h> +#include <stdbool.h> +#include <stdlib.h> + +#include <isc/commandline.h> +#include <isc/log.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> + +#include <dns/db.h> +#include <dns/dbiterator.h> +#include <dns/dbtable.h> +#include <dns/fixedname.h> +#include <dns/log.h> +#include <dns/rdataset.h> +#include <dns/rdatasetiter.h> +#include <dns/result.h> + +#define MAXHOLD 100 +#define MAXVERSIONS 100 + +typedef struct dbinfo { + dns_db_t *db; + dns_dbversion_t *version; + dns_dbversion_t *wversion; + dns_dbversion_t *rversions[MAXVERSIONS]; + int rcount; + dns_dbnode_t *hold_nodes[MAXHOLD]; + int hold_count; + dns_dbiterator_t *dbiterator; + dns_dbversion_t *iversion; + int pause_every; + bool ascending; + ISC_LINK(struct dbinfo) link; +} dbinfo; + +static isc_mem_t *mctx = NULL; +static char dbtype[128]; +static dns_dbtable_t *dbtable; +static ISC_LIST(dbinfo) dbs; +static dbinfo *cache_dbi = NULL; +static int pause_every = 0; +static bool ascending = true; + +static void +print_result(const char *message, isc_result_t result) { + if (message == NULL) { + message = ""; + } + printf("%s%sresult %08x: %s\n", message, (*message == '\0') ? "" : " ", + result, isc_result_totext(result)); +} + +static void +print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) { + isc_buffer_t text; + char t[1000]; + isc_result_t result; + isc_region_t r; + + isc_buffer_init(&text, t, sizeof(t)); + result = dns_rdataset_totext(rdataset, name, false, false, &text); + isc_buffer_usedregion(&text, &r); + if (result == ISC_R_SUCCESS) { + printf("%.*s", (int)r.length, (char *)r.base); + } else { + print_result("", result); + } +} + +static void +print_rdatasets(dns_name_t *name, dns_rdatasetiter_t *rdsiter) { + isc_result_t result; + dns_rdataset_t rdataset; + + dns_rdataset_init(&rdataset); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &rdataset); + print_rdataset(name, &rdataset); + dns_rdataset_disassociate(&rdataset); + result = dns_rdatasetiter_next(rdsiter); + } + if (result != ISC_R_NOMORE) { + print_result("", result); + } +} + +static dbinfo * +select_db(char *origintext) { + dns_fixedname_t forigin; + dns_name_t *origin; + isc_buffer_t source; + size_t len; + dbinfo *dbi; + isc_result_t result; + + if (strcasecmp(origintext, "cache") == 0) { + if (cache_dbi == NULL) { + printf("the cache does not exist\n"); + } + return (cache_dbi); + } + len = strlen(origintext); + isc_buffer_init(&source, origintext, len); + isc_buffer_add(&source, len); + origin = dns_fixedname_initname(&forigin); + result = dns_name_fromtext(origin, &source, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + print_result("bad name", result); + return (NULL); + } + + for (dbi = ISC_LIST_HEAD(dbs); dbi != NULL; + dbi = ISC_LIST_NEXT(dbi, link)) + { + if (dns_name_compare(dns_db_origin(dbi->db), origin) == 0) { + break; + } + } + + return (dbi); +} + +static void +list(dbinfo *dbi, char *seektext) { + dns_fixedname_t fname; + dns_name_t *name; + dns_dbnode_t *node; + dns_rdatasetiter_t *rdsiter; + isc_result_t result; + int i; + size_t len; + dns_fixedname_t fseekname; + dns_name_t *seekname; + isc_buffer_t source; + + name = dns_fixedname_initname(&fname); + + if (dbi->dbiterator == NULL) { + INSIST(dbi->iversion == NULL); + if (dns_db_iszone(dbi->db)) { + if (dbi->version != NULL) { + dns_db_attachversion(dbi->db, dbi->version, + &dbi->iversion); + } else { + dns_db_currentversion(dbi->db, &dbi->iversion); + } + } + + result = dns_db_createiterator(dbi->db, 0, &dbi->dbiterator); + if (result == ISC_R_SUCCESS) { + if (seektext != NULL) { + len = strlen(seektext); + isc_buffer_init(&source, seektext, len); + isc_buffer_add(&source, len); + seekname = dns_fixedname_initname(&fseekname); + result = dns_name_fromtext( + seekname, &source, + dns_db_origin(dbi->db), 0, NULL); + if (result == ISC_R_SUCCESS) { + result = dns_dbiterator_seek( + dbi->dbiterator, seekname); + } + } else if (dbi->ascending) { + result = dns_dbiterator_first(dbi->dbiterator); + } else { + result = dns_dbiterator_last(dbi->dbiterator); + } + } + } else { + result = ISC_R_SUCCESS; + } + + node = NULL; + rdsiter = NULL; + i = 0; + while (result == ISC_R_SUCCESS) { + result = dns_dbiterator_current(dbi->dbiterator, &node, name); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + break; + } + result = dns_db_allrdatasets(dbi->db, node, dbi->iversion, 0, 0, + &rdsiter); + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(dbi->db, &node); + break; + } + print_rdatasets(name, rdsiter); + dns_rdatasetiter_destroy(&rdsiter); + dns_db_detachnode(dbi->db, &node); + if (dbi->ascending) { + result = dns_dbiterator_next(dbi->dbiterator); + } else { + result = dns_dbiterator_prev(dbi->dbiterator); + } + i++; + if (result == ISC_R_SUCCESS && i == dbi->pause_every) { + printf("[more...]\n"); + result = dns_dbiterator_pause(dbi->dbiterator); + if (result == ISC_R_SUCCESS) { + return; + } + } + } + if (result != ISC_R_NOMORE) { + print_result("", result); + } + + dns_dbiterator_destroy(&dbi->dbiterator); + if (dbi->iversion != NULL) { + dns_db_closeversion(dbi->db, &dbi->iversion, false); + } +} + +static isc_result_t +load(const char *filename, const char *origintext, bool cache) { + dns_fixedname_t forigin; + dns_name_t *origin; + isc_result_t result; + isc_buffer_t source; + size_t len; + dbinfo *dbi; + unsigned int i; + + dbi = isc_mem_get(mctx, sizeof(*dbi)); + + dbi->db = NULL; + dbi->version = NULL; + dbi->wversion = NULL; + for (i = 0; i < MAXVERSIONS; i++) { + dbi->rversions[i] = NULL; + } + dbi->hold_count = 0; + for (i = 0; i < MAXHOLD; i++) { + dbi->hold_nodes[i] = NULL; + } + dbi->dbiterator = NULL; + dbi->iversion = NULL; + dbi->pause_every = pause_every; + dbi->ascending = ascending; + ISC_LINK_INIT(dbi, link); + + len = strlen(origintext); + isc_buffer_constinit(&source, origintext, len); + isc_buffer_add(&source, len); + origin = dns_fixedname_initname(&forigin); + result = dns_name_fromtext(origin, &source, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, dbi, sizeof(*dbi)); + return (result); + } + + result = dns_db_create(mctx, dbtype, origin, + cache ? dns_dbtype_cache : dns_dbtype_zone, + dns_rdataclass_in, 0, NULL, &dbi->db); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, dbi, sizeof(*dbi)); + return (result); + } + + printf("loading %s (%s)\n", filename, origintext); + result = dns_db_load(dbi->db, filename, dns_masterformat_text, 0); + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { + dns_db_detach(&dbi->db); + isc_mem_put(mctx, dbi, sizeof(*dbi)); + return (result); + } + printf("loaded\n"); + + if (cache) { + INSIST(cache_dbi == NULL); + dns_dbtable_adddefault(dbtable, dbi->db); + cache_dbi = dbi; + } else { + result = dns_dbtable_add(dbtable, dbi->db); + if (result != ISC_R_SUCCESS) { + dns_db_detach(&dbi->db); + isc_mem_put(mctx, dbi, sizeof(*dbi)); + return (result); + } + } + ISC_LIST_APPEND(dbs, dbi, link); + + return (ISC_R_SUCCESS); +} + +static void +unload_all(void) { + dbinfo *dbi, *dbi_next; + + for (dbi = ISC_LIST_HEAD(dbs); dbi != NULL; dbi = dbi_next) { + dbi_next = ISC_LIST_NEXT(dbi, link); + if (dns_db_iszone(dbi->db)) { + dns_dbtable_remove(dbtable, dbi->db); + } else { + INSIST(dbi == cache_dbi); + dns_dbtable_removedefault(dbtable); + cache_dbi = NULL; + } + dns_db_detach(&dbi->db); + ISC_LIST_UNLINK(dbs, dbi, link); + isc_mem_put(mctx, dbi, sizeof(*dbi)); + } +} + +#define DBI_CHECK(dbi) \ + if ((dbi) == NULL) { \ + printf("You must first select a database with !DB\n"); \ + continue; \ + } + +int +main(int argc, char *argv[]) { + dns_db_t *db; + dns_dbnode_t *node; + isc_result_t result; + dns_name_t name; + dns_offsets_t offsets; + size_t len; + isc_buffer_t source, target; + char s[1000]; + char b[255]; + dns_rdataset_t rdataset, sigrdataset; + int ch; + dns_rdatatype_t type = 1; + bool printnode = false; + bool addmode = false; + bool delmode = false; + bool holdmode = false; + bool verbose = false; + bool done = false; + bool quiet = false; + bool time_lookups = false; + bool found_as; + bool find_zonecut = false; + bool noexact_zonecut = false; + int i, v; + dns_rdatasetiter_t *rdsiter; + char t1[256]; + char t2[256]; + isc_buffer_t tb1, tb2; + isc_region_t r1, r2; + dns_fixedname_t foundname; + dns_name_t *fname; + unsigned int options = 0, zcoptions; + isc_time_t start, finish; + const char *origintext; + dbinfo *dbi; + dns_dbversion_t *version; + const dns_name_t *origin; + dns_trust_t trust = 0; + unsigned int addopts; + isc_log_t *lctx = NULL; + size_t n; + + dns_result_register(); + + isc_mem_create(&mctx); + RUNTIME_CHECK(dns_dbtable_create(mctx, dns_rdataclass_in, &dbtable) == + ISC_R_SUCCESS); + + snprintf(dbtype, sizeof(dbtype), "rbt"); + while ((ch = isc_commandline_parse(argc, argv, "c:d:t:z:P:Q:glpqvT")) != + -1) + { + switch (ch) { + case 'c': + result = load(isc_commandline_argument, ".", true); + if (result != ISC_R_SUCCESS) { + printf("cache load(%s) %08x: %s\n", + isc_commandline_argument, result, + isc_result_totext(result)); + } + break; + case 'd': + n = strlcpy(dbtype, isc_commandline_argument, + sizeof(dbtype)); + if (n >= sizeof(dbtype)) { + fprintf(stderr, "bad db type '%s'\n", + isc_commandline_argument); + exit(1); + } + break; + case 'g': + options |= (DNS_DBFIND_GLUEOK | + DNS_DBFIND_VALIDATEGLUE); + break; + case 'l': + isc_log_create(mctx, &lctx, NULL); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + break; + case 'q': + quiet = true; + verbose = false; + break; + case 'p': + printnode = true; + break; + case 'P': + pause_every = atoi(isc_commandline_argument); + break; + case 't': + type = atoi(isc_commandline_argument); + break; + case 'T': + time_lookups = true; + break; + case 'v': + verbose = true; + break; + case 'z': + origintext = strrchr(isc_commandline_argument, '/'); + if (origintext == NULL) { + origintext = isc_commandline_argument; + } else { + origintext++; /* Skip '/'. */ + } + result = load(isc_commandline_argument, origintext, + false); + if (result != ISC_R_SUCCESS) { + printf("zone load(%s) %08x: %s\n", + isc_commandline_argument, result, + isc_result_totext(result)); + } + break; + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + POST(argv); + + if (argc != 0) { + printf("ignoring trailing arguments\n"); + } + + /* + * Some final initialization... + */ + fname = dns_fixedname_initname(&foundname); + dbi = NULL; + origin = dns_rootname; + version = NULL; + + if (time_lookups) { + TIME_NOW(&start); + } + + while (!done) { + if (!quiet) { + printf("\n"); + } + if (fgets(s, sizeof(s), stdin) == NULL) { + done = true; + continue; + } + len = strlen(s); + if (len > 0U && s[len - 1] == '\n') { + s[len - 1] = '\0'; + len--; + } + if (verbose && dbi != NULL) { + if (dbi->wversion != NULL) { + printf("future version (%p)\n", dbi->wversion); + } + for (i = 0; i < dbi->rcount; i++) { + if (dbi->rversions[i] != NULL) { + printf("open version %d (%p)\n", i, + dbi->rversions[i]); + } + } + } + dns_name_init(&name, offsets); + if (strcmp(s, "!R") == 0) { + DBI_CHECK(dbi); + if (dbi->rcount == MAXVERSIONS) { + printf("too many open versions\n"); + continue; + } + dns_db_currentversion(dbi->db, + &dbi->rversions[dbi->rcount]); + printf("opened version %d\n", dbi->rcount); + dbi->version = dbi->rversions[dbi->rcount]; + version = dbi->version; + dbi->rcount++; + continue; + } else if (strcmp(s, "!W") == 0) { + DBI_CHECK(dbi); + if (dbi->wversion != NULL) { + printf("using existing future version\n"); + dbi->version = dbi->wversion; + version = dbi->version; + continue; + } + result = dns_db_newversion(dbi->db, &dbi->wversion); + if (result != ISC_R_SUCCESS) { + print_result("", result); + } else { + printf("newversion\n"); + } + dbi->version = dbi->wversion; + version = dbi->version; + continue; + } else if (strcmp(s, "!C") == 0) { + DBI_CHECK(dbi); + addmode = false; + delmode = false; + if (dbi->version == NULL) { + continue; + } + if (dbi->version == dbi->wversion) { + printf("closing future version\n"); + dbi->wversion = NULL; + } else { + for (i = 0; i < dbi->rcount; i++) { + if (dbi->version == dbi->rversions[i]) { + dbi->rversions[i] = NULL; + printf("closing open version " + "%d\n", + i); + break; + } + } + } + dns_db_closeversion(dbi->db, &dbi->version, true); + version = NULL; + continue; + } else if (strcmp(s, "!X") == 0) { + DBI_CHECK(dbi); + addmode = false; + delmode = false; + if (dbi->version == NULL) { + continue; + } + if (dbi->version == dbi->wversion) { + printf("aborting future version\n"); + dbi->wversion = NULL; + } else { + for (i = 0; i < dbi->rcount; i++) { + if (dbi->version == dbi->rversions[i]) { + dbi->rversions[i] = NULL; + printf("closing open version " + "%d\n", + i); + break; + } + } + } + dns_db_closeversion(dbi->db, &dbi->version, false); + version = NULL; + continue; + } else if (strcmp(s, "!A") == 0) { + DBI_CHECK(dbi); + delmode = false; + if (addmode) { + addmode = false; + } else { + addmode = true; + } + printf("addmode = %s\n", addmode ? "TRUE" : "FALSE"); + continue; + } else if (strcmp(s, "!D") == 0) { + DBI_CHECK(dbi); + addmode = false; + if (delmode) { + delmode = false; + } else { + delmode = true; + } + printf("delmode = %s\n", delmode ? "TRUE" : "FALSE"); + continue; + } else if (strcmp(s, "!H") == 0) { + DBI_CHECK(dbi); + if (holdmode) { + holdmode = false; + } else { + holdmode = true; + } + printf("holdmode = %s\n", holdmode ? "TRUE" : "FALSE"); + continue; + } else if (strcmp(s, "!HR") == 0) { + DBI_CHECK(dbi); + for (i = 0; i < dbi->hold_count; i++) { + dns_db_detachnode(dbi->db, &dbi->hold_nodes[i]); + } + dbi->hold_count = 0; + holdmode = false; + printf("held nodes have been detached\n"); + continue; + } else if (strcmp(s, "!VC") == 0) { + DBI_CHECK(dbi); + printf("switching to current version\n"); + dbi->version = NULL; + version = NULL; + continue; + } else if (strstr(s, "!V") == s) { + DBI_CHECK(dbi); + v = atoi(&s[2]); + if (v >= dbi->rcount || v < 0) { + printf("unknown open version %d\n", v); + continue; + } + if (dbi->rversions[v] == NULL) { + printf("version %d is not open\n", v); + continue; + } + printf("switching to open version %d\n", v); + dbi->version = dbi->rversions[v]; + version = dbi->version; + continue; + } else if (strstr(s, "!TR") == s) { + trust = (unsigned int)atoi(&s[3]); + printf("trust level is now %u\n", (unsigned int)trust); + continue; + } else if (strstr(s, "!T") == s) { + type = (unsigned int)atoi(&s[2]); + printf("now searching for type %u\n", type); + continue; + } else if (strcmp(s, "!G") == 0) { + if ((options & DNS_DBFIND_GLUEOK) != 0) { + options &= ~DNS_DBFIND_GLUEOK; + } else { + options |= DNS_DBFIND_GLUEOK; + } + printf("glue ok = %s\n", + ((options & DNS_DBFIND_GLUEOK) != 0) ? "TRUE" + : "FALSE"); + continue; + } else if (strcmp(s, "!GV") == 0) { + if ((options & DNS_DBFIND_VALIDATEGLUE) != 0) { + options &= ~DNS_DBFIND_VALIDATEGLUE; + } else { + options |= DNS_DBFIND_VALIDATEGLUE; + } + printf("validate glue = %s\n", + ((options & DNS_DBFIND_VALIDATEGLUE) != 0) + ? "TRUE" + : "FALSE"); + continue; + } else if (strcmp(s, "!WC") == 0) { + if ((options & DNS_DBFIND_NOWILD) != 0) { + options &= ~DNS_DBFIND_NOWILD; + } else { + options |= DNS_DBFIND_NOWILD; + } + printf("wildcard matching = %s\n", + ((options & DNS_DBFIND_NOWILD) == 0) ? "TRUE" + : "FALSE"); + continue; + } else if (strstr(s, "!LS ") == s) { + DBI_CHECK(dbi); + list(dbi, &s[4]); + continue; + } else if (strcmp(s, "!LS") == 0) { + DBI_CHECK(dbi); + list(dbi, NULL); + continue; + } else if (strstr(s, "!DU ") == s) { + DBI_CHECK(dbi); + result = dns_db_dump(dbi->db, dbi->version, s + 4); + if (result != ISC_R_SUCCESS) { + printf("\n"); + print_result("", result); + } + continue; + } else if (strcmp(s, "!PN") == 0) { + if (printnode) { + printnode = false; + } else { + printnode = true; + } + printf("printnode = %s\n", + printnode ? "TRUE" : "FALSE"); + continue; + } else if (strstr(s, "!P") == s) { + DBI_CHECK(dbi); + v = atoi(&s[2]); + dbi->pause_every = v; + continue; + } else if (strcmp(s, "!+") == 0) { + DBI_CHECK(dbi); + dbi->ascending = true; + continue; + } else if (strcmp(s, "!-") == 0) { + DBI_CHECK(dbi); + dbi->ascending = false; + continue; + } else if (strcmp(s, "!DB") == 0) { + dbi = NULL; + origin = dns_rootname; + version = NULL; + printf("now searching all databases\n"); + continue; + } else if (strncmp(s, "!DB ", 4) == 0) { + dbi = select_db(s + 4); + if (dbi != NULL) { + db = dbi->db; + origin = dns_db_origin(dbi->db); + version = dbi->version; + addmode = false; + delmode = false; + holdmode = false; + } else { + db = NULL; + version = NULL; + origin = dns_rootname; + printf("database not found; " + "now searching all databases\n"); + } + continue; + } else if (strcmp(s, "!ZC") == 0) { + if (find_zonecut) { + find_zonecut = false; + } else { + find_zonecut = true; + } + printf("find_zonecut = %s\n", + find_zonecut ? "TRUE" : "FALSE"); + continue; + } else if (strcmp(s, "!NZ") == 0) { + if (noexact_zonecut) { + noexact_zonecut = false; + } else { + noexact_zonecut = true; + } + printf("noexact_zonecut = %s\n", + noexact_zonecut ? "TRUE" : "FALSE"); + continue; + } + + isc_buffer_init(&source, s, len); + isc_buffer_add(&source, len); + isc_buffer_init(&target, b, sizeof(b)); + result = dns_name_fromtext(&name, &source, origin, 0, &target); + if (result != ISC_R_SUCCESS) { + print_result("bad name: ", result); + continue; + } + + if (dbi == NULL) { + zcoptions = 0; + if (noexact_zonecut) { + zcoptions |= DNS_DBTABLEFIND_NOEXACT; + } + db = NULL; + result = dns_dbtable_find(dbtable, &name, zcoptions, + &db); + if (result != ISC_R_SUCCESS && + result != DNS_R_PARTIALMATCH) + { + if (!quiet) { + printf("\n"); + print_result("", result); + } + continue; + } + isc_buffer_init(&tb1, t1, sizeof(t1)); + result = dns_name_totext(dns_db_origin(db), false, + &tb1); + if (result != ISC_R_SUCCESS) { + printf("\n"); + print_result("", result); + dns_db_detach(&db); + continue; + } + isc_buffer_usedregion(&tb1, &r1); + printf("\ndatabase = %.*s (%s)\n", (int)r1.length, + r1.base, (dns_db_iszone(db)) ? "zone" : "cache"); + } + node = NULL; + dns_rdataset_init(&rdataset); + dns_rdataset_init(&sigrdataset); + + if (find_zonecut && dns_db_iscache(db)) { + zcoptions = options; + if (noexact_zonecut) { + zcoptions |= DNS_DBFIND_NOEXACT; + } + result = dns_db_findzonecut(db, &name, zcoptions, 0, + &node, fname, NULL, + &rdataset, &sigrdataset); + } else { + result = dns_db_find(db, &name, version, type, options, + 0, &node, fname, &rdataset, + &sigrdataset); + } + + if (!quiet) { + if (dbi != NULL) { + printf("\n"); + } + print_result("", result); + } + + found_as = false; + switch (result) { + case ISC_R_SUCCESS: + case DNS_R_GLUE: + case DNS_R_CNAME: + case DNS_R_ZONECUT: + break; + case DNS_R_DNAME: + case DNS_R_DELEGATION: + found_as = true; + break; + case DNS_R_NXRRSET: + if (dns_rdataset_isassociated(&rdataset)) { + break; + } + if (dbi != NULL) { + if (holdmode) { + RUNTIME_CHECK(dbi->hold_count < + MAXHOLD); + dbi->hold_nodes[dbi->hold_count++] = + node; + node = NULL; + } else { + dns_db_detachnode(db, &node); + } + } else { + dns_db_detachnode(db, &node); + dns_db_detach(&db); + } + continue; + case DNS_R_NXDOMAIN: + if (dns_rdataset_isassociated(&rdataset)) { + break; + } + FALLTHROUGH; + default: + if (dbi == NULL) { + dns_db_detach(&db); + } + if (quiet) { + print_result("", result); + } + continue; + } + if (found_as && !quiet) { + isc_buffer_init(&tb1, t1, sizeof(t1)); + isc_buffer_init(&tb2, t2, sizeof(t2)); + result = dns_name_totext(&name, false, &tb1); + if (result != ISC_R_SUCCESS) { + print_result("", result); + dns_db_detachnode(db, &node); + if (dbi == NULL) { + dns_db_detach(&db); + } + continue; + } + result = dns_name_totext(fname, false, &tb2); + if (result != ISC_R_SUCCESS) { + print_result("", result); + dns_db_detachnode(db, &node); + if (dbi == NULL) { + dns_db_detach(&db); + } + continue; + } + isc_buffer_usedregion(&tb1, &r1); + isc_buffer_usedregion(&tb2, &r2); + printf("found %.*s as %.*s\n", (int)r1.length, r1.base, + (int)r2.length, r2.base); + } + + if (printnode) { + dns_db_printnode(db, node, stdout); + } + + if (!found_as && type == dns_rdatatype_any) { + rdsiter = NULL; + result = dns_db_allrdatasets(db, node, version, 0, 0, + &rdsiter); + if (result == ISC_R_SUCCESS) { + if (!quiet) { + print_rdatasets(fname, rdsiter); + } + dns_rdatasetiter_destroy(&rdsiter); + } else { + print_result("", result); + } + } else { + if (!quiet) { + print_rdataset(fname, &rdataset); + } + if (dns_rdataset_isassociated(&sigrdataset)) { + if (!quiet) { + print_rdataset(fname, &sigrdataset); + } + dns_rdataset_disassociate(&sigrdataset); + } + if (dbi != NULL && addmode && !found_as) { + rdataset.ttl++; + rdataset.trust = trust; + if (dns_db_iszone(db)) { + addopts = DNS_DBADD_MERGE; + } else { + addopts = 0; + } + result = dns_db_addrdataset(db, node, version, + 0, &rdataset, + addopts, NULL); + if (result != ISC_R_SUCCESS) { + print_result("", result); + } + if (printnode) { + dns_db_printnode(db, node, stdout); + } + } else if (dbi != NULL && delmode && !found_as) { + result = dns_db_deleterdataset( + db, node, version, type, 0); + if (result != ISC_R_SUCCESS) { + print_result("", result); + } + if (printnode) { + dns_db_printnode(db, node, stdout); + } + } + dns_rdataset_disassociate(&rdataset); + } + + if (dbi != NULL) { + if (holdmode) { + RUNTIME_CHECK(dbi->hold_count < MAXHOLD); + dbi->hold_nodes[dbi->hold_count++] = node; + node = NULL; + } else { + dns_db_detachnode(db, &node); + } + } else { + dns_db_detachnode(db, &node); + dns_db_detach(&db); + } + } + + if (time_lookups) { + uint64_t usec; + + TIME_NOW(&finish); + + usec = isc_time_microdiff(&finish, &start); + + printf("elapsed time: %lu.%06lu seconds\n", + (unsigned long)(usec / 1000000), + (unsigned long)(usec % 1000000)); + } + + unload_all(); + + dns_dbtable_detach(&dbtable); + + if (lctx != NULL) { + isc_log_destroy(&lctx); + } + + if (!quiet) { + isc_mem_stats(mctx, stdout); + } + + return (0); +} diff --git a/bin/tests/optional/fsaccess_test.c b/bin/tests/optional/fsaccess_test.c new file mode 100644 index 0000000..db5d21e --- /dev/null +++ b/bin/tests/optional/fsaccess_test.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> /* Non-portable. */ +#include <sys/types.h> /* Non-portable. */ + +#include <isc/fsaccess.h> +#include <isc/print.h> +#include <isc/result.h> + +#define PATH "/tmp/fsaccess" + +int +main(void) { + isc_fsaccess_t access; + isc_result_t result; + FILE *fp; + int n; + + n = remove(PATH); + if (n != 0 && errno != ENOENT) { + fprintf(stderr, "unable to remove(%s)\n", PATH); + exit(1); + } + fp = fopen(PATH, "w"); + if (fp == NULL) { + fprintf(stderr, "unable to fopen(%s)\n", PATH); + exit(1); + } + n = chmod(PATH, 0); + if (n != 0) { + fprintf(stderr, "unable chmod(%s, 0)\n", PATH); + exit(1); + } + + access = 0; + + isc_fsaccess_add(ISC_FSACCESS_OWNER | ISC_FSACCESS_GROUP, + ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, &access); + + printf("fsaccess=%u\n", access); + + isc_fsaccess_add(ISC_FSACCESS_OTHER, ISC_FSACCESS_READ, &access); + + printf("fsaccess=%u\n", access); + + result = isc_fsaccess_set(PATH, access); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "result = %s\n", isc_result_totext(result)); + } + (void)fclose(fp); + + return (0); +} diff --git a/bin/tests/optional/gsstest.c b/bin/tests/optional/gsstest.c new file mode 100644 index 0000000..1cc18eb --- /dev/null +++ b/bin/tests/optional/gsstest.c @@ -0,0 +1,550 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <isc/app.h> +#include <isc/base64.h> +#include <isc/log.h> +#include <isc/managers.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/sockaddr.h> +#include <isc/socket.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +#include <dns/dispatch.h> +#include <dns/dnssec.h> +#include <dns/events.h> +#include <dns/fixedname.h> +#include <dns/keyvalues.h> +#include <dns/log.h> +#include <dns/masterdump.h> +#include <dns/message.h> +#include <dns/name.h> +#include <dns/rdataset.h> +#include <dns/request.h> +#include <dns/resolver.h> +#include <dns/result.h> +#include <dns/tkey.h> +#include <dns/tsig.h> +#include <dns/types.h> +#include <dns/view.h> + +#include <dst/result.h> + +#ifdef GSSAPI +#include ISC_PLATFORM_GSSAPIHEADER + +#define CHECK(str, x) \ + { \ + if ((x) != ISC_R_SUCCESS) { \ + fprintf(stderr, "I:%d:%s: %s\n", __LINE__, (str), \ + isc_result_totext(x)); \ + goto end; \ + } \ + } + +static dns_fixedname_t servername, gssname; + +static isc_mem_t *mctx = NULL; +static dns_requestmgr_t *requestmgr = NULL; +static isc_sockaddr_t address; + +static dns_tsig_keyring_t *ring = NULL; +static dns_tsigkey_t *tsigkey = NULL; +static dns_gss_ctx_id_t gssctx; +static dns_gss_ctx_id_t *gssctxp = &gssctx; + +#define RUNCHECK(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS) + +#define PORT 53 +#define TIMEOUT 30 + +static void +initctx1(isc_task_t *task, isc_event_t *event); +static void +sendquery(isc_task_t *task, isc_event_t *event); +static void +setup(); + +static void +console(isc_task_t *task, isc_event_t *event) { + char buf[32]; + int c; + + isc_event_t *ev = NULL; + + isc_event_free(&event); + + for (;;) { + printf("\nCommand => "); + c = scanf("%31s", buf); + + if (c == EOF || strcmp(buf, "quit") == 0) { + isc_app_shutdown(); + return; + } + + if (strcmp(buf, "initctx") == 0) { + ev = isc_event_allocate(mctx, (void *)1, 1, initctx1, + NULL, sizeof(*event)); + isc_task_send(task, &ev); + return; + } + + if (strcmp(buf, "query") == 0) { + ev = isc_event_allocate(mctx, (void *)1, 1, sendquery, + NULL, sizeof(*event)); + isc_task_send(task, &ev); + return; + } + + printf("Unknown command\n"); + } +} + +static void +recvresponse(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = (dns_requestevent_t *)event; + isc_result_t result, result2; + dns_message_t *query = NULL, *response = NULL; + isc_buffer_t outtoken; + isc_buffer_t outbuf; + char output[10 * 1024]; + + unsigned char array[DNS_NAME_MAXTEXT + 1]; + isc_buffer_init(&outtoken, array, sizeof(array)); + + UNUSED(task); + + REQUIRE(reqev != NULL); + + query = reqev->ev_arg; + + if (reqev->result != ISC_R_SUCCESS) { + fprintf(stderr, "I:request event result: %s\n", + isc_result_totext(reqev->result)); + goto end; + } + + response = NULL; + dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); + + printf("\nReceived Response:\n"); + + result2 = dns_request_getresponse(reqev->request, response, + DNS_MESSAGEPARSE_PRESERVEORDER); + isc_buffer_init(&outbuf, output, sizeof(output)); + result = dns_message_totext(response, &dns_master_style_debug, 0, + &outbuf); + CHECK("dns_message_totext", result); + printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf), + (char *)isc_buffer_base(&outbuf)); + + CHECK("dns_request_getresponse", result2); + + if (response != NULL) { + dns_message_detach(&response); + } + +end: + if (query != NULL) { + dns_message_detach(&query); + } + + if (reqev->request != NULL) { + dns_request_destroy(&reqev->request); + } + + isc_event_free(&event); + + event = isc_event_allocate(mctx, (void *)1, 1, console, NULL, + sizeof(*event)); + isc_task_send(task, &event); + return; +} + +static void +sendquery(isc_task_t *task, isc_event_t *event) { + dns_request_t *request = NULL; + dns_message_t *message = NULL; + dns_name_t *qname = NULL; + dns_rdataset_t *qrdataset = NULL; + isc_result_t result; + dns_fixedname_t queryname; + isc_buffer_t buf; + isc_buffer_t outbuf; + char output[10 * 1024]; + static char host[256]; + int c; + + isc_event_free(&event); + + printf("Query => "); + c = scanf("%255s", host); + if (c == EOF) { + return; + } + + dns_fixedname_init(&queryname); + isc_buffer_init(&buf, host, strlen(host)); + isc_buffer_add(&buf, strlen(host)); + result = dns_name_fromtext(dns_fixedname_name(&queryname), &buf, + dns_rootname, 0, NULL); + CHECK("dns_name_fromtext", result); + + dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message); + + message->opcode = dns_opcode_query; + message->rdclass = dns_rdataclass_in; + message->id = (unsigned short)(random() & 0xFFFF); + + result = dns_message_gettempname(message, &qname); + if (result != ISC_R_SUCCESS) { + goto end; + } + + result = dns_message_gettemprdataset(message, &qrdataset); + if (result != ISC_R_SUCCESS) { + goto end; + } + + dns_name_init(qname, NULL); + dns_name_clone(dns_fixedname_name(&queryname), qname); + dns_rdataset_makequestion(qrdataset, dns_rdataclass_in, + dns_rdatatype_a); + ISC_LIST_APPEND(qname->list, qrdataset, link); + dns_message_addname(message, qname, DNS_SECTION_QUESTION); + + result = dns_request_create(requestmgr, message, &address, 0, tsigkey, + TIMEOUT, task, recvresponse, message, + &request); + CHECK("dns_request_create", result); + + printf("Submitting query:\n"); + isc_buffer_init(&outbuf, output, sizeof(output)); + result = dns_message_totext(message, &dns_master_style_debug, 0, + &outbuf); + CHECK("dns_message_totext", result); + printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf), + (char *)isc_buffer_base(&outbuf)); + + return; + +end: + if (qname != NULL) { + dns_message_puttempname(message, &qname); + } + if (qrdataset != NULL) { + dns_message_puttemprdataset(message, &qrdataset); + } + if (message != NULL) { + dns_message_detach(&message); + } +} + +static void +initctx2(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = (dns_requestevent_t *)event; + isc_result_t result; + dns_message_t *query = NULL, *response = NULL; + isc_buffer_t outtoken; + unsigned char array[DNS_NAME_MAXTEXT + 1]; + dns_rdataset_t *rdataset; + dns_rdatatype_t qtype; + dns_name_t *question_name; + + UNUSED(task); + + REQUIRE(reqev != NULL); + + query = reqev->ev_arg; + + if (reqev->result != ISC_R_SUCCESS) { + fprintf(stderr, "I:request event result: %s\n", + isc_result_totext(reqev->result)); + goto end; + } + + response = NULL; + dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); + + result = dns_request_getresponse(reqev->request, response, + DNS_MESSAGEPARSE_PRESERVEORDER); + CHECK("dns_request_getresponse", result); + + if (response->rcode != dns_rcode_noerror) { + result = ISC_RESULTCLASS_DNSRCODE + response->rcode; + fprintf(stderr, "I:response rcode: %s\n", + isc_result_totext(result)); + goto end; + } + + printf("Received token from server, calling gss_init_sec_context()\n"); + isc_buffer_init(&outtoken, array, DNS_NAME_MAXTEXT + 1); + result = dns_tkey_processgssresponse( + query, response, dns_fixedname_name(&gssname), &gssctx, + &outtoken, &tsigkey, ring, NULL); + gssctx = *gssctxp; + CHECK("dns_tkey_processgssresponse", result); + printf("Context accepted\n"); + + question_name = NULL; + dns_message_currentname(response, DNS_SECTION_ANSWER, &question_name); + rdataset = ISC_LIST_HEAD(question_name->list); + INSIST(rdataset != NULL); + qtype = rdataset->type; + if (qtype == dns_rdatatype_tkey) { + printf("Received TKEY response from server\n"); + printf("Context completed\n"); + } else { + printf("Did not receive TKEY response from server\n"); + printf("Context not completed\n"); + dns_tsigkey_detach(&tsigkey); + tsigkey = NULL; + } + + dns_message_detach(&response); + +end: + if (query != NULL) { + dns_message_detach(&query); + } + + if (reqev->request != NULL) { + dns_request_destroy(&reqev->request); + } + + isc_event_free(&event); + + event = isc_event_allocate(mctx, (void *)1, 1, console, NULL, + sizeof(*event)); + isc_task_send(task, &event); + return; +} + +static void +initctx1(isc_task_t *task, isc_event_t *event) { + char gssid[512]; + char contextname[512]; + isc_result_t result; + isc_buffer_t buf; + dns_message_t *query; + dns_request_t *request; + int c; + + isc_event_free(&event); + + printf("Initctx - GSS name => "); + c = scanf("%511s", gssid); + if (c == EOF) { + return; + } + + snprintf(contextname, sizeof(contextname), "gsstest.context.%d.", + (int)time(NULL)); + + printf("Initctx - context name we're using: %s\n", contextname); + + printf("Negotiating GSSAPI context: "); + printf("%s", gssid); + printf("\n"); + + /* + * Setup a GSSAPI context with the server + */ + dns_fixedname_init(&servername); + isc_buffer_init(&buf, contextname, strlen(contextname)); + isc_buffer_add(&buf, strlen(contextname)); + result = dns_name_fromtext(dns_fixedname_name(&servername), &buf, + dns_rootname, 0, NULL); + CHECK("dns_name_fromtext", result); + + /* Make name happen */ + dns_fixedname_init(&gssname); + isc_buffer_init(&buf, gssid, strlen(gssid)); + isc_buffer_add(&buf, strlen(gssid)); + result = dns_name_fromtext(dns_fixedname_name(&gssname), &buf, + dns_rootname, 0, NULL); + CHECK("dns_name_fromtext", result); + + query = NULL; + dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query); + + printf("Calling gss_init_sec_context()\n"); + gssctx = GSS_C_NO_CONTEXT; + result = dns_tkey_buildgssquery(query, dns_fixedname_name(&servername), + dns_fixedname_name(&gssname), NULL, + 36000, &gssctx, true, mctx, NULL); + CHECK("dns_tkey_buildgssquery", result); + + printf("Sending context token to server\n"); + request = NULL; + result = dns_request_create(requestmgr, query, &address, 0, NULL, + TIMEOUT, task, initctx2, query, &request); + CHECK("dns_request_create", result); + + return; +end: + event = isc_event_allocate(mctx, (void *)1, 1, console, NULL, + sizeof(*event)); + isc_task_send(task, &event); + return; +} + +static void +setup(void) { + for (;;) { + char serveraddress[512]; + struct in_addr inaddr; + int c; + + printf("Server IP => "); + c = scanf("%511s", serveraddress); + + if (c == EOF || strcmp(serveraddress, "quit") == 0) { + isc_app_shutdown(); + return; + } + + if (inet_pton(AF_INET, serveraddress, &inaddr) == 1) { + isc_sockaddr_fromin(&address, &inaddr, PORT); + return; + } + } +} + +int +main(int argc, char *argv[]) { + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_timermgr_t *timermgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_socket_t *sock = NULL; + unsigned int attrs, attrmask; + isc_sockaddr_t bind_any; + dns_dispatchmgr_t *dispatchmgr = NULL; + dns_dispatch_t *dispatchv4 = NULL; + dns_view_t *view = NULL; + isc_task_t *task = NULL; + isc_log_t *lctx = NULL; + isc_logconfig_t *lcfg = NULL; + isc_logdestination_t destination; + + UNUSED(argv); + UNUSED(argc); + + RUNCHECK(isc_app_start()); + + dns_result_register(); + + mctx = NULL; + isc_mem_create(&mctx); + + isc_log_create(mctx, &lctx, &lcfg); + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + /* + * Create and install the default channel. + */ + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, ISC_LOG_PRINTTIME); + + RUNCHECK(isc_log_usechannel(lcfg, "_default", NULL, NULL)); + + isc_log_setdebuglevel(lctx, 9); + + RUNCHECK(dst_lib_init(mctx, NULL)); + + RUNCHECK(isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr)); + RUNCHECK(isc_task_create(taskmgr, 0, &task)); + RUNCHECK(isc_timermgr_create(mctx, &timermgr)); + RUNCHECK(isc_socketmgr_create(mctx, &socketmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + isc_sockaddr_any(&bind_any); + attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | + DNS_DISPATCHATTR_IPV4; + attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP | + DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; + RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any, + 4096, 4, 2, 3, 5, attrs, attrmask, + &dispatchv4)); + RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, + dispatchmgr, dispatchv4, NULL, + &requestmgr)); + + RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); + + RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); + dns_view_setkeyring(view, ring); + + RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, + &sock)); + + setup(); + + RUNCHECK(isc_app_onrun(mctx, task, console, NULL)); + + (void)isc_app_run(); + + if (tsigkey) { + dns_tsigkey_detach(&tsigkey); + } + + dns_requestmgr_shutdown(requestmgr); + dns_requestmgr_detach(&requestmgr); + + dns_dispatch_detach(&dispatchv4); + dns_dispatchmgr_destroy(&dispatchmgr); + + isc_timermgr_destroy(&timermgr); + + isc_task_detach(&task); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_socket_detach(&sock); + isc_socketmgr_destroy(&socketmgr); + + isc_mem_stats(mctx, stdout); + + dns_view_detach(&view); + + dst_lib_destroy(); + + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + isc_app_finish(); + + return (0); +} +#else /* ifdef GSSAPI */ +int +main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + fprintf(stderr, "R:GSSAPIONLY\n"); + return (0); +} +#endif /* ifdef GSSAPI */ diff --git a/bin/tests/optional/inter_test.c b/bin/tests/optional/inter_test.c new file mode 100644 index 0000000..32fbb2e --- /dev/null +++ b/bin/tests/optional/inter_test.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include <stdlib.h> + +#include <isc/interfaceiter.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/util.h> + +int +main(int argc, char **argv) { + isc_mem_t *mctx = NULL; + isc_interfaceiter_t *iter = NULL; + isc_interface_t ifdata; + isc_result_t result; + const char *res; + char buf[128]; + + UNUSED(argc); + UNUSED(argv); + + isc_mem_create(&mctx); + result = isc_interfaceiter_create(mctx, &iter); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + result = isc_interfaceiter_first(iter); + while (result == ISC_R_SUCCESS) { + result = isc_interfaceiter_current(iter, &ifdata); + if (result != ISC_R_SUCCESS) { + fprintf(stdout, "isc_interfaceiter_current: %s", + isc_result_totext(result)); + continue; + } + fprintf(stdout, "%s %u %x\n", ifdata.name, ifdata.af, + ifdata.flags); + INSIST(ifdata.af == AF_INET || ifdata.af == AF_INET6); + res = inet_ntop(ifdata.af, &ifdata.address.type, buf, + sizeof(buf)); + if (ifdata.address.zone != 0) { + fprintf(stdout, "address = %s (zone %u)\n", + res == NULL ? "BAD" : res, ifdata.address.zone); + } else { + fprintf(stdout, "address = %s\n", + res == NULL ? "BAD" : res); + } + INSIST(ifdata.address.family == ifdata.af); + res = inet_ntop(ifdata.af, &ifdata.netmask.type, buf, + sizeof(buf)); + fprintf(stdout, "netmask = %s\n", res == NULL ? "BAD" : res); + INSIST(ifdata.netmask.family == ifdata.af); + if ((ifdata.flags & INTERFACE_F_POINTTOPOINT) != 0) { + res = inet_ntop(ifdata.af, &ifdata.dstaddress.type, buf, + sizeof(buf)); + fprintf(stdout, "dstaddress = %s\n", + res == NULL ? "BAD" : res); + + INSIST(ifdata.dstaddress.family == ifdata.af); + } + result = isc_interfaceiter_next(iter); + if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) { + fprintf(stdout, "isc_interfaceiter_next: %s", + isc_result_totext(result)); + continue; + } + } + isc_interfaceiter_destroy(&iter); + + fprintf(stdout, "\nPass 2\n\n"); + + result = isc_interfaceiter_create(mctx, &iter); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + result = isc_interfaceiter_first(iter); + while (result == ISC_R_SUCCESS) { + result = isc_interfaceiter_current(iter, &ifdata); + if (result != ISC_R_SUCCESS) { + fprintf(stdout, "isc_interfaceiter_current: %s", + isc_result_totext(result)); + continue; + } + fprintf(stdout, "%s %u %x\n", ifdata.name, ifdata.af, + ifdata.flags); + INSIST(ifdata.af == AF_INET || ifdata.af == AF_INET6); + res = inet_ntop(ifdata.af, &ifdata.address.type, buf, + sizeof(buf)); + if (ifdata.address.zone != 0) { + fprintf(stdout, "address = %s (zone %u)\n", + res == NULL ? "BAD" : res, ifdata.address.zone); + } else { + fprintf(stdout, "address = %s\n", + res == NULL ? "BAD" : res); + } + INSIST(ifdata.address.family == ifdata.af); + res = inet_ntop(ifdata.af, &ifdata.netmask.type, buf, + sizeof(buf)); + fprintf(stdout, "netmask = %s\n", res == NULL ? "BAD" : res); + INSIST(ifdata.netmask.family == ifdata.af); + if ((ifdata.flags & INTERFACE_F_POINTTOPOINT) != 0) { + res = inet_ntop(ifdata.af, &ifdata.dstaddress.type, buf, + sizeof(buf)); + fprintf(stdout, "dstaddress = %s\n", + res == NULL ? "BAD" : res); + + INSIST(ifdata.dstaddress.family == ifdata.af); + } + result = isc_interfaceiter_next(iter); + if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) { + fprintf(stdout, "isc_interfaceiter_next: %s", + isc_result_totext(result)); + continue; + } + } + isc_interfaceiter_destroy(&iter); +cleanup: + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/lex_test.c b/bin/tests/optional/lex_test.c new file mode 100644 index 0000000..e0e88f7 --- /dev/null +++ b/bin/tests/optional/lex_test.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include <isc/commandline.h> +#include <isc/lex.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/util.h> + +isc_mem_t *mctx; +isc_lex_t *lex; + +isc_lexspecials_t specials; + +static void +print_token(isc_token_t *tokenp, FILE *stream) { + switch (tokenp->type) { + case isc_tokentype_unknown: + fprintf(stream, "UNKNOWN"); + break; + case isc_tokentype_string: + fprintf(stream, "STRING %.*s", + (int)tokenp->value.as_region.length, + tokenp->value.as_region.base); + break; + case isc_tokentype_number: + fprintf(stream, "NUMBER %lu", tokenp->value.as_ulong); + break; + case isc_tokentype_qstring: + fprintf(stream, "QSTRING \"%.*s\"", + (int)tokenp->value.as_region.length, + tokenp->value.as_region.base); + break; + case isc_tokentype_eol: + fprintf(stream, "EOL"); + break; + case isc_tokentype_eof: + fprintf(stream, "EOF"); + break; + case isc_tokentype_initialws: + fprintf(stream, "INITIALWS"); + break; + case isc_tokentype_special: + fprintf(stream, "SPECIAL %c", tokenp->value.as_char); + break; + case isc_tokentype_nomore: + fprintf(stream, "NOMORE"); + break; + default: + FATAL_ERROR(__FILE__, __LINE__, "Unexpected type %d", + tokenp->type); + } +} + +int +main(int argc, char *argv[]) { + isc_token_t token; + isc_result_t result; + int quiet = 0; + int c; + int masterfile = 1; + int stats = 0; + unsigned int options = 0; + int done = 0; + + while ((c = isc_commandline_parse(argc, argv, "qmcs")) != -1) { + switch (c) { + case 'q': + quiet = 1; + break; + case 'm': + masterfile = 1; + break; + case 'c': + masterfile = 0; + break; + case 's': + stats = 1; + break; + } + } + + isc_mem_create(&mctx); + RUNTIME_CHECK(isc_lex_create(mctx, 256, &lex) == ISC_R_SUCCESS); + + if (masterfile) { + /* Set up to lex DNS master file. */ + + specials['('] = 1; + specials[')'] = 1; + specials['"'] = 1; + isc_lex_setspecials(lex, specials); + options = ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE | + ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING | + ISC_LEXOPT_NOMORE; + isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); + } else { + /* Set up to lex DNS config file. */ + + specials['{'] = 1; + specials['}'] = 1; + specials[';'] = 1; + specials['/'] = 1; + specials['"'] = 1; + specials['!'] = 1; + specials['*'] = 1; + isc_lex_setspecials(lex, specials); + options = ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING | + ISC_LEXOPT_NUMBER | ISC_LEXOPT_NOMORE; + isc_lex_setcomments(lex, (ISC_LEXCOMMENT_C | + ISC_LEXCOMMENT_CPLUSPLUS | + ISC_LEXCOMMENT_SHELL)); + } + + RUNTIME_CHECK(isc_lex_openstream(lex, stdin) == ISC_R_SUCCESS); + + while ((result = isc_lex_gettoken(lex, options, &token)) == + ISC_R_SUCCESS && + !done) + { + if (!quiet) { + char *name = isc_lex_getsourcename(lex); + print_token(&token, stdout); + printf(" line = %lu file = %s\n", + isc_lex_getsourceline(lex), + (name == NULL) ? "<none>" : name); + } + if (token.type == isc_tokentype_eof) { + isc_lex_close(lex); + } + if (token.type == isc_tokentype_nomore) { + done = 1; + } + } + if (result != ISC_R_SUCCESS) { + printf("Result: %s\n", isc_result_totext(result)); + } + + isc_lex_close(lex); + isc_lex_destroy(&lex); + if (!quiet && stats) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/lfsr_test.c b/bin/tests/optional/lfsr_test.c new file mode 100644 index 0000000..c1c99f0 --- /dev/null +++ b/bin/tests/optional/lfsr_test.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include <inttypes.h> +#include <stdio.h> + +#include <isc/lfsr.h> +#include <isc/print.h> +#include <isc/util.h> + +uint32_t state[1024 * 64]; + +int +main(int argc, char **argv) { + isc_lfsr_t lfsr1, lfsr2; + int i; + uint32_t temp; + + UNUSED(argc); + UNUSED(argv); + + /* + * Verify that returned values are reproducible. + */ + isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr1, &state[i], 4); + printf("lfsr1: state[%2d] = %08x\n", i, state[i]); + } + isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr1, &temp, 4); + if (state[i] != temp) { + printf("lfsr1: state[%2d] = %08x, " + "but new state is %08x\n", + i, state[i], temp); + } + } + + /* + * Now do the same with skipping. + */ + isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr1, &state[i], 4); + isc_lfsr_skip(&lfsr1, 32); + printf("lfsr1: state[%2d] = %08x\n", i, state[i]); + } + isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr1, &temp, 4); + isc_lfsr_skip(&lfsr1, 32); + if (state[i] != temp) { + printf("lfsr1: state[%2d] = %08x, " + "but new state is %08x\n", + i, state[i], temp); + } + } + + /* + * Try to find the period of the LFSR. + * + * x^16 + x^5 + x^3 + x^2 + 1 + */ + isc_lfsr_init(&lfsr2, 0, 16, 0x00008016U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr2, &state[i], 4); + printf("lfsr2: state[%2d] = %08x\n", i, state[i]); + } + isc_lfsr_init(&lfsr2, 0, 16, 0x00008016U, 0, NULL, NULL); + for (i = 0; i < 32; i++) { + isc_lfsr_generate(&lfsr2, &temp, 4); + if (state[i] != temp) { + printf("lfsr2: state[%2d] = %08x, " + "but new state is %08x\n", + i, state[i], temp); + } + } + + return (0); +} diff --git a/bin/tests/optional/log_test.c b/bin/tests/optional/log_test.c new file mode 100644 index 0000000..006b1e2 --- /dev/null +++ b/bin/tests/optional/log_test.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> + +#include <isc/commandline.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dns/log.h> + +#define TEST_FILE "/tmp/test_log" +#define SYSLOG_FILE "/var/log/daemon.log" +#define FILE_VERSIONS 10 + +char usage[] = "Usage: %s [-m] [-s syslog_logfile] [-r file_versions]\n"; + +#define CHECK(expr) \ + result = expr; \ + if (result != ISC_R_SUCCESS) { \ + fprintf(stderr, "%s: " #expr "%s: exiting\n", progname, \ + isc_result_totext(result)); \ + } + +int +main(int argc, char **argv) { + const char *progname, *syslog_file, *message; + int ch, i, file_versions, stderr_line; + bool show_final_mem = false; + isc_log_t *lctx; + isc_logconfig_t *lcfg; + isc_mem_t *mctx; + isc_result_t result; + isc_logdestination_t destination; + const isc_logcategory_t *category; + const isc_logmodule_t *module; + + progname = strrchr(*argv, '/'); + if (progname != NULL) { + progname++; + } else { + progname = *argv; + } + + syslog_file = SYSLOG_FILE; + file_versions = FILE_VERSIONS; + + while ((ch = isc_commandline_parse(argc, argv, "ms:r:")) != -1) { + switch (ch) { + case 'm': + show_final_mem = true; + break; + case 's': + syslog_file = isc_commandline_argument; + break; + case 'r': + file_versions = atoi(isc_commandline_argument); + if (file_versions < 0 && + file_versions != ISC_LOG_ROLLNEVER && + file_versions != ISC_LOG_ROLLINFINITE) + { + fprintf(stderr, + "%s: file rotations must be " + "%d (ISC_LOG_ROLLNEVER),\n\t" + "%d (ISC_LOG_ROLLINFINITE) " + "or > 0\n", + progname, ISC_LOG_ROLLNEVER, + ISC_LOG_ROLLINFINITE); + exit(1); + } + break; + case '?': + fprintf(stderr, usage, progname); + exit(1); + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + POST(argv); + + if (argc > 0) { + fprintf(stderr, usage, progname); + exit(1); + } + + fprintf(stderr, "EXPECT:\n%s%d%s%s%s", + "8 lines to stderr (first 4 numbered, #3 repeated)\n", + file_versions == 0 || file_versions == ISC_LOG_ROLLNEVER ? 1 + : file_versions > 0 ? file_versions + 1 + : FILE_VERSIONS + 1, + " " TEST_FILE " files, and\n", "2 lines to syslog\n", + "lines ending with exclamation marks are errors\n\n"); + + isc_log_opensyslog(progname, LOG_PID, LOG_DAEMON); + + mctx = NULL; + lctx = NULL; + lcfg = NULL; + + isc_mem_create(&mctx); + isc_log_create(mctx, &lctx, &lcfg); + + isc_log_settag(lcfg, progname); + + isc_log_setcontext(lctx); + dns_log_init(lctx); + dns_log_setcontext(lctx); + + /* + * Test isc_log_categorybyname and isc_log_modulebyname. + */ + category = isc_log_categorybyname(lctx, "notify"); + if (category != NULL) { + fprintf(stderr, "%s category found. (expected)\n", + category->name); + } else { + fprintf(stderr, "notify category not found!\n"); + } + + module = isc_log_modulebyname(lctx, "xyzzy"); + if (module != NULL) { + fprintf(stderr, "%s module found!\n", module->name); + } else { + fprintf(stderr, "xyzzy module not found. (expected)\n"); + } + + /* + * Create a file channel to test file opening, size limiting and + * version rolling. + */ + + destination.file.name = TEST_FILE; + destination.file.maximum_size = 1; + destination.file.versions = file_versions; + + isc_log_createchannel( + lcfg, "file_test", ISC_LOG_TOFILE, ISC_LOG_INFO, &destination, + ISC_LOG_PRINTTIME | ISC_LOG_PRINTTAG | ISC_LOG_PRINTLEVEL | + ISC_LOG_PRINTCATEGORY | ISC_LOG_PRINTMODULE); + + /* + * Create a dynamic debugging channel to a file descriptor. + */ + destination.file.stream = stderr; + + isc_log_createchannel(lcfg, "debug_test", ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, &destination, + ISC_LOG_PRINTTIME | ISC_LOG_PRINTLEVEL | + ISC_LOG_DEBUGONLY); + + /* + * Test the usability of the four predefined logging channels. + */ + CHECK(isc_log_usechannel(lcfg, "default_syslog", + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE)); + CHECK(isc_log_usechannel(lcfg, "default_stderr", + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE)); + CHECK(isc_log_usechannel(lcfg, "default_debug", + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE)); + CHECK(isc_log_usechannel(lcfg, "null", DNS_LOGCATEGORY_DATABASE, NULL)); + + /* + * Use the custom channels. + */ + CHECK(isc_log_usechannel(lcfg, "file_test", DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DB)); + + CHECK(isc_log_usechannel(lcfg, "debug_test", DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_RBTDB)); + + fprintf(stderr, "\n==> stderr begin\n"); + + /* + * Write to the internal default by testing both a category for which + * no channel has been specified and a category which was specified + * but not with the named module. + */ + stderr_line = 1; + + isc_log_write(lctx, DNS_LOGCATEGORY_SECURITY, DNS_LOGMODULE_RBT, + ISC_LOG_CRITICAL, "%s (%d)", + "Unspecified category and unspecified module to stderr", + stderr_line++); + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBT, + ISC_LOG_CRITICAL, "%s (%d)", + "Specified category and unspecified module to stderr", + stderr_line++); + + /* + * Write to default_syslog, default_stderr and default_debug. + */ + isc_log_write(lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE, + ISC_LOG_WARNING, "%s (%d twice)", + "Using the predefined channels to syslog+stderr", + stderr_line++); + + /* + * Write to predefined null channel. + */ + isc_log_write(lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_RBTDB, + ISC_LOG_INFO, "This is to null and should not appear!"); + + /* + * Reset the internal default to use syslog instead of stderr, + * and test it. + */ + CHECK(isc_log_usechannel(lcfg, "default_syslog", + ISC_LOGCATEGORY_DEFAULT, NULL)); + isc_log_write(lctx, DNS_LOGCATEGORY_SECURITY, DNS_LOGMODULE_RBT, + ISC_LOG_ERROR, "%s%s", + "This message to the redefined default category should ", + "be second in syslog"); + /* + * Write to the file channel. + */ + if (file_versions >= 0 || file_versions == ISC_LOG_ROLLINFINITE) { + /* + * If file_versions is 0 or ISC_LOG_ROLLINFINITE, write + * the "should not appear" and "should be in file" messages + * to ensure they get rolled. + */ + if (file_versions <= 0) { + file_versions = FILE_VERSIONS; + } else { + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DB, ISC_LOG_NOTICE, + "This should be rolled over " + "and not appear!"); + } + + for (i = file_versions - 1; i >= 0; i--) { + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DB, ISC_LOG_NOTICE, + "should be in file %d/%d", i, + file_versions - 1); + } + + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DB, + ISC_LOG_NOTICE, "should be in base file"); + } else { + file_versions = FILE_VERSIONS; + for (i = 1; i <= file_versions; i++) { + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DB, ISC_LOG_NOTICE, + "This is message %d in the log file", i); + } + } + + /* + * Write a debugging message to a category that has no + * debugging channels for the named module. + */ + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DB, + ISC_LOG_DEBUG(1), + "This debug message should not appear!"); + + /* + * Write debugging messages to a dynamic debugging channel. + */ + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, + "This critical message should " + "not appear because the debug level is 0!"); + + isc_log_setdebuglevel(lctx, 3); + + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_DEBUG(1), "%s (%d)", + "Dynamic debugging to stderr", stderr_line++); + isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_DEBUG(5), + "This debug level is too high and should not appear!"); + + /* + * Test out the duplicate filtering using the debug_test channel. + */ + isc_log_setduplicateinterval(lcfg, 10); + message = "This message should appear only once on stderr"; + + isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, "%s", message); + isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, "%s", message); + + isc_log_setduplicateinterval(lcfg, 1); + message = "This message should appear twice on stderr"; + + isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, "%s", message); + sleep(2); + isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB, + ISC_LOG_CRITICAL, "%s", message); + + /* + * Review where everything went. + * XXXDCL NT + */ + fputc('\n', stderr); + if (system("head " TEST_FILE "*; rm -f " TEST_FILE "*") != 0) { + fprintf(stderr, "system(\"head " TEST_FILE "*; rm -f " TEST_FILE + "*\") failed\n"); + goto cleanup; + } + + /* This is highly system specific. */ + if (freopen(syslog_file, "r", stdin) == NULL) { + fprintf(stderr, "freopen(%s, \"r\", stdin) failed\n", + syslog_file); + goto cleanup; + } + fprintf(stderr, "\n==> %s <==\n", syslog_file); + if (system("tail -2") != 0) { + fprintf(stderr, "system(\"tail -2\") failed\n"); + goto cleanup; + } + fputc('\n', stderr); + +cleanup: + isc_log_destroy(&lctx); + + if (show_final_mem) { + isc_mem_stats(mctx, stderr); + } + + return (0); +} diff --git a/bin/tests/optional/master_test.c b/bin/tests/optional/master_test.c new file mode 100644 index 0000000..1cd6ec7 --- /dev/null +++ b/bin/tests/optional/master_test.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdlib.h> +#include <string.h> + +#include <isc/buffer.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/util.h> + +#include <dns/callbacks.h> +#include <dns/master.h> +#include <dns/name.h> +#include <dns/rdataset.h> +#include <dns/result.h> + +isc_mem_t *mctx; + +static isc_result_t +print_dataset(void *arg, const dns_name_t *owner, dns_rdataset_t *dataset) { + char buf[64 * 1024]; + isc_buffer_t target; + isc_result_t result; + + UNUSED(arg); + + isc_buffer_init(&target, buf, 64 * 1024); + result = dns_rdataset_totext(dataset, owner, false, false, &target); + if (result == ISC_R_SUCCESS) { + fprintf(stdout, "%.*s\n", (int)target.used, + (char *)target.base); + } else { + fprintf(stdout, "dns_rdataset_totext: %s\n", + dns_result_totext(result)); + } + + return (ISC_R_SUCCESS); +} + +int +main(int argc, char *argv[]) { + isc_result_t result; + dns_name_t origin; + isc_buffer_t source; + isc_buffer_t target; + unsigned char name_buf[255]; + dns_rdatacallbacks_t callbacks; + + UNUSED(argc); + + isc_mem_create(&mctx); + + if (argv[1]) { + isc_buffer_init(&source, argv[1], strlen(argv[1])); + isc_buffer_add(&source, strlen(argv[1])); + isc_buffer_setactive(&source, strlen(argv[1])); + isc_buffer_init(&target, name_buf, 255); + dns_name_init(&origin, NULL); + result = dns_name_fromtext(&origin, &source, dns_rootname, 0, + &target); + if (result != ISC_R_SUCCESS) { + fprintf(stdout, "dns_name_fromtext: %s\n", + dns_result_totext(result)); + exit(1); + } + + dns_rdatacallbacks_init_stdio(&callbacks); + callbacks.add = print_dataset; + + result = dns_master_loadfile( + argv[1], &origin, &origin, dns_rdataclass_in, 0, 0, + &callbacks, NULL, NULL, mctx, dns_masterformat_text, 0); + fprintf(stdout, "dns_master_loadfile: %s\n", + dns_result_totext(result)); + } + return (0); +} diff --git a/bin/tests/optional/mempool_test.c b/bin/tests/optional/mempool_test.c new file mode 100644 index 0000000..b3d04ee --- /dev/null +++ b/bin/tests/optional/mempool_test.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <isc/mem.h> +#include <isc/util.h> + +isc_mem_t *mctx; + +int +main(int argc, char *argv[]) { + void *items1[50]; + void *items2[50]; + void *tmp; + isc_mempool_t *mp1, *mp2; + unsigned int i, j; + + UNUSED(argc); + UNUSED(argv); + + isc_mem_debugging = ISC_MEM_DEBUGRECORD; + + mctx = NULL; + isc_mem_create(&mctx); + + mp1 = NULL; + isc_mempool_create(mctx, 24, &mp1); + + mp2 = NULL; + isc_mempool_create(mctx, 31, &mp2); + + isc_mem_stats(mctx, stderr); + + isc_mempool_setfreemax(mp1, 10); + isc_mempool_setfillcount(mp1, 10); + isc_mempool_setmaxalloc(mp1, 30); + + /* + * Allocate 30 items from the pool. This is our max. + */ + for (i = 0; i < 30; i++) { + items1[i] = isc_mempool_get(mp1); + RUNTIME_CHECK(items1[i] != NULL); + } + + /* + * Try to allocate one more. This should fail. + */ + tmp = isc_mempool_get(mp1); + RUNTIME_CHECK(tmp == NULL); + + /* + * Free the first 11 items. Verify that there are 10 free items on + * the free list (which is our max). + */ + + for (i = 0; i < 11; i++) { + isc_mempool_put(mp1, items1[i]); + items1[i] = NULL; + } + + RUNTIME_CHECK(isc_mempool_getfreecount(mp1) == 10); + RUNTIME_CHECK(isc_mempool_getallocated(mp1) == 19); + + isc_mem_stats(mctx, stderr); + + /* + * Now, beat up on mp2 for a while. Allocate 50 items, then free + * them, then allocate 50 more, etc. + */ + isc_mempool_setfreemax(mp2, 25); + isc_mempool_setfillcount(mp2, 25); + for (j = 0; j < 5000; j++) { + for (i = 0; i < 50; i++) { + items2[i] = isc_mempool_get(mp2); + RUNTIME_CHECK(items2[i] != NULL); + } + for (i = 0; i < 50; i++) { + isc_mempool_put(mp2, items2[i]); + items2[i] = NULL; + } + } + + /* + * Free all the other items and blow away this pool. + */ + for (i = 11; i < 30; i++) { + isc_mempool_put(mp1, items1[i]); + items1[i] = NULL; + } + + isc_mempool_destroy(&mp1); + + isc_mem_stats(mctx, stderr); + + isc_mempool_destroy(&mp2); + + isc_mem_stats(mctx, stderr); + + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/name_test.c b/bin/tests/optional/name_test.c new file mode 100644 index 0000000..4c37441 --- /dev/null +++ b/bin/tests/optional/name_test.c @@ -0,0 +1,365 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdbool.h> +#include <stdlib.h> + +#include <isc/commandline.h> +#include <isc/print.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dns/fixedname.h> +#include <dns/result.h> + +static void +print_wirename(isc_region_t *name) { + unsigned char *ccurr, *cend; + + if (name->length == 0) { + printf("<empty wire name>\n"); + return; + } + ccurr = name->base; + cend = ccurr + name->length; + while (ccurr != cend) { + printf("%02x ", *ccurr++); + } + printf("\n"); +} + +static void +print_name(dns_name_t *name) { + isc_result_t result; + isc_buffer_t source; + isc_region_t r; + char s[1000]; + + isc_buffer_init(&source, s, sizeof(s)); + if (dns_name_countlabels(name) > 0) { + result = dns_name_totext(name, false, &source); + } else { + result = ISC_R_SUCCESS; + } + if (result == ISC_R_SUCCESS) { + isc_buffer_usedregion(&source, &r); + if (r.length > 0) { + printf("%.*s\n", (int)r.length, r.base); + } else { + printf("<empty text name>\n"); + } + } else { + printf("error: %s\n", dns_result_totext(result)); + } +} + +int +main(int argc, char *argv[]) { + char s[1000]; + isc_result_t result; + dns_fixedname_t wname, wname2, oname, compname, downname; + isc_buffer_t source; + isc_region_t r; + dns_name_t *name, *comp, *down; + const dns_name_t *origin; + unsigned int downcase = 0; + size_t len; + bool quiet = false; + bool concatenate = false; + bool got_name = false; + bool check_absolute = false; + bool check_wildcard = false; + bool test_downcase = false; + bool inplace = false; + bool want_split = false; + unsigned int labels, split_label = 0; + dns_fixedname_t fprefix, fsuffix; + dns_name_t *prefix, *suffix; + int ch; + + while ((ch = isc_commandline_parse(argc, argv, "acdiqs:w")) != -1) { + switch (ch) { + case 'a': + check_absolute = true; + break; + case 'c': + concatenate = true; + break; + case 'd': + test_downcase = true; + break; + case 'i': + inplace = true; + break; + case 'q': + quiet = true; + break; + case 's': + want_split = true; + split_label = atoi(isc_commandline_argument); + break; + case 'w': + check_wildcard = true; + break; + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (argc > 0) { + if (strcasecmp("none", argv[0]) == 0) { + origin = NULL; + } else { + len = strlen(argv[0]); + isc_buffer_init(&source, argv[0], len); + isc_buffer_add(&source, len); + dns_fixedname_init(&oname); + result = dns_name_fromtext(dns_fixedname_name(&oname), + &source, dns_rootname, 0, + NULL); + if (result != 0) { + fprintf(stderr, + "dns_name_fromtext() failed: %s\n", + dns_result_totext(result)); + exit(1); + } + origin = dns_fixedname_name(&oname); + } + } else if (concatenate) { + origin = NULL; + } else { + origin = dns_rootname; + } + + if (argc >= 1) { + if (strcasecmp("none", argv[1]) == 0) { + comp = NULL; + } else { + len = strlen(argv[1]); + isc_buffer_init(&source, argv[1], len); + isc_buffer_add(&source, len); + comp = dns_fixedname_initname(&compname); + result = dns_name_fromtext(comp, &source, origin, 0, + NULL); + if (result != 0) { + fprintf(stderr, + "dns_name_fromtext() failed: %s\n", + dns_result_totext(result)); + exit(1); + } + } + } else { + comp = NULL; + } + + name = dns_fixedname_initname(&wname); + dns_fixedname_init(&wname2); + while (fgets(s, sizeof(s), stdin) != NULL) { + len = strlen(s); + if (len > 0U && s[len - 1] == '\n') { + s[len - 1] = '\0'; + len--; + } + isc_buffer_init(&source, s, len); + isc_buffer_add(&source, len); + + if (len > 0U) { + result = dns_name_fromtext(name, &source, origin, + downcase, NULL); + } else { + if (name == dns_fixedname_name(&wname)) { + dns_fixedname_init(&wname); + } else { + dns_fixedname_init(&wname2); + } + result = ISC_R_SUCCESS; + } + + if (result != ISC_R_SUCCESS) { + printf("%s\n", dns_result_totext(result)); + if (name == dns_fixedname_name(&wname)) { + dns_fixedname_init(&wname); + } else { + dns_fixedname_init(&wname2); + } + continue; + } + + if (check_absolute && dns_name_countlabels(name) > 0) { + if (dns_name_isabsolute(name)) { + printf("absolute\n"); + } else { + printf("relative\n"); + } + } + if (check_wildcard && dns_name_countlabels(name) > 0) { + if (dns_name_iswildcard(name)) { + printf("wildcard\n"); + } else { + printf("not wildcard\n"); + } + } + dns_name_toregion(name, &r); + if (!quiet) { + print_wirename(&r); + printf("%u labels, %u bytes.\n", + dns_name_countlabels(name), r.length); + } + + if (concatenate) { + if (got_name) { + printf("Concatenating.\n"); + result = dns_name_concatenate( + dns_fixedname_name(&wname), + dns_fixedname_name(&wname2), + dns_fixedname_name(&wname2), NULL); + name = dns_fixedname_name(&wname2); + if (result == ISC_R_SUCCESS) { + if (check_absolute && + dns_name_countlabels(name) > 0) + { + if (dns_name_isabsolute(name)) { + printf("absolute\n"); + } else { + printf("relative\n"); + } + } + if (check_wildcard && + dns_name_countlabels(name) > 0) + { + if (dns_name_iswildcard(name)) { + printf("wildcard\n"); + } else { + printf("not " + "wildcard\n"); + } + } + dns_name_toregion(name, &r); + if (!quiet) { + print_wirename(&r); + printf("%u labels, " + "%u bytes.\n", + dns_name_countlabels( + name), + r.length); + } + } else { + printf("%s\n", + dns_result_totext(result)); + } + got_name = false; + } else { + got_name = true; + } + } + isc_buffer_init(&source, s, sizeof(s)); + if (dns_name_countlabels(name) > 0) { + result = dns_name_totext(name, false, &source); + } else { + result = ISC_R_SUCCESS; + } + if (result == ISC_R_SUCCESS) { + isc_buffer_usedregion(&source, &r); + if (r.length > 0) { + printf("%.*s\n", (int)r.length, r.base); + } else { + printf("<empty text name>\n"); + } + if (!quiet) { + printf("%u bytes.\n", source.used); + } + } else { + printf("%s\n", dns_result_totext(result)); + } + + if (test_downcase) { + if (inplace) { + down = name; + } else { + down = dns_fixedname_initname(&downname); + } + result = dns_name_downcase(name, down, NULL); + INSIST(result == ISC_R_SUCCESS); + if (!quiet) { + dns_name_toregion(down, &r); + print_wirename(&r); + printf("%u labels, %u bytes.\n", + dns_name_countlabels(down), r.length); + } + isc_buffer_init(&source, s, sizeof(s)); + print_name(down); + } + + if (comp != NULL && dns_name_countlabels(name) > 0) { + int order; + unsigned int nlabels; + dns_namereln_t namereln; + + namereln = dns_name_fullcompare(name, comp, &order, + &nlabels); + if (!quiet) { + if (order < 0) { + printf("<"); + } else if (order > 0) { + printf(">"); + } else { + printf("="); + } + switch (namereln) { + case dns_namereln_contains: + printf(", contains"); + break; + case dns_namereln_subdomain: + printf(", subdomain"); + break; + case dns_namereln_commonancestor: + printf(", common ancestor"); + break; + default: + break; + } + if (namereln != dns_namereln_none && + namereln != dns_namereln_equal) + { + printf(", nlabels = %u", nlabels); + } + printf("\n"); + } + printf("dns_name_equal() returns %s\n", + dns_name_equal(name, comp) ? "TRUE" : "FALSE"); + } + + labels = dns_name_countlabels(name); + if (want_split && split_label < labels) { + prefix = dns_fixedname_initname(&fprefix); + suffix = dns_fixedname_initname(&fsuffix); + printf("splitting at label %u: ", split_label); + dns_name_split(name, split_label, prefix, suffix); + printf("\n prefix = "); + print_name(prefix); + printf(" suffix = "); + print_name(suffix); + } + + if (concatenate) { + if (got_name) { + name = dns_fixedname_name(&wname2); + } else { + name = dns_fixedname_name(&wname); + } + } + } + + return (0); +} diff --git a/bin/tests/optional/nsecify.c b/bin/tests/optional/nsecify.c new file mode 100644 index 0000000..357b47f --- /dev/null +++ b/bin/tests/optional/nsecify.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdbool.h> +#include <stdlib.h> + +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/string.h> + +#include <dns/db.h> +#include <dns/dbiterator.h> +#include <dns/fixedname.h> +#include <dns/nsec.h> +#include <dns/rdataset.h> +#include <dns/rdatasetiter.h> +#include <dns/result.h> + +static isc_mem_t *mctx = NULL; + +ISC_PLATFORM_NORETURN_PRE static void +fatal(const char *message) ISC_PLATFORM_NORETURN_POST; + +static void +fatal(const char *message) { + fprintf(stderr, "%s\n", message); + exit(1); +} + +static void +check_result(isc_result_t result, const char *message) { + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "%s: %s\n", message, isc_result_totext(result)); + exit(1); + } +} + +static bool +active_node(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) { + dns_rdatasetiter_t *rdsiter; + bool active = false; + isc_result_t result; + dns_rdataset_t rdataset; + + dns_rdataset_init(&rdataset); + rdsiter = NULL; + result = dns_db_allrdatasets(db, node, version, 0, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets()"); + result = dns_rdatasetiter_first(rdsiter); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &rdataset); + if (rdataset.type != dns_rdatatype_nsec) { + active = true; + } + dns_rdataset_disassociate(&rdataset); + if (!active) { + result = dns_rdatasetiter_next(rdsiter); + } else { + result = ISC_R_NOMORE; + } + } + if (result != ISC_R_NOMORE) { + fatal("rdataset iteration failed"); + } + dns_rdatasetiter_destroy(&rdsiter); + + if (!active) { + /* + * Make sure there is no NSEC record for this node. + */ + result = dns_db_deleterdataset(db, node, version, + dns_rdatatype_nsec, 0); + if (result == DNS_R_UNCHANGED) { + result = ISC_R_SUCCESS; + } + check_result(result, "dns_db_deleterdataset"); + } + + return (active); +} + +static isc_result_t +next_active(dns_db_t *db, dns_dbversion_t *version, dns_dbiterator_t *dbiter, + dns_name_t *name, dns_dbnode_t **nodep) { + isc_result_t result; + bool active; + + do { + active = false; + result = dns_dbiterator_current(dbiter, nodep, name); + if (result == ISC_R_SUCCESS) { + active = active_node(db, version, *nodep); + if (!active) { + dns_db_detachnode(db, nodep); + result = dns_dbiterator_next(dbiter); + } + } + } while (result == ISC_R_SUCCESS && !active); + + return (result); +} + +static void +nsecify(char *filename) { + isc_result_t result; + dns_db_t *db; + dns_dbversion_t *wversion; + dns_dbnode_t *node, *nextnode; + const char *origintext; + dns_fixedname_t fname, fnextname; + dns_name_t *name, *nextname, *target; + isc_buffer_t b; + size_t len; + dns_dbiterator_t *dbiter; + char newfilename[1024]; + + name = dns_fixedname_initname(&fname); + nextname = dns_fixedname_initname(&fnextname); + + origintext = strrchr(filename, '/'); + if (origintext == NULL) { + origintext = filename; + } else { + origintext++; /* Skip '/'. */ + } + len = strlen(origintext); + isc_buffer_constinit(&b, origintext, len); + isc_buffer_add(&b, len); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + check_result(result, "dns_name_fromtext()"); + + db = NULL; + result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, + dns_rdataclass_in, 0, NULL, &db); + check_result(result, "dns_db_create()"); + result = dns_db_load(db, filename, dns_masterformat_text, 0); + if (result == DNS_R_SEENINCLUDE) { + result = ISC_R_SUCCESS; + } + check_result(result, "dns_db_load()"); + wversion = NULL; + result = dns_db_newversion(db, &wversion); + check_result(result, "dns_db_newversion()"); + dbiter = NULL; + result = dns_db_createiterator(db, 0, &dbiter); + check_result(result, "dns_db_createiterator()"); + result = dns_dbiterator_first(dbiter); + check_result(result, "dns_dbiterator_first()"); + node = NULL; + result = next_active(db, wversion, dbiter, name, &node); + while (result == ISC_R_SUCCESS) { + nextnode = NULL; + result = dns_dbiterator_next(dbiter); + if (result == ISC_R_SUCCESS) { + result = next_active(db, wversion, dbiter, nextname, + &nextnode); + } + if (result == ISC_R_SUCCESS) { + target = nextname; + } else if (result == ISC_R_NOMORE) { + target = dns_db_origin(db); + } else { + target = NULL; /* Make compiler happy. */ + fatal("db iteration failed"); + } + dns_nsec_build(db, wversion, node, target, 3600); /* XXX BEW */ + dns_db_detachnode(db, &node); + node = nextnode; + } + if (result != ISC_R_NOMORE) { + fatal("db iteration failed"); + } + dns_dbiterator_destroy(&dbiter); + /* + * XXXRTH For now, we don't increment the SOA serial. + */ + dns_db_closeversion(db, &wversion, true); + len = strlen(filename); + if (len + 4 + 1 > sizeof(newfilename)) { + fatal("filename too long"); + } + snprintf(newfilename, sizeof(newfilename), "%s.new", filename); + result = dns_db_dump(db, NULL, newfilename); + check_result(result, "dns_db_dump"); + dns_db_detach(&db); +} + +int +main(int argc, char *argv[]) { + int i; + + dns_result_register(); + + isc_mem_create(&mctx); + + argc--; + argv++; + + for (i = 0; i < argc; i++) { + nsecify(argv[i]); + } + + /* isc_mem_stats(mctx, stdout); */ + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/ratelimiter_test.c b/bin/tests/optional/ratelimiter_test.c new file mode 100644 index 0000000..c8972f8 --- /dev/null +++ b/bin/tests/optional/ratelimiter_test.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <isc/app.h> +#include <isc/managers.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/ratelimiter.h> +#include <isc/task.h> +#include <isc/time.h> +#include <isc/timer.h> +#include <isc/util.h> + +isc_ratelimiter_t *rlim = NULL; +isc_nm_t *netmgr = NULL; +isc_taskmgr_t *taskmgr = NULL; +isc_timermgr_t *timermgr = NULL; +isc_task_t *g_task = NULL; +isc_mem_t *mctx = NULL; + +static void +utick(isc_task_t *task, isc_event_t *event); +static void +shutdown_rl(isc_task_t *task, isc_event_t *event); +static void +shutdown_all(isc_task_t *task, isc_event_t *event); + +typedef struct { + int milliseconds; + void (*fun)(isc_task_t *, isc_event_t *); +} schedule_t; + +schedule_t schedule[] = { { 100, utick }, { 200, utick }, + { 300, utick }, { 3000, utick }, + { 3100, utick }, { 3200, utick }, + { 3300, shutdown_rl }, { 5000, utick }, + { 6000, shutdown_all } }; + +#define NEVENTS (int)(sizeof(schedule) / sizeof(schedule[0])) + +isc_timer_t *timers[NEVENTS]; + +static void +ltick(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + printf("** ltick%s **\n", + (event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 ? " (" + "canceled" + ")" + : ""); + isc_event_free(&event); +} + +static void +utick(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + UNUSED(task); + event->ev_action = ltick; + event->ev_sender = NULL; + result = isc_ratelimiter_enqueue(rlim, g_task, &event); + printf("enqueue: %s\n", result == ISC_R_SUCCESS ? "ok" : "failed"); +} + +static void +shutdown_rl(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + UNUSED(event); + printf("shutdown ratelimiter\n"); + isc_ratelimiter_shutdown(rlim); +} + +static void +shutdown_all(isc_task_t *task, isc_event_t *event) { + int i; + UNUSED(task); + UNUSED(event); + printf("shutdown all\n"); + for (i = 0; i < NEVENTS; i++) { + isc_timer_destroy(&timers[i]); + } + + isc_app_shutdown(); +} + +int +main(int argc, char *argv[]) { + isc_interval_t linterval; + int i; + + UNUSED(argc); + UNUSED(argv); + + isc_app_start(); + isc_interval_set(&linterval, 1, 0); + + isc_mem_create(&mctx); + RUNTIME_CHECK(isc_managers_create(mctx, 3, 0, &netmgr, &taskmgr) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &g_task) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_ratelimiter_create(mctx, timermgr, g_task, &rlim) == + ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_ratelimiter_setinterval(rlim, &linterval) == + ISC_R_SUCCESS); + + for (i = 0; i < NEVENTS; i++) { + isc_interval_t uinterval; + int ms = schedule[i].milliseconds; + isc_interval_set(&uinterval, ms / 1000, (ms % 1000) * 1000000); + timers[i] = NULL; + RUNTIME_CHECK(isc_timer_create(timermgr, isc_timertype_once, + NULL, &uinterval, g_task, + schedule[i].fun, NULL, + &timers[i]) == ISC_R_SUCCESS); + } + + isc_app_run(); + + isc_task_destroy(&g_task); + + isc_ratelimiter_detach(&rlim); + + isc_timermgr_destroy(&timermgr); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_mem_stats(mctx, stdout); + + isc_app_finish(); + return (0); +} diff --git a/bin/tests/optional/rbt_test.c b/bin/tests/optional/rbt_test.c new file mode 100644 index 0000000..735c229 --- /dev/null +++ b/bin/tests/optional/rbt_test.c @@ -0,0 +1,432 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdbool.h> +#include <stdlib.h> + +#include <isc/commandline.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dns/fixedname.h> +#include <dns/rbt.h> +#include <dns/result.h> + +const char *progname; +isc_mem_t *mctx; + +#define DNSNAMELEN 255 + +static dns_name_t * +create_name(char *s) { + int length; + isc_result_t result; + isc_buffer_t source, target; + static dns_name_t *name; + + if (s == NULL || *s == '\0') { + printf("missing name argument\n"); + return (NULL); + } + + length = strlen(s); + + isc_buffer_init(&source, s, length); + isc_buffer_add(&source, length); + + /* + * It isn't really necessary in this program to create individual + * memory spaces for each name structure and its associated character + * string. It is done here to provide a relatively easy way to test + * the callback from dns_rbt_deletename that is supposed to free the + * data associated with a node. + * + * The buffer for the actual name will immediately follow the + * name structure. + */ + name = isc_mem_get(mctx, sizeof(*name) + DNSNAMELEN); + + dns_name_init(name, NULL); + isc_buffer_init(&target, name + 1, DNSNAMELEN); + + result = dns_name_fromtext(name, &source, dns_rootname, 0, &target); + + if (result != ISC_R_SUCCESS) { + printf("dns_name_fromtext(%s) failed: %s\n", s, + dns_result_totext(result)); + return (NULL); + } + + return (name); +} + +static void +delete_name(void *data, void *arg) { + dns_name_t *name; + + UNUSED(arg); + name = data; + isc_mem_put(mctx, name, sizeof(*name) + DNSNAMELEN); +} + +static void +print_name(dns_name_t *name) { + isc_buffer_t target; + char buffer[1024]; + + isc_buffer_init(&target, buffer, sizeof(buffer)); + + /* + * false means absolute names have the final dot added. + */ + dns_name_totext(name, false, &target); + + printf("%.*s", (int)target.used, (char *)target.base); +} + +static void +detail(dns_rbt_t *rbt, dns_name_t *name) { + dns_name_t *foundname, *origin, *fullname; + dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname; + dns_rbtnode_t *node1, *node2; + dns_rbtnodechain_t chain; + isc_result_t result; + bool nodes_should_match = false; + + dns_rbtnodechain_init(&chain); + + origin = dns_fixedname_initname(&fixedorigin); + fullname = dns_fixedname_initname(&fixedfullname); + foundname = dns_fixedname_initname(&fixedfoundname); + + node1 = node2 = NULL; + + printf("checking chain information for "); + print_name(name); + printf("\n"); + + result = dns_rbt_findnode(rbt, name, foundname, &node1, &chain, + DNS_RBTFIND_EMPTYDATA, NULL, NULL); + + switch (result) { + case ISC_R_SUCCESS: + printf(" found exact."); + nodes_should_match = true; + break; + case DNS_R_PARTIALMATCH: + printf(" found parent."); + break; + case ISC_R_NOTFOUND: + printf(" name not found."); + break; + default: + printf(" unexpected result: %s\n", dns_result_totext(result)); + return; + } + + if (node1 != NULL && node1->data != NULL) { + printf(" data at node: "); + print_name(node1->data); + } else { + printf(" no data at node."); + } + + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { + printf("\n name from dns_rbt_findnode: "); + print_name(foundname); + } + + result = dns_rbtnodechain_current(&chain, foundname, origin, &node2); + + if (result == ISC_R_SUCCESS) { + printf("\n name from dns_rbtnodechain_current: "); + + result = dns_name_concatenate(foundname, origin, fullname, + NULL); + if (result == ISC_R_SUCCESS) { + print_name(fullname); + } else { + printf("%s\n", dns_result_totext(result)); + } + printf("\n (foundname = "); + print_name(foundname); + printf(", origin = "); + print_name(origin); + printf(")\n"); + if (nodes_should_match && node1 != node2) { + printf(" nodes returned from each function " + "DO NOT match!\n"); + } + } else { + printf("\n result from dns_rbtnodechain_current: %s\n", + dns_result_totext(result)); + } + + printf(" level_matches = %u, level_count = %u\n", chain.level_matches, + chain.level_count); +} + +static void +iterate(dns_rbt_t *rbt, bool forward) { + dns_name_t foundname, *origin; + dns_rbtnodechain_t chain; + dns_fixedname_t fixedorigin; + isc_result_t result; + isc_result_t (*move)(dns_rbtnodechain_t *chain, dns_name_t *name, + dns_name_t *origin); + + dns_rbtnodechain_init(&chain); + + dns_name_init(&foundname, NULL); + origin = dns_fixedname_initname(&fixedorigin); + + if (forward) { + printf("iterating forward\n"); + move = dns_rbtnodechain_next; + + result = dns_rbtnodechain_first(&chain, rbt, &foundname, + origin); + } else { + printf("iterating backward\n"); + move = dns_rbtnodechain_prev; + + result = dns_rbtnodechain_last(&chain, rbt, &foundname, origin); + } + + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + printf("start not found!\n"); + } else { + for (;;) { + if (result == DNS_R_NEWORIGIN) { + printf(" new origin: "); + print_name(origin); + printf("\n"); + } + + if (result == ISC_R_SUCCESS || + result == DNS_R_NEWORIGIN) + { + print_name(&foundname); + printf("\n"); + } else { + if (result != ISC_R_NOMORE) { + printf("UNEXPECTED ITERATION ERROR: %s", + dns_result_totext(result)); + } + break; + } + + result = move(&chain, &foundname, origin); + } + } +} + +#define CMDCHECK(s) (strncasecmp(command, (s), length) == 0) +#define PRINTERR(r) \ + if (r != ISC_R_SUCCESS) \ + printf("... %s\n", dns_result_totext(r)); + +int +main(int argc, char **argv) { + char *command, *arg, buffer[1024]; + const char *whitespace; + dns_name_t *name, *foundname; + dns_fixedname_t fixedname; + dns_rbt_t *rbt = NULL; + int length, ch; + bool show_final_mem = false; + isc_result_t result; + void *data; + + progname = strrchr(*argv, '/'); + if (progname != NULL) { + progname++; + } else { + progname = *argv; + } + + while ((ch = isc_commandline_parse(argc, argv, "m")) != -1) { + switch (ch) { + case 'm': + show_final_mem = true; + break; + } + } + + argc -= isc_commandline_index; + argv += isc_commandline_index; + POST(argv); + + if (argc > 1) { + printf("Usage: %s [-m]\n", progname); + exit(1); + } + + setbuf(stdout, NULL); + + /* + * So isc_mem_stats() can report any allocation leaks. + */ + isc_mem_debugging = ISC_MEM_DEBUGRECORD; + + isc_mem_create(&mctx); + + result = dns_rbt_create(mctx, delete_name, NULL, &rbt); + if (result != ISC_R_SUCCESS) { + printf("dns_rbt_create: %s: exiting\n", + dns_result_totext(result)); + exit(1); + } + + whitespace = " \t"; + + while (fgets(buffer, sizeof(buffer), stdin) != NULL) { + length = strlen(buffer); + + if (buffer[length - 1] != '\n') { + printf("line to long (%lu max), ignored\n", + (unsigned long)sizeof(buffer) - 2); + continue; + } + + buffer[length - 1] = '\0'; + + command = buffer + strspn(buffer, whitespace); + + if (*command == '#') { + continue; + } + + arg = strpbrk(command, whitespace); + if (arg != NULL) { + *arg++ = '\0'; + arg += strspn(arg, whitespace); + } + + length = strlen(command); + if (*command != '\0') { + if (CMDCHECK("add")) { + name = create_name(arg); + if (name != NULL) { + printf("adding name %s\n", arg); + result = dns_rbt_addname(rbt, name, + name); + PRINTERR(result); + } + } else if (CMDCHECK("delete")) { + name = create_name(arg); + if (name != NULL) { + printf("deleting name %s\n", arg); + result = dns_rbt_deletename(rbt, name, + false); + PRINTERR(result); + delete_name(name, NULL); + } + } else if (CMDCHECK("nuke")) { + name = create_name(arg); + if (name != NULL) { + printf("nuking name %s " + "and its descendants\n", + arg); + result = dns_rbt_deletename(rbt, name, + true); + PRINTERR(result); + delete_name(name, NULL); + } + } else if (CMDCHECK("search")) { + name = create_name(arg); + if (name != NULL) { + printf("searching for name %s ... ", + arg); + + foundname = dns_fixedname_initname( + &fixedname); + data = NULL; + + result = dns_rbt_findname( + rbt, name, 0, foundname, &data); + switch (result) { + case ISC_R_SUCCESS: + printf("found exact: "); + print_name(data); + putchar('\n'); + break; + case DNS_R_PARTIALMATCH: + printf("found parent: "); + print_name(data); + printf("\n\t(foundname: "); + print_name(foundname); + printf(")\n"); + break; + case ISC_R_NOTFOUND: + printf("NOT FOUND!\n"); + break; + case ISC_R_NOMEMORY: + printf("OUT OF MEMORY!\n"); + break; + default: + printf("UNEXPECTED RESULT\n"); + } + + delete_name(name, NULL); + } + } else if (CMDCHECK("check")) { + /* + * Or "chain". I know, I know. Lame name. + * I was having a hard time thinking of a + * name (especially one that did not have + * a conflicting first letter with another + * command) that would differentiate this + * from the search command. + * + * But it is just a test program, eh? + */ + name = create_name(arg); + if (name != NULL) { + detail(rbt, name); + + delete_name(name, NULL); + } + } else if (CMDCHECK("forward")) { + iterate(rbt, true); + } else if (CMDCHECK("backward")) { + iterate(rbt, false); + } else if (CMDCHECK("print")) { + if (arg == NULL || *arg == '\0') { + dns_rbt_printtext(rbt, NULL, stdout); + } else { + printf("usage: print\n"); + } + } else if (CMDCHECK("quit")) { + if (arg == NULL || *arg == '\0') { + break; + } else { + printf("usage: quit\n"); + } + } else { + printf("a(dd) NAME, d(elete) NAME, " + "s(earch) NAME, p(rint), or q(uit)\n"); + } + } + } + + dns_rbt_destroy(&rbt); + + if (show_final_mem) { + isc_mem_stats(mctx, stderr); + } + + return (0); +} diff --git a/bin/tests/optional/rbt_test.out b/bin/tests/optional/rbt_test.out new file mode 100644 index 0000000..95bf4f9 --- /dev/null +++ b/bin/tests/optional/rbt_test.out @@ -0,0 +1,395 @@ +adding name a.vix.com +adding name b.vix.com +adding name c.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (RED from b) + NULL + NULL + c (RED from b) + NULL + NULL + -- END down from vix.com. + NULL + NULL +adding name a.b.c.d.e.f.vix.com +adding name b.b.c.d.e.f.vix.com +adding name c.b.c.d.e.f.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + NULL + NULL + c (black from b) + NULL + b.c.d.e.f (RED from c) + ++ BEG down from b.c.d.e.f + b (black) + a (RED from b) + NULL + NULL + c (RED from b) + NULL + NULL + -- END down from b.c.d.e.f + NULL + NULL + -- END down from vix.com. + NULL + NULL +adding name a.d.e.f.vix.com +adding name q.d.e.f.vix.com +adding name d.e.f.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + NULL + NULL + c (black from b) + NULL + d.e.f (RED from c) + ++ BEG down from d.e.f + b.c (black) + ++ BEG down from b.c + b (black) + a (RED from b) + NULL + NULL + c (RED from b) + NULL + NULL + -- END down from b.c + a (RED from b.c) + NULL + NULL + q (RED from b.c) + NULL + NULL + -- END down from d.e.f + NULL + NULL + -- END down from vix.com. + NULL + NULL +adding name g.h.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + NULL + NULL + d.e.f (black from b) + ++ BEG down from d.e.f + b.c (black) + ++ BEG down from b.c + b (black) + a (RED from b) + NULL + NULL + c (RED from b) + NULL + NULL + -- END down from b.c + a (RED from b.c) + NULL + NULL + q (RED from b.c) + NULL + NULL + -- END down from d.e.f + c (RED from d.e.f) + NULL + NULL + g.h (RED from d.e.f) + NULL + NULL + -- END down from vix.com. + NULL + NULL +searching for name q.d.e.f.vix.com ... found exact: q.d.e.f.vix.com. +searching for name just-parent.a.vix.com ... found parent: a.vix.com. + (foundname: a.vix.com.) +searching for name no-real-parent.vix.com ... NOT FOUND! +searching for name does.not.exist.at.all ... NOT FOUND! +iterating forward + new origin: . +vix.com + new origin: vix.com. +a +b +c +d.e.f + new origin: d.e.f.vix.com. +a +b.c + new origin: b.c.d.e.f.vix.com. +a +b +c + new origin: d.e.f.vix.com. +q + new origin: vix.com. +g.h +iterating backward + new origin: vix.com. +g.h + new origin: d.e.f.vix.com. +q + new origin: b.c.d.e.f.vix.com. +c +b +a + new origin: d.e.f.vix.com. +b.c +a + new origin: vix.com. +d.e.f +c +b +a + new origin: . +vix.com +checking chain information for vix.com. + found exact. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: vix.com. + (foundname = vix.com, origin = .) + level_matches = 0, level_count = 0 +checking chain information for zzz.com. + name not found. no data at node. + name from dns_rbtnodechain_current: g.h.vix.com. + (foundname = g.h, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for 0.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: vix.com. + (foundname = vix.com, origin = .) + level_matches = 0, level_count = 0 +checking chain information for d.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: c.vix.com. + (foundname = c, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for f.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: c.vix.com. + (foundname = c, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for a.e.f.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: c.vix.com. + (foundname = c, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for z.e.f.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: q.d.e.f.vix.com. + (foundname = q, origin = d.e.f.vix.com.) + level_matches = 0, level_count = 2 +checking chain information for g.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: q.d.e.f.vix.com. + (foundname = q, origin = d.e.f.vix.com.) + level_matches = 0, level_count = 2 +checking chain information for i.vix.com. + found parent. no data at node. + name from dns_rbt_findnode: vix.com. + name from dns_rbtnodechain_current: g.h.vix.com. + (foundname = g.h, origin = vix.com.) + level_matches = 0, level_count = 1 +checking chain information for b.c.vix.com. + found parent. data at node: c.vix.com. + name from dns_rbt_findnode: c.vix.com. + name from dns_rbtnodechain_current: c.vix.com. + (foundname = c, origin = vix.com.) + level_matches = 1, level_count = 1 +nuking name d.e.f.vix.com and its descendants +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + NULL + NULL + g.h (black from b) + c (RED from g.h) + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +adding name x.a.vix.com +adding name y.x.a.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + ++ BEG down from a + x (black) + ++ BEG down from x + y (black) + NULL + NULL + -- END down from x + NULL + NULL + -- END down from a + NULL + NULL + g.h (black from b) + c (RED from g.h) + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +deleting name a.vix.com +deleting name x.a.vix.com +vix.com. (black) + ++ BEG down from vix.com. + b (black) + a (black from b) + ++ BEG down from a + x (black) + ++ BEG down from x + y (black) + NULL + NULL + -- END down from x + NULL + NULL + -- END down from a + NULL + NULL + g.h (black from b) + c (RED from g.h) + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +deleting name b.vix.com +deleting name c.vix.com +vix.com. (black) + ++ BEG down from vix.com. + g.h (black) + a (RED from g.h) + ++ BEG down from a + x (black) + ++ BEG down from x + y (black) + NULL + NULL + -- END down from x + NULL + NULL + -- END down from a + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +deleting name y.x.a.vix.com +vix.com. (black) + ++ BEG down from vix.com. + g.h (black) + a (RED from g.h) + ++ BEG down from a + x (black) + NULL + NULL + -- END down from a + NULL + NULL + NULL + -- END down from vix.com. + NULL + NULL +deleting name g.h.vix.com. +adding name \[b100000].vix.com. +adding name \[b010000].vix.com. +adding name \[b001000].vix.com. +adding name \[b000100].vix.com. +adding name \[b000010].vix.com. +adding name \[b000001].vix.com. +vix.com. (black) + ++ BEG down from vix.com. + \[x80/6] (black) + \[x0/1] (RED from \[x80/6]) + ++ BEG down from \[x0/1] + \[x80/5] (black) + \[x0/1] (RED from \[x80/5]) + ++ BEG down from \[x0/1] + \[x8/4] (black) + \[x0/1] (RED from \[x8/4]) + ++ BEG down from \[x0/1] + \[x8/3] (black) + \[x0/1] (RED from \[x8/3]) + ++ BEG down from \[x0/1] + \[x8/2] (black) + \[x4/2] (RED from \[x8/2]) + NULL + NULL + NULL + -- END down from \[x0/1] + NULL + NULL + NULL + -- END down from \[x0/1] + NULL + NULL + NULL + -- END down from \[x0/1] + NULL + NULL + NULL + -- END down from \[x0/1] + NULL + NULL + a (RED from \[x80/6]) + ++ BEG down from a + x (black) + NULL + NULL + -- END down from a + NULL + NULL + -- END down from vix.com. + NULL + NULL +searching for name \[b000100].vix.com. ... found exact: \[x10/6].vix.com. +adding name vix.com. +nuking name vix.com. and its descendants +adding name a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. +adding name b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. +b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. (black) + ++ BEG down from b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. + a (black) + NULL + NULL + -- END down from b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. + NULL + NULL +adding name . +nuking name . and its descendants +adding name \[xFFFF/16].\[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/256].com +adding name \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com +\[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com. (black) + ++ BEG down from \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com. + \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/144] (black) + NULL + NULL + -- END down from \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com. + NULL + NULL diff --git a/bin/tests/optional/rbt_test.txt b/bin/tests/optional/rbt_test.txt new file mode 100644 index 0000000..e44d72e --- /dev/null +++ b/bin/tests/optional/rbt_test.txt @@ -0,0 +1,87 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +add a.vix.com +add b.vix.com +add c.vix.com +print +add a.b.c.d.e.f.vix.com +add b.b.c.d.e.f.vix.com +add c.b.c.d.e.f.vix.com +print +add a.d.e.f.vix.com +add q.d.e.f.vix.com +add d.e.f.vix.com +print +add g.h.vix.com +print +search q.d.e.f.vix.com +search just-parent.a.vix.com +search no-real-parent.vix.com +search does.not.exist.at.all +forward +backward +# existing name +check vix.com. +# greater than stop node, which has down pointer +check zzz.com. +# less than lowest in level (would be left link from stop node) +check 0.vix.com +# greater than stop node, no down pointer +check d.vix.com +# superdomain stored in existing node +check f.vix.com +# common ancestor stored in existing node; existing is successor +check a.e.f.vix.com +# common ancestor stored in existing node; existing is less but not predecessor +check z.e.f.vix.com +# +check g.vix.com +# +check i.vix.com +# +check b.c.vix.com +nuke d.e.f.vix.com +print +add x.a.vix.com +add y.x.a.vix.com +print +delete a.vix.com +delete x.a.vix.com +print +delete b.vix.com +delete c.vix.com +print +delete y.x.a.vix.com +print +delete g.h.vix.com. +add \[b100000].vix.com. +add \[b010000].vix.com. +add \[b001000].vix.com. +add \[b000100].vix.com. +add \[b000010].vix.com. +add \[b000001].vix.com. +p +search \[b000100].vix.com. +# zap the entire tree +add vix.com. +nuke vix.com. +add a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. +add b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. +print +add . +# zap it again +nuke . +# test splitting of maximal bitstring +add \[xFFFF/16].\[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/256].com +add \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com +print +quit diff --git a/bin/tests/optional/rwlock_test.c b/bin/tests/optional/rwlock_test.c new file mode 100644 index 0000000..fc94eaf --- /dev/null +++ b/bin/tests/optional/rwlock_test.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <isc/print.h> +#include <isc/rwlock.h> +#include <isc/string.h> +#include <isc/thread.h> +#include <isc/util.h> + +#ifdef WIN32 +#define sleep(x) Sleep(1000 * x) +#endif /* ifdef WIN32 */ + +isc_rwlock_t lock; + +static isc_threadresult_t +#ifdef WIN32 + WINAPI +#endif /* ifdef WIN32 */ + run1(void *arg) { + char *message = arg; + + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + printf("%s got READ lock\n", message); + sleep(1); + printf("%s giving up READ lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + printf("%s got READ lock\n", message); + sleep(1); + printf("%s giving up READ lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + printf("%s got WRITE lock\n", message); + sleep(1); + printf("%s giving up WRITE lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + return ((isc_threadresult_t)0); +} + +static isc_threadresult_t +#ifdef WIN32 + WINAPI +#endif /* ifdef WIN32 */ + run2(void *arg) { + char *message = arg; + + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + printf("%s got WRITE lock\n", message); + sleep(1); + printf("%s giving up WRITE lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + printf("%s got WRITE lock\n", message); + sleep(1); + printf("%s giving up WRITE lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + printf("%s got READ lock\n", message); + sleep(1); + printf("%s giving up READ lock\n", message); + RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) == + ISC_R_SUCCESS); + return ((isc_threadresult_t)0); +} + +int +main(int argc, char *argv[]) { + unsigned int nworkers; + unsigned int i; + isc_thread_t workers[100]; + char name[100]; + void *dupname; + + if (argc > 1) { + nworkers = atoi(argv[1]); + } else { + nworkers = 2; + } + if (nworkers > 100) { + nworkers = 100; + } + printf("%u workers\n", nworkers); + + isc_rwlock_init(&lock, 5, 10); + + for (i = 0; i < nworkers; i++) { + snprintf(name, sizeof(name), "%02u", i); + dupname = strdup(name); + RUNTIME_CHECK(dupname != NULL); + if (i != 0 && i % 3 == 0) { + isc_thread_create(run1, dupname, &workers[i]); + } else { + isc_thread_create(run2, dupname, &workers[i]); + } + } + + for (i = 0; i < nworkers; i++) { + isc_thread_join(workers[i], NULL); + } + + isc_rwlock_destroy(&lock); + + return (0); +} diff --git a/bin/tests/optional/serial_test.c b/bin/tests/optional/serial_test.c new file mode 100644 index 0000000..c16acc0 --- /dev/null +++ b/bin/tests/optional/serial_test.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> + +#include <isc/print.h> +#include <isc/serial.h> + +int +main() { + uint32_t a, b; + char buf[1024]; + char *s, *e; + + while (fgets(buf, sizeof(buf), stdin) != NULL) { + buf[sizeof(buf) - 1] = '\0'; + s = buf; + a = strtoul(s, &e, 0); + if (s == e) { + continue; + } + s = e; + b = strtoul(s, &e, 0); + if (s == e) { + continue; + } + fprintf(stdout, "%u %u gt:%d lt:%d ge:%d le:%d eq:%d ne:%d\n", + a, b, isc_serial_gt(a, b), isc_serial_lt(a, b), + isc_serial_ge(a, b), isc_serial_le(a, b), + isc_serial_eq(a, b), isc_serial_ne(a, b)); + } + return (0); +} diff --git a/bin/tests/optional/shutdown_test.c b/bin/tests/optional/shutdown_test.c new file mode 100644 index 0000000..c8cf03c --- /dev/null +++ b/bin/tests/optional/shutdown_test.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include <isc/app.h> +#include <isc/managers.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/time.h> +#include <isc/timer.h> +#include <isc/util.h> + +typedef struct { + isc_mem_t *mctx; + isc_task_t *task; + isc_timer_t *timer; + unsigned int ticks; + char name[16]; + bool exiting; + isc_task_t *peer; +} t_info; + +#define MAX_TASKS 3 +#define T2_SHUTDOWNOK (ISC_EVENTCLASS(1024) + 0) +#define T2_SHUTDOWNDONE (ISC_EVENTCLASS(1024) + 1) +#define FOO_EVENT (ISC_EVENTCLASS(1024) + 2) + +static t_info tasks[MAX_TASKS]; +static unsigned int task_count; +static isc_nm_t *netmgr = NULL; +static isc_taskmgr_t *taskmgr = NULL; +static isc_timermgr_t *timer_manager; + +static void +t1_shutdown(isc_task_t *task, isc_event_t *event) { + t_info *info = event->ev_arg; + + printf("task %s (%p) t1_shutdown\n", info->name, task); + isc_task_detach(&info->task); + isc_event_free(&event); +} + +static void +t2_shutdown(isc_task_t *task, isc_event_t *event) { + t_info *info = event->ev_arg; + + printf("task %s (%p) t2_shutdown\n", info->name, task); + info->exiting = true; + isc_event_free(&event); +} + +static void +shutdown_action(isc_task_t *task, isc_event_t *event) { + t_info *info = event->ev_arg; + isc_event_t *nevent; + + INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN); + + printf("task %s (%p) shutdown\n", info->name, task); + if (strcmp(info->name, "0") == 0) { + isc_timer_destroy(&info->timer); + nevent = isc_event_allocate(info->mctx, info, T2_SHUTDOWNOK, + t2_shutdown, &tasks[1], + sizeof(*event)); + RUNTIME_CHECK(nevent != NULL); + info->exiting = true; + isc_task_sendanddetach(&info->peer, &nevent); + } + isc_event_free(&event); +} + +static void +foo_event(isc_task_t *task, isc_event_t *event) { + printf("task(%p) foo\n", task); + isc_event_free(&event); +} + +static void +tick(isc_task_t *task, isc_event_t *event) { + t_info *info = event->ev_arg; + isc_event_t *nevent; + + INSIST(event->ev_type == ISC_TIMEREVENT_TICK); + + printf("task %s (%p) tick\n", info->name, task); + + info->ticks++; + if (strcmp(info->name, "1") == 0) { + if (info->ticks == 10) { + isc_app_shutdown(); + } else if (info->ticks >= 15 && info->exiting) { + isc_timer_destroy(&info->timer); + isc_task_detach(&info->task); + nevent = isc_event_allocate( + info->mctx, info, T2_SHUTDOWNDONE, t1_shutdown, + &tasks[0], sizeof(*event)); + RUNTIME_CHECK(nevent != NULL); + isc_task_send(info->peer, &nevent); + isc_task_detach(&info->peer); + } + } else if (strcmp(info->name, "foo") == 0) { + isc_timer_destroy(&info->timer); + nevent = isc_event_allocate(info->mctx, info, FOO_EVENT, + foo_event, task, sizeof(*event)); + RUNTIME_CHECK(nevent != NULL); + isc_task_sendanddetach(&task, &nevent); + } + + isc_event_free(&event); +} + +static t_info * +new_task(isc_mem_t *mctx, const char *name) { + t_info *ti; + isc_time_t expires; + isc_interval_t interval; + + RUNTIME_CHECK(task_count < MAX_TASKS); + ti = &tasks[task_count]; + ti->mctx = mctx; + ti->task = NULL; + ti->timer = NULL; + ti->ticks = 0; + if (name != NULL) { + INSIST(strlen(name) < sizeof(ti->name)); + strlcpy(ti->name, name, sizeof(ti->name)); + } else { + snprintf(ti->name, sizeof(ti->name), "%u", task_count); + } + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &ti->task) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(ti->task, shutdown_action, ti) == + ISC_R_SUCCESS); + + isc_time_settoepoch(&expires); + isc_interval_set(&interval, 1, 0); + RUNTIME_CHECK(isc_timer_create(timer_manager, isc_timertype_ticker, + &expires, &interval, ti->task, tick, ti, + &ti->timer) == ISC_R_SUCCESS); + + task_count++; + + return (ti); +} + +int +main(int argc, char *argv[]) { + unsigned int workers; + t_info *t1, *t2 = NULL; + isc_task_t *task = NULL; + isc_mem_t *mctx = NULL, *mctx2 = NULL; + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + + if (argc > 1) { + workers = atoi(argv[1]); + if (workers < 1) { + workers = 1; + } + if (workers > 8192) { + workers = 8192; + } + } else { + workers = 2; + } + printf("%u workers\n", workers); + + isc_mem_create(&mctx); + isc_mem_create(&mctx2); + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_timermgr_create(mctx, &timer_manager) == + ISC_R_SUCCESS); + + t1 = new_task(mctx, NULL); + t2 = new_task(mctx2, NULL); + isc_task_attach(t2->task, &t1->peer); + isc_task_attach(t1->task, &t2->peer); + + /* + * Test run-triggered shutdown. + */ + (void)new_task(mctx2, "foo"); + + /* + * Test implicit shutdown. + */ + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS); + isc_task_detach(&task); + + /* + * Test anti-zombie code. + */ + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS); + isc_task_detach(&task); + + RUNTIME_CHECK(isc_app_run() == ISC_R_SUCCESS); + + isc_managers_destroy(&netmgr, &taskmgr); + isc_timermgr_destroy(&timer_manager); + + printf("Statistics for mctx:\n"); + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + printf("Statistics for mctx2:\n"); + isc_mem_stats(mctx2, stdout); + isc_mem_destroy(&mctx2); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/sig0_test.c b/bin/tests/optional/sig0_test.c new file mode 100644 index 0000000..e419700 --- /dev/null +++ b/bin/tests/optional/sig0_test.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include <isc/app.h> +#include <isc/assertions.h> +#include <isc/commandline.h> +#include <isc/error.h> +#include <isc/log.h> +#include <isc/managers.h> +#include <isc/mem.h> +#include <isc/mutex.h> +#include <isc/net.h> +#include <isc/print.h> +#include <isc/socket.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +#include <dns/dnssec.h> +#include <dns/events.h> +#include <dns/fixedname.h> +#include <dns/keyvalues.h> +#include <dns/masterdump.h> +#include <dns/message.h> +#include <dns/name.h> +#include <dns/rdataset.h> +#include <dns/resolver.h> +#include <dns/result.h> +#include <dns/types.h> + +#include <dst/dst.h> +#include <dst/result.h> + +#define CHECK(str, x) \ + { \ + if ((x) != ISC_R_SUCCESS) { \ + printf("%s: %s\n", (str), isc_result_totext(x)); \ + exit(-1); \ + } \ + } + +isc_mutex_t lock; +dst_key_t *key = NULL; +isc_mem_t *mctx = NULL; +unsigned char qdata[1024], rdata[1024]; +isc_buffer_t qbuffer, rbuffer; +isc_nm_t *netmgr = NULL; +isc_taskmgr_t *taskmgr = NULL; +isc_task_t *task1 = NULL; +isc_log_t *lctx = NULL; +isc_logconfig_t *logconfig = NULL; +isc_socket_t *s = NULL; +isc_sockaddr_t address; +char output[10 * 1024]; +isc_buffer_t outbuf; +static const dns_master_style_t *style = &dns_master_style_debug; + +static void +senddone(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + + REQUIRE(sevent != NULL); + REQUIRE(sevent->ev_type == ISC_SOCKEVENT_SENDDONE); + REQUIRE(task == task1); + + printf("senddone\n"); + + isc_event_free(&event); +} + +static void +recvdone(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *sevent = (isc_socketevent_t *)event; + isc_buffer_t source; + isc_result_t result; + dns_message_t *response = NULL; + + REQUIRE(sevent != NULL); + REQUIRE(sevent->ev_type == ISC_SOCKEVENT_RECVDONE); + REQUIRE(task == task1); + + printf("recvdone\n"); + if (sevent->result != ISC_R_SUCCESS) { + printf("failed\n"); + exit(-1); + } + + isc_buffer_init(&source, sevent->region.base, sevent->region.length); + isc_buffer_add(&source, sevent->n); + + dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); + result = dns_message_parse(response, &source, 0); + CHECK("dns_message_parse", result); + + isc_buffer_init(&outbuf, output, sizeof(output)); + result = dns_message_totext(response, style, 0, &outbuf); + CHECK("dns_message_totext", result); + printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf), + (char *)isc_buffer_base(&outbuf)); + + dns_message_detach(&response); + isc_event_free(&event); + + isc_app_shutdown(); +} + +static void +buildquery(void) { + isc_result_t result; + dns_rdataset_t *question = NULL; + dns_name_t *qname = NULL; + isc_region_t r, inr; + dns_message_t *query = NULL; + char nametext[] = "host.example"; + isc_buffer_t namesrc, namedst; + unsigned char namedata[256]; + isc_sockaddr_t sa; + dns_compress_t cctx; + + dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query); + result = dns_message_setsig0key(query, key); + CHECK("dns_message_setsig0key", result); + + result = dns_message_gettemprdataset(query, &question); + CHECK("dns_message_gettemprdataset", result); + dns_rdataset_makequestion(question, dns_rdataclass_in, dns_rdatatype_a); + result = dns_message_gettempname(query, &qname); + CHECK("dns_message_gettempname", result); + isc_buffer_init(&namesrc, nametext, strlen(nametext)); + isc_buffer_add(&namesrc, strlen(nametext)); + isc_buffer_init(&namedst, namedata, sizeof(namedata)); + dns_name_init(qname, NULL); + result = dns_name_fromtext(qname, &namesrc, dns_rootname, 0, &namedst); + CHECK("dns_name_fromtext", result); + ISC_LIST_APPEND(qname->list, question, link); + dns_message_addname(query, qname, DNS_SECTION_QUESTION); + + isc_buffer_init(&qbuffer, qdata, sizeof(qdata)); + + result = dns_compress_init(&cctx, -1, mctx); + CHECK("dns_compress_init", result); + result = dns_message_renderbegin(query, &cctx, &qbuffer); + CHECK("dns_message_renderbegin", result); + result = dns_message_rendersection(query, DNS_SECTION_QUESTION, 0); + CHECK("dns_message_rendersection(question)", result); + result = dns_message_rendersection(query, DNS_SECTION_ANSWER, 0); + CHECK("dns_message_rendersection(answer)", result); + result = dns_message_rendersection(query, DNS_SECTION_AUTHORITY, 0); + CHECK("dns_message_rendersection(auth)", result); + result = dns_message_rendersection(query, DNS_SECTION_ADDITIONAL, 0); + CHECK("dns_message_rendersection(add)", result); + result = dns_message_renderend(query); + CHECK("dns_message_renderend", result); + dns_compress_invalidate(&cctx); + + isc_buffer_init(&outbuf, output, sizeof(output)); + result = dns_message_totext(query, style, 0, &outbuf); + CHECK("dns_message_totext", result); + printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf), + (char *)isc_buffer_base(&outbuf)); + + isc_buffer_usedregion(&qbuffer, &r); + isc_sockaddr_any(&sa); + result = isc_socket_bind(s, &sa, 0); + CHECK("isc_socket_bind", result); + result = isc_socket_sendto(s, &r, task1, senddone, NULL, &address, + NULL); + CHECK("isc_socket_sendto", result); + + inr.base = rdata; + inr.length = sizeof(rdata); + result = isc_socket_recv(s, &inr, 1, task1, recvdone, NULL); + CHECK("isc_socket_recv", result); + dns_message_detach(&query); +} + +int +main(int argc, char *argv[]) { + bool verbose = false; + isc_socketmgr_t *socketmgr = NULL; + isc_timermgr_t *timermgr = NULL; + struct in_addr inaddr; + dns_fixedname_t fname; + dns_name_t *name = NULL; + isc_buffer_t b; + int ch; + isc_result_t result; + in_port_t port = 53; + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + + isc_mutex_init(&lock); + + mctx = NULL; + isc_mem_create(&mctx); + + while ((ch = isc_commandline_parse(argc, argv, "vp:")) != -1) { + switch (ch) { + case 'v': + verbose = true; + break; + case 'p': + port = (unsigned int)atoi(isc_commandline_argument); + break; + } + } + + RUNTIME_CHECK(dst_lib_init(mctx, NULL) == ISC_R_SUCCESS); + + dns_result_register(); + dst_result_register(); + + RUNTIME_CHECK(isc_managers_create(mctx, 2, 0, &netmgr, &taskmgr) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task1) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + + isc_log_create(mctx, &lctx, &logconfig); + + RUNTIME_CHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, + &s) == ISC_R_SUCCESS); + + inaddr.s_addr = htonl(INADDR_LOOPBACK); + isc_sockaddr_fromin(&address, &inaddr, port); + + name = dns_fixedname_initname(&fname); + isc_buffer_constinit(&b, "child.example.", strlen("child.example.")); + isc_buffer_add(&b, strlen("child.example.")); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + CHECK("dns_name_fromtext", result); + + result = dst_key_fromfile(name, 33180, DNS_KEYALG_RSASHA1, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, NULL, + mctx, &key); + CHECK("dst_key_fromfile", result); + + buildquery(); + + (void)isc_app_run(); + + isc_task_shutdown(task1); + isc_task_detach(&task1); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_socket_detach(&s); + isc_socketmgr_destroy(&socketmgr); + isc_timermgr_destroy(&timermgr); + + dst_key_free(&key); + + dst_lib_destroy(); + + isc_log_destroy(&lctx); + + if (verbose) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + isc_mutex_destroy(&lock); + + isc_app_finish(); + + return (0); +} diff --git a/bin/tests/optional/sock_test.c b/bin/tests/optional/sock_test.c new file mode 100644 index 0000000..f88f76d --- /dev/null +++ b/bin/tests/optional/sock_test.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <isc/managers.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/socket.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +isc_mem_t *mctx = NULL; +isc_nm_t *netmgr = NULL; +isc_taskmgr_t *taskmgr = NULL; + +static void +my_shutdown(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + printf("shutdown %s (%p)\n", name, task); + fflush(stdout); + isc_event_free(&event); +} + +static void +my_send(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock; + isc_socketevent_t *dev; + + sock = event->ev_sender; + dev = (isc_socketevent_t *)event; + + printf("my_send: %s task %p\n\t(sock %p, base %p, length %u, n %u, " + "result %u)\n", + (char *)(event->ev_arg), task, sock, dev->region.base, + dev->region.length, dev->n, dev->result); + + if (dev->result != ISC_R_SUCCESS) { + isc_socket_detach(&sock); + isc_task_shutdown(task); + } + + if (dev->region.base != NULL) { + isc_mem_put(mctx, dev->region.base, dev->region.length); + } + + isc_event_free(&event); +} + +static void +my_recv(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock; + isc_socketevent_t *dev; + isc_region_t region; + char buf[1024]; + char host[256]; + + sock = event->ev_sender; + dev = (isc_socketevent_t *)event; + + printf("Socket %s (sock %p, base %p, length %u, n %u, result %u)\n", + (char *)(event->ev_arg), sock, dev->region.base, + dev->region.length, dev->n, dev->result); + if (dev->address.type.sa.sa_family == AF_INET6) { + inet_ntop(AF_INET6, &dev->address.type.sin6.sin6_addr, host, + sizeof(host)); + printf("\tFrom: %s port %d\n", host, + ntohs(dev->address.type.sin6.sin6_port)); + } else { + inet_ntop(AF_INET, &dev->address.type.sin.sin_addr, host, + sizeof(host)); + printf("\tFrom: %s port %d\n", host, + ntohs(dev->address.type.sin.sin_port)); + } + + if (dev->result != ISC_R_SUCCESS) { + isc_socket_detach(&sock); + + if (dev->region.base != NULL) { + isc_mem_put(mctx, dev->region.base, dev->region.length); + } + isc_event_free(&event); + + isc_task_shutdown(task); + return; + } + + /* + * Echo the data back. + */ + if (strcmp(event->ev_arg, "so2") != 0) { + region = dev->region; + snprintf(buf, sizeof(buf), "\r\nReceived: %.*s\r\n\r\n", + (int)dev->n, (char *)region.base); + region.base = isc_mem_get(mctx, strlen(buf) + 1); + { + region.length = strlen(buf) + 1; + strlcpy((char *)region.base, buf, region.length); + } + isc_socket_send(sock, ®ion, task, my_send, event->ev_arg); + } else { + region = dev->region; + printf("\r\nReceived: %.*s\r\n\r\n", (int)dev->n, + (char *)region.base); + } + + isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->ev_arg); + + isc_event_free(&event); +} + +static void +my_http_get(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock; + isc_socketevent_t *dev; + + sock = event->ev_sender; + dev = (isc_socketevent_t *)event; + + printf("my_http_get: %s task %p\n\t(sock %p, base %p, length %u, " + "n %u, result %u)\n", + (char *)(event->ev_arg), task, sock, dev->region.base, + dev->region.length, dev->n, dev->result); + + if (dev->result != ISC_R_SUCCESS) { + isc_socket_detach(&sock); + isc_task_shutdown(task); + if (dev->region.base != NULL) { + isc_mem_put(mctx, dev->region.base, dev->region.length); + } + isc_event_free(&event); + return; + } + + isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->ev_arg); + + isc_event_free(&event); +} + +static void +my_connect(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock; + isc_socket_connev_t *dev; + isc_region_t region; + char buf[1024]; + + sock = event->ev_sender; + dev = (isc_socket_connev_t *)event; + + printf("%s: Connection result: %u\n", (char *)(event->ev_arg), + dev->result); + + if (dev->result != ISC_R_SUCCESS) { + isc_socket_detach(&sock); + isc_event_free(&event); + isc_task_shutdown(task); + return; + } + + /* + * Send a GET string, and set up to receive (and just display) + * the result. + */ + snprintf(buf, sizeof(buf), + "GET / HTTP/1.1\r\nHost: www.flame.org\r\n" + "Connection: Close\r\n\r\n"); + region.base = isc_mem_get(mctx, strlen(buf) + 1); + { + region.length = strlen(buf) + 1; + strlcpy((char *)region.base, buf, region.length); + } + + isc_socket_send(sock, ®ion, task, my_http_get, event->ev_arg); + + isc_event_free(&event); +} + +static void +my_listen(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + isc_socket_newconnev_t *dev = NULL; + isc_region_t region; + isc_socket_t *oldsock = NULL; + isc_task_t *newtask = NULL; + + dev = (isc_socket_newconnev_t *)event; + + printf("newcon %s (task %p, oldsock %p, newsock %p, result %u)\n", name, + task, event->ev_sender, dev->newsocket, dev->result); + fflush(stdout); + + if (dev->result == ISC_R_SUCCESS) { + /* + * Queue another listen on this socket. + */ + RUNTIME_CHECK(isc_socket_accept(event->ev_sender, task, + my_listen, event->ev_arg) == + ISC_R_SUCCESS); + + region.base = isc_mem_get(mctx, 20); + region.length = 20; + + /* + * Create a new task for this socket, and queue up a + * recv on it. + */ + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &newtask) == + ISC_R_SUCCESS); + isc_socket_recv(dev->newsocket, ®ion, 1, newtask, my_recv, + event->ev_arg); + isc_task_detach(&newtask); + } else { + printf("detaching from socket %p\n", event->ev_sender); + oldsock = event->ev_sender; + + isc_socket_detach(&oldsock); + + isc_event_free(&event); + isc_task_shutdown(task); + return; + } + + isc_event_free(&event); +} + +static void +timeout(isc_task_t *task, isc_event_t *event) { + isc_socket_t *sock = event->ev_arg; + + printf("Timeout, canceling IO on socket %p (task %p)\n", sock, task); + + isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_ALL); + isc_timer_destroy((isc_timer_t **)&event->ev_sender); + isc_event_free(&event); +} + +static char one[] = "1"; +static char two[] = "2"; +static char xso1[] = "so1"; +static char xso2[] = "so2"; + +int +main(int argc, char *argv[]) { + isc_task_t *t1 = NULL, *t2 = NULL; + isc_timermgr_t *timgr = NULL; + isc_time_t expires; + isc_interval_t interval; + isc_timer_t *ti1 = NULL; + unsigned int workers; + isc_socketmgr_t *socketmgr = NULL; + isc_socket_t *so1 = NULL, *so2 = NULL; + isc_sockaddr_t sockaddr; + struct in_addr ina; + struct in6_addr in6a; + isc_result_t result; + int pf; + + if (argc > 1) { + workers = atoi(argv[1]); + if (workers < 1) { + workers = 1; + } + if (workers > 8192) { + workers = 8192; + } + } else { + workers = 2; + } + printf("%u workers\n", workers); + + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + pf = PF_INET6; + } else { + pf = PF_INET; + } + + /* + * EVERYTHING needs a memory context. + */ + isc_mem_create(&mctx); + + /* + * The task manager is independent (other than memory context) + */ + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + + /* + * Timer manager depends only on the memory context as well. + */ + RUNTIME_CHECK(isc_timermgr_create(mctx, &timgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t1) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t2) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t1, my_shutdown, one) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t2, my_shutdown, two) == + ISC_R_SUCCESS); + + printf("task 1 = %p\n", t1); + printf("task 2 = %p\n", t2); + + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + + /* + * Open up a listener socket. + */ + + if (pf == PF_INET6) { + in6a = in6addr_any; + isc_sockaddr_fromin6(&sockaddr, &in6a, 5544); + } else { + ina.s_addr = INADDR_ANY; + isc_sockaddr_fromin(&sockaddr, &ina, 5544); + } + RUNTIME_CHECK(isc_socket_create(socketmgr, pf, isc_sockettype_tcp, + &so1) == ISC_R_SUCCESS); + result = isc_socket_bind(so1, &sockaddr, ISC_SOCKET_REUSEADDRESS); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socket_listen(so1, 0) == ISC_R_SUCCESS); + + /* + * Queue up the first accept event. + */ + RUNTIME_CHECK(isc_socket_accept(so1, t1, my_listen, xso1) == + ISC_R_SUCCESS); + isc_time_settoepoch(&expires); + isc_interval_set(&interval, 10, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, &expires, + &interval, t1, timeout, so1, + &ti1) == ISC_R_SUCCESS); + + /* + * Open up a socket that will connect to www.flame.org, port 80. + * Why not. :) + */ + ina.s_addr = inet_addr("204.152.184.97"); + if (0 && pf == PF_INET6) { + isc_sockaddr_v6fromin(&sockaddr, &ina, 80); + } else { + isc_sockaddr_fromin(&sockaddr, &ina, 80); + } + RUNTIME_CHECK(isc_socket_create(socketmgr, isc_sockaddr_pf(&sockaddr), + isc_sockettype_tcp, + &so2) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_socket_connect(so2, &sockaddr, t2, my_connect, + xso2) == ISC_R_SUCCESS); + + /* + * Detaching these is safe, since the socket will attach to the + * task for any outstanding requests. + */ + isc_task_detach(&t1); + isc_task_detach(&t2); + + /* + * Wait a short while. + */ +#ifndef WIN32 + sleep(10); +#else /* ifndef WIN32 */ + Sleep(10000); +#endif /* ifndef WIN32 */ + + fprintf(stderr, "Destroying socket manager\n"); + isc_socketmgr_destroy(&socketmgr); + + fprintf(stderr, "Destroying timer manager\n"); + isc_timermgr_destroy(&timgr); + + fprintf(stderr, "Destroying task manager\n"); + isc_managers_destroy(&netmgr, &taskmgr); + + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/sym_test.c b/bin/tests/optional/sym_test.c new file mode 100644 index 0000000..81e2916 --- /dev/null +++ b/bin/tests/optional/sym_test.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdbool.h> +#include <string.h> + +#include <isc/commandline.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/symtab.h> +#include <isc/util.h> + +isc_mem_t *mctx; +isc_symtab_t *st; + +static void +undefine_action(char *key, unsigned int type, isc_symvalue_t value, void *arg) { + UNUSED(arg); + + INSIST(type == 1); + isc_mem_free(mctx, key); + isc_mem_free(mctx, value.as_pointer); +} + +int +main(int argc, char *argv[]) { + char s[1000], *cp, *key; + size_t len; + isc_result_t result; + isc_symvalue_t value; + int trace = 0; + int c; + isc_symexists_t exists_policy = isc_symexists_reject; + bool case_sensitive = false; + + while ((c = isc_commandline_parse(argc, argv, "tarc")) != -1) { + switch (c) { + case 't': + trace = 1; + break; + case 'a': + exists_policy = isc_symexists_add; + break; + case 'r': + exists_policy = isc_symexists_replace; + break; + case 'c': + case_sensitive = true; + break; + } + } + + isc_mem_create(&mctx); + RUNTIME_CHECK(isc_symtab_create(mctx, 691, undefine_action, NULL, + case_sensitive, &st) == ISC_R_SUCCESS); + + while (fgets(s, sizeof(s), stdin) != NULL) { + len = strlen(s); + if (len > 0U && s[len - 1] == '\n') { + s[len - 1] = '\0'; + len--; + } + + cp = s; + + if (cp[0] == '!') { + cp++; + result = isc_symtab_undefine(st, cp, 1); + if (trace || result != ISC_R_SUCCESS) { + printf("undefine('%s'): %s\n", cp, + isc_result_totext(result)); + } + } else { + key = cp; + while (*cp != '\0' && *cp != ' ' && *cp != '\t') { + cp++; + } + if (*cp == '\0') { + result = isc_symtab_lookup(st, key, 0, &value); + if (trace || result != ISC_R_SUCCESS) { + printf("lookup('%s'): %s", key, + isc_result_totext(result)); + if (result == ISC_R_SUCCESS) { + cp = value.as_pointer; + printf(", value == '%s'", cp); + } + printf("\n"); + } + } else { + *cp++ = '\0'; + key = isc_mem_strdup(mctx, key); + value.as_pointer = isc_mem_strdup(mctx, cp); + result = isc_symtab_define(st, key, 1, value, + exists_policy); + if (trace || result != ISC_R_SUCCESS) { + printf("define('%s', '%s'): %s\n", key, + cp, isc_result_totext(result)); + if (result != ISC_R_SUCCESS) { + undefine_action(key, 1, value, + NULL); + } + } + } + } + } + + isc_symtab_destroy(&st); + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/task_test.c b/bin/tests/optional/task_test.c new file mode 100644 index 0000000..48e6bfd --- /dev/null +++ b/bin/tests/optional/task_test.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdlib.h> +#include <unistd.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> + +isc_mem_t *mctx = NULL; + +static void +my_callback(isc_task_t *task, isc_event_t *event) { + int i, j; + char *name = event->ev_arg; + + j = 0; + for (i = 0; i < 1000000; i++) { + j += 100; + } + printf("task %s (%p): %d\n", name, task, j); + isc_event_free(&event); +} + +static void +my_shutdown(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + printf("shutdown %s (%p)\n", name, task); + isc_event_free(&event); +} + +static void +my_tick(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + printf("task %p tick %s\n", task, name); + isc_event_free(&event); +} + +static char one[] = "1"; +static char two[] = "2"; +static char three[] = "3"; +static char four[] = "4"; +static char foo[] = "foo"; +static char bar[] = "bar"; + +int +main(int argc, char *argv[]) { + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_task_t *t1 = NULL, *t2 = NULL; + isc_task_t *t3 = NULL, *t4 = NULL; + isc_event_t *event; + unsigned int workers; + isc_timermgr_t *timgr; + isc_timer_t *ti1, *ti2; + struct isc_interval interval; + + if (argc > 1) { + workers = atoi(argv[1]); + if (workers < 1) { + workers = 1; + } + if (workers > 8192) { + workers = 8192; + } + } else { + workers = 2; + } + printf("%u workers\n", workers); + + isc_mem_create(&mctx); + + RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t1) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t2) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t3) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t4) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_task_onshutdown(t1, my_shutdown, one) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t2, my_shutdown, two) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t3, my_shutdown, three) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t4, my_shutdown, four) == + ISC_R_SUCCESS); + + timgr = NULL; + RUNTIME_CHECK(isc_timermgr_create(mctx, &timgr) == ISC_R_SUCCESS); + ti1 = NULL; + + isc_interval_set(&interval, 1, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_ticker, NULL, + &interval, t1, my_tick, foo, + &ti1) == ISC_R_SUCCESS); + + ti2 = NULL; + isc_interval_set(&interval, 1, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_ticker, NULL, + &interval, t2, my_tick, bar, + &ti2) == ISC_R_SUCCESS); + + printf("task 1 = %p\n", t1); + printf("task 2 = %p\n", t2); +#ifndef WIN32 + sleep(2); +#else /* ifndef WIN32 */ + Sleep(2000); +#endif /* ifndef WIN32 */ + + /* + * Note: (void *)1 is used as a sender here, since some compilers + * don't like casting a function pointer to a (void *). + * + * In a real use, it is more likely the sender would be a + * structure (socket, timer, task, etc) but this is just a test + * program. + */ + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one, + sizeof(*event)); + isc_task_send(t1, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, two, + sizeof(*event)); + isc_task_send(t2, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, three, + sizeof(*event)); + isc_task_send(t3, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, four, + sizeof(*event)); + isc_task_send(t4, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, two, + sizeof(*event)); + isc_task_send(t2, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, three, + sizeof(*event)); + isc_task_send(t3, &event); + event = isc_event_allocate(mctx, (void *)1, 1, my_callback, four, + sizeof(*event)); + isc_task_send(t4, &event); + isc_task_purgerange(t3, NULL, ISC_EVENTTYPE_FIRSTEVENT, + ISC_EVENTTYPE_LASTEVENT, NULL); + + isc_task_detach(&t1); + isc_task_detach(&t2); + isc_task_detach(&t3); + isc_task_detach(&t4); + +#ifndef WIN32 + sleep(10); +#else /* ifndef WIN32 */ + Sleep(10000); +#endif /* ifndef WIN32 */ + printf("destroy\n"); + isc_timer_destroy(&ti1); + isc_timer_destroy(&ti2); + isc_timermgr_destroy(&timgr); + isc_managers_destroy(&netmgr, &taskmgr); + printf("destroyed\n"); + + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/tests/optional/timer_test.c b/bin/tests/optional/timer_test.c new file mode 100644 index 0000000..0eb6e9f --- /dev/null +++ b/bin/tests/optional/timer_test.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.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> + +isc_mem_t *mctx1, *mctx2, *mctx3; +isc_task_t *t1, *t2, *t3; +isc_timer_t *ti1, *ti2, *ti3; +int tick_count = 0; + +static void +shutdown_task(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + printf("task %p shutdown %s\n", task, name); + isc_event_free(&event); +} + +static void +tick(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + + INSIST(event->ev_type == ISC_TIMEREVENT_TICK); + + printf("task %s (%p) tick\n", name, task); + + tick_count++; + if (ti3 != NULL && tick_count % 3 == 0) { + isc_timer_touch(ti3); + } + + if (ti3 != NULL && tick_count == 7) { + isc_time_t expires; + isc_interval_t interval; + + isc_interval_set(&interval, 5, 0); + (void)isc_time_nowplusinterval(&expires, &interval); + isc_interval_set(&interval, 4, 0); + printf("*** resetting ti3 ***\n"); + RUNTIME_CHECK(isc_timer_reset(ti3, isc_timertype_once, &expires, + &interval, + true) == ISC_R_SUCCESS); + } + + isc_event_free(&event); +} + +static void +timeout(isc_task_t *task, isc_event_t *event) { + char *name = event->ev_arg; + const char *type; + + INSIST(event->ev_type == ISC_TIMEREVENT_IDLE || + event->ev_type == ISC_TIMEREVENT_LIFE); + + if (event->ev_type == ISC_TIMEREVENT_IDLE) { + type = "idle"; + } else { + type = "life"; + } + printf("task %s (%p) %s timeout\n", name, task, type); + + if (strcmp(name, "3") == 0) { + printf("*** saving task 3 ***\n"); + isc_event_free(&event); + return; + } + + isc_event_free(&event); + isc_task_shutdown(task); +} + +static char one[] = "1"; +static char two[] = "2"; +static char three[] = "3"; + +int +main(int argc, char *argv[]) { + isc_nm_t *netmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_timermgr_t *timgr = NULL; + unsigned int workers; + isc_time_t expires, now; + isc_interval_t interval; + + if (argc > 1) { + workers = atoi(argv[1]); + if (workers < 1) { + workers = 1; + } + if (workers > 8192) { + workers = 8192; + } + } else { + workers = 2; + } + printf("%u workers\n", workers); + + isc_mem_create(&mctx1); + RUNTIME_CHECK(isc_managers_create(mctx1, workers, 0, &netmgr, + &taskmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_timermgr_create(mctx1, &timgr) == ISC_R_SUCCESS); + + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t1) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t2) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t3) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t1, shutdown_task, one) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t2, shutdown_task, two) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_task_onshutdown(t3, shutdown_task, three) == + ISC_R_SUCCESS); + + printf("task 1: %p\n", t1); + printf("task 2: %p\n", t2); + printf("task 3: %p\n", t3); + + TIME_NOW(&now); + + isc_interval_set(&interval, 2, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, NULL, + &interval, t2, timeout, two, + &ti2) == ISC_R_SUCCESS); + + isc_interval_set(&interval, 1, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_ticker, NULL, + &interval, t1, tick, one, + &ti1) == ISC_R_SUCCESS); + + isc_interval_set(&interval, 10, 0); + RUNTIME_CHECK(isc_time_add(&now, &interval, &expires) == ISC_R_SUCCESS); + isc_interval_set(&interval, 2, 0); + RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, &expires, + &interval, t3, timeout, three, + &ti3) == ISC_R_SUCCESS); + + isc_task_detach(&t1); + isc_task_detach(&t2); + isc_task_detach(&t3); + +#ifndef WIN32 + sleep(15); +#else /* ifndef WIN32 */ + Sleep(15000); +#endif /* ifndef WIN32 */ + printf("destroy\n"); + isc_timer_destroy(&ti1); + isc_timer_destroy(&ti2); + isc_timer_destroy(&ti3); +#ifndef WIN32 + sleep(2); +#else /* ifndef WIN32 */ + Sleep(2000); +#endif /* ifndef WIN32 */ + isc_timermgr_destroy(&timgr); + isc_managers_destroy(&netmgr, &taskmgr); + printf("destroyed\n"); + + printf("Statistics for mctx1:\n"); + isc_mem_stats(mctx1, stdout); + isc_mem_destroy(&mctx1); + + return (0); +} diff --git a/bin/tests/optional/zone_test.c b/bin/tests/optional/zone_test.c new file mode 100644 index 0000000..05193f8 --- /dev/null +++ b/bin/tests/optional/zone_test.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdlib.h> +#include <sys/param.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +#include <isc/app.h> +#include <isc/commandline.h> +#include <isc/managers.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/socket.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +#include <dns/db.h> +#include <dns/fixedname.h> +#include <dns/rdataclass.h> +#include <dns/rdataset.h> +#include <dns/result.h> +#include <dns/zone.h> + +static int debug = 0; +static int quiet = 0; +static int stats = 0; +static isc_mem_t *mctx = NULL; +dns_zone_t *zone = NULL; +isc_nm_t *netmgr = NULL; +isc_taskmgr_t *taskmgr = NULL; +isc_timermgr_t *timermgr = NULL; +isc_socketmgr_t *socketmgr = NULL; +dns_zonemgr_t *zonemgr = NULL; +dns_zonetype_t zonetype = dns_zone_primary; +isc_sockaddr_t addr; + +#define ERRRET(result, function) \ + do { \ + if (result != ISC_R_SUCCESS) { \ + fprintf(stderr, "%s() returned %s\n", function, \ + dns_result_totext(result)); \ + return; \ + } \ + } while (0) + +#define ERRCONT(result, function) \ + if (result != ISC_R_SUCCESS) { \ + fprintf(stderr, "%s() returned %s\n", function, \ + dns_result_totext(result)); \ + continue; \ + } else \ + (void)NULL + +static void +usage(void) { + fprintf(stderr, "usage: zone_test [-dqsSM] [-c class] [-f file] " + "zone\n"); + exit(1); +} + +static void +setup(const char *zonename, const char *filename, const char *classname) { + isc_result_t result; + dns_rdataclass_t rdclass; + isc_consttextregion_t region; + isc_buffer_t buffer; + dns_fixedname_t fixorigin; + dns_name_t *origin; + const char *rbt = "rbt"; + + if (debug) { + fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n", + zonename, filename, classname); + } + result = dns_zone_create(&zone, mctx); + ERRRET(result, "dns_zone_new"); + + dns_zone_settype(zone, zonetype); + + isc_buffer_constinit(&buffer, zonename, strlen(zonename)); + isc_buffer_add(&buffer, strlen(zonename)); + dns_fixedname_init(&fixorigin); + result = dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer, + dns_rootname, 0, NULL); + ERRRET(result, "dns_name_fromtext"); + origin = dns_fixedname_name(&fixorigin); + + result = dns_zone_setorigin(zone, origin); + ERRRET(result, "dns_zone_setorigin"); + + dns_zone_setdbtype(zone, 1, &rbt); + + result = dns_zone_setfile(zone, filename, dns_masterformat_text, + &dns_master_style_default); + ERRRET(result, "dns_zone_setfile"); + + region.base = classname; + region.length = strlen(classname); + result = dns_rdataclass_fromtext(&rdclass, + (isc_textregion_t *)(void *)®ion); + ERRRET(result, "dns_rdataclass_fromtext"); + + dns_zone_setclass(zone, rdclass); + + if (zonetype == dns_zone_secondary) { + dns_zone_setprimaries(zone, &addr, 1); + } + + result = dns_zone_load(zone, false); + ERRRET(result, "dns_zone_load"); + + result = dns_zonemgr_managezone(zonemgr, zone); + ERRRET(result, "dns_zonemgr_managezone"); +} + +static void +print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) { + isc_buffer_t text; + char t[1000]; + isc_result_t result; + isc_region_t r; + + isc_buffer_init(&text, t, sizeof(t)); + result = dns_rdataset_totext(rdataset, name, false, false, &text); + isc_buffer_usedregion(&text, &r); + if (result == ISC_R_SUCCESS) { + printf("%.*s", (int)r.length, (char *)r.base); + } else { + printf("%s\n", dns_result_totext(result)); + } +} + +static void +query(void) { + char buf[1024]; + dns_fixedname_t name; + dns_fixedname_t found; + dns_db_t *db; + isc_buffer_t buffer; + isc_result_t result; + dns_rdataset_t rdataset; + dns_rdataset_t sigset; + fd_set rfdset = { { 0 } }; + + db = NULL; + result = dns_zone_getdb(zone, &db); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "%s() returned %s\n", "dns_zone_getdb", + dns_result_totext(result)); + return; + } + + dns_fixedname_init(&found); + dns_rdataset_init(&rdataset); + dns_rdataset_init(&sigset); + + do { + char *s; + fprintf(stdout, "zone_test "); + fflush(stdout); + FD_ZERO(&rfdset); + FD_SET(0, &rfdset); + select(1, &rfdset, NULL, NULL, NULL); + if (fgets(buf, sizeof(buf), stdin) == NULL) { + fprintf(stdout, "\n"); + break; + } + buf[sizeof(buf) - 1] = '\0'; + + s = strchr(buf, '\n'); + if (s != NULL) { + *s = '\0'; + } + s = strchr(buf, '\r'); + if (s != NULL) { + *s = '\0'; + } + if (strcmp(buf, "dump") == 0) { + dns_zone_dumptostream(zone, stdout, + dns_masterformat_text, + &dns_master_style_default, 0); + continue; + } + if (strlen(buf) == 0U) { + continue; + } + dns_fixedname_init(&name); + isc_buffer_init(&buffer, buf, strlen(buf)); + isc_buffer_add(&buffer, strlen(buf)); + result = dns_name_fromtext(dns_fixedname_name(&name), &buffer, + dns_rootname, 0, NULL); + ERRCONT(result, "dns_name_fromtext"); + + result = dns_db_find(db, dns_fixedname_name(&name), + NULL /*version*/, dns_rdatatype_a, + 0 /*options*/, 0 /*time*/, NULL /*nodep*/, + dns_fixedname_name(&found), &rdataset, + &sigset); + fprintf(stderr, "%s() returned %s\n", "dns_db_find", + dns_result_totext(result)); + switch (result) { + case DNS_R_DELEGATION: + print_rdataset(dns_fixedname_name(&found), &rdataset); + break; + case ISC_R_SUCCESS: + print_rdataset(dns_fixedname_name(&name), &rdataset); + break; + default: + break; + } + + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + if (dns_rdataset_isassociated(&sigset)) { + dns_rdataset_disassociate(&sigset); + } + } while (1); + dns_rdataset_invalidate(&rdataset); + dns_db_detach(&db); +} + +int +main(int argc, char **argv) { + int c; + char *filename = NULL; + const char *classname = "IN"; + + while ((c = isc_commandline_parse(argc, argv, "cdf:m:qsMS")) != EOF) { + switch (c) { + case 'c': + classname = isc_commandline_argument; + break; + case 'd': + debug++; + break; + case 'f': + if (filename != NULL) { + usage(); + } + filename = isc_commandline_argument; + break; + case 'm': + memset(&addr, 0, sizeof(addr)); + addr.type.sin.sin_family = AF_INET; + if (inet_pton(AF_INET, isc_commandline_argument, + &addr.type.sin.sin_addr) != 1) + { + fprintf(stderr, "bad master address '%s'\n", + isc_commandline_argument); + exit(1); + } + addr.type.sin.sin_port = htons(53); + break; + case 'q': + quiet++; + break; + case 's': + stats++; + break; + case 'S': + zonetype = dns_zone_secondary; + break; + case 'M': + zonetype = dns_zone_primary; + break; + default: + usage(); + } + } + + if (argv[isc_commandline_index] == NULL) { + usage(); + } + + RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); + isc_mem_create(&mctx); + RUNTIME_CHECK(isc_managers_create(mctx, 2, 0, NULL, &taskmgr) == + ISC_R_SUCCESS); + RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); + RUNTIME_CHECK(dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr, + &zonemgr) == ISC_R_SUCCESS); + if (filename == NULL) { + filename = argv[isc_commandline_index]; + } + setup(argv[isc_commandline_index], filename, classname); + query(); + if (zone != NULL) { + dns_zone_detach(&zone); + } + dns_zonemgr_shutdown(zonemgr); + dns_zonemgr_detach(&zonemgr); + isc_socketmgr_destroy(&socketmgr); + isc_managers_destroy(&netmgr, &taskmgr); + isc_timermgr_destroy(&timermgr); + if (!quiet && stats) { + isc_mem_stats(mctx, stdout); + } + isc_mem_destroy(&mctx); + + return (0); +} |