diff --git a/ax_pthread.m4 b/ax_pthread.m4 index 9f35d1391..a9019832e 100644 --- a/ax_pthread.m4 +++ b/ax_pthread.m4 @@ -87,7 +87,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 31 +#serial 32 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ @@ -249,7 +249,22 @@ AS_IF([test "x$ax_pthread_clang" = "xyes"], # correctly enabled case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) + solaris*) + # Solaris 11.4 introduced XPG7 support and did away with the need for + # _REENTRANT. + + AC_EGREP_CPP([AX_PTHREAD_SOLARIS__REENTRANT], + [ +# undef _XOPEN_SOURCE +# include +# if _XOPEN_VERSION < 700 + AX_PTHREAD_SOLARIS__REENTRANT +# endif + ], + [ax_pthread_check_macro="_REENTRANT"], + [ax_pthread_check_macro="--"]) + ;; + darwin* | hpux* | linux* | osf*) ax_pthread_check_macro="_REENTRANT" ;; diff --git a/compat/getentropy_osx.c b/compat/getentropy_osx.c index 26dcc824d..ab9456a24 100644 --- a/compat/getentropy_osx.c +++ b/compat/getentropy_osx.c @@ -20,398 +20,25 @@ * http://man.openbsd.org/getentropy.2 */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +/* Modified to use SecRandomCopyBytes. It is from macOS 10.7 (2011) and + * iOS 2.0 (2008), and is the primary API for cryptographic random numbers. */ #include -#include -#include -#include -#include -#include -#if TARGET_OS_OSX -#include -#include -#endif -#include -#include -#if TARGET_OS_OSX -#include -#include -#include -#include -#endif -#include -#define SHA512_Update(a, b, c) (CC_SHA512_Update((a), (b), (c))) -#define SHA512_Init(xxx) (CC_SHA512_Init((xxx))) -#define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy))) -#define SHA512_CTX CC_SHA512_CTX -#define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH - -#define REPEAT 5 -#define min(a, b) (((a) < (b)) ? (a) : (b)) - -#define HX(a, b) \ - do { \ - if ((a)) \ - HD(errno); \ - else \ - HD(b); \ - } while (0) - -#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) -#define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) -#define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) +#include int getentropy(void *buf, size_t len); -static int getentropy_urandom(void *buf, size_t len); -static int getentropy_fallback(void *buf, size_t len); - int getentropy(void *buf, size_t len) { - int ret = -1; - if (len > 256) { - errno = EIO; - return (-1); + goto error; } - /* - * Try to get entropy with /dev/urandom - * - * This can fail if the process is inside a chroot or if file - * descriptors are exhausted. - */ - ret = getentropy_urandom(buf, len); - if (ret != -1) - return (ret); - - /* - * Entropy collection via /dev/urandom and sysctl have failed. - * - * No other API exists for collecting entropy, and we have - * no failsafe way to get it on OSX that is not sensitive - * to resource exhaustion. - * - * We have very few options: - * - Even syslog_r is unsafe to call at this low level, so - * there is no way to alert the user or program. - * - Cannot call abort() because some systems have unsafe - * corefiles. - * - Could raise(SIGKILL) resulting in silent program termination. - * - Return EIO, to hint that arc4random's stir function - * should raise(SIGKILL) - * - Do the best under the circumstances.... - * - * This code path exists to bring light to the issue that OSX - * does not provide a failsafe API for entropy collection. - * - * We hope this demonstrates that OSX should consider - * providing a new failsafe API which works in a chroot or - * when file descriptors are exhausted. - */ -#undef FAIL_INSTEAD_OF_TRYING_FALLBACK -#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK - raise(SIGKILL); -#endif - ret = getentropy_fallback(buf, len); - if (ret != -1) - return (ret); + if (SecRandomCopyBytes(kSecRandomDefault, len, buf) == errSecSuccess) { + return 0; + } +error: errno = EIO; - return (ret); -} - -static int -getentropy_urandom(void *buf, size_t len) -{ - struct stat st; - size_t i; - int fd, flags; - int save_errno = errno; - -start: - - flags = O_RDONLY; -#ifdef O_NOFOLLOW - flags |= O_NOFOLLOW; -#endif -#ifdef O_CLOEXEC - flags |= O_CLOEXEC; -#endif - fd = open("/dev/urandom", flags, 0); - if (fd == -1) { - if (errno == EINTR) - goto start; - goto nodevrandom; - } -#ifndef O_CLOEXEC - fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); -#endif - - /* Lightly verify that the device node looks sane */ - if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) { - close(fd); - goto nodevrandom; - } - for (i = 0; i < len; ) { - size_t wanted = len - i; - ssize_t ret = read(fd, (char *)buf + i, wanted); - - if (ret == -1) { - if (errno == EAGAIN || errno == EINTR) - continue; - close(fd); - goto nodevrandom; - } - i += ret; - } - close(fd); - errno = save_errno; - return (0); /* satisfied */ -nodevrandom: - errno = EIO; - return (-1); -} - -#if TARGET_OS_OSX -static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS }; -static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS }; -static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS }; -#endif -static int kmib[] = { CTL_KERN, KERN_USRSTACK }; -static int hwmib[] = { CTL_HW, HW_USERMEM }; - -static int -getentropy_fallback(void *buf, size_t len) -{ - uint8_t results[SHA512_DIGEST_LENGTH]; - int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat; - static int cnt; - struct timespec ts; - struct timeval tv; - struct rusage ru; - sigset_t sigset; - struct stat st; - SHA512_CTX ctx; - static pid_t lastpid; - pid_t pid; - size_t i, ii, m; - char *p; -#if TARGET_OS_OSX - struct tcpstat tcpstat; - struct udpstat udpstat; - struct ipstat ipstat; -#endif - u_int64_t mach_time; - unsigned int idata; - void *addr; - - pid = getpid(); - if (lastpid == pid) { - faster = 1; - repeat = 2; - } else { - faster = 0; - lastpid = pid; - repeat = REPEAT; - } - for (i = 0; i < len; ) { - int j; - SHA512_Init(&ctx); - for (j = 0; j < repeat; j++) { - HX((e = gettimeofday(&tv, NULL)) == -1, tv); - if (e != -1) { - cnt += (int)tv.tv_sec; - cnt += (int)tv.tv_usec; - } - - mach_time = mach_absolute_time(); - HD(mach_time); - - ii = sizeof(addr); - HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]), - &addr, &ii, NULL, 0) == -1, addr); - - ii = sizeof(idata); - HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]), - &idata, &ii, NULL, 0) == -1, idata); - -#if TARGET_OS_OSX - ii = sizeof(tcpstat); - HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]), - &tcpstat, &ii, NULL, 0) == -1, tcpstat); - - ii = sizeof(udpstat); - HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]), - &udpstat, &ii, NULL, 0) == -1, udpstat); - - ii = sizeof(ipstat); - HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]), - &ipstat, &ii, NULL, 0) == -1, ipstat); -#endif - - HX((pid = getpid()) == -1, pid); - HX((pid = getsid(pid)) == -1, pid); - HX((pid = getppid()) == -1, pid); - HX((pid = getpgid(0)) == -1, pid); - HX((e = getpriority(0, 0)) == -1, e); - - if (!faster) { - ts.tv_sec = 0; - ts.tv_nsec = 1; - (void) nanosleep(&ts, NULL); - } - - HX(sigpending(&sigset) == -1, sigset); - HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, - sigset); - - HF(getentropy); /* an addr in this library */ - HF(printf); /* an addr in libc */ - p = (char *)&p; - HD(p); /* an addr on stack */ - p = (char *)&errno; - HD(p); /* the addr of errno */ - - if (i == 0) { - struct sockaddr_storage ss; - struct statvfs stvfs; - struct termios tios; - struct statfs stfs; - socklen_t ssl; - off_t off; - - /* - * Prime-sized mappings encourage fragmentation; - * thus exposing some address entropy. - */ - struct mm { - size_t npg; - void *p; - } mm[] = { - { 17, MAP_FAILED }, { 3, MAP_FAILED }, - { 11, MAP_FAILED }, { 2, MAP_FAILED }, - { 5, MAP_FAILED }, { 3, MAP_FAILED }, - { 7, MAP_FAILED }, { 1, MAP_FAILED }, - { 57, MAP_FAILED }, { 3, MAP_FAILED }, - { 131, MAP_FAILED }, { 1, MAP_FAILED }, - }; - - for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { - HX(mm[m].p = mmap(NULL, - mm[m].npg * pgs, - PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANON, -1, - (off_t)0), mm[m].p); - if (mm[m].p != MAP_FAILED) { - size_t mo; - - /* Touch some memory... */ - p = mm[m].p; - mo = cnt % - (mm[m].npg * pgs - 1); - p[mo] = 1; - cnt += (int)((long)(mm[m].p) - / pgs); - } - - /* Check cnts and times... */ - mach_time = mach_absolute_time(); - HD(mach_time); - cnt += (int)mach_time; - - HX((e = getrusage(RUSAGE_SELF, - &ru)) == -1, ru); - if (e != -1) { - cnt += (int)ru.ru_utime.tv_sec; - cnt += (int)ru.ru_utime.tv_usec; - } - } - - for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { - if (mm[m].p != MAP_FAILED) - munmap(mm[m].p, mm[m].npg * pgs); - mm[m].p = MAP_FAILED; - } - - HX(stat(".", &st) == -1, st); - HX(statvfs(".", &stvfs) == -1, stvfs); - HX(statfs(".", &stfs) == -1, stfs); - - HX(stat("/", &st) == -1, st); - HX(statvfs("/", &stvfs) == -1, stvfs); - HX(statfs("/", &stfs) == -1, stfs); - - HX((e = fstat(0, &st)) == -1, st); - if (e == -1) { - if (S_ISREG(st.st_mode) || - S_ISFIFO(st.st_mode) || - S_ISSOCK(st.st_mode)) { - HX(fstatvfs(0, &stvfs) == -1, - stvfs); - HX(fstatfs(0, &stfs) == -1, - stfs); - HX((off = lseek(0, (off_t)0, - SEEK_CUR)) < 0, off); - } - if (S_ISCHR(st.st_mode)) { - HX(tcgetattr(0, &tios) == -1, - tios); - } else if (S_ISSOCK(st.st_mode)) { - memset(&ss, 0, sizeof ss); - ssl = sizeof(ss); - HX(getpeername(0, - (void *)&ss, &ssl) == -1, - ss); - } - } - - HX((e = getrusage(RUSAGE_CHILDREN, - &ru)) == -1, ru); - if (e != -1) { - cnt += (int)ru.ru_utime.tv_sec; - cnt += (int)ru.ru_utime.tv_usec; - } - } else { - /* Subsequent hashes absorb previous result */ - HD(results); - } - - HX((e = gettimeofday(&tv, NULL)) == -1, tv); - if (e != -1) { - cnt += (int)tv.tv_sec; - cnt += (int)tv.tv_usec; - } - - HD(cnt); - } - - SHA512_Final(results, &ctx); - memcpy((char *)buf + i, results, min(sizeof(results), len - i)); - i += min(sizeof(results), len - i); - } - explicit_bzero(&ctx, sizeof ctx); - explicit_bzero(results, sizeof results); - errno = save_errno; - return (0); /* satisfied */ + return -1; } diff --git a/config.h.in b/config.h.in index 1785ae5c0..ce8141b53 100644 --- a/config.h.in +++ b/config.h.in @@ -529,6 +529,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_BN_H +/* Define to 1 if you have the `OPENSSL_cleanup' function. */ +#undef HAVE_OPENSSL_CLEANUP + /* Define to 1 if you have the `OPENSSL_config' function. */ #undef HAVE_OPENSSL_CONFIG diff --git a/configure b/configure index 71eb3a3b2..699d67006 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for unbound 1.25.2. +# Generated by GNU Autoconf 2.71 for unbound 1.26.1. # # Report bugs to . # @@ -622,8 +622,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.25.2' -PACKAGE_STRING='unbound 1.25.2' +PACKAGE_VERSION='1.26.1' +PACKAGE_STRING='unbound 1.26.1' PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues' PACKAGE_URL='' @@ -1513,7 +1513,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures unbound 1.25.2 to adapt to many kinds of systems. +\`configure' configures unbound 1.26.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1579,7 +1579,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of unbound 1.25.2:";; + short | recursive ) echo "Configuration of unbound 1.26.1:";; esac cat <<\_ACEOF @@ -1832,7 +1832,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -unbound configure 1.25.2 +unbound configure 1.26.1 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -2489,7 +2489,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by unbound $as_me 1.25.2, which was +It was created by unbound $as_me 1.26.1, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -3251,13 +3251,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu UNBOUND_VERSION_MAJOR=1 -UNBOUND_VERSION_MINOR=25 +UNBOUND_VERSION_MINOR=26 -UNBOUND_VERSION_MICRO=2 +UNBOUND_VERSION_MICRO=1 LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=38 +LIBUNBOUND_REVISION=40 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -3363,6 +3363,8 @@ LIBUNBOUND_AGE=1 # 1.25.0 had 9:36:1 # 1.25.1 had 9:37:1 # 1.25.2 had 9:38:1 +# 1.26.0 had 9:39:1 +# 1.26.1 had 9:40:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -18414,7 +18416,31 @@ fi # correctly enabled case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) + solaris*) + # Solaris 11.4 introduced XPG7 support and did away with the need for + # _REENTRANT. + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# undef _XOPEN_SOURCE +# include +# if _XOPEN_VERSION < 700 + AX_PTHREAD_SOLARIS__REENTRANT +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_SOLARIS__REENTRANT" >/dev/null 2>&1 +then : + ax_pthread_check_macro="_REENTRANT" +else $as_nop + ax_pthread_check_macro="--" +fi +rm -rf conftest* + + ;; + darwin* | hpux* | linux* | osf*) ax_pthread_check_macro="_REENTRANT" ;; @@ -21068,6 +21094,12 @@ then : printf "%s\n" "#define HAVE_BIO_SET_CALLBACK_EX 1" >>confdefs.h fi +ac_fn_c_check_func "$LINENO" "OPENSSL_cleanup" "ac_cv_func_OPENSSL_cleanup" +if test "x$ac_cv_func_OPENSSL_cleanup" = xyes +then : + printf "%s\n" "#define HAVE_OPENSSL_CLEANUP 1" >>confdefs.h + +fi # these check_funcs need -lssl @@ -23021,6 +23053,29 @@ printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_fn_check_decl "$LINENO" "CLOCK_MONOTONIC + " "ac_cv_have_decl_CLOCK_MONOTONIC_________" "$ac_includes_default +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_CLOCK_MONOTONIC_________" = xyes +then : + + +else $as_nop + as_fn_error $? "ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system" "$LINENO" 5 + +fi + fi # set static linking for uninstalled libraries if requested @@ -25657,7 +25712,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h -version=1.25.2 +version=1.26.1 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5 printf %s "checking for build time... " >&6; } @@ -26187,7 +26242,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by unbound $as_me 1.25.2, which was +This file was extended by unbound $as_me 1.26.1, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -26255,7 +26310,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -unbound config.status 1.25.2 +unbound config.status 1.26.1 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 7cdf5803f..afedb889e 100644 --- a/configure.ac +++ b/configure.ac @@ -11,15 +11,15 @@ sinclude(dnscrypt/dnscrypt.m4) # must be numbers. ac_defun because of later processing m4_define([VERSION_MAJOR],[1]) -m4_define([VERSION_MINOR],[25]) -m4_define([VERSION_MICRO],[2]) +m4_define([VERSION_MINOR],[26]) +m4_define([VERSION_MICRO],[1]) AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound]) AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR]) AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR]) AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO]) LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=38 +LIBUNBOUND_REVISION=40 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -125,6 +125,8 @@ LIBUNBOUND_AGE=1 # 1.25.0 had 9:36:1 # 1.25.1 had 9:37:1 # 1.25.2 had 9:38:1 +# 1.26.0 had 9:39:1 +# 1.26.1 had 9:40:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -1080,7 +1082,7 @@ else AC_MSG_RESULT([no]) fi AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h openssl/core_names.h openssl/param_build.h],,, [AC_INCLUDES_DEFAULT]) -AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex]) +AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex OPENSSL_cleanup]) # these check_funcs need -lssl BAKLIBS="$LIBS" @@ -1747,6 +1749,22 @@ if test x_$withval = x_yes -o x_$withval != x_no; then AC_MSG_RESULT(no) ]) + AC_CHECK_DECL([CLOCK_MONOTONIC] + , [] + , [AC_MSG_ERROR([ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system])] + , [AC_INCLUDES_DEFAULT +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + ]) + fi # set static linking for uninstalled libraries if requested diff --git a/daemon/daemon.c b/daemon/daemon.c index aa90535f7..d9a2e6cdc 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -79,6 +79,7 @@ #include "util/tcp_conn_limit.h" #include "util/edns.h" #include "services/listen_dnsport.h" +#include "services/outside_network.h" #include "services/cache/rrset.h" #include "services/cache/infra.h" #include "services/localzone.h" @@ -837,6 +838,10 @@ daemon_create_workers(struct daemon* daemon) fatal_exit("out of memory during daemon init"); numport = daemon_get_shufport(daemon, shufport); verbose(VERB_ALGO, "total of %d outgoing ports available", numport); + if(!(daemon->shared_ports = shared_ports_create(daemon->cfg->out_ifs, + daemon->cfg->num_out_ifs, daemon->cfg->do_ip4, + daemon->cfg->do_ip6, shufport, numport))) + fatal_exit("could not setup shared ports: out of memory"); #ifdef HAVE_NGTCP2 if (cfg_has_quic(daemon->cfg)) { @@ -867,10 +872,7 @@ daemon_create_workers(struct daemon* daemon) #endif } for(i=0; inum; i++) { - if(!(daemon->workers[i] = worker_create(daemon, i, - shufport+numport*i/daemon->num, - numport*(i+1)/daemon->num - numport*i/daemon->num))) - /* the above is not ports/numthr, due to rounding */ + if(!(daemon->workers[i] = worker_create(daemon, i))) fatal_exit("could not create worker"); } /* create per-worker alloc caches if not reusing existing ones. */ @@ -1231,6 +1233,8 @@ daemon_cleanup(struct daemon* daemon) if(!daemon->reuse_cache || daemon->need_to_exit) daemon_clear_allocs(daemon); daemon->num = 0; + shared_ports_delete(daemon->shared_ports); + daemon->shared_ports = NULL; #ifdef USE_DNSTAP dt_delete(daemon->dtenv); daemon->dtenv = NULL; @@ -1317,6 +1321,9 @@ daemon_delete(struct daemon* daemon) # if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) ub_openssl_lock_delete(); # endif +#ifdef HAVE_OPENSSL_CLEANUP + OPENSSL_cleanup(); +#endif #ifndef HAVE_ARC4RANDOM _ARC4_LOCK_DESTROY(); #endif diff --git a/daemon/daemon.h b/daemon/daemon.h index 9965ed558..dad339940 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -63,6 +63,7 @@ struct cookie_secrets; struct fast_reload_thread; struct fast_reload_printq; struct auth_load_general_info; +struct shared_ports; #include "dnstap/dnstap_config.h" #ifdef USE_DNSTAP @@ -98,6 +99,8 @@ struct daemon { int rc_port; /** listening ports for remote control */ struct listen_port* rc_ports; + /** the shared ports structure, with random ports numbers. */ + struct shared_ports* shared_ports; /** remote control connections management (for first worker) */ struct daemon_remote* rc; /** ssl context for listening to dnstcp over ssl */ diff --git a/daemon/remote.c b/daemon/remote.c index 66aad5e6f..2ec4e1c5c 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1732,6 +1732,14 @@ do_view_data_add(RES* ssl, struct worker* worker, char* arg) ssl_printf(ssl,"error out of memory\n"); return; } + if(!v->isfirst) { + /* Global local-zone is not used for this view, + * therefore add defaults to this view-specific + * local-zone. */ + struct config_file lz_cfg; + memset(&lz_cfg, 0, sizeof(lz_cfg)); + local_zone_enter_defaults(v->local_zones, &lz_cfg); + } } do_data_add(ssl, v->local_zones, arg2); lock_rw_unlock(&v->lock); @@ -1757,6 +1765,14 @@ do_view_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker, ssl_printf(ssl,"error out of memory\n"); return; } + if(!v->isfirst) { + /* Global local-zone is not used for this view, + * therefore add defaults to this view-specific + * local-zone. */ + struct config_file lz_cfg; + memset(&lz_cfg, 0, sizeof(lz_cfg)); + local_zone_enter_defaults(v->local_zones, &lz_cfg); + } } /* put the view name in the command buf */ (void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg); @@ -2662,7 +2678,7 @@ static int ssl_print_name_dp(RES* ssl, const char* str, uint8_t* nm, uint16_t dclass, struct delegpt* dp) { - char buf[LDNS_MAX_DOMAINLEN]; + char buf[LDNS_MAX_DOMAINLEN], portstr[128], tls_auth_name[256]; struct delegpt_ns* ns; struct delegpt_addr* a; int f = 0; @@ -2677,13 +2693,32 @@ ssl_print_name_dp(RES* ssl, const char* str, uint8_t* nm, uint16_t dclass, } for(ns = dp->nslist; ns; ns = ns->next) { dname_str(ns->name, buf); - if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf)) + if(ns->port != UNBOUND_DNS_PORT) + snprintf(portstr, sizeof(portstr), "@%d", ns->port); + else portstr[0]=0; + if(ns->tls_auth_name) + snprintf(tls_auth_name, sizeof(tls_auth_name), "#%s", + ns->tls_auth_name); + else tls_auth_name[0]=0; + if(!ssl_printf(ssl, "%s%s%s%s", (f?" ":""), buf, portstr, + tls_auth_name)) return 0; f = 1; } for(a = dp->target_list; a; a = a->next_target) { + int port = (unsigned)((a->addr.ss_family == AF_INET) ? + ntohs(((struct sockaddr_in*)&a->addr)->sin_port) : + ntohs(((struct sockaddr_in6*)&a->addr)->sin6_port)); addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf)); - if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf)) + if(port != UNBOUND_DNS_PORT) + snprintf(portstr, sizeof(portstr), "@%d", port); + else portstr[0]=0; + if(a->tls_auth_name) + snprintf(tls_auth_name, sizeof(tls_auth_name), "#%s", + a->tls_auth_name); + else tls_auth_name[0]=0; + if(!ssl_printf(ssl, "%s%s%s%s", (f?" ":""), buf, portstr, + tls_auth_name)) return 0; f = 1; } @@ -4921,6 +4956,74 @@ fr_check_changed_cfg_str2list(struct config_str2list* cmp1, } } +/** fast reload thread, check if config str3list has changed. */ +#define FR_CHECK_CHANGED_CFG_STR3LIST(desc, var, buff) do { \ + fr_check_changed_cfg_str3list(cfg->var, newcfg->var, desc, buff,\ + sizeof(buff)); \ + } while(0); +static void +fr_check_changed_cfg_str3list(struct config_str3list* cmp1, + struct config_str3list* cmp2, const char* desc, char* str, size_t len) +{ + struct config_str3list* p1 = cmp1, *p2 = cmp2; + while(p1 && p2) { + if((!p1->str && p2->str) || + (p1->str && !p2->str) || + (p1->str && p2->str && strcmp(p1->str, p2->str) != 0)) { + /* The str3list is different. */ + fr_add_incompatible_option(desc, str, len); + return; + } + if((!p1->str2 && p2->str2) || + (p1->str2 && !p2->str2) || + (p1->str2 && p2->str2 && + strcmp(p1->str2, p2->str2) != 0)) { + /* The str3list is different. */ + fr_add_incompatible_option(desc, str, len); + return; + } + if((!p1->str3 && p2->str3) || + (p1->str3 && !p2->str3) || + (p1->str3 && p2->str3 && + strcmp(p1->str3, p2->str3) != 0)) { + /* The str3list is different. */ + fr_add_incompatible_option(desc, str, len); + return; + } + p1 = p1->next; + p2 = p2->next; + } + if((!p1 && p2) || (p1 && !p2)) { + fr_add_incompatible_option(desc, str, len); + } +} + +/** fast reload thread, check tag datas. */ +static int +fr_check_tag_datas(struct fast_reload_thread* fr, struct config_file* newcfg) +{ + char changed_str[1024]; + struct config_file* cfg = fr->worker->env.cfg; + changed_str[0]=0; + + /* Check for tag_datas in acl_addr. */ + FR_CHECK_CHANGED_CFG_STR3LIST("interface-tag-data", interface_tag_datas, changed_str); + FR_CHECK_CHANGED_CFG_STR3LIST("access-control-tag-data", acl_tag_datas, changed_str); + + if(changed_str[0] != 0) { + if(fr->fr_drop_mesh) + return 1; /* already dropping queries */ + fr->fr_drop_mesh = 1; + fr->worker->daemon->fast_reload_drop_mesh = fr->fr_drop_mesh; + if(!fr_output_printf(fr, "recursion referenced data has changed, with: '%s" + "', and the queries have to be dropped" + ", setting '+d'\n", changed_str)) + return 0; + fr_send_notification(fr, fast_reload_notification_printout); + } + return 1; +} + /** fast reload thread, check compatible config items */ static int fr_check_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg) @@ -6807,6 +6910,10 @@ fr_load_config(struct fast_reload_thread* fr, struct timeval* time_read, config_delete(newcfg); return 0; } + if(!fr_check_tag_datas(fr, newcfg)) { + config_delete(newcfg); + return 0; + } if(!fr_check_compat_cfg(fr, newcfg)) { config_delete(newcfg); return 0; diff --git a/daemon/worker.c b/daemon/worker.c index 7d76ffee0..5cc586442 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1555,6 +1555,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, return 0; } query_error(c->buffer, LDNS_RCODE_FORMERR, 0); + sldns_buffer_copy(c->dnscrypt_buffer, c->buffer); return 1; } dname_str(qinfo.qname, buf); @@ -1573,6 +1574,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, query_error(c->buffer, LDNS_RCODE_SERVFAIL, qinfo.qname_len); worker->stats.num_query_dnscrypt_cleartext++; + sldns_buffer_copy(c->dnscrypt_buffer, c->buffer); return 1; } worker->stats.num_query_dnscrypt_cert++; @@ -1833,7 +1835,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error, server_stats_insquery(&worker->stats, c, qinfo.qtype, qinfo.qclass, &edns, repinfo); if(c->type != comm_udp) +#ifdef USE_DNSCRYPT + edns.udp_size = (c->dnscrypt && repinfo->is_dnscrypted) + ? sldns_buffer_capacity(c->buffer) - DNSCRYPT_REPLY_HEADER_SIZE + : 65535; +#else edns.udp_size = 65535; /* max size for TCP replies */ +#endif if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, &edns, repinfo, c->buffer)) { regional_free_all(worker->scratchpad); @@ -2121,7 +2129,7 @@ send_reply_rc: } } #ifdef USE_DNSCRYPT - if(!dnsc_handle_uncurved_request(repinfo)) { + if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) { return 0; } #endif @@ -2234,23 +2242,16 @@ void worker_probe_timer_cb(void* arg) } struct worker* -worker_create(struct daemon* daemon, int id, int* ports, int n) +worker_create(struct daemon* daemon, int id) { unsigned int seed; struct worker* worker = (struct worker*)calloc(1, sizeof(struct worker)); if(!worker) return NULL; - worker->numports = n; - worker->ports = (int*)memdup(ports, sizeof(int)*n); - if(!worker->ports) { - free(worker); - return NULL; - } worker->daemon = daemon; worker->thread_num = id; if(!(worker->cmd = tube_create())) { - free(worker->ports); free(worker); return NULL; } @@ -2258,7 +2259,6 @@ worker_create(struct daemon* daemon, int id, int* ports, int n) if(!(worker->rndstate = ub_initstate(daemon->rand))) { log_err("could not init random numbers."); tube_delete(worker->cmd); - free(worker->ports); free(worker); return NULL; } @@ -2357,14 +2357,14 @@ worker_init(struct worker* worker, struct config_file *cfg, cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, worker->daemon->env->infra_cache, worker->rndstate, - cfg->use_caps_bits_for_id, worker->ports, worker->numports, + cfg->use_caps_bits_for_id, cfg->unwanted_threshold, cfg->outgoing_tcp_mss, &worker_alloc_cleanup, worker, cfg->do_udp || cfg->udp_upstream_without_downstream, worker->daemon->connect_dot_sslctx, cfg->delay_close, cfg->tls_use_sni, dtenv, cfg->udp_connect, cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout, - cfg->tcp_auth_query_timeout); + cfg->tcp_auth_query_timeout, worker->daemon->shared_ports); if(!worker->back) { log_err("could not create outgoing sockets"); worker_delete(worker); @@ -2517,7 +2517,6 @@ worker_delete(struct worker* worker) tube_delete(worker->cmd); comm_timer_delete(worker->stat_timer); comm_timer_delete(worker->env.probe_timer); - free(worker->ports); if(worker->thread_num == 0) { #ifdef UB_ON_WINDOWS wsvc_desetup_worker(worker); @@ -2653,6 +2652,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), log_assert(0); } +void libworker_alloc_cleanup(void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) { log_assert(0); diff --git a/daemon/worker.h b/daemon/worker.h index b7bb52fd7..37f3728ef 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -104,10 +104,6 @@ struct worker { struct listen_dnsport* front; /** the backside outside network interface to the auth servers */ struct outside_network* back; - /** ports to be used by this worker. */ - int* ports; - /** number of ports for this worker */ - int numports; /** the signal handler */ struct comm_signal* comsig; /** commpoint to listen to commands. */ @@ -146,11 +142,9 @@ struct worker { * with backpointers only. Use worker_init on it later. * @param daemon: the daemon that this worker thread is part of. * @param id: the thread number from 0.. numthreads-1. - * @param ports: the ports it is allowed to use, array. - * @param n: the number of ports. * @return: the new worker or NULL on alloc failure. */ -struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n); +struct worker* worker_create(struct daemon* daemon, int id); /** * Initialize worker. diff --git a/dnscrypt/dnscrypt.c b/dnscrypt/dnscrypt.c index c4289dd68..fb7dff861 100644 --- a/dnscrypt/dnscrypt.c +++ b/dnscrypt/dnscrypt.c @@ -474,10 +474,18 @@ dnscrypt_server_curve(const dnsccert *cert, uint8_t *const buf = sldns_buffer_begin(buffer); size_t len = sldns_buffer_limit(buffer); + if(len + DNSCRYPT_REPLY_HEADER_SIZE > sldns_buffer_capacity(buffer)) + return -1; + sldns_buffer_clear(buffer); + if(udp){ if (max_len > max_reply_size) max_len = max_reply_size; } + if(max_len > sldns_buffer_capacity(buffer)) + max_len = sldns_buffer_capacity(buffer); + if(max_len > 65535) + max_len = 65535; memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES); @@ -520,6 +528,7 @@ dnscrypt_server_curve(const dnsccert *cert, DNSCRYPT_MAGIC_HEADER_LEN, nonce, crypto_box_NONCEBYTES); + sldns_buffer_flip(buffer); sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE); return 0; } @@ -663,6 +672,8 @@ dnsc_find_cert(struct dnsc_env* dnscenv, struct sldns_buffer* buffer) } dnscrypt_header = (struct dnscrypt_query_header *)sldns_buffer_begin(buffer); for (i = 0U; i < dnscenv->signed_certs_count; i++) { + if(!certs[i].keypair) + continue; if (memcmp(certs[i].magic_query, dnscrypt_header->magic_query, DNSCRYPT_MAGIC_HEADER_LEN) == 0) { return &certs[i]; @@ -804,6 +815,7 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg) sizeof *env->keypairs); env->certs = sodium_allocarray(env->signed_certs_count, sizeof *env->certs); + memset(env->certs, 0, env->signed_certs_count * sizeof(*env->certs)); cert_id = 0U; keypair_id = 0U; @@ -919,12 +931,13 @@ dnsc_handle_curved_request(struct dnsc_env* dnscenv, } int -dnsc_handle_uncurved_request(struct comm_reply *repinfo) +dnsc_handle_uncurved_request(struct comm_reply *repinfo, + struct sldns_buffer* buffer) { if(!repinfo->c->dnscrypt) { return 1; } - sldns_buffer_copy(repinfo->c->dnscrypt_buffer, repinfo->c->buffer); + sldns_buffer_copy(repinfo->c->dnscrypt_buffer, buffer); if(!repinfo->is_dnscrypted) { return 1; } @@ -970,12 +983,19 @@ dnsc_create(void) int dnsc_apply_cfg(struct dnsc_env *env, struct config_file *cfg) { + int nkeys; if(dnsc_parse_certs(env, cfg) <= 0) { fatal_exit("dnsc_apply_cfg: no cert file loaded"); } - if(dnsc_parse_keys(env, cfg) <= 0) { + nkeys = dnsc_parse_keys(env, cfg); + if(nkeys <= 0) { fatal_exit("dnsc_apply_cfg: no key file loaded"); } + if((size_t)nkeys < env->signed_certs_count) { + fatal_exit("dnsc_apply_cfg: %u dnscrypt-provider-cert file(s) have no " + "matching dnscrypt-secret-key", + (unsigned)(env->signed_certs_count - (size_t)nkeys)); + } randombytes_buf(env->hash_key, sizeof env->hash_key); env->provider_name = cfg->dnscrypt_provider; diff --git a/dnscrypt/dnscrypt.h b/dnscrypt/dnscrypt.h index b0da9b732..998237d48 100644 --- a/dnscrypt/dnscrypt.h +++ b/dnscrypt/dnscrypt.h @@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv, * \return 0 in case of failure. */ -int dnsc_handle_uncurved_request(struct comm_reply *repinfo); +int dnsc_handle_uncurved_request(struct comm_reply *repinfo, + struct sldns_buffer* buffer); /** * Computes the size of the shared secret cache entry. diff --git a/dnstap/unbound-dnstap-socket.c b/dnstap/unbound-dnstap-socket.c index d6d5e2a7e..2b9ab9528 100644 --- a/dnstap/unbound-dnstap-socket.c +++ b/dnstap/unbound-dnstap-socket.c @@ -1737,6 +1737,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), log_assert(0); } +void libworker_alloc_cleanup(void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) { log_assert(0); diff --git a/doc/Changelog b/doc/Changelog index 348c4e01c..25a43cfd6 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,213 @@ +7 August 2026: Wouter + - Fix #1489 from jplesnik: Replace removed Python 2 C API + macros for SWIG 4.5.0 compatibility. + +6 August 2026: Alex Khanin + - Fix #1488: bounds check in packed_rr_to_string, it checked + the assembled rr length against the output string length + dest_len, instead of against the size of the rr buffer it + writes into. Callers in cachedump.c and remote.c pass a + dest_len larger than that buffer. + - Unit test for packed_rr_to_string. + +6 August 2026: Wouter + - Fix #1485: the list_forwards command omits port numbers. + The list_forwards and list_stubs commands for + unbound-control print port and tls auth name. + - Fix #1487: regression in 1.26.0, ipsecmod is now always + partly enabled. + +4 August 2026: Wouter + - Fix to set makedist.sh to not wget config.sub and + config.guess from git repo. The fetch times out, and the + version from libtoolize is much more recent now than + that it was when the wget was added. + +31 July 2026: Wouter + - For #1483: The failure reason when an NSEC NXDOMAIN is + encountered when looking for an insecure delegation, is + fixed to mention the NSEC records, instead of nonexistent + NSEC3 records, that it attempted. + +30 July 2026: Wouter + - Fix #1482: DNS-over-QUIC doesn't work with simple config. + That fixes interface-automatic for use with doq service. + +28 July 2026: Wouter + - Tag for 1.26.0rc1. The repo continues with version 1.26.1. + This became 1.26.0 on 4 aug 2026. + +24 July 2026: Wouter + - Merge #1433 from jisakiel: Add new static zone type + block_aaaa to suppress AAAA queries. + - Unit test for block_a and block_aaaa. + - Fix #1477: respip + dns64: dns64 uses A records modified by + respip instead of original A records. Adds local-zone types + block_a_wdata and block_aaaa_wdata, that are like block_a + and block_aaaa, and uses local-data if present. + - set code repository version to 1.26.0. + - Update generated man pages. + - Fix to allow test fake sha1 on systems with possible sha1 + support. + - Fix to use sha256 for unbound-anchor unit test. + - Fix unbound-anchor check for return value of + X509_NAME_get_text_by_NID of the emailaddress. + - Fix lock test protect for auth zone change. + - Fix to lock shared_ports structure during initialisation. + - Fix to lock anchor structure when file is set for it in + parse of the header. + - Merge #1480 from petrvaganoff: authzone: fix memory leak in + xfer_set_masters() error path. + - Fix unused variable warnings in shared_ports_fetch_random + and shared_ports_return_port when compiled without threads. + - Fix to guard access to shared ports interface array during + set up, for analyzer. + - Fix sign of comparison warning in shared ports setup. + - Fix #1481: Fix to use tls-port after referral if + tls-upstream is set. + - Merge #1479 from psumbera: Fix pthread detection on + Solaris 11.4. + - Fix to call OPENSSL_cleanup on exit when that is defined. + +23 July 2026: Wouter + - Updated credits for Xuanchao Xie in 22 july changelog. + - Merge #1478 from petrvaganoff: pythonmod: add check return + value after ftell(). + - Fix that for NSEC3 proofs the NSEC3 zone, as the b32.name is + checked to be the same as the signer name. Also RRSIGs are + not considered valid when an NSEC3 is not b32.signerzone. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that the aggressive negative cache does not insert NSEC + records with overreaching next owner name. Also the result + is not above the trust anchor's bailiwick. Also RRSIGS are + not considered valid when an NSEC next owner name is not + under the signer zone name. Thanks to Qifan Zhang, Palo + Alto Networks, for the report. + - Fix mesh cycle detection for configuration with respip CNAME + loop and tagged clients. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + +22 July 2026: Wouter + - Release tag for 1.25.2, with the security commits: + - Fix CVE-2026-14586, Assertion in libngtcp2 when under pressure + in high concurrency DNS-over-QUIC environments. Thanks to Kunta + Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University, + for the report. + - Fix CVE-2026-32665, Remote DNS-over-QUIC denial of + service due to `quic-size` budget bypass. Thanks to N0zoM1z0 + (https://github.com/N0zoM1z0) for the report. In addition, thanks to + Kunta Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University, + for also reporting this issue. In addition, thanks to Qifan Zhang, + Palo Alto Networks, for also reporting this issue. In addition, + thanks to Xuanchao Xie, Lutong Chen, and Kaiping Xue of the + University of Science and Technology of China (USTC), for also + reporting this issue. + - Fix CVE-2026-40691, Packet of death for DNSCrypt over TCP. Thanks + to Qifan Zhang, Palo Alto Networks, for the report. In addition, + thanks to Trung Nguyen (@everping) of CyStack, for also reporting + this issue. + - Fix CVE-2026-41637, Degradation of resolution service from + improperly accounted client-terminated DNS-over-QUIC queries. Thanks + to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-42955, Extra fix for CVE-2026-40622 to also clamp + the TTL of A/AAAA records disallowing a one-time 'ghost domain' + delegation renewal via glue records. Thanks to Qifan Zhang, Palo + Alto Networks, for the report. + - Fix CVE-2026-44621, Libunbound applications configured with + 'unwanted-reply-threshold' could eventually be abruptly + terminated. Thanks to Qifan Zhang, Palo Alto Networks, for the + report. + - Fix CVE-2026-44687, Off-by-one error in 'harden-below-nxdomain' + logic can shadow a stub/forward zone by a legitimate parent's + NXDOMAIN. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-44690, Cross-zone wildcard cache poisoning via + RRSIG.labels manipulation. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix CVE-2026-46582, A wildcard replay, as another piece of data, + triggers poisoning in the serve expired reply path. Thanks to + Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-50045, 'max-global-quota' reset by DNSSEC validation + restarts. Thanks to Kunjie Shang, University of Science and + Technology of China, for the report. + - Fix CVE-2026-50046, Possible heap use-after-free in an error path + when a DoT forwarded query is jostled out. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix CVE-2026-50243, 'response-ip'/'rpz' can rewrite BOGUS answers + instead of returning SERVFAIL. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix CVE-2026-50248, BOGUS configured primary hostname accepted for + XFR in auth/rpz zones. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix CVE-2026-50251, Attacker supplied `0.0.0.0`/`::` glue triggers + defensive full-cache flush. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix CVE-2026-50252, Possible cache poisoning attack by mapping + source port population per thread. Thanks to Inbal Schussheim and + Amit Klein, Hebrew University, for the report. + - Fix CVE-2026-52863, Memory corruption could lead to crash and + denial of service. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix CVE-2026-54478, DNS Cookie bypass when combined with + proxy-protocol use. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix CVE-2026-55708, Privacy/configuration issue when adding local + data in views through 'unbound-control'. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix CVE-2026-55717, 'serve-expired-client-timeout' and 'response-ip' + CNAME redirect could lead to a crash. Thanks to Qifan Zhang, Palo + Alto Networks, for the report. In addition, thanks to Xin Wang, + Jiapeng Li, and Jiajia Liu, Northwestern Polytechnical University, + for also reporting this issue. + - Fix CVE-2026-55973, 'dns-error-reporting: yes' leads to stack buffer + overflow. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-55990, Packet of death for a DNSCrypt misconfigured + Unbound. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-55991, Remote DNS-over-QUIC (DoQ) flow-control + assertion failure in libngtcp2. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. In addition, thanks to Xuanchao Xie, + Lutong Chen, and Kaiping Xue of the University of Science and + Technology of China (USTC), for also reporting this issue. + - Fix CVE-2026-56416, Possible heap buffer overflow when validator + canonicalizes RDATA that contains domain name. Thanks to Qifan + Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-56444, Degradation of resolution service when + 'discard-timeout' and 'serve-expired-client-timeout' are combined in + unusual configuration. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. In addition, thanks to Xin Wang, Jiapeng Li, + and Jiajia Liu, Northwestern Polytechnical University, for also + reporting this issue. In addition, thanks to Haruki Oyama (Waseda + University), for also reporting this issue. + - Set the repository to 1.25.3, it continues with the previous + changes. + - Unit test for CVE-2026-42955. + - Unit test for CVE-2026-44687. + - Unit test for CVE-2026-44690. + - Unit test for CVE-2026-46582. + - Unit test for CVE-2026-50045. + - Unit test for CVE-2026-50243. + - Unit test for CVE-2026-50248. + - Unit test for CVE-2026-55717. + - Unit test for CVE-2026-55973. + - Unit test for CVE-2026-56416. + - Fix error in log printout in fix for CVE-2026-50248, when the + primary name is bogus. + - iana portlist update. + +21 July 2026: Wouter + - Merge #1476 from petrvaganoff: ipsecmod: fix possible deref + on null after reply_find_answer_rrset(). + +20 July 2026: Wouter + - Merge #1475 from petrvaganoff: ipsecmod: fix deref on null + in ipsecmod-whitelist after OOM. + - Fix #1474: DoQ responses are never padded - pad-responses + does not apply to comm_doq (RFC 9250 ยง5.4 MUST). + +9 July 2026: Wouter + - Merge #1383 from jdek: Fix randomness generation on + macOS/iOS under chroot. + - Fix unit test for malformed svcb for test on Windows. + 2 July 2026: Wouter - Merge #1087: Overload `local_data_remove` to support removing specific records. diff --git a/doc/example.conf.in b/doc/example.conf.in index 5250ef456..c5e4e242e 100644 --- a/doc/example.conf.in +++ b/doc/example.conf.in @@ -899,6 +899,10 @@ server: # that name # o block_a resolves all records normally but returns # NODATA for A queries and ignores local data for that name + # o block_aaaa similarly to block_a, resolves all records normally but + # returns NODATA for AAAA queries and ignores local data for that name + # o block_a_wdata like block_a but uses local data if present. + # o block_aaaa_wdata like block_aaaa but uses local data if present. # o always_null returns 0.0.0.0 or ::0 for any name in the zone. # o noview breaks out of that view towards global local-zones. # diff --git a/doc/unbound-control.8.in b/doc/unbound-control.8.in index e07684019..5743d09b4 100644 --- a/doc/unbound-control.8.in +++ b/doc/unbound-control.8.in @@ -354,6 +354,8 @@ If the name already has no items, nothing happens. Often results in NXDOMAIN for the name (in a static zone), but if the name has become an empty nonterminal (there is still data in domain names below the removed name), NOERROR nodata answers are the result for that name. +With a specific RR instead of a domain name, that specific record is +removed from the local data, and not all the RR data. .UNINDENT .INDENT 0.0 .TP diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in index 25fcca373..54116af23 100644 --- a/doc/unbound.conf.5.in +++ b/doc/unbound.conf.5.in @@ -691,7 +691,7 @@ Default: 0 (use system value) .TP .B so\-sndbuf: \fI\fP If not 0, then set the SO_SNDBUF socket option to get more buffer space on -UDP port 53 outgoing queries. +UDP port 53 outgoing responses. This for very busy servers handles spikes in answer traffic, otherwise: .INDENT 7.0 .INDENT 3.5 @@ -2312,6 +2312,13 @@ The defensive action is to clear the rrset and message caches, hopefully flushing away any poison. A value of 10 million is suggested. .sp +It is useful to add 0.0.0.0/8 and \(aq::\(aq to the +\fI\%do\-not\-query\-address\fP list. +Otherwise they may be answered, from localhost, and the different source +makes an unwanted reply that unnecessarily ticks up. +The \fI\%do\-not\-query\-localhost\fP +option includes them, the zero subnets, when it is enabled. +.sp Default: 0 (disabled) .UNINDENT .INDENT 0.0 @@ -2362,6 +2369,8 @@ If yes, deny queries of type ANY with an empty response. If disabled, Unbound responds with a short list of resource records if some can be found in the cache and makes the upstream type ANY query if there are none. +The option stops the DNSSEC validation from processing, possibly lengthy, +ANY responses, when the option is enabled. .sp Default: no .UNINDENT @@ -2910,6 +2919,9 @@ The types are \fI\%inform_redirect\fP, \fI\%always_transparent\fP, \fI\%block_a\fP, +\fI\%block_aaaa\fP, +\fI\%block_a_wdata\fP, +\fI\%block_aaaa_wdata\fP, \fI\%always_refuse\fP, \fI\%always_nxdomain\fP, \fI\%always_null\fP, @@ -3100,6 +3112,32 @@ use IPv6 protocol and avoid any queries to IPv4. .UNINDENT .INDENT 7.0 .TP +.B block_aaaa +Like \fI\%transparent\fP or +\fI\%block_a\fP, but +ignores local data and resolves normally all query types excluding AAAA. +For AAAA queries it unconditionally returns NODATA. +Useful in cases when there is a need to explicitly force all apps to +use IPv4 protocol and avoid any queries to IPv6. +.UNINDENT +.INDENT 7.0 +.TP +.B block_a_wdata +Like \fI\%block_a\fP, but +uses local data if present. +If there is local data that is returned, and it acts like transparent. +For A queries it returns NODATA. +.UNINDENT +.INDENT 7.0 +.TP +.B block_aaaa_wdata +Like \fI\%block_aaaa\fP, but +uses local data if present. +If there is local data that is returned, and it acts like transparent. +For AAAA queries it returns NODATA. +.UNINDENT +.INDENT 7.0 +.TP .B always_refuse Like \fI\%refuse\fP, but ignores local data and refuses the query. @@ -3567,6 +3605,18 @@ For example, 1000 may be a suitable value to stop the server from being overloaded with random names, and keeps unbound from sending traffic to the nameservers for those zones. .sp +It is intended to count the number of queries towards the nameservers +for the zone, and keep those queries limited. +When there is a delegation that needs a lot of lookups, those are +charged in the counters for the destination, the target name, of +the NS records. +Since that is where the nameserver lookup queries are sent to. +That keeps the target, the victim domain, from having many queries. +With the \fI\%ratelimit\-factor\fP, some +genuine queries that are also made to the target zone, can filter +through, and then end up in cache, where the genuine answers have +a chance to collect, keeping up service to some extent. +.sp \fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 @@ -4594,6 +4644,32 @@ If not given then no zonefile is used. If the file does not exist or is empty, Unbound will attempt to fetch zone data (eg. from the primary servers). .UNINDENT +.INDENT 0.0 +.TP +.B max\-transfer\-size: \fI\fP +Number of bytes size of the maximum zone transfer size. +Larger transfers, over AXFR, IXFR and HTTP, are not allowed. +A plain number is in bytes, append \(aqk\(aq, \(aqm\(aq or \(aqg\(aq for kilobytes, megabytes +or gigabytes (1024*1024 bytes in a megabyte). +The value \fB0\fP disables the feature. +.sp +Only consider for untrusted/misbehaving primaries that could hog resources +and bring down the resolver. +.sp +Default: 0 +.UNINDENT +.INDENT 0.0 +.TP +.B max\-transfer\-time: \fI\fP +Maximum time in milliseconds that a zone transfer is allowed to take from +the start. +The value \fB0\fP disables the feature. +.sp +Only consider for untrusted/misbehaving primaries that could hog resources +and bring down the resolver. +.sp +Default: 0 +.UNINDENT .SH VIEW OPTIONS .sp These options are part of the \fBview:\fP section. @@ -5806,6 +5882,10 @@ from a webserver that would work. If you specify the hostname, you cannot use the domain from the zonefile, because it may not have that when retrieving that data, instead use a plain IP address to avoid a circular dependency on retrieving that IP address. +.sp +Every number of IXFR transfers, a full AXFR is performed. +This is to consolidate the rpz memory, that would otherwise grow. +The fixed value is after 5 IXFR transfers. .UNINDENT .INDENT 0.0 .TP @@ -5928,6 +6008,32 @@ Enclose list of tags in quotes (\fB\(dq\(dq\fP) and put spaces between tags. If no tags are specified the policies from this section will be applied for all clients. .UNINDENT +.INDENT 0.0 +.TP +.B max\-transfer\-size: \fI\fP +Number of bytes size of the maximum zone transfer size. +Larger transfers, over AXFR, IXFR and HTTP, are not allowed. +A plain number is in bytes, append \(aqk\(aq, \(aqm\(aq or \(aqg\(aq for kilobytes, megabytes +or gigabytes (1024*1024 bytes in a megabyte). +The value \fB0\fP disables the feature. +.sp +Only consider for untrusted/misbehaving primaries that could hog resources +and bring down the resolver. +.sp +Default: 0 +.UNINDENT +.INDENT 0.0 +.TP +.B max\-transfer\-time: \fI\fP +Maximum time in milliseconds that a zone transfer is allowed to take from +the start. +The value \fB0\fP disables the feature. +.sp +Only consider for untrusted/misbehaving primaries that could hog resources +and bring down the resolver. +.sp +Default: 0 +.UNINDENT .SH MEMORY CONTROL EXAMPLE .sp In the example config settings below memory usage is reduced. diff --git a/doc/unbound.conf.rst b/doc/unbound.conf.rst index b96f1722b..e341c516f 100644 --- a/doc/unbound.conf.rst +++ b/doc/unbound.conf.rst @@ -2055,6 +2055,13 @@ These options are part of the ``server:`` section. flushing away any poison. A value of 10 million is suggested. + It is useful to add 0.0.0.0/8 and '::' to the + :ref:`do-not-query-address` list. + Otherwise they may be answered, from localhost, and the different source + makes an unwanted reply that unnecessarily ticks up. + The :ref:`do-not-query-localhost` + option includes them, the zero subnets, when it is enabled. + Default: 0 (disabled) @@ -2585,6 +2592,9 @@ These options are part of the ``server:`` section. :ref:`inform_redirect`, :ref:`always_transparent`, :ref:`block_a`, + :ref:`block_aaaa`, + :ref:`block_a_wdata`, + :ref:`block_aaaa_wdata`, :ref:`always_refuse`, :ref:`always_nxdomain`, :ref:`always_null`, @@ -2734,6 +2744,26 @@ These options are part of the ``server:`` section. Useful in cases when there is a need to explicitly force all apps to use IPv6 protocol and avoid any queries to IPv4. + @@UAHL@unbound.conf.local-zone.type@block_aaaa@@ + Like :ref:`transparent` or + :ref:`block_a`, but + ignores local data and resolves normally all query types excluding AAAA. + For AAAA queries it unconditionally returns NODATA. + Useful in cases when there is a need to explicitly force all apps to + use IPv4 protocol and avoid any queries to IPv6. + + @@UAHL@unbound.conf.local-zone.type@block_a_wdata@@ + Like :ref:`block_a`, but + uses local data if present. + If there is local data that is returned, and it acts like transparent. + For A queries it returns NODATA. + + @@UAHL@unbound.conf.local-zone.type@block_aaaa_wdata@@ + Like :ref:`block_aaaa`, but + uses local data if present. + If there is local data that is returned, and it acts like transparent. + For AAAA queries it returns NODATA. + @@UAHL@unbound.conf.local-zone.type@always_refuse@@ Like :ref:`refuse`, but ignores local data and refuses the query. diff --git a/ipsecmod/ipsecmod-whitelist.c b/ipsecmod/ipsecmod-whitelist.c index c2b1f5d4a..0ff59145f 100644 --- a/ipsecmod/ipsecmod-whitelist.c +++ b/ipsecmod/ipsecmod-whitelist.c @@ -100,6 +100,8 @@ ipsecmod_whitelist_apply_cfg(struct ipsecmod_env* ie, struct config_file* cfg) { ie->whitelist = rbtree_create(name_tree_compare); + if (!ie->whitelist) + return 0; if(!read_whitelist(ie->whitelist, cfg)) return 0; name_tree_init_parents(ie->whitelist); diff --git a/ipsecmod/ipsecmod.c b/ipsecmod/ipsecmod.c index 2c146a775..71b42f180 100644 --- a/ipsecmod/ipsecmod.c +++ b/ipsecmod/ipsecmod.c @@ -59,6 +59,11 @@ static int ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg) { + if(cfg->ipsecmod_whitelist && + !ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg)) + return 0; + if(!cfg->ipsecmod_enabled) + return 1; if(!cfg->ipsecmod_hook || (cfg->ipsecmod_hook && !cfg->ipsecmod_hook[0])) { log_err("ipsecmod: missing ipsecmod-hook."); return 0; @@ -68,9 +73,6 @@ ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg) cfg->ipsecmod_hook, strerror(errno)); return 0; } - if(cfg->ipsecmod_whitelist && - !ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg)) - return 0; return 1; } @@ -294,6 +296,10 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq, rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo, qstate->return_msg->rep); + if(!rrset_key) { + log_err("ipsecmod: could not find answer rrset for A/AAAA"); + return 0; + } /* Double check that the records are indeed A/AAAA. * This should never happen as this function is only executed for A/AAAA * queries but make sure we don't pass anything other than A/AAAA to the @@ -475,6 +481,12 @@ ipsecmod_handle_query(struct module_qstate* qstate, * ipsecmod_max_ttl. */ rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo, qstate->return_msg->rep); + if(!rrset_key) { + log_err("ipsecmod: reply-find-answer failed"); + errinf(qstate, "ipsecmod: reply-find-answer failed"); + ipsecmod_error(qstate, id); + return; + } rrset_data = (struct packed_rrset_data*)rrset_key->entry.data; if(rrset_data->ttl > (time_t)qstate->env->cfg->ipsecmod_max_ttl) { /* Update TTL for rrset to fixed value. */ @@ -616,6 +628,8 @@ ipsecmod_inform_super(struct module_qstate* qstate, int id, verbose(VERB_ALGO, "super has no ipsecmod state"); return; } + if(!siq->enabled) + return; if(qstate->return_msg) { struct ub_packed_rrset_key* rrset_key = reply_find_answer_rrset( diff --git a/iterator/iter_delegpt.c b/iterator/iter_delegpt.c index 6ba12c443..f0f94cadd 100644 --- a/iterator/iter_delegpt.c +++ b/iterator/iter_delegpt.c @@ -412,7 +412,7 @@ find_NS(struct reply_info* rep, size_t from, size_t to, uint16_t qclass) } struct delegpt* -delegpt_from_message(struct dns_msg* msg, struct regional* region) +delegpt_from_message(struct dns_msg* msg, struct regional* region, int port) { struct ub_packed_rrset_key* ns_rrset = NULL; struct delegpt* dp; @@ -441,7 +441,7 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region) dp->has_parent_side_NS = 1; /* created from message */ if(!delegpt_set_name(dp, region, ns_rrset->rk.dname)) return NULL; - if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0)) + if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0, port)) return NULL; /* add glue, A and AAAA in answer and additional section */ @@ -467,7 +467,7 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region) int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ns_rrset, uint8_t lame) + struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port) { struct packed_rrset_data* nsdata = (struct packed_rrset_data*) ns_rrset->entry.data; @@ -482,7 +482,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, continue; /* bad format */ /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame, - NULL, UNBOUND_DNS_PORT)) + NULL, (port==-1?UNBOUND_DNS_PORT:port))) return 0; } return 1; @@ -541,7 +541,7 @@ delegpt_add_rrset(struct delegpt* dp, struct regional* region, if(!rrset) return 1; if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) - return delegpt_rrset_add_ns(dp, region, rrset, lame); + return delegpt_rrset_add_ns(dp, region, rrset, lame, -1); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) return delegpt_add_rrset_A(dp, region, rrset, lame, additions); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) diff --git a/iterator/iter_delegpt.h b/iterator/iter_delegpt.h index 287bf9213..db15277fc 100644 --- a/iterator/iter_delegpt.h +++ b/iterator/iter_delegpt.h @@ -221,10 +221,11 @@ int delegpt_add_ns(struct delegpt* dp, struct regional* regional, * @param regional: where to allocate the info. * @param ns_rrset: NS rrset. * @param lame: rrset is lame, disprefer it. + * @param port: port or -1 if not set. * @return 0 on alloc error. */ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* ns_rrset, uint8_t lame); + struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port); /** * Add target address to the delegation point. @@ -365,11 +366,12 @@ size_t delegpt_count_targets(struct delegpt* dp); * * @param msg: the dns message, referral. * @param regional: where to allocate delegation point. + * @param port: if not -1 specifies a port number. * @return new delegation point or NULL on alloc error, or if the * message was not appropriate. */ struct delegpt* delegpt_from_message(struct dns_msg* msg, - struct regional* regional); + struct regional* regional, int port); /** * Mark negative return in delegation point for specific nameserver. diff --git a/iterator/iter_donotq.c b/iterator/iter_donotq.c index 40ffb45c4..7eecf1354 100644 --- a/iterator/iter_donotq.c +++ b/iterator/iter_donotq.c @@ -132,6 +132,18 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg) if(cfg->do_ip6) { if(!donotq_str_cfg(dq, "::1")) return 0; + if(!donotq_str_cfg(dq, "::ffff:127.0.0.0/104")) + return 0; + } + /* RFC 1122 3.2.1.3 / RFC 6890 / RFC 4291 2.5.2: not valid as + * destination; on Linux these route to the local host. */ + if(!donotq_str_cfg(dq, "0.0.0.0/8")) + return 0; + if(cfg->do_ip6) { + if(!donotq_str_cfg(dq, "::")) + return 0; + if(!donotq_str_cfg(dq, "::ffff:0:0/96")) + return 0; } } addr_tree_init_parents(&dq->tree); diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index cc09fa524..e848e83ba 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -1313,7 +1313,8 @@ iter_lookup_parent_NS_from_cache(struct module_env* env, struct delegpt* dp, log_rrset_key(VERB_ALGO, "found parent-side NS in cache", akey); dp->has_parent_side_NS = 1; /* and mark the new names as lame */ - if(!delegpt_rrset_add_ns(dp, region, akey, 1)) { + if(!delegpt_rrset_add_ns(dp, region, akey, 1, + deleg_port_number(env))) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -1703,3 +1704,11 @@ iter_make_minimal(struct reply_info* rep) rep->ar_numrrsets = 0; rep->rrset_count -= rem; } + +int +deleg_port_number(struct module_env* env) +{ + if(env->cfg->ssl_upstream) + return env->cfg->ssl_port; + return -1; +} diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index f7f374742..9fb361ab5 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -483,4 +483,7 @@ void limit_nsec_ttl(struct dns_msg* msg); */ void iter_make_minimal(struct reply_info* rep); +/** See if we need a different port number */ +int deleg_port_number(struct module_env* env); + #endif /* ITERATOR_ITER_UTILS_H */ diff --git a/iterator/iterator.c b/iterator/iterator.c index 3b81b1385..cadb95ebd 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -81,7 +81,8 @@ int BLACKLIST_PENALTY = (120000*4); /** Timeout when only a single probe query per IP is allowed. */ int PROBE_MAXRTO = PROBE_MAXRTO_DEFAULT; /* in msec */ -static void target_count_increase_nx(struct iter_qstate* iq, int num); +static void target_count_increase_nx(struct module_qstate* qstate, + struct iter_qstate* iq, int num); int iter_init(struct module_env* env, int id) @@ -250,7 +251,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super) if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) && (dpns->got6 == 2 || !ie->supports_ipv6)) { dpns->resolved = 1; /* mark as failed */ - target_count_increase_nx(super_iq, 1); + target_count_increase_nx(super, super_iq, 1); } } if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) { @@ -734,7 +735,7 @@ is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq) * created for the parent query. */ static void -target_count_create(struct iter_qstate* iq) +target_count_create(struct module_qstate* qstate, struct iter_qstate* iq) { if(!iq->target_count) { iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int)); @@ -742,33 +743,57 @@ target_count_create(struct iter_qstate* iq) if(iq->target_count) { iq->target_count[TARGET_COUNT_REF] = 1; iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*)); + /* continue global quota from where it was. */ + if(qstate->global_quota_reached > + iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]) + iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] = + qstate->global_quota_reached; } } } static void -target_count_increase(struct iter_qstate* iq, int num) +target_count_store(struct module_qstate* qstate, struct iter_qstate* iq) { - target_count_create(iq); + if(iq->target_count) { + /* By storing the global quota counter, it stays + * there to be picked up if the module is restarted, + * eg. due to a validator retry, and then the + * target_count_create routine picks it up. */ + if(iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] > + qstate->global_quota_reached) + qstate->global_quota_reached = + iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]; + } +} + +static void +target_count_increase(struct module_qstate* qstate, + struct iter_qstate* iq, int num) +{ + target_count_create(qstate, iq); if(iq->target_count) iq->target_count[TARGET_COUNT_QUERIES] += num; iq->dp_target_count++; } static void -target_count_increase_nx(struct iter_qstate* iq, int num) +target_count_increase_nx(struct module_qstate* qstate, + struct iter_qstate* iq, int num) { - target_count_create(iq); + target_count_create(qstate, iq); if(iq->target_count) iq->target_count[TARGET_COUNT_NX] += num; } static void -target_count_increase_global_quota(struct iter_qstate* iq, int num) +target_count_increase_global_quota(struct module_qstate* qstate, + struct iter_qstate* iq, int num) { - target_count_create(iq); + target_count_create(qstate, iq); if(iq->target_count) iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num; + target_count_store(qstate, iq); } /** @@ -861,7 +886,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype, subiq = (struct iter_qstate*)subq->minfo[id]; memset(subiq, 0, sizeof(*subiq)); subiq->num_target_queries = 0; - target_count_create(iq); + target_count_create(qstate, iq); subiq->target_count = iq->target_count; if(iq->target_count) { iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */ @@ -1506,7 +1531,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase, qstate->region, qstate->env->rrset_cache, qstate->env->scratch_buffer, - *qstate->env->now, 1/*add SOA*/, NULL, + *qstate->env->now, 1/*add SOA*/, dpname, qstate->env->cfg); } /* item taken from cache does not match our query name, thus @@ -2235,7 +2260,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += qs; - target_count_increase(iq, qs); + target_count_increase(qstate, iq, qs); if(qs != 0) { qstate->ext_state[id] = module_wait_subquery; return 0; /* and wait for them */ @@ -2291,7 +2316,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, * lookups at a time. */ verbose(VERB_ALGO, "try parent-side glue lookup"); iq->num_target_queries += query_count; - target_count_increase(iq, query_count); + target_count_increase(qstate, iq, query_count); qstate->ext_state[id] = module_wait_subquery; return 0; } @@ -2311,7 +2336,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, if(query_count != 0) { /* suspend to await results */ verbose(VERB_ALGO, "try parent-side glue lookup"); iq->num_target_queries += query_count; - target_count_increase(iq, query_count); + target_count_increase(qstate, iq, query_count); qstate->ext_state[id] = module_wait_subquery; return 0; } @@ -2795,7 +2820,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += extra; - target_count_increase(iq, extra); + target_count_increase(qstate, iq, extra); if(iq->num_target_queries > 0) { /* wait to get all targets, we want to try em */ verbose(VERB_ALGO, "wait for all targets for fallback"); @@ -2846,7 +2871,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, /* errors ignored, these targets are not strictly necessary for * this result, we do not have to reply with SERVFAIL */ iq->num_target_queries += extra; - target_count_increase(iq, extra); + target_count_increase(qstate, iq, extra); } /* Add the current set of unused targets to our queue. */ @@ -2969,7 +2994,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += qs; - target_count_increase(iq, qs); + target_count_increase(qstate, iq, qs); } /* Since a target query might have been made, we * need to check again. */ @@ -3029,7 +3054,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, * this result, we do not have to reply with SERVFAIL */ if(extra > 0) { iq->num_target_queries += extra; - target_count_increase(iq, extra); + target_count_increase(qstate, iq, extra); check_waiting_queries(iq, qstate, id); /* undo qname minimise step because we'll get back here * to do it again */ @@ -3042,7 +3067,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, } } - target_count_increase_global_quota(iq, 1); + target_count_increase_global_quota(qstate, iq, 1); if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] > MAX_GLOBAL_QUOTA) { char s[LDNS_MAX_DOMAINLEN]; @@ -3122,7 +3147,6 @@ find_NS(struct reply_info* rep, size_t from, size_t to) return NULL; } - /** * Process the query response. All queries end up at this state first. This * process generally consists of analyzing the response and routing the @@ -3449,7 +3473,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, infra_ratelimit_dec(qstate->env->infra_cache, old_dp->name, old_dp->namelen, *qstate->env->now); - iq->dp = delegpt_from_message(iq->response, qstate->region); + iq->dp = delegpt_from_message(iq->response, qstate->region, + deleg_port_number(qstate->env)); if (qstate->env->cfg->qname_minimisation) iq->minimisation_state = INIT_MINIMISE_STATE; if(!iq->dp) { @@ -3726,7 +3751,8 @@ prime_supers(struct module_qstate* qstate, int id, struct module_qstate* forq) log_assert(qstate->is_priming || foriq->wait_priming_stub); log_assert(qstate->return_rcode == LDNS_RCODE_NOERROR); /* Convert our response to a delegation point */ - dp = delegpt_from_message(qstate->return_msg, forq->region); + dp = delegpt_from_message(qstate->return_msg, forq->region, + deleg_port_number(forq->env)); if(!dp) { /* if there is no convertible delegation point, then * the ANSWER type was (presumably) a negative answer. */ @@ -3897,7 +3923,7 @@ processTargetResponse(struct module_qstate* qstate, int id, /* no new addresses, increase the nxns counter, like * this could be a list of wildcards with no new * addresses */ - target_count_increase_nx(foriq, 1); + target_count_increase_nx(qstate, foriq, 1); } verbose(VERB_ALGO, "added target response"); delegpt_log(VERB_ALGO, foriq->dp); @@ -3909,7 +3935,7 @@ processTargetResponse(struct module_qstate* qstate, int id, dpns->resolved = 1; /* fail the target */ /* do not count cached answers */ if(qstate->reply_origin && qstate->reply_origin->len != 0) { - target_count_increase_nx(foriq, 1); + target_count_increase_nx(qstate, foriq, 1); } } } @@ -3942,7 +3968,8 @@ processDSNSResponse(struct module_qstate* qstate, int id, /* else, store as DP and continue at querytargets */ foriq->state = QUERYTARGETS_STATE; - foriq->dp = delegpt_from_message(qstate->return_msg, forq->region); + foriq->dp = delegpt_from_message(qstate->return_msg, forq->region, + deleg_port_number(forq->env)); if(!foriq->dp) { log_err("out of memory in dsns dp alloc"); errinf(qstate, "malloc failure, in DS search"); @@ -4159,6 +4186,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq, iter_store_parentside_neg(qstate->env, &qstate->qinfo, iq->deleg_msg?iq->deleg_msg->rep: (iq->response?iq->response->rep:NULL)); + target_count_store(qstate, iq); if(!iq->response) { verbose(VERB_ALGO, "No response is set, servfail"); errinf(qstate, "(no response found at query finish)"); @@ -4577,6 +4605,7 @@ iter_clear(struct module_qstate* qstate, int id) iq = (struct iter_qstate*)qstate->minfo[id]; if(iq) { outbound_list_clear(&iq->outlist); + target_count_store(qstate, iq); if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) { free(iq->target_count); if(*iq->nxns_dp) free(*iq->nxns_dp); diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 9ce747bce..2d6029f0c 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -105,6 +105,7 @@ libworker_delete_env(struct libworker* w) SSL_CTX_free(w->sslctx); #endif outside_network_delete(w->back); + shared_ports_delete(w->shared_ports); } /** delete libworker struct */ @@ -219,17 +220,25 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) libworker_delete(w); return NULL; } + if(!(w->shared_ports = shared_ports_create(cfg->out_ifs, + cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, ports, numports))) { + if(!w->is_bg || w->is_bg_thread) { + lock_basic_unlock(&ctx->cfglock); + } + libworker_delete(w); + return NULL; + } w->back = outside_network_create(w->base, cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, - ports, numports, cfg->unwanted_threshold, + cfg->unwanted_threshold, cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w, cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx, cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect, cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout, - cfg->tcp_auth_query_timeout); + cfg->tcp_auth_query_timeout, w->shared_ports); w->env->outnet = w->back; if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); diff --git a/libunbound/libworker.h b/libunbound/libworker.h index 42aa5bae3..f527cb093 100644 --- a/libunbound/libworker.h +++ b/libunbound/libworker.h @@ -60,6 +60,7 @@ struct tube; struct sldns_buffer; struct ub_event_base; struct query_info; +struct shared_ports; /** * The library-worker status structure @@ -84,6 +85,8 @@ struct libworker { struct comm_base* base; /** the backside outside network interface to the auth servers */ struct outside_network* back; + /** shared ports structure */ + struct shared_ports* shared_ports; /** random() table for this worker. */ struct ub_randstate* rndstate; /** sslcontext for SSL wrapped DNS over TCP queries */ diff --git a/makedist.sh b/makedist.sh index ec9021c2c..07b097738 100755 --- a/makedist.sh +++ b/makedist.sh @@ -608,6 +608,8 @@ rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Fail info "Adding libtool utils (libtoolize)." libtoolize -c --install || libtoolize -c || error_cleanup "Libtoolize failed." +# Turn this off, if the git repo times out for lookups. +if test "updateconfigsub" = "false"; then # https://www.gnu.org/software/gettext/manual/html_node/config_002eguess.html info "Updating config.guess and config.sub" wget -O config.guess 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD' @@ -621,6 +623,7 @@ if [ `uname -s | grep -i -c darwin` -ne 0 ]; then xattr -d com.apple.quarantine config.sub fi fi +fi info "Building configure script (autoreconf)." autoreconf -f || error_cleanup "Autoconf failed." diff --git a/pythonmod/interface.i b/pythonmod/interface.i index 735f2ed50..7e2a188aa 100644 --- a/pythonmod/interface.i +++ b/pythonmod/interface.i @@ -79,7 +79,7 @@ i+(int)((unsigned int)name[i]) < len) { memmove(buf, name + i + 1, (unsigned int)name[i]); buf[(unsigned int)name[i]] = 0; - PyList_SetItem(list, cnt, PyString_FromString(buf)); + PyList_SetItem(list, cnt, PyUnicode_FromString(buf)); } i += ((unsigned int)name[i]) + 1; cnt++; @@ -96,7 +96,7 @@ list = PyList_New(len); for (i=0; i < len; i++) { - PyList_SET_ITEM(list, i, PyString_FromString(array[i])); + PyList_SET_ITEM(list, i, PyUnicode_FromString(array[i])); } return list; } @@ -207,7 +207,7 @@ struct query_info { char buf[LDNS_MAX_DOMAINLEN]; buf[0] = '\0'; dname_str((uint8_t*)PyBytes_AsString(dname), buf); - return PyString_FromString(buf); + return PyUnicode_FromString(buf); } %} @@ -345,7 +345,7 @@ struct packed_rrset_data { PyObject* _get_data_rr_len(struct packed_rrset_data* d, int idx) { if ((d != NULL) && (idx >= 0) && ((size_t)idx < (d->count+d->rrsig_count))) - return PyInt_FromLong(d->rr_len[idx]); + return PyLong_FromLong(d->rr_len[idx]); return Py_None; } void _set_data_rr_ttl(struct packed_rrset_data* d, int idx, uint32_t ttl) @@ -357,7 +357,7 @@ struct packed_rrset_data { PyObject* _get_data_rr_ttl(struct packed_rrset_data* d, int idx) { if ((d != NULL) && (idx >= 0) && ((size_t)idx < (d->count+d->rrsig_count))) - return PyInt_FromLong(d->rr_ttl[idx]); + return PyLong_FromLong(d->rr_ttl[idx]); return Py_None; } PyObject* _get_data_rr_data(struct packed_rrset_data* d, int idx) { @@ -555,12 +555,12 @@ struct sockaddr_storage {}; if (ss->ss_family == AF_INET) { const struct sockaddr_in *sa4 = (struct sockaddr_in *)ss; - return PyInt_FromLong(ntohs(sa4->sin_port)); + return PyLong_FromLong(ntohs(sa4->sin_port)); } if (ss->ss_family == AF_INET6) { const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ss; - return PyInt_FromLong(ntohs(sa6->sin6_port)); + return PyLong_FromLong(ntohs(sa6->sin6_port)); } return Py_None; @@ -574,7 +574,7 @@ struct sockaddr_storage {}; } sa6 = (struct sockaddr_in6 *)ss; - return PyInt_FromLong(ntohl(sa6->sin6_flowinfo)); + return PyLong_FromLong(ntohl(sa6->sin6_flowinfo)); } PyObject *_sockaddr_storage_scope_id(const struct sockaddr_storage *ss) { @@ -585,7 +585,7 @@ struct sockaddr_storage {}; } sa6 = (struct sockaddr_in6 *)ss; - return PyInt_FromLong(ntohl(sa6->sin6_scope_id)); + return PyLong_FromLong(ntohl(sa6->sin6_scope_id)); } %} @@ -661,7 +661,7 @@ struct edns_option { %inline %{ PyObject* _edns_option_opt_code_get(struct edns_option* option) { uint16_t opt_code = option->opt_code; - return PyInt_FromLong(opt_code); + return PyLong_FromLong(opt_code); } PyObject* _edns_option_opt_data_get(struct edns_option* option) { @@ -1627,7 +1627,7 @@ int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, } result = PyObject_Call(func, py_args, py_kwargs); if (result) { - res = PyInt_AsLong(result); + res = PyLong_AsLong(result); } out: Py_XDECREF(py_edns); @@ -1711,7 +1711,7 @@ out: } result = PyObject_Call(func, py_args, py_kwargs); if (result) { - res = PyInt_AsLong(result); + res = PyLong_AsLong(result); } out: Py_XDECREF(py_qinfo); @@ -1765,7 +1765,7 @@ out: } result = PyObject_Call(func, py_args, py_kwargs); if (result) { - res = PyInt_AsLong(result); + res = PyLong_AsLong(result); } out: Py_XDECREF(py_qstate); @@ -1814,7 +1814,7 @@ out: } result = PyObject_Call(func, py_args, py_kwargs); if (result) { - res = PyInt_AsLong(result); + res = PyLong_AsLong(result); } out: Py_XDECREF(py_qstate); diff --git a/pythonmod/pythonmod.c b/pythonmod/pythonmod.c index 1b077bb6f..1aef55612 100644 --- a/pythonmod/pythonmod.c +++ b/pythonmod/pythonmod.c @@ -246,14 +246,14 @@ log_py_err(void) } /* And it should be a string all ready to go - duplicate it. */ - if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) { + if (!PyBytes_Check(obResult) && !PyUnicode_Check(obResult)) { log_err("pythonmod: cannot print exception, " "StringIO.getvalue() result did not String_Check" " or Unicode_Check"); goto cleanup; } - if(PyString_Check(obResult)) { - result = PyString_AsString(obResult); + if(PyBytes_Check(obResult)) { + result = PyBytes_AsString(obResult); } else { ascstr = PyUnicode_AsASCIIString(obResult); result = PyBytes_AsString(ascstr); @@ -450,7 +450,7 @@ int pythonmod_init(struct module_env* env, int id) pe->data = PyDict_New(); /* add the script filename to the global "mod_env" for trivial access */ - fname = PyString_FromString(pe->fname); + fname = PyUnicode_FromString(pe->fname); if(PyDict_SetItemString(pe->data, "script", fname) < 0) { log_err("pythonmod: could not add item to dictionary"); Py_XDECREF(fname); @@ -487,10 +487,17 @@ int pythonmod_init(struct module_env* env, int id) /* for python 3.9 and newer */ char* fstr = NULL; size_t flen = 0; + long pos = 0; log_err("pythonmod: can't parse Python script %s", pe->fname); /* print the error to logs too, run it again */ fseek(script_py, 0, SEEK_END); - flen = (size_t)ftell(script_py); + pos = ftell(script_py); + if (pos == -1L) { + log_err("ftell failed to print parse error: %s: %s", + pe->fname, strerror(errno)); + goto fail_close_file; + } + flen = (size_t)pos; #ifdef SIZE_MAX if(flen > SIZE_MAX-2) { log_err("script file too large"); diff --git a/respip/respip.c b/respip/respip.c index e5805edac..fc9de4c01 100644 --- a/respip/respip.c +++ b/respip/respip.c @@ -1121,7 +1121,13 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id, if((qstate->qinfo.qtype == LDNS_RR_TYPE_A || qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA || qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) && - qstate->return_msg && qstate->return_msg->rep) { + qstate->return_msg && qstate->return_msg->rep && + !(qstate->env->need_to_validate && + (!(qstate->query_flags & BIT_CD) + || qstate->env->cfg->ignore_cd) && + (qstate->return_msg->rep->security <= sec_status_bogus + || qstate->return_msg->rep->security == + sec_status_secure_sentinel_fail))) { struct reply_info* new_rep = qstate->return_msg->rep; struct ub_packed_rrset_key* alias_rrset = NULL; struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; @@ -1158,8 +1164,10 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id, * clients. */ qstate->is_drop = 1; } else if(alias_rrset) { - if(!generate_cname_request(qstate, alias_rrset)) + if(!generate_cname_request(qstate, alias_rrset)) { + errinf(qstate, "Could not generate CNAME request"); goto servfail; + } next_state = module_wait_subquery; } qstate->return_msg->rep = new_rep; @@ -1173,6 +1181,7 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id, servfail: qstate->return_rcode = LDNS_RCODE_SERVFAIL; qstate->return_msg = NULL; + qstate->ext_state[id] = module_finished; } int @@ -1269,6 +1278,7 @@ respip_inform_super(struct module_qstate* qstate, int id, return; fail: + errinf(super, "CNAME lookup failed"); super->return_rcode = LDNS_RCODE_SERVFAIL; super->return_msg = NULL; return; diff --git a/services/authzone.c b/services/authzone.c index 99edb7d42..0822f62a4 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -443,7 +443,12 @@ auth_zone_create(struct auth_zones* az, uint8_t* nm, size_t nmlen, rbtree_init(&z->data, &auth_data_cmp); lock_rw_init(&z->lock); lock_protect(&z->lock, &z->name, sizeof(*z)-sizeof(rbnode_type)- - sizeof(&z->rpz_az_next)-sizeof(&z->rpz_az_prev)); + sizeof(z->rpz_az_next)-sizeof(z->rpz_az_prev)- + sizeof(z->max_transfer_size)-sizeof(z->max_transfer_size)); + lock_protect(&z->lock, &z->max_transfer_size, + sizeof(z->max_transfer_size)); + lock_protect(&z->lock, &z->max_transfer_time, + sizeof(z->max_transfer_time)); lock_rw_wrlock(&z->lock); /* z lock protects all, except rbtree itself and the rpz linked list * pointers, which are protected using az->lock */ @@ -5938,8 +5943,7 @@ xfer_target_equals_answer_name(struct auth_master* lookup_target, /** callback for task_transfer lookup of host name, of A or AAAA */ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), - int ATTR_UNUSED(was_ratelimited)) + enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited)) { struct auth_xfer* xfr = (struct auth_xfer*)arg; struct module_env* env; @@ -5952,7 +5956,16 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, } /* process result */ - if(rcode == LDNS_RCODE_NOERROR) { + if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) { + if(verbosity >= VERB_OPS) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_OPS, "auth zone %s: primary %s address lookup is DNSSEC bogus: %s", + zname, xfr->task_transfer->lookup_target->host, + (why_bogus?why_bogus:"")); + } + /* fall through to next-lookup / next-master */ + } else if(rcode == LDNS_RCODE_NOERROR) { uint16_t wanted_qtype = LDNS_RR_TYPE_A; struct regional* temp = env->scratch; struct query_info rq; @@ -7251,8 +7264,7 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) /** callback for task_probe lookup of host name, of A or AAAA */ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), - int ATTR_UNUSED(was_ratelimited)) + enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited)) { struct auth_xfer* xfr = (struct auth_xfer*)arg; struct module_env* env; @@ -7265,7 +7277,16 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, } /* process result */ - if(rcode == LDNS_RCODE_NOERROR) { + if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) { + if(verbosity >= VERB_OPS) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_OPS, "auth zone %s: primary %s address probe lookup is DNSSEC bogus: %s", + zname, xfr->task_probe->lookup_target->host, + (why_bogus?why_bogus:"")); + } + /* fall through to next-lookup / next-master */ + } else if(rcode == LDNS_RCODE_NOERROR) { uint16_t wanted_qtype = LDNS_RR_TYPE_A; struct regional* temp = env->scratch; struct query_info rq; @@ -7795,35 +7816,48 @@ xfer_set_masters(struct auth_master** list, struct config_auth* c, { struct auth_master* m; struct config_strlist* p; + struct auth_master** tail; /* list points to the first, or next pointer for the new element */ while(*list) { list = &( (*list)->next ); } if(with_http) for(p = c->urls; p; p = p->next) { + tail = list; m = auth_master_new(&list); if(!m) return 0; m->http = 1; - if(!parse_url(p->str, &m->host, &m->file, &m->port, &m->ssl)) + if(!parse_url(p->str, &m->host, &m->file, &m->port, &m->ssl)) { + free(m->host); + free(m->file); + free(m); + *tail = NULL; return 0; + } } for(p = c->masters; p; p = p->next) { + tail = list; m = auth_master_new(&list); if(!m) return 0; m->ixfr = 1; /* this flag is not configurable */ m->host = strdup(p->str); if(!m->host) { log_err("malloc failure"); + free(m); + *tail = NULL; return 0; } } for(p = c->allow_notify; p; p = p->next) { + tail = list; m = auth_master_new(&list); if(!m) return 0; m->allow_notify = 1; m->host = strdup(p->str); if(!m->host) { log_err("malloc failure"); + free(m); + *tail = NULL; return 0; } } diff --git a/services/cache/dns.c b/services/cache/dns.c index 9731ff1fa..04d5ae2d6 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -43,6 +43,7 @@ #include "iterator/iter_utils.h" #include "validator/val_nsec.h" #include "validator/val_utils.h" +#include "iterator/iter_utils.h" #include "services/cache/dns.h" #include "services/cache/rrset.h" #include "util/data/msgparse.h" @@ -277,6 +278,8 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen, /* snip off front label */ lablen = *qname; + if(lablen == 0) + break; qname += lablen + 1; qnamelen -= lablen + 1; } @@ -584,7 +587,8 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname, return NULL; } } - if(!delegpt_rrset_add_ns(dp, region, nskey, 0)) { + if(!delegpt_rrset_add_ns(dp, region, nskey, 0, + deleg_port_number(env))) { lock_rw_unlock(&nskey->entry.lock); log_err("find_delegation: addns out of memory"); return NULL; @@ -1075,7 +1079,7 @@ dns_cache_lookup(struct module_env* env, if(env->cfg->harden_below_nxdomain) { while(!dname_is_root(k.qname)) { if(dpname && dpnamelen - && !dname_subdomain_c(k.qname, dpname)) + && !dname_strict_subdomain_c(k.qname, dpname)) break; /* no synth nxdomain above the stub */ dname_remove_label(&k.qname, &k.qname_len); h = query_info_hash(&k, flags); diff --git a/services/cache/rrset.c b/services/cache/rrset.c index 6fd9bc6e7..9b0319140 100644 --- a/services/cache/rrset.c +++ b/services/cache/rrset.c @@ -50,6 +50,7 @@ #include "util/regional.h" #include "util/alloc.h" #include "util/net_help.h" +#include "validator/val_utils.h" void rrset_markdel(void* key) @@ -126,7 +127,8 @@ rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key, /** see if rrset needs to be updated in the cache */ static int -need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) +need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns, + int a_aaaa) { struct packed_rrset_data* newd = (struct packed_rrset_data*)nd; struct packed_rrset_data* cached = (struct packed_rrset_data*)cd; @@ -151,9 +153,13 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) return 0; /* ghost-domain: never let an NS overwrite extend lifetime * past the entry it replaces, regardless of trust. */ - if(ns && !TTL_IS_EXPIRED(cached->ttl, timenow) && + /* Also for A/AAAA and it is glue. */ + if((ns || + (a_aaaa && cached->trust==rrset_trust_add_noAA)) + && !TTL_IS_EXPIRED(cached->ttl, timenow) && newd->ttl > cached->ttl) { size_t i; + if(a_aaaa) newd->trust=rrset_trust_add_noAA; newd->ttl = cached->ttl; for(i=0; i<(newd->count+newd->rrsig_count); i++) if(newd->rr_ttl[i] > newd->ttl) @@ -230,7 +236,8 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, equal = rrsetdata_equal((struct packed_rrset_data*)k->entry. data, (struct packed_rrset_data*)e->data); if(!need_to_update_rrset(k->entry.data, e->data, timenow, - equal, (rrset_type==LDNS_RR_TYPE_NS))) { + equal, (rrset_type==LDNS_RR_TYPE_NS), + (rrset_type==LDNS_RR_TYPE_A || rrset_type==LDNS_RR_TYPE_AAAA))) { /* cache is superior, return that value */ lock_rw_unlock(&e->lock); ub_packed_rrset_parsedelete(k, alloc); @@ -262,6 +269,29 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, return 0; } +/** See if the name is a within signer authority */ +static int +dname_subdomain_rrsig_signers(uint8_t* dname, + struct ub_packed_rrset_key* rrset) +{ + struct packed_rrset_data* d = (struct packed_rrset_data*) + rrset->entry.data; + size_t i; + if(!d || !d->rrsig_count) + return 0; + for(i=0; irrsig_count; i++) { + uint8_t* sname = NULL; + size_t slen = 0; + rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i], + &sname, &slen); + if(!sname || !slen) + return 0; /* malformed */ + if(!dname_subdomain_c(dname, sname)) + return 0; /* not a subdomain */ + } + return 1; +} + void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache, struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len, struct alloc_cache* alloc, time_t timenow) @@ -270,6 +300,14 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache, uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3]; uint8_t* new_dname; size_t new_dname_len; + + /* See if the RRSIG signer name allows this wildcard, + * the new rrset should fall within the zone of the RRSIG signer(s). */ + if(!dname_subdomain_rrsig_signers(ce, rrset)) { + verbose(VERB_ALGO, "wildcard canonical parent outside signer authority"); + return; + } + rrset = packed_rrset_copy_alloc(rrset, alloc, timenow); if(!rrset) { log_err("malloc failure in rrset_cache_update_wildcard"); diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 58b74863f..7da23126e 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -42,7 +42,6 @@ #ifdef HAVE_SYS_TYPES_H # include #endif -#include #include #ifdef USE_TCP_FASTOPEN #include @@ -1342,13 +1341,33 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, if((is_doq) && !(is_https || is_ssl)) do_tcp = 0; if(do_auto) { + enum listen_type auto_port_type; ub_sock = calloc(1, sizeof(struct unbound_socket)); if(!ub_sock) return 0; + if(is_dnscrypt) { + auto_port_type = listen_type_udpancil_dnscrypt; + add = "udpancil_dnscrypt"; + } else if(is_doq) { + auto_port_type = listen_type_doq; + add = "doq"; + if(if_listens_on(ifname, port, 53, NULL)) { + log_err("DNS over QUIC is strictly not " + "allowed on port 53 as per RFC 9250. " + "Port 53 is for DNS datagrams. Error " + "for interface '%s'.", ifname); + free(ub_sock->addr); + free(ub_sock); + return 0; + } + } else { + auto_port_type = listen_type_udpancil; + add = "udpancil"; + } if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, &noip6, rcv, snd, reuseport, transparent, tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock, - (is_dnscrypt?"udpancil_dnscrypt":"udpancil"))) == -1) { + add)) == -1) { free(ub_sock->addr); free(ub_sock); if(noip6) { @@ -1367,9 +1386,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, if (sock_queue_timeout && !set_recvtimestamp(s)) { log_warn("socket timestamping is not available"); } - if(!port_insert(list, s, is_dnscrypt - ?listen_type_udpancil_dnscrypt:listen_type_udpancil, - is_pp2, ub_sock)) { + if(!port_insert(list, s, auto_port_type, is_pp2, ub_sock)) { sock_close(s); free(ub_sock->addr); free(ub_sock); @@ -2168,7 +2185,7 @@ void tcp_req_info_clear(struct tcp_req_info* req) while(open) { nopen = open->next; mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp, - NULL); + NULL, NULL); free(open); open = nopen; } @@ -3400,14 +3417,13 @@ doq_table_delete(struct doq_table* table) } struct doq_timer* -doq_timer_find_time(struct doq_table* table, struct timeval* tv) +doq_timer_find_time(struct doq_table* table, ngtcp2_tstamp ts) { struct doq_timer key; struct rbnode_type* node; log_assert(table != NULL); memset(&key, 0, sizeof(key)); - key.time.tv_sec = tv->tv_sec; - key.time.tv_usec = tv->tv_usec; + key.time_mono = ts; node = rbtree_search(table->timer_tree, &key); if(node) return (struct doq_timer*)node->key; @@ -3455,7 +3471,7 @@ doq_timer_list_remove(struct doq_table* table, struct doq_timer* timer) if(!timer->timer_in_list) return; /* The item in the rbtree has the list start and end. */ - rb_timer = doq_timer_find_time(table, &timer->time); + rb_timer = doq_timer_find_time(table, timer->time_mono); if(rb_timer) { if(timer->setlist_prev) timer->setlist_prev->setlist_next = timer->setlist_next; @@ -3501,7 +3517,8 @@ doq_timer_unset(struct doq_table* table, struct doq_timer* timer) } void doq_timer_set(struct doq_table* table, struct doq_timer* timer, - struct doq_server_socket* worker_doq_socket, struct timeval* tv) + struct doq_server_socket* worker_doq_socket, struct timeval* tv, + ngtcp2_tstamp ts) { struct doq_timer* rb_timer; if(verbosity >= VERB_ALGO && timer->conn) { @@ -3515,14 +3532,14 @@ void doq_timer_set(struct doq_table* table, struct doq_timer* timer, (int)rel.tv_sec, (int)rel.tv_usec); } if(timer->timer_in_tree || timer->timer_in_list) { - if(timer->time.tv_sec == tv->tv_sec && - timer->time.tv_usec == tv->tv_usec) + if(timer->time_mono == ts) return; /* already set on that time */ doq_timer_unset(table, timer); } - timer->time.tv_sec = tv->tv_sec; - timer->time.tv_usec = tv->tv_usec; - rb_timer = doq_timer_find_time(table, tv); + timer->time_real.tv_sec = tv->tv_sec; + timer->time_real.tv_usec = tv->tv_usec; + timer->time_mono = ts; + rb_timer = doq_timer_find_time(table, ts); if(rb_timer) { /* There is a timeout already with this value. Timer is * added to the setlist. */ @@ -3598,15 +3615,29 @@ doq_conn_create(struct comm_point* c, struct doq_pkt_addr* paddr, return conn; } +/** The arguments for doq stream tree del. */ +struct doq_stream_tree_del_args { + /** The doq table. */ + struct doq_table* table; + /** The doq connection for the stream. */ + struct doq_conn* conn; +}; + /** delete stream tree node */ static void stream_tree_del(rbnode_type* node, void* arg) { - struct doq_table* table = (struct doq_table*)arg; + struct doq_stream_tree_del_args* args = (struct doq_stream_tree_del_args*)arg; + struct doq_table* table = args->table; struct doq_stream* stream; if(!node) return; stream = (struct doq_stream*)node; + if(stream->mesh_state) { + mesh_state_remove_reply(stream->mesh, stream->mesh_state, + args->conn->doq_socket->cp, NULL, stream); + stream->mesh_state = NULL; + } if(stream->in) doq_table_quic_size_subtract(table, stream->inlen); if(stream->out) @@ -3629,7 +3660,11 @@ doq_conn_delete(struct doq_conn* conn, struct doq_table* table) if(conn->ssl) SSL_set_app_data(conn->ssl, NULL); if(conn->stream_tree.count != 0) { - traverse_postorder(&conn->stream_tree, stream_tree_del, table); + struct doq_stream_tree_del_args args; + memset(&args, 0, sizeof(args)); + args.table = table; + args.conn = conn; + traverse_postorder(&conn->stream_tree, stream_tree_del, &args); } free(conn->key.dcid); SSL_free(conn->ssl); @@ -3702,13 +3737,9 @@ int doq_timer_cmp(const void* key1, const void* key2) { struct doq_timer* e = (struct doq_timer*)key1; struct doq_timer* f = (struct doq_timer*)key2; - if(e->time.tv_sec < f->time.tv_sec) + if(e->time_mono < f->time_mono) return -1; - if(e->time.tv_sec > f->time.tv_sec) - return 1; - if(e->time.tv_usec < f->time.tv_usec) - return -1; - if(e->time.tv_usec > f->time.tv_usec) + if(e->time_mono > f->time_mono) return 1; return 0; } @@ -3942,6 +3973,11 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream, if(stream->is_closed) return 1; stream->is_closed = 1; + if(stream->mesh_state) { + mesh_state_remove_reply(stream->mesh, stream->mesh_state, + conn->doq_socket->cp, NULL, stream); + stream->mesh_state = NULL; + } doq_stream_off_write_list(conn, stream); if(send_shutdown) { verbose(VERB_ALGO, "doq: shutdown stream_id %d with app_error_code %d", @@ -3971,7 +4007,8 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream, /** doq stream pick up answer data from buffer */ static int -doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf) +doq_stream_pickup_answer(struct doq_conn* conn, struct doq_stream* stream, + struct sldns_buffer* buf) { stream->is_answer_available = 1; if(stream->out) { @@ -3981,6 +4018,11 @@ doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf) } stream->nwrite = 0; stream->outlen = sldns_buffer_limit(buf); + if(!doq_table_quic_size_available(conn->doq_socket->table, + conn->doq_socket->cfg, stream->outlen)) { + verbose(VERB_ALGO, "doq stream: no space for reply length"); + return 0; + } /* For quic the output bytes have to stay allocated and available, * for potential resends, until the remote end has acknowledged them. * This includes the tcplen start uint16_t, in outlen_wire. */ @@ -4007,24 +4049,56 @@ doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream, if(stream->out) doq_table_quic_size_subtract(conn->doq_socket->table, stream->outlen); - if(!doq_stream_pickup_answer(stream, buf)) + if(!doq_stream_pickup_answer(conn, stream, buf)) return 0; doq_table_quic_size_add(conn->doq_socket->table, stream->outlen); doq_stream_on_write_list(conn, stream); doq_conn_write_enable(conn); return 1; } +#endif /* HAVE_NGTCP2 */ +void +doq_stream_add_meshstate(struct doq_stream* stream, + struct mesh_area* mesh, struct mesh_state* m) +{ +#ifdef HAVE_NGTCP2 + stream->mesh = mesh; + stream->mesh_state = m; +#else + (void)stream; (void)mesh; (void)m; +#endif +} + +void +doq_stream_remove_mesh_state(struct doq_stream* stream) +{ +#ifdef HAVE_NGTCP2 + if(!stream) + return; + stream->mesh_state = NULL; +#else + (void)stream; +#endif +} + +#ifdef HAVE_NGTCP2 /** doq stream data length has completed, allocations can be done. False on * allocation failure. */ static int -doq_stream_datalen_complete(struct doq_stream* stream, struct doq_table* table) +doq_stream_datalen_complete(struct doq_conn* conn, struct doq_stream* stream, + struct doq_table* table) { if(stream->inlen > 1024*1024) { log_err("doq stream in length too large %d", (int)stream->inlen); return 0; } + if(!doq_table_quic_size_available(table, conn->doq_socket->cfg, + stream->inlen)) { + verbose(VERB_ALGO, "doq stream: no space for query length"); + return 0; + } stream->in = calloc(1, stream->inlen); if(!stream->in) { log_err("doq could not read stream, calloc failed: " @@ -4069,6 +4143,7 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream) return 0; } c->repinfo.doq_streamid = stream->stream_id; + c->repinfo.doq_stream = stream; conn->doq_socket->current_conn = conn; fptr_ok(fptr_whitelist_comm_point(c->callback)); if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo)) { @@ -4085,8 +4160,9 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream) /** doq receive data for a stream, more bytes of the incoming data */ static int -doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data, - size_t datalen, int* recv_done, struct doq_table* table) +doq_stream_recv_data(struct doq_conn* conn, struct doq_stream* stream, + const uint8_t* data, size_t datalen, int* recv_done, + struct doq_table* table) { int got_data = 0; /* read the tcplength uint16_t at the start */ @@ -4107,7 +4183,7 @@ doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data, if(stream->nread == 2) { /* the initial length value is completed */ stream->inlen = ntohs(tcplen); - if(!doq_stream_datalen_complete(stream, table)) + if(!doq_stream_datalen_complete(conn, stream, table)) return 0; } else { /* store for later */ @@ -4256,12 +4332,11 @@ doq_submit_new_token(struct doq_conn* conn) ngtcp2_ssize tokenlen; int ret; const ngtcp2_path* path = ngtcp2_conn_get_path(conn->conn); - ngtcp2_tstamp ts = doq_get_timestamp_nanosec(); tokenlen = ngtcp2_crypto_generate_regular_token(token, conn->doq_socket->static_secret, conn->doq_socket->static_secret_len, path->remote.addr, - path->remote.addrlen, ts); + path->remote.addrlen, doq_get_timestamp_nanosec()); if(tokenlen < 0) { log_err("doq ngtcp2_crypto_generate_regular_token failed"); return 1; @@ -4324,8 +4399,7 @@ doq_stream_open_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id, verbose(VERB_ALGO, "doq: stream with this id already exists"); return 0; } - if(stream_id != 0 && stream_id != 4 && /* allow one stream on a new connection */ - !doq_table_quic_size_available(doq_conn->doq_socket->table, + if(!doq_table_quic_size_available(doq_conn->doq_socket->table, doq_conn->doq_socket->cfg, sizeof(*stream) + 100 /* estimated query in */ + 512 /* estimated response out */ @@ -4383,8 +4457,8 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags, return 0; } if(datalen != 0) { - if(!doq_stream_recv_data(stream, data, datalen, &recv_done, - doq_conn->doq_socket->table)) + if(!doq_stream_recv_data(doq_conn, stream, data, datalen, + &recv_done, doq_conn->doq_socket->table)) return NGTCP2_ERR_CALLBACK_FAILURE; } if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) { @@ -4453,6 +4527,29 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id, return 0; } +/** ngtcp2 extend_max_stream_data function */ +int doq_extend_max_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), + int64_t stream_id, uint64_t max_data, void* user_data, + void* ATTR_UNUSED(stream_user_data)) +{ + struct doq_conn* doq_conn = (struct doq_conn*)user_data; + struct doq_stream* stream; + verbose(VERB_ALGO, "doq extend_max_stream_data stream id %d " + "max_data %d ", (int)stream_id, (int)max_data); + if(max_data == 0) + return 0; + stream = doq_stream_find(doq_conn, stream_id); + if(!stream) { + verbose(VERB_ALGO, "doq: unknown stream %d", (int)stream_id); + return 0; + } + if(!stream->is_answer_available) + return 0; + doq_stream_on_write_list(doq_conn, stream); + doq_conn_write_enable(doq_conn); + return 0; +} + /** ngtcp2 acked_stream_data_offset callback function */ static int doq_acked_stream_data_offset_cb(ngtcp2_conn* ATTR_UNUSED(conn), @@ -4827,6 +4924,7 @@ doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen, callbacks.stream_open = doq_stream_open_cb; callbacks.stream_close = doq_stream_close_cb; callbacks.stream_reset = doq_stream_reset_cb; + callbacks.extend_max_stream_data = doq_extend_max_stream_data_cb; callbacks.acked_stream_data_offset = doq_acked_stream_data_offset_cb; callbacks.recv_stream_data = doq_recv_stream_data_cb; @@ -5104,23 +5202,30 @@ doq_conn_clear_conids(struct doq_conn* conn) ngtcp2_tstamp doq_get_timestamp_nanosec(void) { -#ifdef CLOCK_REALTIME struct timespec tp; memset(&tp, 0, sizeof(tp)); - /* Get a nanosecond time, that can be compared with the event base. */ - if(clock_gettime(CLOCK_REALTIME, &tp) == -1) { - log_err("clock_gettime failed: %s", strerror(errno)); +#ifdef CLOCK_BOOTTIME + if(clock_gettime(CLOCK_BOOTTIME, &tp) == -1) { +#endif + if(clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { + log_err("clock_gettime failed: %s", strerror(errno)); + } +#ifdef CLOCK_BOOTTIME } +#endif return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) + ((uint64_t)tp.tv_nsec); -#else +} + +static struct timeval doq_get_timevalue(void) +{ struct timeval tv; + memset(&tv, 0, sizeof(tv)); if(gettimeofday(&tv, NULL) < 0) { log_err("gettimeofday failed: %s", strerror(errno)); + memset(&tv, 0, sizeof(tv)); } - return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) + - ((uint64_t)tv.tv_usec)*((uint64_t)1000); -#endif /* CLOCK_REALTIME */ + return tv; } /** doq start the closing period for the connection. */ @@ -5243,18 +5348,17 @@ doq_conn_recv(struct comm_point* c, struct doq_pkt_addr* paddr, int* err_drop) { int ret; - ngtcp2_tstamp ts; struct ngtcp2_path path; memset(&path, 0, sizeof(path)); path.remote.addr = (struct sockaddr*)&paddr->addr; path.remote.addrlen = paddr->addrlen; path.local.addr = (struct sockaddr*)&paddr->localaddr; path.local.addrlen = paddr->localaddrlen; - ts = doq_get_timestamp_nanosec(); ret = ngtcp2_conn_read_pkt(conn->conn, &path, pi, sldns_buffer_begin(c->doq_socket->pkt_buf), - sldns_buffer_limit(c->doq_socket->pkt_buf), ts); + sldns_buffer_limit(c->doq_socket->pkt_buf), + doq_get_timestamp_nanosec()); if(ret != 0) { if(err_retry) *err_retry = 0; @@ -5342,7 +5446,6 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn, { struct doq_stream* stream = conn->stream_write_first; ngtcp2_path_storage ps; - ngtcp2_tstamp ts = doq_get_timestamp_nanosec(); size_t num_packets = 0, max_packets = 65535; ngtcp2_path_storage_zero(&ps); @@ -5395,7 +5498,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn, ret = ngtcp2_conn_writev_stream(conn->conn, &ps.path, &pi, sldns_buffer_begin(c->doq_socket->pkt_buf), sldns_buffer_remaining(c->doq_socket->pkt_buf), - &ndatalen, flags, stream_id, datav, datav_count, ts); + &ndatalen, flags, stream_id, datav, datav_count, + doq_get_timestamp_nanosec()); if(ret < 0) { if(ret == NGTCP2_ERR_WRITE_MORE) { verbose(VERB_ALGO, "doq: write more, ndatalen %d", (int)ndatalen); @@ -5410,26 +5514,20 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn, continue; } else if(ret == NGTCP2_ERR_STREAM_DATA_BLOCKED) { verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_DATA_BLOCKED"); -#ifdef HAVE_NGTCP2_CCERR_DEFAULT - ngtcp2_ccerr_set_application_error( - &conn->ccerr, -1, NULL, 0); -#else - ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0); -#endif - if(err_drop) - *err_drop = 0; - if(!doq_conn_close_error(c, conn)) { - if(err_drop) - *err_drop = 1; + if(stream) { + doq_stream_off_write_list(conn, stream); + stream = stream->write_next; + continue; + } else { + break; } - return 0; } else if(ret == NGTCP2_ERR_STREAM_SHUT_WR) { verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_SHUT_WR"); #ifdef HAVE_NGTCP2_CCERR_DEFAULT ngtcp2_ccerr_set_application_error( - &conn->ccerr, -1, NULL, 0); + &conn->ccerr, DOQ_APP_ERROR_CODE, NULL, 0); #else - ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0); + ngtcp2_connection_close_error_set_application_error(&conn->last_error, DOQ_APP_ERROR_CODE, NULL, 0); #endif if(err_drop) *err_drop = 0; @@ -5467,7 +5565,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn, if(ret == 0) { /* congestion limited */ doq_conn_write_disable(conn); - ngtcp2_conn_update_pkt_tx_time(conn->conn, ts); + ngtcp2_conn_update_pkt_tx_time(conn->conn, + doq_get_timestamp_nanosec()); return 1; } sldns_buffer_set_position(c->doq_socket->pkt_buf, ret); @@ -5481,7 +5580,7 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn, if(stream) stream = stream->write_next; } - ngtcp2_conn_update_pkt_tx_time(conn->conn, ts); + ngtcp2_conn_update_pkt_tx_time(conn->conn, doq_get_timestamp_nanosec()); return 1; } @@ -5558,32 +5657,35 @@ doq_table_pop_first(struct doq_table* table) } int -doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv) +doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, ngtcp2_tstamp* ts) { - ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(conn->conn); - ngtcp2_tstamp now = doq_get_timestamp_nanosec(); + ngtcp2_tstamp doq_expiry = ngtcp2_conn_get_expiry(conn->conn); + ngtcp2_tstamp doq_now = doq_get_timestamp_nanosec(); ngtcp2_tstamp t; + struct timeval now = doq_get_timevalue(); - if(expiry <= now) { + if(doq_expiry <= doq_now || doq_expiry == UINT64_MAX) { + /* UINT64_MAX means there is no next expiry. */ /* The timer has already expired, add with zero timeout. * This should call the callback straight away. Calling it * from the event callbacks is cleaner than calling it here, * because then it is always called with the same locks and * so on. This routine only has the conn.lock. */ - t = now; + t = doq_now; + memcpy(tv, &now, sizeof(*tv)); } else { - t = expiry; + t = doq_expiry; + memset(tv, 0, sizeof(*tv)); + tv->tv_sec = (doq_expiry - doq_now) / NGTCP2_SECONDS; + tv->tv_usec = ((doq_expiry - doq_now) / NGTCP2_MICROSECONDS)%1000000; + timeval_add(tv, &now); } - /* convert to timeval */ - memset(tv, 0, sizeof(*tv)); - tv->tv_sec = t / NGTCP2_SECONDS; - tv->tv_usec = (t / NGTCP2_MICROSECONDS)%1000000; + *ts = t; /* If we already have a timer, is it the right value? */ if(conn->timer.timer_in_tree || conn->timer.timer_in_list) { - if(conn->timer.time.tv_sec == tv->tv_sec && - conn->timer.time.tv_usec == tv->tv_usec) + if(conn->timer.time_mono == *ts) return 0; } return 1; @@ -5604,13 +5706,12 @@ doq_conn_log_line(struct doq_conn* conn, char* s) int doq_conn_handle_timeout(struct doq_conn* conn) { - ngtcp2_tstamp now = doq_get_timestamp_nanosec(); int rv; if(verbosity >= VERB_ALGO) doq_conn_log_line(conn, "timeout"); - rv = ngtcp2_conn_handle_expiry(conn->conn, now); + rv = ngtcp2_conn_handle_expiry(conn->conn, doq_get_timestamp_nanosec()); if(rv != 0) { verbose(VERB_ALGO, "ngtcp2_conn_handle_expiry failed: %s", ngtcp2_strerror(rv)); diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index 963595a1c..ae0463468 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -61,6 +61,8 @@ struct config_file; struct addrinfo; struct sldns_buffer; struct tcl_list; +struct mesh_area; +struct mesh_state; /** * Listening for queries structure. @@ -538,8 +540,11 @@ void doq_table_delete(struct doq_table* table); struct doq_timer { /** The rbnode in the tree sorted by timeout value. Key this struct. */ struct rbnode_type node; + /** The timeout value. Monotonic value used with ngtcp2. + * This time value is used for the tree operations. */ + ngtcp2_tstamp time_mono; /** The timeout value. Absolute time value. */ - struct timeval time; + struct timeval time_real; /** If the timer is in the time tree, with the node. */ int timer_in_tree; /** If there are more timers with the exact same timeout value, @@ -689,6 +694,11 @@ struct doq_stream { uint8_t* out; /** if the stream is on the write list */ uint8_t on_write_list; + /** The mesh area and mesh state, set when this stream's query was + * dispatched into the mesh; used to detach the reply on stream close */ + struct mesh_area* mesh; + /** the mesh state for the query, is nonNULL when there is one. */ + struct mesh_state* mesh_state; /** the prev and next on the write list, if on the list */ struct doq_stream* write_prev, *write_next; }; @@ -791,7 +801,16 @@ int doq_stream_close(struct doq_conn* conn, struct doq_stream* stream, /** send reply for a connection */ int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream, struct sldns_buffer* buf); +#endif /* HAVE_NGTCP2 */ +/** add mesh state to doq stream */ +void doq_stream_add_meshstate(struct doq_stream* stream, + struct mesh_area* mesh, struct mesh_state* m); + +/** remove mesh state from doq stream */ +void doq_stream_remove_mesh_state(struct doq_stream* stream); + +#ifdef HAVE_NGTCP2 /** the connection has write interest, wants to write packets */ void doq_conn_write_enable(struct doq_conn* conn); @@ -813,10 +832,12 @@ struct doq_conn* doq_table_pop_first(struct doq_table* table); * doq check if the timer for the conn needs to be changed. * @param conn: connection, caller must hold lock on it. * @param tv: time value, absolute time, returned. + * @param ts: time stamp, absolute time, returned. * @return true if timer needs to be set to tv, false if no change is needed * to the timer. The timer is already set to the right time in that case. */ -int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv); +int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, + ngtcp2_tstamp* ts); /** doq remove timer from tree */ void doq_timer_tree_remove(struct doq_table* table, struct doq_timer* timer); @@ -829,11 +850,12 @@ void doq_timer_unset(struct doq_table* table, struct doq_timer* timer); /** doq set the timer and add it. */ void doq_timer_set(struct doq_table* table, struct doq_timer* timer, - struct doq_server_socket* worker_doq_socket, struct timeval* tv); + struct doq_server_socket* worker_doq_socket, struct timeval* tv, + ngtcp2_tstamp ts); /** doq find a timeout in the timer tree */ struct doq_timer* doq_timer_find_time(struct doq_table* table, - struct timeval* tv); + ngtcp2_tstamp ts); /** doq handle timeout for a connection. Pass conn locked. Returns false for * deletion. */ @@ -851,6 +873,9 @@ int doq_table_quic_size_available(struct doq_table* table, /** doq get the quic size value */ size_t doq_table_quic_size_get(struct doq_table* table); + +/** get a timestamp in nanoseconds */ +ngtcp2_tstamp doq_get_timestamp_nanosec(void); #endif /* HAVE_NGTCP2 */ char* set_ip_dscp(int socket, int addrfamily, int ds); @@ -866,8 +891,4 @@ void doq_client_event_cb(int fd, short event, void* arg); /** timer event callback for testcode/doqclient */ void doq_client_timer_cb(int fd, short event, void* arg); -#ifdef HAVE_NGTCP2 -/** get a timestamp in nanoseconds */ -ngtcp2_tstamp doq_get_timestamp_nanosec(void); -#endif #endif /* LISTEN_DNSPORT_H */ diff --git a/services/localzone.c b/services/localzone.c index 77fc5b6b9..5de780127 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -1668,7 +1668,7 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo, struct local_data key; struct local_data* ld = NULL; struct local_rrset* lr = NULL; - if(z->type == local_zone_always_transparent || z->type == local_zone_block_a) + if(z->type == local_zone_always_transparent || z->type == local_zone_block_a || z->type == local_zone_block_aaaa) return 1; if(z->type != local_zone_transparent && z->type != local_zone_typetransparent @@ -1679,7 +1679,9 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo, key.namelen = qinfo->qname_len; key.namelabs = labs; ld = (struct local_data*)rbtree_search(&z->data, &key.node); - if(z->type == local_zone_transparent || z->type == local_zone_inform) + if(z->type == local_zone_transparent || z->type == local_zone_inform + || z->type == local_zone_block_a_wdata + || z->type == local_zone_block_aaaa_wdata) return (ld == NULL); if(ld) lr = local_data_find_type(ld, qinfo->qtype, 1); @@ -1745,7 +1747,8 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env, || lz_type == local_zone_always_transparent) { /* no NODATA or NXDOMAINS for this zone type */ return 0; - } else if(lz_type == local_zone_block_a) { + } else if(lz_type == local_zone_block_a || + lz_type == local_zone_block_a_wdata) { /* Return NODATA for all A queries */ if(qinfo->qtype == LDNS_RR_TYPE_A) { local_error_encode(qinfo, env, edns, repinfo, buf, temp, @@ -1754,6 +1757,17 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env, return 1; } + return 0; + } else if(lz_type == local_zone_block_aaaa || + lz_type == local_zone_block_aaaa_wdata) { + /* Return NODATA for all AAAA queries */ + if(qinfo->qtype == LDNS_RR_TYPE_AAAA) { + local_error_encode(qinfo, env, edns, repinfo, buf, temp, + LDNS_RCODE_NOERROR, (LDNS_RCODE_NOERROR|BIT_AA), + LDNS_EDE_NONE, NULL); + return 1; + } + return 0; } else if(lz_type == local_zone_always_null) { /* 0.0.0.0 or ::0 or noerror/nodata for this zone type, @@ -1922,7 +1936,10 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, lzt == local_zone_typetransparent || lzt == local_zone_inform || lzt == local_zone_always_transparent || - lzt == local_zone_block_a) && + lzt == local_zone_block_a || + lzt == local_zone_block_aaaa || + lzt == local_zone_block_a_wdata || + lzt == local_zone_block_aaaa_wdata) && local_zone_does_not_cover(z, qinfo, labs)) { lock_rw_unlock(&z->lock); z = NULL; @@ -1971,6 +1988,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, if(lzt != local_zone_always_refuse && lzt != local_zone_always_transparent && lzt != local_zone_block_a + && lzt != local_zone_block_aaaa && lzt != local_zone_always_nxdomain && lzt != local_zone_always_nodata && lzt != local_zone_always_deny @@ -2002,6 +2020,9 @@ const char* local_zone_type2str(enum localzone_type t) case local_zone_inform_redirect: return "inform_redirect"; case local_zone_always_transparent: return "always_transparent"; case local_zone_block_a: return "block_a"; + case local_zone_block_aaaa: return "block_aaaa"; + case local_zone_block_a_wdata: return "block_a_wdata"; + case local_zone_block_aaaa_wdata: return "block_aaaa_wdata"; case local_zone_always_refuse: return "always_refuse"; case local_zone_always_nxdomain: return "always_nxdomain"; case local_zone_always_nodata: return "always_nodata"; @@ -2038,6 +2059,12 @@ int local_zone_str2type(const char* type, enum localzone_type* t) *t = local_zone_always_transparent; else if(strcmp(type, "block_a") == 0) *t = local_zone_block_a; + else if(strcmp(type, "block_aaaa") == 0) + *t = local_zone_block_aaaa; + else if(strcmp(type, "block_a_wdata") == 0) + *t = local_zone_block_a_wdata; + else if(strcmp(type, "block_aaaa_wdata") == 0) + *t = local_zone_block_aaaa_wdata; else if(strcmp(type, "always_refuse") == 0) *t = local_zone_always_refuse; else if(strcmp(type, "always_nxdomain") == 0) diff --git a/services/localzone.h b/services/localzone.h index 76c011836..436874e0f 100644 --- a/services/localzone.h +++ b/services/localzone.h @@ -93,6 +93,12 @@ enum localzone_type { local_zone_always_transparent, /** resolve normally, even when there is local data but return NODATA for A queries */ local_zone_block_a, + /** resolve normally, even when there is local data, but return NODATA for AAAA queries */ + local_zone_block_aaaa, + /** resolve normally, use local data, else return NODATA for A queries */ + local_zone_block_a_wdata, + /** resolve normally, use local data, else return NODATA for AAAA queries */ + local_zone_block_aaaa_wdata, /** answer with error, even when there is local data */ local_zone_always_refuse, /** answer with nxdomain, even when there is local data */ @@ -573,7 +579,7 @@ enum respip_action { respip_always_nxdomain = local_zone_always_nxdomain, /** answer with nodata response */ respip_always_nodata = local_zone_always_nodata, - /** answer with nodata response */ + /** drop query */ respip_always_deny = local_zone_always_deny, /** RPZ: truncate answer in order to force switch to tcp */ respip_truncate = local_zone_truncate, diff --git a/services/mesh.c b/services/mesh.c index edfac6cf4..add773b88 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -506,6 +506,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, "incoming query."); if(rep->c->use_h2) http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_drop_reply(rep); mesh->stats_dropped++; return; @@ -519,6 +521,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, "dropping incoming query."); if(rep->c->use_h2) http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_drop_reply(rep); mesh->num_queries_replyaddr_limit++; return; @@ -593,6 +597,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, added_tcp = 1; if(rep->c->use_h2) { http2_stream_add_meshstate(rep->c->h2_stream, mesh, s); + } else if(rep->c->type == comm_doq && rep->doq_stream) { + doq_stream_add_meshstate(rep->doq_stream, mesh, s); } /* add serve expired timer if required and not already there */ if(timeout && !mesh_serve_expired_init(s, timeout)) { @@ -648,6 +654,8 @@ servfail_mem: qinfo, qid, qflags, edns); if(rep->c->use_h2) http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_send_reply(rep); if(added_reply_without_accounting) { mesh_remove_reply_without_accounting(s, repadded); @@ -957,33 +965,9 @@ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, mesh_run(mesh, e->qstate->mesh_info, event, e); } -/** copy strlist to region */ -static struct config_strlist* -cfg_region_strlist_copy(struct regional* region, struct config_strlist* list) -{ - struct config_strlist* result = NULL, *last = NULL, *s = list; - while(s) { - struct config_strlist* n = regional_alloc_zero(region, - sizeof(*n)); - if(!n) - return NULL; - n->str = regional_strdup(region, s->str); - if(!n->str) - return NULL; - if(last) - last->next = n; - else result = n; - last = n; - s = s->next; - } - return result; -} - -/** Copy the client info to the query region. */ -static struct respip_client_info* +struct respip_client_info* mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo) { - size_t i; struct respip_client_info* client_info; client_info = regional_alloc_init(region, cinfo, sizeof(*cinfo)); if(!client_info) @@ -1002,20 +986,13 @@ mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo) if(!client_info->tag_actions) return NULL; } - if(cinfo->tag_datas) { - client_info->tag_datas = regional_alloc_zero(region, - sizeof(struct config_strlist*)*cinfo->tag_datas_size); - if(!client_info->tag_datas) - return NULL; - for(i=0; itag_datas_size; i++) { - if(cinfo->tag_datas[i]) { - client_info->tag_datas[i] = cfg_region_strlist_copy( - region, cinfo->tag_datas[i]); - if(!client_info->tag_datas[i]) - return NULL; - } - } - } + /* tag_datas is owned by the matched acl_addr in config_file; its + * lifetime is until config reload, which tears down all mesh states + * first. Keep the original pointer so client_info_compare() + * can recognise two states from the same ACL entry. */ + /* fast reload insists on dropping the queries when interface-tag-data + * or access-control-tag-data are changed. */ + /* client_info->tag_datas already copied by regional_alloc_init above */ if(cinfo->view) { /* Do not copy the view pointer but store a name instead. * The name is looked up later when done, this means that @@ -1025,6 +1002,11 @@ mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo) cinfo->view->name); if(!client_info->view_name) return NULL; + } else if(cinfo->view_name) { + client_info->view_name = regional_strdup(region, + cinfo->view_name); + if(!client_info->view_name) + return NULL; } return client_info; } @@ -1533,6 +1515,10 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, * for HTTP/2 stream to refer to mesh state, in case * connection gets cleanup before HTTP/2 stream close. */ r->h2_stream->mesh_state = NULL; +#ifdef HAVE_NGTCP2 + } else if(r->query_reply.doq_stream) { + r->query_reply.doq_stream->mesh_state = NULL; +#endif } /* send the reply */ /* We don't reuse the encoded answer if: @@ -1687,9 +1673,9 @@ static void dns_error_reporting(struct module_qstate* qstate, opt = edns_opt_list_find(qstate->edns_opts_back_in, LDNS_EDNS_REPORT_CHANNEL); if(!opt) return; - agent_domain_len = opt->opt_len; agent_domain = opt->opt_data; - if(dname_valid(agent_domain, agent_domain_len) < 3) { + agent_domain_len = dname_valid(agent_domain, opt->opt_len); + if(agent_domain_len < 3) { /* The agent domain needs to be a valid dname that is not the * root; from RFC9567. */ return; @@ -1827,6 +1813,8 @@ void mesh_query_done(struct mesh_state* mstate) mstate->reply_list = NULL; if(r->query_reply.c->use_h2) http2_stream_remove_mesh_state(r->h2_stream); + else if(r->query_reply.doq_stream) + doq_stream_remove_mesh_state(r->query_reply.doq_stream); comm_point_drop_reply(&r->query_reply); mstate->reply_list = reply_list; log_assert(mstate->s.env->mesh->num_reply_addrs > 0); @@ -1864,6 +1852,8 @@ void mesh_query_done(struct mesh_state* mstate) mstate->reply_list = NULL; if(r->query_reply.c->use_h2) { http2_stream_remove_mesh_state(r->h2_stream); + } else if(r->query_reply.doq_stream) { + doq_stream_remove_mesh_state(r->query_reply.doq_stream); } comm_point_drop_reply(&r->query_reply); mstate->reply_list = reply_list; @@ -2079,6 +2069,8 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, if(rep->c->use_h2) r->h2_stream = rep->c->h2_stream; else r->h2_stream = NULL; + if(rep->c->type != comm_doq) + r->query_reply.doq_stream = NULL; /* Data related to local alias stored in 'qinfo' (if any) is ephemeral * and can be different for different original queries (even if the @@ -2284,8 +2276,29 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate, enum module_ev ev, struct outbound_entry* e) { enum module_ext_state s; + int numrun = 0; verbose(VERB_ALGO, "mesh_run: start"); while(mstate) { + if(numrun++ > MESH_MAX_RUN_ITER) { + /* These modules are too much to activate, stop them.*/ + log_err("Too many module run iterations, deleting"); + while(mstate) { + /* notify supers */ + if(mstate->super_set.count > 0) { + verbose(VERB_ALGO, "notify supers of failure"); + mstate->s.return_msg = NULL; + mstate->s.return_rcode = LDNS_RCODE_SERVFAIL; + mesh_walk_supers(mesh, mstate); + } + mesh_state_delete(&mstate->s); + if(mesh->run.count > 0) { + /* pop random element off the runnable tree */ + mstate = (struct mesh_state*)mesh->run.root->key; + (void)rbtree_delete(&mesh->run, mstate); + } else mstate = NULL; + } + break; + } /* run the module */ fptr_ok(fptr_whitelist_mod_operate( mesh->mods.mod[mstate->s.curmod]->operate)); @@ -2437,7 +2450,8 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp, } void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, - struct comm_point* cp, struct http2_stream* h2_stream) + struct comm_point* cp, struct http2_stream* h2_stream, + struct doq_stream* doq_stream) { struct mesh_reply* n, *prev = NULL; n = m->reply_list; @@ -2446,7 +2460,8 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, if(!n) return; /* nothing to remove, also no accounting needed */ while(n) { if(n->query_reply.c == cp - && (!h2_stream || n->h2_stream == h2_stream)) { + && (!h2_stream || n->h2_stream == h2_stream) + && (!doq_stream || n->query_reply.doq_stream == doq_stream)) { /* unlink it */ if(prev) prev->next = n->next; else m->reply_list = n->next; @@ -2459,6 +2474,10 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, * share the same comm_point); make sure the streams * don't point back. */ if(n->h2_stream) n->h2_stream->mesh_state = NULL; +#ifdef HAVE_NGTCP2 + if(n->query_reply.doq_stream) + n->query_reply.doq_stream->mesh_state = NULL; +#endif /* prev = prev; */ n = n->next; @@ -2499,9 +2518,10 @@ apply_respip_action(struct module_qstate* qstate, /* xxx_deny actions mean dropping the reply, unless the original reply * was redirected to response-ip data. */ - if((actinfo->action == respip_deny || + if(actinfo->action == respip_always_deny || + ((actinfo->action == respip_deny || actinfo->action == respip_inform_deny) && - *encode_repp == rep) + *encode_repp == rep)) *encode_repp = NULL; return 1; @@ -2566,12 +2586,15 @@ mesh_serve_expired_callback(void* arg) qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep, qstate->env->auth_zones)) { return; - } else if(partial_rep && - !respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep, + } else if(partial_rep) { + if(!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep, qstate->client_info, must_validate, &encode_rep, qstate->region, qstate->env->auth_zones, qstate->env->views, qstate->env->respip_set)) { - return; + return; + } + /* merge succeeded; final reply, no further alias pass */ + partial_rep = NULL; } if(!encode_rep || alias_rrset) { if(!encode_rep) { @@ -2582,6 +2605,7 @@ mesh_serve_expired_callback(void* arg) partial_rep = encode_rep; } } + msg->rep = encode_rep; /* We've found a partial reply ending with an * alias. Replace the lookup qinfo for the * alias target and lookup the cache again to @@ -2608,9 +2632,10 @@ mesh_serve_expired_callback(void* arg) log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep); for(r = mstate->reply_list; r; r = r->next) { - struct timeval old; - timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); - if(mstate->s.env->cfg->discard_timeout != 0 && + if(mesh_is_udp(r)) { + struct timeval old; + timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); + if(mstate->s.env->cfg->discard_timeout != 0 && ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > mstate->s.env->cfg->discard_timeout) { /* Drop the reply, it is too old */ @@ -2626,10 +2651,15 @@ mesh_serve_expired_callback(void* arg) mstate->reply_list = NULL; if(r->query_reply.c->use_h2) http2_stream_remove_mesh_state(r->h2_stream); + else if(r->query_reply.doq_stream) + doq_stream_remove_mesh_state(r->query_reply.doq_stream); comm_point_drop_reply(&r->query_reply); mstate->reply_list = reply_list; + log_assert(mstate->s.env->mesh->num_reply_addrs > 0); + mstate->s.env->mesh->num_reply_addrs--; mstate->s.env->mesh->num_queries_discard_timeout++; continue; + } } i++; diff --git a/services/mesh.h b/services/mesh.h index 77b3c7025..9e3da53a7 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -69,6 +69,13 @@ struct respip_client_info; */ #define MESH_MAX_ACTIVATION 10000 +/** + * Maximum number of mesh state run items. These are different modules + * activated during a mesh run. Any more is likely an infinite loop + * in the module. It is then terminated, and states are deleted. + */ +#define MESH_MAX_RUN_ITER 10000 + /** * Max number of references-to-references-to-references.. search size. * Any more is treated like 'too large', and the creation of a new @@ -707,9 +714,12 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp, * @param cp: the comm_point to remove from the list. * @param h2_stream: if not NULL, it specifies the h2_stream to match * for the delete. + * @param doq_stream: if not NULL, it specifies the doq_stream to match + * for the delete. */ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, - struct comm_point* cp, struct http2_stream* h2_stream); + struct comm_point* cp, struct http2_stream* h2_stream, + struct doq_stream* doq_stream); /** Callback for when the serve expired client timer has run out. Tries to * find an expired answer in the cache and reply that to the client. @@ -761,4 +771,8 @@ void mesh_respond_serve_expired(struct mesh_state* mstate); void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info); +/** Copy the client info to the query region. */ +struct respip_client_info* mesh_copy_client_info(struct regional* region, + struct respip_client_info* cinfo); + #endif /* SERVICES_MESH_H */ diff --git a/services/outside_network.c b/services/outside_network.c index 4d29165d3..0f22c920f 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -208,6 +208,7 @@ static void waiting_tcp_delete(struct waiting_tcp* w) { if(!w) return; + free(w->tls_auth_name); if(w->timer) comm_timer_delete(w->timer); free(w); @@ -1480,7 +1481,7 @@ portcomm_loweruse(struct outside_network* outnet, struct port_comm* pc) pif = pc->pif; log_assert(pif->inuse > 0); #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pif->avail_ports[pif->avail_total - pif->inuse] = pc->number; + shared_ports_return_port(outnet->shared_ports, pif->shpif, pc->number); #endif pif->inuse--; pif->out[pc->index] = pif->out[pif->inuse]; @@ -1694,15 +1695,9 @@ create_pending_tcp(struct outside_network* outnet, size_t bufsize) } /** setup an outgoing interface, ready address */ -static int setup_if(struct port_if* pif, const char* addrstr, - int* avail, int numavail, size_t numfd) +static int setup_if(struct port_if* pif, const char* addrstr, size_t numfd, + struct shared_ports* shp) { -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pif->avail_total = numavail; - pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int)); - if(!pif->avail_ports) - return 0; -#endif if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) && !netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen, &pif->pfxlen)) @@ -1712,6 +1707,12 @@ static int setup_if(struct port_if* pif, const char* addrstr, log_err("num_ports exceeds INT_MAX"); return 0; } +#endif +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + pif->shpif = shared_ports_find_if(shp, &pif->addr, pif->addrlen, + pif->pfxlen); +#else + (void)shp; #endif pif->maxout = (int)numfd; pif->inuse = 0; @@ -1726,12 +1727,12 @@ struct outside_network* outside_network_create(struct comm_base *base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, - struct ub_randstate* rnd, int use_caps_for_id, int* availports, - int numavailports, size_t unwanted_threshold, int tcp_mss, + struct ub_randstate* rnd, int use_caps_for_id, + size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv, int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout, - int tcp_auth_query_timeout) + int tcp_auth_query_timeout, struct shared_ports* shared_ports) { struct outside_network* outnet = (struct outside_network*) calloc(1, sizeof(struct outside_network)); @@ -1766,6 +1767,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, outnet->do_udp = do_udp; outnet->tcp_mss = tcp_mss; outnet->ip_dscp = dscp; + outnet->shared_ports = shared_ports; #ifndef S_SPLINT_S if(delayclose) { outnet->delayclose = 1; @@ -1776,7 +1778,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, if(udp_connect) { outnet->udp_connect = 1; } - if(numavailports == 0 || num_ports == 0) { + if(num_ports == 0) { log_err("no outgoing ports available"); outside_network_delete(outnet); return NULL; @@ -1844,13 +1846,13 @@ outside_network_create(struct comm_base *base, size_t bufsize, /* allocate interfaces */ if(num_ifs == 0) { if(do_ip4 && !setup_if(&outnet->ip4_ifs[0], "0.0.0.0", - availports, numavailports, num_ports)) { + num_ports, outnet->shared_ports)) { log_err("malloc failed"); outside_network_delete(outnet); return NULL; } if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::", - availports, numavailports, num_ports)) { + num_ports, outnet->shared_ports)) { log_err("malloc failed"); outside_network_delete(outnet); return NULL; @@ -1861,7 +1863,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, for(i=0; iip6_ifs[done_6], ifs[i], - availports, numavailports, num_ports)){ + num_ports, outnet->shared_ports)){ log_err("malloc failed"); outside_network_delete(outnet); return NULL; @@ -1870,7 +1872,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, } if(!str_is_ip6(ifs[i]) && do_ip4) { if(!setup_if(&outnet->ip4_ifs[done_4], ifs[i], - availports, numavailports, num_ports)){ + num_ports, outnet->shared_ports)){ log_err("malloc failed"); outside_network_delete(outnet); return NULL; @@ -1948,9 +1950,6 @@ outside_network_delete(struct outside_network* outnet) comm_point_delete(pc->cp); free(pc); } -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - free(outnet->ip4_ifs[i].avail_ports); -#endif free(outnet->ip4_ifs[i].out); } free(outnet->ip4_ifs); @@ -1964,9 +1963,6 @@ outside_network_delete(struct outside_network* outnet) comm_point_delete(pc->cp); free(pc); } -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - free(outnet->ip6_ifs[i].avail_ports); -#endif free(outnet->ip6_ifs[i].out); } free(outnet->ip6_ifs); @@ -2176,7 +2172,10 @@ static int select_ifport(struct outside_network* outnet, struct pending* pend, int num_if, struct port_if* ifs) { - int my_if, my_port, fd, portno, inuse, tries=0; + int my_if, fd, portno, inuse, tries=0; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int reused; +#endif struct port_if* pif; /* randomly select interface and port */ if(num_if == 0) { @@ -2190,37 +2189,35 @@ select_ifport(struct outside_network* outnet, struct pending* pend, my_if = ub_random_max(outnet->rnd, num_if); pif = &ifs[my_if]; #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - if(outnet->udp_connect) { - /* if we connect() we cannot reuse fds for a port */ - if(pif->inuse >= pif->avail_total) { - tries++; - if(tries < MAX_PORT_RETRY) - continue; - log_err("failed to find an open port, drop msg"); - return 0; - } - my_port = pif->inuse + ub_random_max(outnet->rnd, - pif->avail_total - pif->inuse); - } else { - my_port = ub_random_max(outnet->rnd, pif->avail_total); - if(my_port < pif->inuse) { - /* port already open */ - pend->pc = pif->out[my_port]; - verbose(VERB_ALGO, "using UDP if=%d port=%d", - my_if, pend->pc->number); - break; - } + if(!shared_ports_fetch_random(outnet->shared_ports, + pif->shpif, outnet->rnd, outnet->udp_connect, + pif->inuse, &portno, &reused)) { + tries++; + if(tries < MAX_PORT_RETRY) + continue; + log_err("failed to find an open port, drop msg"); + return 0; + } + if(reused) { + /* port already open */ + log_assert(portno < pif->inuse); + pend->pc = pif->out[portno]; + verbose(VERB_ALGO, "using UDP if=%d port=%d", + my_if, pend->pc->number); + break; } - /* try to open new port, if fails, loop to try again */ - log_assert(pif->inuse < pif->maxout); - portno = pif->avail_ports[my_port - pif->inuse]; #else - my_port = portno = 0; + portno = 0; #endif + /* try to open new port, if fails, loop to try again */ fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen, portno, &inuse, outnet->rnd, outnet->ip_dscp); if(fd == -1 && !inuse) { /* nonrecoverable error making socket */ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + shared_ports_return_port(outnet->shared_ports, + pif->shpif, portno); +#endif return 0; } if(fd != -1) { @@ -2237,6 +2234,11 @@ select_ifport(struct outside_network* outnet, struct pending* pend, pend->addrlen); } sock_close(fd); +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + shared_ports_return_port( + outnet->shared_ports, + pif->shpif, portno); +#endif return 0; } } @@ -2254,14 +2256,14 @@ select_ifport(struct outside_network* outnet, struct pending* pend, /* grab port in interface */ pif->out[pif->inuse] = pend->pc; -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pif->avail_ports[my_port - pif->inuse] = - pif->avail_ports[pif->avail_total-pif->inuse-1]; -#endif pif->inuse++; break; } /* failed, already in use */ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + shared_ports_return_port(outnet->shared_ports, pif->shpif, + portno); +#endif verbose(VERB_QUERY, "port %d in use, trying another", portno); tries++; if(tries == MAX_PORT_RETRY) { @@ -2553,7 +2555,16 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet, w->cb = callback; w->cb_arg = callback_arg; w->ssl_upstream = sq->ssl_upstream; - w->tls_auth_name = sq->tls_auth_name; + if(sq->tls_auth_name) { + w->tls_auth_name = strdup(sq->tls_auth_name); + if(!w->tls_auth_name) { + comm_timer_delete(w->timer); + free(w); + return NULL; + } + } else { + w->tls_auth_name = NULL; + } w->timeout = timeout; w->id_node.key = NULL; w->write_wait_prev = NULL; @@ -3645,13 +3656,16 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, { struct sockaddr_storage* addr; socklen_t addrlen; - int i, try, pnum, dscp; + int i, try, dscp; struct port_if* pif; /* create fd */ dscp = outnet->ip_dscp; for(try = 0; try<1000; try++) { int port = 0; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int reused = 0; +#endif int freebind = 0; int noproto = 0; int inuse = 0; @@ -3680,16 +3694,18 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, addr = &pif->addr; addrlen = pif->addrlen; #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pnum = ub_random_max(outnet->rnd, pif->avail_total); - if(pnum < pif->inuse) { - /* port already open */ - port = pif->out[pnum]->number; - } else { - /* unused ports in start part of array */ - port = pif->avail_ports[pnum - pif->inuse]; + if(!shared_ports_fetch_random(outnet->shared_ports, + pif->shpif, outnet->rnd, 0, pif->inuse, + &port, &reused)) { + /* try again, perhaps another interface. */ + continue; + } + if(reused) { + log_assert(port < pif->inuse); + port = pif->out[port]->number; } #else - pnum = port = 0; + port = 0; #endif if(addr_is_ip6(to_addr, to_addrlen)) { struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; @@ -3704,6 +3720,14 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, (struct sockaddr*)addr, addrlen, 1, &inuse, &noproto, 0, 0, 0, NULL, 0, freebind, 0, dscp); } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + if(!reused) { + /* Return the port to the pool, since the caller does + * not keep track of it, also have done fd, and bind. */ + shared_ports_return_port(outnet->shared_ports, + pif->shpif, port); + } +#endif if(fd != -1) { return fd; } @@ -3961,11 +3985,7 @@ if_get_mem(struct port_if* pif) { size_t s; int i; - s = sizeof(*pif) + -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - sizeof(int)*pif->avail_total + -#endif - sizeof(struct port_comm*)*pif->maxout; + s = sizeof(*pif) + sizeof(struct port_comm*)*pif->maxout; for(i=0; iinuse; i++) s += sizeof(*pif->out[i]) + comm_point_get_mem(pif->out[i]->cp); @@ -4053,3 +4073,250 @@ serviced_get_mem(struct serviced_query* sq) return s; } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION +/** Setup shared port interface */ +static int shared_ports_setup_if(struct shared_ports_if* shpif, char* str, + int* availports, int numavailports) +{ + shpif->avail_ports = (int*)memdup(availports, + (size_t)numavailports*sizeof(int)); + if(!shpif->avail_ports) + return 0; + shpif->avail_total = numavailports; + shpif->inuse = 0; + shpif->pfxlen = 0; + if(!ipstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, &shpif->addrlen) && + !netblockstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, + &shpif->addrlen, &shpif->pfxlen)) + return 0; + return 1; +} +#endif + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION +/** Allocate shared ports interfaces */ +static int shared_ports_alloc_ifs(struct shared_ports* shp, char** ifs, + int num_ifs, int do_ip4, int do_ip6, int* availports, + int numavailports) +{ +#ifndef INET6 + do_ip6 = 0; +#endif + calc_num46(ifs, num_ifs, do_ip4, do_ip6, + &shp->num_ip4, &shp->num_ip6); + if(shp->num_ip4 != 0) { + if(!(shp->ip4_ifs = (struct shared_ports_if*)calloc( + (size_t)shp->num_ip4, + sizeof(struct shared_ports_if)))) + return 0; + } + if(shp->num_ip6 != 0) { + if(!(shp->ip6_ifs = (struct shared_ports_if*)calloc( + (size_t)shp->num_ip6, + sizeof(struct shared_ports_if)))) + return 0; + } + if(num_ifs == 0) { + if(do_ip4 && !shared_ports_setup_if(&shp->ip4_ifs[0], + "0.0.0.0", availports, numavailports)) + return 0; + if(do_ip6 && !shared_ports_setup_if(&shp->ip6_ifs[0], + "::", availports, numavailports)) + return 0; + } else { + size_t done_4 = 0, done_6 = 0; + int i; + for(i=0; inum_ip6) { + if(!shared_ports_setup_if(&shp->ip6_ifs[done_6], + ifs[i], availports, numavailports)) + return 0; + done_6++; + } + if(!str_is_ip6(ifs[i]) && do_ip4 && + (int)done_4 < shp->num_ip4) { + if(!shared_ports_setup_if(&shp->ip4_ifs[done_4], + ifs[i], availports, numavailports)) + return 0; + done_4++; + } + } + } + return 1; +} +#endif + +struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4, + int do_ip6, int* availports, int numavailports) +{ + struct shared_ports* shp = calloc(1, sizeof(*shp)); + if(!shp) { + log_err("malloc failed"); + return NULL; + } + lock_basic_init(&shp->lock); + lock_protect(&shp->lock, &shp->ip4_ifs, sizeof(shp->ip4_ifs)); + lock_protect(&shp->lock, &shp->num_ip4, sizeof(shp->num_ip4)); + lock_protect(&shp->lock, &shp->ip6_ifs, sizeof(shp->ip6_ifs)); + lock_protect(&shp->lock, &shp->num_ip6, sizeof(shp->num_ip6)); + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + /* Allocate interfaces */ + lock_basic_lock(&shp->lock); + if(!shared_ports_alloc_ifs(shp, ifs, num_ifs, do_ip4, do_ip6, + availports, numavailports)) { + log_err("malloc failed"); + shared_ports_delete(shp); + return NULL; + } + lock_basic_unlock(&shp->lock); +#else + (void)ifs; (void)num_ifs; (void)do_ip4; (void)do_ip6; + (void)availports; (void)numavailports; +#endif + return shp; +} + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION +/** Delete shared ports interface structure */ +static void shared_ports_if_delete(struct shared_ports_if* shpif) +{ + if(!shpif) + return; + free(shpif->avail_ports); +} +#endif + +void shared_ports_delete(struct shared_ports* shp) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int i; +#endif + if(!shp) + return; + lock_basic_destroy(&shp->lock); +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + for(i=0; inum_ip4; i++) { + shared_ports_if_delete(&shp->ip4_ifs[i]); + } + free(shp->ip4_ifs); + for(i=0; inum_ip6; i++) { + shared_ports_if_delete(&shp->ip6_ifs[i]); + } + free(shp->ip6_ifs); +#endif + free(shp); +} + +struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp, + struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + struct shared_ports_if* ret, *ifs = NULL; + int i, num_ifs = 0; + lock_basic_lock(&shp->lock); + if(addr_is_ip6(addr, addrlen)) { + ifs = shp->ip6_ifs; + num_ifs = shp->num_ip6; + } else { + ifs = shp->ip4_ifs; + num_ifs = shp->num_ip4; + } + for(i=0; ilock); + return ret; + } + } + lock_basic_unlock(&shp->lock); + return NULL; +#else + (void)shp; (void)addr; (void)addrlen; (void)pfxlen; + return NULL; +#endif +} + +int shared_ports_fetch_random(struct shared_ports* shp, + struct shared_ports_if* shpif, struct ub_randstate* rnd, + int udp_connect, int reusenum, int* port, int* reused) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int portno = 0, my_port = 0; + if(!shpif) + return 0; +# ifdef THREADS_DISABLED + (void)shp; +# endif + lock_basic_lock(&shp->lock); + if(udp_connect) { + /* if we connect() we cannot reuse fds for a port. */ + if(shpif->inuse >= shpif->avail_total) { + lock_basic_unlock(&shp->lock); + return 0; + } + my_port = ub_random_max(rnd, + shpif->avail_total - shpif->inuse); + } else { + /* select from free ports and open ports on this thread. */ + if(shpif->inuse >= shpif->avail_total) { + lock_basic_unlock(&shp->lock); + if(reusenum == 0) { + return 0; + } + my_port = ub_random_max(rnd, reusenum); + *port = my_port; + *reused = 1; + return 1; + } + my_port = ub_random_max(rnd, shpif->avail_total - shpif->inuse + + reusenum); + if(my_port < reusenum) { + /* port already open */ + lock_basic_unlock(&shp->lock); + *port = my_port; + *reused = 1; + return 1; + } + my_port -= reusenum; + } + log_assert(shpif->inuse < shpif->avail_total); + log_assert(my_port >= 0 && my_port < shpif->avail_total); + portno = shpif->avail_ports[my_port]; + shpif->avail_ports[my_port] = + shpif->avail_ports[shpif->avail_total-shpif->inuse-1]; + shpif->inuse++; + lock_basic_unlock(&shp->lock); + *port = portno; + *reused = 0; + return 1; +#else + (void)shp; (void)shpif; (void)rnd; (void)udp_connect; + (void)reusenum; + *port = 0; + *reused = 0; + return 1; +#endif +} + +void shared_ports_return_port(struct shared_ports* shp, + struct shared_ports_if* shpif, int port) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + if(!shpif) + return; +# ifdef THREADS_DISABLED + (void)shp; +# endif + lock_basic_lock(&shp->lock); + log_assert(shpif->inuse > 0); + shpif->avail_ports[shpif->avail_total - shpif->inuse] = port; + shpif->inuse--; + lock_basic_unlock(&shp->lock); +#else + (void)shp; (void)shpif; (void)port; +#endif +} diff --git a/services/outside_network.h b/services/outside_network.h index a2dd2c6d6..f135a4847 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -70,6 +70,8 @@ struct module_env; struct module_qstate; struct query_info; struct config_file; +struct shared_ports; +struct shared_ports_if; /** * Send queries to outside servers and wait for answers from servers. @@ -119,6 +121,9 @@ struct outside_network { int udp_connect; /** number of udp packets sent. */ size_t num_udp_outgoing; + /** the shared ports structure, with random ports numbers. + * This is a reference to the member in the daemon structure. */ + struct shared_ports* shared_ports; /** array of outgoing IP4 interfaces */ struct port_if* ip4_ifs; @@ -211,11 +216,8 @@ struct port_if { int pfxlen; #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - /** the available ports array. These are unused. - * Only the first total-inuse part is filled. */ - int* avail_ports; - /** the total number of available ports (size of the array) */ - int avail_total; + /** the shared port numbers for this interface. */ + struct shared_ports_if* shpif; #endif /** array of the commpoints currently in use. @@ -245,6 +247,42 @@ struct port_comm { struct comm_point* cp; }; +/** + * Shared ports, the list of ports shared across threads + */ +struct shared_ports { + /** mutex on the ports */ + lock_basic_type lock; + /** array of IP4 interfaces */ + struct shared_ports_if* ip4_ifs; + /** number of outgoing IP4 interfaces */ + int num_ip4; + /** array of IP6 interfaces */ + struct shared_ports_if* ip6_ifs; + /** number of outgoing IP6 interfaces */ + int num_ip6; +}; + +/** + * Shared ports for an interface. + */ +struct shared_ports_if { + /** address ready to allocate new socket (except port no). */ + struct sockaddr_storage addr; + /** length of addr field */ + socklen_t addrlen; + /** if a netblock, the prefix */ + int pfxlen; + + /** the available ports array. These are unused. + * Only the first total-inuse part is filled. */ + int* avail_ports; + /** the total number of available ports (size of the array) */ + int avail_total; + /** the number in use. */ + int inuse; +}; + /** * Reuse TCP connection, still open can be used again. */ @@ -419,7 +457,7 @@ struct waiting_tcp { void* cb_arg; /** if it uses ssl upstream */ int ssl_upstream; - /** ref to the tls_auth_name from the serviced_query */ + /** owned copy of the tls_auth_name (malloced) */ char* tls_auth_name; /** the packet was involved in an error, to stop looping errors */ int error_count; @@ -551,8 +589,6 @@ struct serviced_query { * @param infra: pointer to infra cached used for serviced queries. * @param rnd: stored to create random numbers for serviced queries. * @param use_caps_for_id: enable to use 0x20 bits to encode id randomness. - * @param availports: array of available ports. - * @param numavailports: number of available ports in array. * @param unwanted_threshold: when to take defensive action. * @param unwanted_action: the action to take. * @param unwanted_param: user parameter to action. @@ -567,17 +603,18 @@ struct serviced_query { * @param max_reuse_tcp_queries: max number of queries on a reuse connection. * @param tcp_reuse_timeout: timeout for REUSE entries in milliseconds. * @param tcp_auth_query_timeout: timeout in milliseconds for TCP queries to auth servers. + * @param shared_ports: the shared_ports structure. * @return: the new structure (with no pending answers) or NULL on error. */ struct outside_network* outside_network_create(struct comm_base* base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, - struct ub_randstate* rnd, int use_caps_for_id, int* availports, - int numavailports, size_t unwanted_threshold, int tcp_mss, + struct ub_randstate* rnd, int use_caps_for_id, + size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv, int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout, - int tcp_auth_query_timeout); + int tcp_auth_query_timeout, struct shared_ports* shared_ports); /** * Delete outside_network structure. @@ -822,6 +859,54 @@ struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet, /** connect tcp connection to addr, 0 on failure */ int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen); +/** + * Create new shared ports structure. + * @param ifs: interface names (or NULL for default interface). + * These interfaces must be able to access all authoritative servers. + * @param num_ifs: number of names in array ifs. + * @param do_ip4: service IP4. + * @param do_ip6: service IP6. + * @param availports: array of available ports. + * @param numavailports: number of available ports in array. + * @return new, or NULL on failure. + */ +struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4, + int do_ip6, int* availports, int numavailports); + +/** + * Delete shared ports structure. + * @param shp: shared ports structure. + */ +void shared_ports_delete(struct shared_ports* shp); + +/** Find interface in shared ports. */ +struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp, + struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen); + +/** + * Get a shared port from the list of random ports. + * @param shp: shared ports structure. + * @param shpif: the shared ports interface. + * @param rnd: used to make random numbers. + * @param udp_connect: set to true if no reuse is possible. + * @param reusenum: number of ports that can be reused (already open). + * @param port: the port number is returned. + * @param reused: if the port numer is reused, returned. + * @return false on failure. That can mean no more free ports to use. + */ +int shared_ports_fetch_random(struct shared_ports* shp, + struct shared_ports_if* shpif, struct ub_randstate* rnd, + int udp_connect, int reusenum, int* port, int* reused); + +/** + * Return a shared port to the list of random ports. + * @param shp: shared ports structure. + * @param shpif: the shared ports interface. + * @param port: port number to return to be used again. + */ +void shared_ports_return_port(struct shared_ports* shp, + struct shared_ports_if* shpif, int port); + /** callback for incoming udp answers from the network */ int outnet_udp_cb(struct comm_point* c, void* arg, int error, struct comm_reply *reply_info); diff --git a/smallapp/unbound-anchor.c b/smallapp/unbound-anchor.c index 93379d27f..8f84bae0e 100644 --- a/smallapp/unbound-anchor.c +++ b/smallapp/unbound-anchor.c @@ -1861,10 +1861,10 @@ get_valid_signers(PKCS7* p7, const char* p7signer) } #else if(verb >= 3 && X509_NAME_get_text_by_NID(nm, - NID_commonName, buf, (int)sizeof(buf))) + NID_commonName, buf, (int)sizeof(buf)) > 0) printf("commonName: %s\n", buf); if(verb >= 3 && X509_NAME_get_text_by_NID(nm, - NID_pkcs9_emailAddress, buf, (int)sizeof(buf))) + NID_pkcs9_emailAddress, buf, (int)sizeof(buf)) > 0) printf("emailAddress: %s\n", buf); #endif } @@ -1890,18 +1890,18 @@ get_valid_signers(PKCS7* p7, const char* p7signer) } else { #if !defined(HAVE_X509_NAME_GET_TEXT_BY_NID) || defined(DEPRECATED_X509_NAME_GET_TEXT_BY_NID) if(!has_valid_emailaddr(nm, p7signer)) { - if(verb) printf("removed cert with wrong name\n"); + if(verb) printf("removed cert with wrong emailaddress\n"); continue; /* wrong name, skip it */ } #else - if(!X509_NAME_get_text_by_NID(nm, + if(X509_NAME_get_text_by_NID(nm, NID_pkcs9_emailAddress, - buf, (int)sizeof(buf))) { - if(verb) printf("removed cert with no name\n"); + buf, (int)sizeof(buf)) <= 0) { + if(verb) printf("removed cert with no emailaddress\n"); continue; /* no name, no use */ } if(strcmp(buf, p7signer) != 0) { - if(verb) printf("removed cert with wrong name\n"); + if(verb) printf("removed cert with wrong emailaddress\n"); continue; /* wrong name, skip it */ } #endif diff --git a/smallapp/worker_cb.c b/smallapp/worker_cb.c index 1a191be50..3f48da508 100644 --- a/smallapp/worker_cb.c +++ b/smallapp/worker_cb.c @@ -129,6 +129,12 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg)) log_assert(0); } +void +libworker_alloc_cleanup(void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + struct outbound_entry* libworker_send_query( struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), diff --git a/testcode/doqclient.c b/testcode/doqclient.c index e83766673..050248f8c 100644 --- a/testcode/doqclient.c +++ b/testcode/doqclient.c @@ -1522,9 +1522,9 @@ doq_client_send_pkt(struct doq_client_data* data, uint32_t ecn, uint8_t* buf, } log_err("doq sendmsg: %s", strerror(errno)); #ifdef HAVE_NGTCP2_CCERR_DEFAULT - ngtcp2_ccerr_set_application_error(&data->ccerr, -1, NULL, 0); + ngtcp2_ccerr_set_application_error(&data->ccerr, 1, NULL, 0); #else - ngtcp2_connection_close_error_set_application_error(&data->last_error, -1, NULL, 0); + ngtcp2_connection_close_error_set_application_error(&data->last_error, 1, NULL, 0); #endif return 0; } @@ -2676,6 +2676,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), log_assert(0); } +void libworker_alloc_cleanup(void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) { log_assert(0); diff --git a/testcode/fake_event.c b/testcode/fake_event.c index b457ba42e..629eae87f 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -1126,15 +1126,16 @@ outside_network_create(struct comm_base* base, size_t bufsize, int ATTR_UNUSED(dscp), struct infra_cache* infra, struct ub_randstate* ATTR_UNUSED(rnd), - int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports), - int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold), + int ATTR_UNUSED(use_caps_for_id), + size_t ATTR_UNUSED(unwanted_threshold), int ATTR_UNUSED(outgoing_tcp_mss), void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param), int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx), int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni), struct dt_env* ATTR_UNUSED(dtenv), int ATTR_UNUSED(udp_connect), int ATTR_UNUSED(max_reuse_tcp_queries), int ATTR_UNUSED(tcp_reuse_timeout), - int ATTR_UNUSED(tcp_auth_query_timeout)) + int ATTR_UNUSED(tcp_auth_query_timeout), + struct shared_ports* ATTR_UNUSED(shared_ports)) { struct replay_runtime* runtime = (struct replay_runtime*)base; struct outside_network* outnet = calloc(1, @@ -1981,6 +1982,20 @@ int outnet_tcp_connect(int ATTR_UNUSED(s), struct sockaddr_storage* ATTR_UNUSED( return 0; } +struct shared_ports* shared_ports_create(char** ATTR_UNUSED(ifs), + int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4), + int ATTR_UNUSED(do_ip6), int* ATTR_UNUSED(availports), + int ATTR_UNUSED(numavailports)) +{ + return calloc(1, sizeof(struct shared_ports)); +} + +void shared_ports_delete(struct shared_ports* shp) +{ + if(!shp) return; + free(shp); +} + int tcp_req_info_add_meshstate(struct tcp_req_info* ATTR_UNUSED(req), struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m)) { @@ -2022,6 +2037,15 @@ void http2_stream_remove_mesh_state(struct http2_stream* ATTR_UNUSED(h2_stream)) { } +void doq_stream_add_meshstate(struct doq_stream* ATTR_UNUSED(stream), + struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m)) +{ +} + +void doq_stream_remove_mesh_state(struct doq_stream* ATTR_UNUSED(stream)) +{ +} + void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) { diff --git a/testcode/unitmain.c b/testcode/unitmain.c index 4bc756a07..a3f2f12a8 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -1282,6 +1282,144 @@ static void localzone_test(void) localzone_parents_test(); } +#include "services/mesh.h" +/** mesh unit tests */ +static void mesh_test(void) +{ + struct regional* r2, *r3; + struct respip_client_info* c1, *c2, *c3; + unit_show_func("services/mesh.c", "mesh_copy_client_info"); + r2 = regional_create(); + r3 = regional_create(); + if(!r2 || !r3) fatal_exit("out of memory"); + + c1 = calloc(1, sizeof(*c1)); + if(!c1) fatal_exit("out of memory"); + c1->view = calloc(1, sizeof(*c1->view)); + if(!c1->view) fatal_exit("out of memory"); + c1->view->name = strdup("view1"); + if(!c1->view->name) fatal_exit("out of memory"); + + c2 = mesh_copy_client_info(r2, c1); + if(!c2) fatal_exit("out of memory"); + c3 = mesh_copy_client_info(r3, c2); + if(!c3) fatal_exit("out of memory"); + + unit_assert(strcmp(c1->view->name, c2->view_name) == 0); + unit_assert(strcmp(c1->view->name, c3->view_name) == 0); + + /* make sure that the c3 view_name is in the r3 region. */ + unit_assert(r3->next == NULL); /* only the first chunk present atm */ + if(strlen(c3->view_name) >= r3->large_object_size) { + char* a = r3->large_list; + int found = 0; + while(a) { + if(strcmp(c3->view_name, + a + /* ALIGNEMENT */ sizeof(uint64_t)) == 0) { + found = 1; + break; + } + a = *(char**)a; + } + unit_assert(found == 1); + } else { + /* The allocation is expected in the r3 region first chunk */ + unit_assert((uint8_t*)c3->view_name < ((uint8_t*)r3)+r3->first_size); + } + + regional_destroy(r2); + /* ASAN should complain for the freed access below */ + unit_assert(strcmp(c1->view->name, c3->view_name) == 0); + + regional_destroy(r3); + free(c1->view->name); + free(c1->view); + free(c1); +} + +#include "util/data/packed_rrset.h" +#include "sldns/sbuffer.h" +/** packed_rrset unit tests */ +static void packed_rrset_test(void) +{ + /* packed_rr_to_string assembles the dname, type, class, ttl and + * rdata of one rr into a buffer of 65535 bytes. Check that it + * refuses an rr that does not fit in there, also when the caller + * passes a dest_len that is larger than that, like the callers in + * daemon/cachedump.c and daemon/remote.c do. Without the check it + * writes past the end of the assembly buffer. */ + uint8_t smalldname[] = "\003www\007example\003com"; + uint8_t smallrdata[] = {0, 4, 1, 2, 3, 4}; + uint8_t maxdname[LDNS_MAX_DOMAINLEN]; + struct ub_packed_rrset_key rrk; + struct packed_rrset_data d; + uint8_t* rr_data[1]; + size_t rr_len[1]; + time_t rr_ttl[1]; + size_t dest_len = 65535*4+2048; /* the size daemon/cachedump.c uses */ + char* dest = (char*)malloc(dest_len); + int i; + + unit_show_func("util/data/packed_rrset.c", "packed_rr_to_string"); + if(!dest) fatal_exit("out of memory"); + memset(&rrk, 0, sizeof(rrk)); + memset(&d, 0, sizeof(d)); + rrk.entry.data = &d; + rrk.rk.rrset_class = htons(LDNS_RR_CLASS_IN); + d.count = 1; + d.rr_len = rr_len; + d.rr_ttl = rr_ttl; + d.rr_data = rr_data; + rr_ttl[0] = 3600; + + /* an ordinary rr is printed, also with the large dest_len */ + rrk.rk.dname = smalldname; + rrk.rk.dname_len = sizeof(smalldname); + rrk.rk.type = htons(LDNS_RR_TYPE_A); + rr_data[0] = smallrdata; + rr_len[0] = sizeof(smallrdata); + unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1); + unit_assert(strstr(dest, "1.2.3.4") != NULL); + + /* a dname of the maximum length, 127 labels of one character */ + for(i=0; i<127; i++) { + maxdname[i*2] = 1; + maxdname[i*2+1] = (uint8_t)'a'; + } + maxdname[254] = 0; + rrk.rk.dname = maxdname; + rrk.rk.dname_len = sizeof(maxdname); + rrk.rk.type = htons(LDNS_RR_TYPE_TXT); + + /* 255+2+2+4+65272 is exactly 65535, that still fits */ + rr_len[0] = 65535 - 255 - 8; + rr_data[0] = (uint8_t*)calloc(1, rr_len[0]); + if(!rr_data[0]) fatal_exit("out of memory"); + sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2)); + unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1); + free(rr_data[0]); + + /* one more byte of rdata does not fit and must be refused */ + rr_len[0] = 65535 - 255 - 8 + 1; + rr_data[0] = (uint8_t*)calloc(1, rr_len[0]); + if(!rr_data[0]) fatal_exit("out of memory"); + sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2)); + unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0); + unit_assert(dest[0] == 0); + free(rr_data[0]); + + /* the largest rdata an rr can hold, well over the buffer */ + rr_len[0] = 2 + 65535; + rr_data[0] = (uint8_t*)calloc(1, rr_len[0]); + if(!rr_data[0]) fatal_exit("out of memory"); + sldns_write_uint16(rr_data[0], 65535); + unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0); + unit_assert(dest[0] == 0); + free(rr_data[0]); + + free(dest); +} + void unit_show_func(const char* file, const char* func) { printf("test %s:%s\n", file, func); @@ -1354,8 +1492,10 @@ main(int argc, char* argv[]) zonemd_test(); tcpreuse_test(); msgparse_test(); + packed_rrset_test(); edns_ede_answer_encode_test(); localzone_test(); + mesh_test(); #ifdef CLIENT_SUBNET ecs_test(); #endif /* CLIENT_SUBNET */ @@ -1389,6 +1529,9 @@ main(int argc, char* argv[]) # ifdef HAVE_RAND_CLEANUP RAND_cleanup(); # endif +#ifdef HAVE_OPENSSL_CLEANUP + OPENSSL_cleanup(); +#endif #elif defined(HAVE_NSS) if(NSS_Shutdown() != SECSuccess) fatal_exit("could not shutdown NSS"); diff --git a/testcode/unittcpreuse.c b/testcode/unittcpreuse.c index 5f45a4b45..ce62e3325 100644 --- a/testcode/unittcpreuse.c +++ b/testcode/unittcpreuse.c @@ -41,6 +41,7 @@ #include "config.h" #include "testcode/unitmain.h" #include "util/log.h" +#include "util/net_help.h" #include "util/random.h" #include "services/outside_network.h" @@ -479,6 +480,278 @@ static void reuse_write_wait_test(void) check_reuse_write_wait_removal(1, &reuse, store, 0, 1); } +static void shared_port_test_ifs(void) +{ + struct shared_ports* shp; + struct shared_ports_if* shpif; + char* ifs[] = {"1.2.3.4", "1.2.3.5", "::1:2", "::1:3"}; + int availports[] = {1, 2, 3, 4}; + struct sockaddr_storage addr; + socklen_t addrlen; + + shp = shared_ports_create(ifs, 4, 1, 1, availports, 4); + unit_assert(shp); + + if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + if(!ipstrtoaddr("1.2.3.5", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + if(!ipstrtoaddr("::1:2", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + if(!ipstrtoaddr("::1:3", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + shared_ports_delete(shp); +} + +/** See if a port is on the shared_ports ports list */ +static int +pif_list_contains(struct shared_ports_if* shpif, int item) +{ + int i; + unit_assert(shpif->inuse >= 0 && shpif->inuse <= shpif->avail_total); + for(i=0; i< shpif->avail_total - shpif->inuse; i++) { + if(shpif->avail_ports[i] == item) + return 1; + } + return 0; +} + +/** See if a number of ports are on the shared_ports list */ +static int +pif_list_contains_items(struct shared_ports_if* shpif, int item1, + int item2, int item3, int item4) +{ + if(item1 != -1 && !pif_list_contains(shpif, item1)) + return 0; + if(item2 != -1 && !pif_list_contains(shpif, item2)) + return 0; + if(item3 != -1 && !pif_list_contains(shpif, item3)) + return 0; + if(item4 != -1 && !pif_list_contains(shpif, item4)) + return 0; + return 1; +} + +static void shared_port_test_port(void) +{ + struct shared_ports* shp; + struct shared_ports_if* shpif; + char* ifs[] = {"1.2.3.4", "1.2.3.5"}; + int availports[] = {1, 2, 3, 4}; + struct sockaddr_storage addr; + socklen_t addrlen; + int p1, p2, p3, reused; + struct ub_randstate* rnd; + + rnd = ub_initstate(NULL); + unit_assert(rnd); + + shp = shared_ports_create(ifs, 2, 1, 1, availports, 4); + unit_assert(shp); + + if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + unit_assert(!pif_list_contains(shpif, p1)); + if(p1 != 1) unit_assert(pif_list_contains(shpif, 1)); + if(p1 != 2) unit_assert(pif_list_contains(shpif, 2)); + if(p1 != 3) unit_assert(pif_list_contains(shpif, 3)); + if(p1 != 4) unit_assert(pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 1); + + shared_ports_return_port(shp, shpif, p1); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + /* pick up two items */ + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p2, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p2 != 0); + unit_assert(!pif_list_contains(shpif, p1)); + unit_assert(!pif_list_contains(shpif, p2)); + if(p1 != 1 && p2 != 1) unit_assert(pif_list_contains(shpif, 1)); + if(p1 != 2 && p2 != 2) unit_assert(pif_list_contains(shpif, 2)); + if(p1 != 3 && p2 != 3) unit_assert(pif_list_contains(shpif, 3)); + if(p1 != 4 && p2 != 4) unit_assert(pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 2); + + shared_ports_return_port(shp, shpif, p1); + unit_assert(pif_list_contains(shpif, p1)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 1); + + shared_ports_return_port(shp, shpif, p2); + unit_assert(pif_list_contains(shpif, p2)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + /* pick up three items */ + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p2, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p2 != 0); + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p3, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p3 != 0); + unit_assert(!pif_list_contains(shpif, p1)); + unit_assert(!pif_list_contains(shpif, p2)); + unit_assert(!pif_list_contains(shpif, p3)); + if(p1 != 1 && p2 != 1 && p3 != 1) + unit_assert(pif_list_contains(shpif, 1)); + if(p1 != 2 && p2 != 2 && p3 != 2) + unit_assert(pif_list_contains(shpif, 2)); + if(p1 != 3 && p2 != 3 && p3 != 3) + unit_assert(pif_list_contains(shpif, 3)); + if(p1 != 4 && p2 != 4 && p3 != 4) + unit_assert(pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 3); + + shared_ports_return_port(shp, shpif, p1); + unit_assert(pif_list_contains(shpif, p1)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 2); + + shared_ports_return_port(shp, shpif, p2); + unit_assert(pif_list_contains(shpif, p2)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 1); + + shared_ports_return_port(shp, shpif, p3); + unit_assert(pif_list_contains(shpif, p3)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + /* pick up all four items */ + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + unit_assert(!pif_list_contains(shpif, 1)); + unit_assert(!pif_list_contains(shpif, 2)); + unit_assert(!pif_list_contains(shpif, 3)); + unit_assert(!pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 4); + + /* more fetches fail, it is fully inuse. */ + unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p2, + &reused)); + unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p3, + &reused)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 4); + + /* reuse is then always the case */ + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 1); + unit_assert(p1 >= 0 && p1 < 4 /* reusenum */); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 1); + unit_assert(p1 >= 0 && p1 < 4 /* reusenum */); + + /* return all the ports */ + shared_ports_return_port(shp, shpif, 1); + unit_assert(pif_list_contains(shpif, 1)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 3); + shared_ports_return_port(shp, shpif, 2); + unit_assert(pif_list_contains(shpif, 2)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 2); + shared_ports_return_port(shp, shpif, 3); + unit_assert(pif_list_contains(shpif, 3)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 1); + shared_ports_return_port(shp, shpif, 4); + unit_assert(pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + shared_ports_delete(shp); + ub_randfree(rnd); +} + void tcpreuse_test(void) { unit_show_feature("tcp_reuse"); @@ -486,4 +759,7 @@ void tcpreuse_test(void) tcp_reuse_tree_list_test(); waiting_tcp_list_test(); reuse_write_wait_test(); + unit_show_feature("shared_ports"); + shared_port_test_ifs(); + shared_port_test_port(); } diff --git a/testdata/10-unbound-anchor.tdir/10-unbound-anchor.conf b/testdata/10-unbound-anchor.tdir/10-unbound-anchor.conf index bb125c0d5..9ce1fa223 100644 --- a/testdata/10-unbound-anchor.tdir/10-unbound-anchor.conf +++ b/testdata/10-unbound-anchor.tdir/10-unbound-anchor.conf @@ -2,6 +2,7 @@ server: do-not-query-localhost: no fake-sha1: yes + verbosity: 8 forward-zone: name: "." forward-addr: "127.0.0.1@@TOPORT@" diff --git a/testdata/10-unbound-anchor.tdir/10-unbound-anchor.test b/testdata/10-unbound-anchor.tdir/10-unbound-anchor.test index 46cea626c..d779fca34 100644 --- a/testdata/10-unbound-anchor.tdir/10-unbound-anchor.test +++ b/testdata/10-unbound-anchor.tdir/10-unbound-anchor.test @@ -35,11 +35,13 @@ function check_insecure() { # test with good start key, and must do 5011 (no URL possible) echo "*** TEST 1 ***" echo $DS > root.key -$PRE/unbound-anchor -x "notexist.xml" -s "notexist.p7s" $OPTS +cat root.key +$PRE/unbound-anchor -x "notexist.xml" -s "notexist.p7s" $OPTS -vvvv if test $? != 0; then echo "Exitcode not OK" exit 1 fi +cat root.key check_works # save for test 5 cp root.key root.key.probed diff --git a/testdata/10-unbound-anchor.tdir/127.0.0.1/no_more_keys.p7s b/testdata/10-unbound-anchor.tdir/127.0.0.1/no_more_keys.p7s index c76b5b6e4..c7c33d3db 100644 Binary files a/testdata/10-unbound-anchor.tdir/127.0.0.1/no_more_keys.p7s and b/testdata/10-unbound-anchor.tdir/127.0.0.1/no_more_keys.p7s differ diff --git a/testdata/10-unbound-anchor.tdir/127.0.0.1/root.p7s b/testdata/10-unbound-anchor.tdir/127.0.0.1/root.p7s index afbdb1b91..b0dc637a3 100644 Binary files a/testdata/10-unbound-anchor.tdir/127.0.0.1/root.p7s and b/testdata/10-unbound-anchor.tdir/127.0.0.1/root.p7s differ diff --git a/testdata/10-unbound-anchor.tdir/key-setup.sh b/testdata/10-unbound-anchor.tdir/key-setup.sh new file mode 100644 index 000000000..7e37c62b9 --- /dev/null +++ b/testdata/10-unbound-anchor.tdir/key-setup.sh @@ -0,0 +1,201 @@ +#!/bin/sh + +# run in temp dir. +# Then for petal, move into basedir. +# For test_cert.key and test_cert.pem, rename the output files to that. +# And run signit.sh for both signature files, by commenting infile and outfile. +# for test_cert.pem it has emailAddress and keyUsage, but petal.pem does not +# need that. + +# settings: + +# directory for files +DESTDIR=. + +# issuer and subject name for certificates +SERVERNAME=petal +CLIENTNAME=petal + +# validity period for certificates +DAYS=7200 + +# size of keys in bits +BITS=3072 + +# hash algorithm +HASH=sha256 + +# base name for unbound server keys +SVR_BASE=petal + +# base name for unbound-control keys +CTL_BASE=petal + +# flag to recreate generated certificates +RECREATE=0 + +# we want -rw-r----- access (say you run this as root: grp=yes (server), all=no). +umask 0027 + +# end of options + +set -eu + +cleanup() { + echo "removing artifacts" + + rm -rf \ + server.cnf \ + client.cnf \ + "${SVR_BASE}_trust.pem" \ + "${CTL_BASE}_trust.pem" \ + "${SVR_BASE}_trust.srl" +} + +fatal() { + printf "fatal error: $*\n" >/dev/stderr + exit 1 +} + +usage() { + cat < used directory to store keys and certificates (default: $DESTDIR) +-h show help notice +-r recreate certificates +EOF +} + +OPTIND=1 +while getopts 'd:hr' arg; do + case "$arg" in + d) DESTDIR="$OPTARG" ;; + h) usage; exit 1 ;; + r) RECREATE=1 ;; + ?) fatal "'$arg' unknown option" ;; + esac +done +shift $((OPTIND - 1)) + +if ! openssl version /dev/null 2>&1; then + echo "$0 requires openssl to be installed for keys/certificates generation." >&2 + exit 1 +fi + +echo "setup in directory $DESTDIR" +cd "$DESTDIR" + +trap cleanup INT + +# === +# Generate server certificate +# === + +# generate private key; do no recreate it if they already exist. +if [ ! -f "$SVR_BASE.key" ]; then + openssl genrsa -out "$SVR_BASE.key" "$BITS" +fi + +cat >server.cnf <client.cnf < dig TCP www.example.com. DNSCrypt port" -dig +tcp @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile +# Query plain request over DNSCrypt. +# This used to close the channel; now it returns SERVFAIL. +# Old: We use TCP to avoid hanging on waiting for UDP. +# We expect `outfile` to contain no DNS payload +echo "> dig www.example.com. DNSCrypt port" +dig @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile echo "> cat logfiles" cat fwd.log cat unbound.log echo "> check answer" -if grep "QUESTION SECTION" outfile; then +if grep "SERVFAIL" outfile; then + echo "OK" +else echo "NOK" exit 1 -else - echo "OK" fi diff --git a/testdata/dnscrypt_cert_chacha.tdir/dnscrypt_cert_chacha.test b/testdata/dnscrypt_cert_chacha.tdir/dnscrypt_cert_chacha.test index 2db073ad6..a92f196f5 100644 --- a/testdata/dnscrypt_cert_chacha.tdir/dnscrypt_cert_chacha.test +++ b/testdata/dnscrypt_cert_chacha.tdir/dnscrypt_cert_chacha.test @@ -9,20 +9,21 @@ PRE="../.." # do the test -# Query plain request over DNSCrypt channel get closed -# We use TCP to avoid hanging on waiting for UDP. -# We expect `outfile` to contain no DNS payload -echo "> dig TCP www.example.com. DNSCrypt port" -dig +tcp @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile +# Query plain request over DNSCrypt. +# This used to close the channel; now it returns SERVFAIL. +# Old: We use TCP to avoid hanging on waiting for UDP. +# We expect `outfile` to contain no DNS payload +echo "> dig www.example.com. DNSCrypt port" +dig @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile echo "> cat logfiles" cat fwd.log cat unbound.log echo "> check answer" -if grep "QUESTION SECTION" outfile; then +if grep "SERVFAIL" outfile; then + echo "OK" +else echo "NOK" exit 1 -else - echo "OK" fi diff --git a/testdata/errreport_agent_domain_len.rpl b/testdata/errreport_agent_domain_len.rpl new file mode 100644 index 000000000..9efdbb659 --- /dev/null +++ b/testdata/errreport_agent_domain_len.rpl @@ -0,0 +1,221 @@ +; Test DNS Error Reporting. + +server: + module-config: "validator iterator" + trust-anchor-signaling: no + target-fetch-policy: "0 0 0 0 0" + verbosity: 4 + qname-minimisation: no + minimal-responses: no + rrset-roundrobin: no + trust-anchor: "test. DS 1444 8 2 8a87d067fd09a5965244fe2e317dd26d182c468e0a7f26ecc4c7b479bf89db9b" + val-override-date: "20201020135527" + ede: no # It is not needed for dns-error-reporting; only for clients to receive EDEs + dns-error-reporting: yes + do-ip6: no + local-zone: test. nodefault + log-servfail: yes + +stub-zone: + name: test + stub-addr: 1.2.3.5 +stub-zone: + name: an.agent + stub-addr: 0.0.0.2 +CONFIG_END + +SCENARIO_BEGIN Test DNS Error Reporting with agent domain len malformed. + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +test. 3600 IN RRSIG NS 8 1 3600 20201116135527 20201019135527 1444 test. RGCxIO32TbbLTk6xZmTr+fjYPH50hntBxeOQ2DIj2pDsmjALcHYtVkOfpfk2EhOhHZd+9PLuoJPbJh6a9NqLSFeBvr0XZoCZoQ2g0tCHUNHcH5EVjA2TuYBQem6DVYnPLJ3914aRx0uA1j42b8dC2xsam/XkOo7U+dLbUW2Os1s= +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +ns.test. 3600 IN NSEC nz.test. A RRSIG +ns.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. PElArVB3KPg8KHAP7lzcNbhFuXNxTsHNTn1dZVncB5qmWRdIaeKpaXDjpH0JSXMaelGFS+/QhuQ6Hmw9+4VyZFRqMzGhw4agUR/2bxABHcDIG4ZpUwyeSP61ATTfHUkQVxaH2wjCWI/tfmesdP2xVE4GXyUvCIBxU914MkZbULU= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN DNSKEY +SECTION ANSWER +test. 3600 IN DNSKEY 257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b} +test. 3600 IN RRSIG DNSKEY 8 1 3600 20201116135527 20201019135527 1444 test. UmRMS4iG9NBBHZYOtpwFFcJgbEb5SfHSgHd9XRe/8pTWM31WSDayn5ViPOBMqI1T5TXg2amc13dDI574xIM2oKMus3b5cBW72jJLW13jprBtslO6P8BMWb4HNnvLrJtQjwf3ErRirtTxinLmywQtmyr1cdthyG3Gp4N7i90fHSc= +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.test. IN DS +SECTION ANSWER +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +example.test. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55567 example.test. l1JT0wMlK0YI7/CWHzexf/k0iafUhCgN+BdgjBXIRXmSQNf4HDTiAkbcWL2/15qtnp12nQy9JeiTdSQ3vtPoHAJX4C5uTWaze4ms+Wrrf+n92sLCjacP9x50uuicH3URT6cKb1QCAPwlvlWxIlZjAMYFScSns7+C441NMJT8aE4= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN DNSKEY +SECTION ANSWER +example.test. 3600 IN DNSKEY 257 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55567 (ksk), size = 1024b} +example.test. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g= +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 3600 IN A 10.20.30.40 +; valid signature +;www.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. OQEgDcpez8Bvdwd+hxA3v63FWJhutWkv9w+k+8RLcWv34WPhebsf7CBV74ggY2c+HafvYiuIFfhdF5CX28YQjxqWVzFgE6bEA6spPc6qdHiQaY/096/4SLCDcL+2EtOqcR/uZGj5uNhhaCJ9UjscBKfEZmHUOAMXKmjsvl0I/+I= +; invalid: expired signature +www.example.test. 3600 IN RRSIG A 8 3 3600 20200816135527 20200719135527 55567 example.test. DNM4PJALboBNDe5pJ2NScYqYYmmpq8E0NogjbDNithIcQ7HtzkssLIR46DiPb/B7QIhBRpfQ6sUwMb4l+NDhm82DxaecEwnAV6Y0zYK6dZ5jI7e8rDI2hkW/LO75qSZ8Y1I9pgX5uyeBCon42IVjc3vyYbRbFNv1xgJs5rk308U= +SECTION ADDITIONAL +HEX_EDNSDATA_BEGIN +; This dns error reporting option is malformed, with garbage at end. + 00 12 ; opt-code (Report-Channel) + 00 28 ; opt-len 10 + 30 + 02 61 6E 05 61 67 65 6E 74 00 ; an.agent. + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ; 30 0xFF tail + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +HEX_EDNSDATA_END +ENTRY_END +RANGE_END + +; an.agent +RANGE_BEGIN 10 20 + ADDRESS 0.0.0.2 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +_er.1.www.example.test.7._er.an.agent. IN TXT +SECTION ANSWER +_er.1.www.example.test.7._er.an.agent. IN TXT "OK" +ENTRY_END +RANGE_END + +; Query again +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +; Check that validation failed +; (a DNS Error Report query should have been generated) +STEP 11 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA SERVFAIL +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +; answer the reporting agent reply. +STEP 20 TRAFFIC + +SCENARIO_END diff --git a/testdata/ghost_glue_a.rpl b/testdata/ghost_glue_a.rpl new file mode 100644 index 000000000..5468ab842 --- /dev/null +++ b/testdata/ghost_glue_a.rpl @@ -0,0 +1,365 @@ +; config options +; The island of trust is at test. +server: + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: no + minimal-responses: yes + iter-scrub-promiscuous: yes + aggressive-nsec: no + local-zone: test. nodefault + log-servfail: yes + module-config: "iterator" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test ghost domain glue TTL extension +; for A and AAAA records. + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 20 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. 4 IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. 4 IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 25 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. 4 IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. 4 IN A 1.2.3.7 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 20 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. 7200 IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. 7200 IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. 7200 IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; ns.example.test. +; after the delegation change, the old hoster. +RANGE_BEGIN 20 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www3.example.test. IN A +SECTION ANSWER +www3.example.test. IN A 10.20.30.46 +ENTRY_END +RANGE_END + +; ns.example.test. +; the new hoster +RANGE_BEGIN 20 100 + ADDRESS 1.2.3.7 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.7 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www2.example.test. IN A +SECTION ANSWER +www2.example.test. IN A 10.20.30.47 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA SERVFAIL +SECTION QUESTION +www3.example.test. IN A +SECTION ANSWER +ENTRY_END +RANGE_END + +; The TTL of the NS and glue is 4 for example.test. +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +STEP 2 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA DO NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END + +; query for the NS record +STEP 8 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +example.test. IN NS +ENTRY_END + +STEP 9 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA DO NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. 7200 IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. 4 IN A 1.2.3.4 +ENTRY_END + +; query for glue specifically +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +ns.example.test. IN A +ENTRY_END + +STEP 11 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA DO NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. 7200 IN A 1.2.3.4 +ENTRY_END + +; query for glue from cache again +STEP 12 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +ns.example.test. IN A +ENTRY_END + +STEP 13 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA DO NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. 4 IN A 1.2.3.4 +ENTRY_END + +; Move time to expire the delegation +STEP 20 TIME_PASSES ELAPSE 6 + +; The upstream changes to delegate to another server. +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www2.example.test. IN A +ENTRY_END + +STEP 31 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA DO NOERROR +SECTION QUESTION +www2.example.test. IN A +SECTION ANSWER +www2.example.test. IN A 10.20.30.47 +ENTRY_END + +; the new server, 1.2.3.7 is not responsive (SERVFAILs), it +; should not have the old one 1.2.3.4 now. +STEP 40 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www3.example.test. IN A +ENTRY_END + +STEP 50 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +www3.example.test. IN A +SECTION ANSWER +ENTRY_END + + +SCENARIO_END diff --git a/testdata/iter_prefetch_fail.rpl b/testdata/iter_prefetch_fail.rpl index d1e308305..aa94d0fe5 100644 --- a/testdata/iter_prefetch_fail.rpl +++ b/testdata/iter_prefetch_fail.rpl @@ -319,7 +319,7 @@ example.com. 360 IN NS ns.example.com. SECTION ADDITIONAL ; this is picked up from the parent (because this simulation has the ; parent respond with servfail, not actually timeout) -ns.example.com. 3600 IN A 1.2.3.4 +ns.example.com. 360 IN A 1.2.3.4 ENTRY_END ; another query to see if there is another lookup towards the authority @@ -342,7 +342,7 @@ www.example.com. 360 IN A 10.20.30.40 SECTION AUTHORITY example.com. 360 IN NS ns.example.com. SECTION ADDITIONAL -ns.example.com. 3600 IN A 1.2.3.4 +ns.example.com. 360 IN A 1.2.3.4 ENTRY_END ; some time later another query, and now it is fine to bother the authority @@ -367,7 +367,7 @@ www.example.com. 330 IN A 10.20.30.40 SECTION AUTHORITY example.com. 330 IN NS ns.example.com. SECTION ADDITIONAL -ns.example.com. 3570 IN A 1.2.3.4 +ns.example.com. 330 IN A 1.2.3.4 ENTRY_END ; now the just-looked-up entry STEP 190 QUERY @@ -388,7 +388,7 @@ www.example.com. 3600 IN A 10.20.30.40 SECTION AUTHORITY example.com. 3600 IN NS ns.example.com. SECTION ADDITIONAL -ns.example.com. 3570 IN A 1.2.3.4 +ns.example.com. 3600 IN A 1.2.3.4 ENTRY_END diff --git a/testdata/iter_svcb_malformed.rpl b/testdata/iter_svcb_malformed.rpl index 8ac31fd2d..e08ed8e52 100644 --- a/testdata/iter_svcb_malformed.rpl +++ b/testdata/iter_svcb_malformed.rpl @@ -151,7 +151,14 @@ REPLY QR RD RA NOERROR SECTION QUESTION www.example.com. IN HTTPS SECTION ANSWER -www.example.com. 0 IN HTTPS 1 . alpn="h2" alpn="h3" +; www.example.com. 0 IN HTTPS 1 . alpn="h2" alpn="h3" +; in unknown record format, otherwise the zonefile format reader converts +; the svcb and sorts the svcbparams, and puts them in-order. That qsort is +; not stable, on some systems(windows), and that would put the identical +; key elements in a different order. With the unknown record format this +; conversion is ommitted, and the bad svcb record with duplicate keys stays +; in the same byte format. +www.example.com. IN HTTPS \# 17 00 01 00 00 01 00 03 02 68 32 00 01 00 03 02 68 33 ENTRY_END STEP 20 QUERY diff --git a/testdata/local_block_a.rpl b/testdata/local_block_a.rpl new file mode 100644 index 000000000..6db5cb200 --- /dev/null +++ b/testdata/local_block_a.rpl @@ -0,0 +1,334 @@ +; config options +; The island of trust is at example.com +server: + qname-minimisation: no + local-zone: "example1.com." block_a + local-zone: "example2.com." block_aaaa + local-zone: "example3.com." block_a_wdata + local-data: "b.example3.com. A 1.2.3.5" + local-data: "b.example3.com. AAAA 1:2:3::5" + local-zone: "example4.com." block_aaaa_wdata + local-data: "b.example4.com. A 1.2.3.5" + local-data: "b.example4.com. AAAA 1:2:3::5" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN test local data with block_a and block_aaaa + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 400 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example1.com. IN A +SECTION ANSWER +a.example1.com. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example1.com. IN AAAA +SECTION ANSWER +a.example1.com. IN AAAA 1:2:3::4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example2.com. IN A +SECTION ANSWER +a.example2.com. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example2.com. IN AAAA +SECTION ANSWER +a.example2.com. IN AAAA 1:2:3::4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example3.com. IN A +SECTION ANSWER +a.example3.com. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example3.com. IN AAAA +SECTION ANSWER +a.example3.com. IN AAAA 1:2:3::4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example4.com. IN A +SECTION ANSWER +a.example4.com. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example4.com. IN AAAA +SECTION ANSWER +a.example4.com. IN AAAA 1:2:3::4 +ENTRY_END +RANGE_END + +; block_a for example1.com +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.example1.com. IN A +ENTRY_END + +; block_a blocks A +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA DO NOERROR +SECTION QUESTION +a.example1.com. IN A +SECTION ANSWER +SECTION AUTHORITY +ENTRY_END + +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.example1.com. IN AAAA +ENTRY_END + +; block_a allows AAAA from upstream +STEP 30 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +a.example1.com. IN AAAA +SECTION ANSWER +a.example1.com. IN AAAA 1:2:3::4 +ENTRY_END + +; block_aaaa for example2.com +STEP 40 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.example2.com. IN A +ENTRY_END + +; block_aaaa allows A from upstream +STEP 50 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +a.example2.com. IN A +SECTION ANSWER +a.example2.com. IN A 1.2.3.4 +ENTRY_END + +STEP 60 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.example2.com. IN AAAA +ENTRY_END + +; block_aaaa blocks AAAA +STEP 70 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA DO NOERROR +SECTION QUESTION +a.example2.com. IN AAAA +SECTION ANSWER +ENTRY_END + +; block_a_wdata for example3.com +STEP 80 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.example3.com. IN A +ENTRY_END + +; block_a_wdata blocks A +STEP 90 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA DO NOERROR +SECTION QUESTION +a.example3.com. IN A +SECTION ANSWER +ENTRY_END + +STEP 100 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.example3.com. IN AAAA +ENTRY_END + +; block_a_wdata allows AAAA from upstream +STEP 110 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +a.example3.com. IN AAAA +SECTION ANSWER +a.example3.com. IN AAAA 1:2:3::4 +ENTRY_END + +STEP 120 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +b.example3.com. IN A +ENTRY_END + +; block_a_wdata allows local-data A +STEP 130 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA DO NOERROR +SECTION QUESTION +b.example3.com. IN A +SECTION ANSWER +b.example3.com. A 1.2.3.5 +ENTRY_END + +STEP 140 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +b.example3.com. IN AAAA +ENTRY_END + +; block_a_wdata allows local-data AAAA +STEP 150 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA DO NOERROR +SECTION QUESTION +b.example3.com. IN AAAA +SECTION ANSWER +b.example3.com. AAAA 1:2:3::5 +ENTRY_END + +; block_aaaa_wdata for example4.com +STEP 160 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.example4.com. IN A +ENTRY_END + +; block_aaaa_wdata allows A from upstream +STEP 170 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +a.example4.com. IN A +SECTION ANSWER +a.example4.com. IN A 1.2.3.4 +ENTRY_END + +STEP 180 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.example4.com. IN AAAA +ENTRY_END + +; block_aaaa_wdata blocks AAAA +STEP 190 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA DO NOERROR +SECTION QUESTION +a.example4.com. IN AAAA +SECTION ANSWER +ENTRY_END + +STEP 200 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +b.example4.com. IN A +ENTRY_END + +; block_aaaa_wdata allows local-data A +STEP 210 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA DO NOERROR +SECTION QUESTION +b.example4.com. IN A +SECTION ANSWER +b.example4.com. A 1.2.3.5 +ENTRY_END + +STEP 220 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +b.example4.com. IN AAAA +ENTRY_END + +; block_aaaa_wdata allows local-data AAAA +STEP 230 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA DO NOERROR +SECTION QUESTION +b.example4.com. IN AAAA +SECTION ANSWER +b.example4.com. AAAA 1:2:3::5 +ENTRY_END + +SCENARIO_END diff --git a/testdata/nsec_cross_zone.rpl b/testdata/nsec_cross_zone.rpl new file mode 100644 index 000000000..8973fae9f --- /dev/null +++ b/testdata/nsec_cross_zone.rpl @@ -0,0 +1,216 @@ +; config options +; The island of trust is at test. +server: + trust-anchor: "test. DS 1444 8 2 8a87d067fd09a5965244fe2e317dd26d182c468e0a7f26ecc4c7b479bf89db9b" + val-override-date: "20201020135527" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: yes + local-zone: test. nodefault + log-servfail: yes + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test overreaching NSEC with aggressive cache + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +test. 3600 IN RRSIG NS 8 1 3600 20201116135527 20201019135527 1444 test. RGCxIO32TbbLTk6xZmTr+fjYPH50hntBxeOQ2DIj2pDsmjALcHYtVkOfpfk2EhOhHZd+9PLuoJPbJh6a9NqLSFeBvr0XZoCZoQ2g0tCHUNHcH5EVjA2TuYBQem6DVYnPLJ3914aRx0uA1j42b8dC2xsam/XkOo7U+dLbUW2Os1s= +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +ns.test. 3600 IN NSEC nz.test. A RRSIG +ns.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. PElArVB3KPg8KHAP7lzcNbhFuXNxTsHNTn1dZVncB5qmWRdIaeKpaXDjpH0JSXMaelGFS+/QhuQ6Hmw9+4VyZFRqMzGhw4agUR/2bxABHcDIG4ZpUwyeSP61ATTfHUkQVxaH2wjCWI/tfmesdP2xVE4GXyUvCIBxU914MkZbULU= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN DNSKEY +SECTION ANSWER +test. 3600 IN DNSKEY 257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b} +test. 3600 IN RRSIG DNSKEY 8 1 3600 20201116135527 20201019135527 1444 test. UmRMS4iG9NBBHZYOtpwFFcJgbEb5SfHSgHd9XRe/8pTWM31WSDayn5ViPOBMqI1T5TXg2amc13dDI574xIM2oKMus3b5cBW72jJLW13jprBtslO6P8BMWb4HNnvLrJtQjwf3ErRirtTxinLmywQtmyr1cdthyG3Gp4N7i90fHSc= +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.test. IN DS +SECTION ANSWER +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +example.test. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55567 example.test. l1JT0wMlK0YI7/CWHzexf/k0iafUhCgN+BdgjBXIRXmSQNf4HDTiAkbcWL2/15qtnp12nQy9JeiTdSQ3vtPoHAJX4C5uTWaze4ms+Wrrf+n92sLCjacP9x50uuicH3URT6cKb1QCAPwlvlWxIlZjAMYFScSns7+C441NMJT8aE4= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN DNSKEY +SECTION ANSWER +example.test. 3600 IN DNSKEY 257 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55567 (ksk), size = 1024b} +example.test. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g= +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.test. IN NSEC +SECTION ANSWER +; normal record has next owner in example.test. +; example.test. IN NSEC b.example.test. SOA DNSKEY NS RRSIG NSEC +example.test. IN NSEC b.foo.test. NS SOA RRSIG NSEC DNSKEY +example.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 55567 example.test. xxepzzIxsJURk4/eZrwcDm5jhQNHtf1OmnPuu3T/w8y5NWwzlgn/hL17xoI71dIgTJg2GAq97wxEUhp951jtGMCeLH2Dz5lDZXxQI4wf2Wl43u2mTBQFRagDwfAauFc6Z4FYI/biDZyYcylZ3A5Q6j6ifFnsgMTL+cP0UIEZBTQ= +ENTRY_END +RANGE_END + +; CD=1 query for type NSEC +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD CD DO +SECTION QUESTION +example.test. IN NSEC +ENTRY_END + +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD CD RA DO NOERROR +SECTION QUESTION +example.test. IN NSEC +SECTION ANSWER +; The overreaching NSEC is removed by the scrubber. +ENTRY_END + +SCENARIO_END diff --git a/testdata/respip_bogus_rewrite.rpl b/testdata/respip_bogus_rewrite.rpl new file mode 100644 index 000000000..7f80612dd --- /dev/null +++ b/testdata/respip_bogus_rewrite.rpl @@ -0,0 +1,216 @@ +; config options +; The island of trust is at test. +server: + trust-anchor: "test. DS 1444 8 2 8a87d067fd09a5965244fe2e317dd26d182c468e0a7f26ecc4c7b479bf89db9b" + val-override-date: "20201020135527" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: yes + local-zone: test. nodefault + log-servfail: yes + module-config: "respip validator iterator" + response-ip: 192.0.2.0/24 redirect + response-ip-data: 192.0.2.0/24 "A 10.10.10.10" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test respip with rewrite of a bogus reply + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +test. 3600 IN RRSIG NS 8 1 3600 20201116135527 20201019135527 1444 test. RGCxIO32TbbLTk6xZmTr+fjYPH50hntBxeOQ2DIj2pDsmjALcHYtVkOfpfk2EhOhHZd+9PLuoJPbJh6a9NqLSFeBvr0XZoCZoQ2g0tCHUNHcH5EVjA2TuYBQem6DVYnPLJ3914aRx0uA1j42b8dC2xsam/XkOo7U+dLbUW2Os1s= +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +ns.test. 3600 IN NSEC nz.test. A RRSIG +ns.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. PElArVB3KPg8KHAP7lzcNbhFuXNxTsHNTn1dZVncB5qmWRdIaeKpaXDjpH0JSXMaelGFS+/QhuQ6Hmw9+4VyZFRqMzGhw4agUR/2bxABHcDIG4ZpUwyeSP61ATTfHUkQVxaH2wjCWI/tfmesdP2xVE4GXyUvCIBxU914MkZbULU= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN DNSKEY +SECTION ANSWER +test. 3600 IN DNSKEY 257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b} +test. 3600 IN RRSIG DNSKEY 8 1 3600 20201116135527 20201019135527 1444 test. UmRMS4iG9NBBHZYOtpwFFcJgbEb5SfHSgHd9XRe/8pTWM31WSDayn5ViPOBMqI1T5TXg2amc13dDI574xIM2oKMus3b5cBW72jJLW13jprBtslO6P8BMWb4HNnvLrJtQjwf3ErRirtTxinLmywQtmyr1cdthyG3Gp4N7i90fHSc= +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.test. IN DS +SECTION ANSWER +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +example.test. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55567 example.test. l1JT0wMlK0YI7/CWHzexf/k0iafUhCgN+BdgjBXIRXmSQNf4HDTiAkbcWL2/15qtnp12nQy9JeiTdSQ3vtPoHAJX4C5uTWaze4ms+Wrrf+n92sLCjacP9x50uuicH3URT6cKb1QCAPwlvlWxIlZjAMYFScSns7+C441NMJT8aE4= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN DNSKEY +SECTION ANSWER +example.test. 3600 IN DNSKEY 257 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55567 (ksk), size = 1024b} +example.test. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g= +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +; this is expired +www.example.test. 3600 IN A 192.0.2.1 +www.example.test. 3600 IN RRSIG A 8 3 3600 20181116135527 20181019135527 55567 example.test. GIyjRM2i5plokjqjH7DRCaEi3AnP8+Wf02fOW6vrDSThr/yvvFXYKLhYwfddPNZRehANOmLQxuXyk6pEHh26Mi7T2Gh7n0SNkQ79e3Ba4Zu6Pih0nRBuEDvlSXjcFzvY9jx+7zZolg3KW8eC/Fn7moxAuDT/+1ZgZdhMOQ802+Q= +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +ENTRY_END + +SCENARIO_END diff --git a/testdata/respip_cname_loop_tagged.rpl b/testdata/respip_cname_loop_tagged.rpl new file mode 100644 index 000000000..a97ae77ad --- /dev/null +++ b/testdata/respip_cname_loop_tagged.rpl @@ -0,0 +1,254 @@ +; config options +; The island of trust is at test. +server: + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: no + local-zone: test. nodefault + log-servfail: yes + discard-timeout: 0 + module-config: "respip iterator" + define-tag: "turqoise" + access-control-tag: 127.0.0.0/8 "turqoise" + access-control-tag-data: 127.0.0.0/8 "turqoise" "A 127.0.0.1" + + ; These two CNAMEs form a loop. + response-ip: 192.0.2.1/32 redirect + response-ip-data: 192.0.2.1/32 "CNAME loop2.far.test." + response-ip: 192.0.2.2/32 redirect + response-ip-data: 192.0.2.2/32 "CNAME loop1.far.test." + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test respip CNAME loop that is tagged. + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +far.test. IN NS +SECTION AUTHORITY +far.test. IN NS ns.far.test. +SECTION ADDITIONAL +ns.far.test. IN A 1.2.3.6 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 20 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 45 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; ns.far.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.6 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +far.test. IN NS +SECTION ANSWER +far.test. IN NS ns.far.test. +SECTION ADDITIONAL +ns.far.test. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.far.test. IN A +SECTION ANSWER +ns.far.test. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.far.test. IN AAAA +SECTION AUTHORITY +far.test. 3600 IN SOA ns.far.test. host.far.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +loop1.far.test. IN A +SECTION ANSWER +loop1.far.test. IN A 192.0.2.1 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +loop2.far.test. IN A +SECTION ANSWER +loop2.far.test. IN A 192.0.2.2 +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +loop1.far.test. IN A +ENTRY_END + +STEP 2 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +loop1.far.test. IN A +SECTION ANSWER +ENTRY_END + +SCENARIO_END diff --git a/testdata/rrsig_agr_wild.rpl b/testdata/rrsig_agr_wild.rpl new file mode 100644 index 000000000..7281aa759 --- /dev/null +++ b/testdata/rrsig_agr_wild.rpl @@ -0,0 +1,374 @@ +; config options +; The island of trust is at com. +server: + trust-anchor: "test. DS 1444 8 2 8a87d067fd09a5965244fe2e317dd26d182c468e0a7f26ecc4c7b479bf89db9b" + val-override-date: "20201020135527" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: yes + local-zone: test. nodefault + log-servfail: yes + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test with RRSIG labels for wildcard with aggressive cache. + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +test. 3600 IN RRSIG NS 8 1 3600 20201116135527 20201019135527 1444 test. RGCxIO32TbbLTk6xZmTr+fjYPH50hntBxeOQ2DIj2pDsmjALcHYtVkOfpfk2EhOhHZd+9PLuoJPbJh6a9NqLSFeBvr0XZoCZoQ2g0tCHUNHcH5EVjA2TuYBQem6DVYnPLJ3914aRx0uA1j42b8dC2xsam/XkOo7U+dLbUW2Os1s= +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +ns.test. 3600 IN NSEC nz.test. A RRSIG +ns.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. PElArVB3KPg8KHAP7lzcNbhFuXNxTsHNTn1dZVncB5qmWRdIaeKpaXDjpH0JSXMaelGFS+/QhuQ6Hmw9+4VyZFRqMzGhw4agUR/2bxABHcDIG4ZpUwyeSP61ATTfHUkQVxaH2wjCWI/tfmesdP2xVE4GXyUvCIBxU914MkZbULU= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN DNSKEY +SECTION ANSWER +test. 3600 IN DNSKEY 257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b} +test. 3600 IN RRSIG DNSKEY 8 1 3600 20201116135527 20201019135527 1444 test. UmRMS4iG9NBBHZYOtpwFFcJgbEb5SfHSgHd9XRe/8pTWM31WSDayn5ViPOBMqI1T5TXg2amc13dDI574xIM2oKMus3b5cBW72jJLW13jprBtslO6P8BMWb4HNnvLrJtQjwf3ErRirtTxinLmywQtmyr1cdthyG3Gp4N7i90fHSc= +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NXDOMAIN +SECTION QUESTION +domain1.test. IN A +SECTION ANSWER +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +test. 3600 IN NSEC abc.test. NS SOA DNSKEY RRSIG NSEC +test. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 1444 test. SHU0veyxtCpPvwdJxn2xCEq9xXJZLIvAlYYy7/dBMSjo6ugBPSxs1+8hUZFxks+YQoPLR5nTU0C0yuhZ9dfg/2VGkCYLsDLYnh1lJj6uQ2VgwfhbwSJC0E9hwYvD7yl6LcmpySbGiyI0cCbK/wWHE8wVw4VBcbuv01f3Cj6F+mo= +cee.test. 3600 IN NSEC erts.test. RRSIG DS +cee.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NXDOMAIN +SECTION QUESTION +domain2.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +test. 3600 IN NSEC abc.test. NS SOA DNSKEY RRSIG NSEC +test. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 1444 test. SHU0veyxtCpPvwdJxn2xCEq9xXJZLIvAlYYy7/dBMSjo6ugBPSxs1+8hUZFxks+YQoPLR5nTU0C0yuhZ9dfg/2VGkCYLsDLYnh1lJj6uQ2VgwfhbwSJC0E9hwYvD7yl6LcmpySbGiyI0cCbK/wWHE8wVw4VBcbuv01f3Cj6F+mo= +cee.test. 3600 IN NSEC erts.test. RRSIG DS +cee.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.test. IN DS +SECTION ANSWER +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +example.test. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55567 example.test. l1JT0wMlK0YI7/CWHzexf/k0iafUhCgN+BdgjBXIRXmSQNf4HDTiAkbcWL2/15qtnp12nQy9JeiTdSQ3vtPoHAJX4C5uTWaze4ms+Wrrf+n92sLCjacP9x50uuicH3URT6cKb1QCAPwlvlWxIlZjAMYFScSns7+C441NMJT8aE4= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN DNSKEY +SECTION ANSWER +example.test. 3600 IN DNSKEY 257 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55567 (ksk), size = 1024b} +example.test. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g= +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +wild.example.test. IN A +SECTION ANSWER +wild.example.test. IN A 10.20.30.40 +; normal RRSIG: +;wild.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. RzIsliJeEcLIHQGJqr5U2tfgxjzyxvwpqWYMdF2qOmb5a5erx3AFwRLbHhl7383Kdpdi+KxVKIWmkG6YCta0sWE42UeDXAVtZnFK/VeADRWpzWljQaTdIG8eN6FdB/X3gSPXnxMhsd9OoAWHPJYrwXtoFbciH6Hy0gl4Cosc+7Q= +; with labelcount lower, 2 lower. +; like it is : *.test. IN A 10.20.30.40 +wild.example.test. 3600 IN RRSIG A 8 1 3600 20201116135527 20201019135527 55567 example.test. XR1dPkaZmhIXoKRBmVLiDdIROYxlVNuII0kD/Nh/L3QteSvjwdfDBbVvwWGc+y011is0eFZBlFHWxmhw8BXytktlcJ3rZ1GPbcixkX7XPIIZER7jvZiFnKDS2Fwgh2wgpAXdo8KrmMgeUGPjP9scbzbBxLfSV/ja93PTuTSi6VA= +SECTION AUTHORITY +un.example.test. 3600 IN NSEC xy.example.test. A RRSIG +un.example.test. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55567 example.test. rP0p0viq8A3y/RSth9BNkDVAufPRVp8uohX+Wp1lby4naxlOjZCONz3aeLz8c0XgrIUtdU4t2sZZz9gF9jfr/QnAr5JDMDAIpMXKYGx/3dk5mSP/OBRX9sNVuBdr9YuyYy5N9K97aKTSQTRNU8FdTVYx9yjImVlwA8KI+SkztJ4= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +wild2.example.test. IN DS +SECTION ANSWER +wild2.example.test. IN DS 12345 250 2 00000000 +; normal RRSIG +; wild2.example.test. 3600 IN RRSIG DS 8 3 3600 20201116135527 20201019135527 55567 example.test. GdSaD9J3c2QwsAPRbzY7lbuqguaBNEu/19jnZIrdMx4nmRRaMOS1MqMGZyOJdYvupVA0zg32bhCbmZdHSQLwzybjIgixGeiPC9MnfHdSqZKG7QG/AlUR2A/Mhmedp7RngROgIf6c7de88zsX+60xSfvBgNtg55YmODHqOICvTLs= +; with labelcount lower, 2 lower. +; for *.test. IN DS 12345 250 2 00000000 +wild2.example.test. 3600 IN RRSIG DS 8 1 3600 20201116135527 20201019135527 55567 example.test. qZQ/bfTCVuGISm6Pkq6OYDnyZMx8/uQQE3vq402UVWyy7ZrDBVI/CAErEIqz7Xl4cGgFUoezL2LCBIS7BMERCbQ0cVm3YTpnSzCgiDNJsu9W778SLOTcWlqJaiJn9EieFGkiFo2k3c1iuW++yufdhQmuXGk+DdLzE87tgvIkQm0= +SECTION AUTHORITY +un.example.test. 3600 IN NSEC xy.example.test. A RRSIG +un.example.test. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55567 example.test. rP0p0viq8A3y/RSth9BNkDVAufPRVp8uohX+Wp1lby4naxlOjZCONz3aeLz8c0XgrIUtdU4t2sZZz9gF9jfr/QnAr5JDMDAIpMXKYGx/3dk5mSP/OBRX9sNVuBdr9YuyYy5N9K97aKTSQTRNU8FdTVYx9yjImVlwA8KI+SkztJ4= +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +domain1.test. IN A +ENTRY_END + +; Picks up NSECs for aggressive negative cache. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AD DO NXDOMAIN +SECTION QUESTION +domain1.test. IN A +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +test. 3600 IN NSEC abc.test. NS SOA DNSKEY RRSIG NSEC +test. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 1444 test. SHU0veyxtCpPvwdJxn2xCEq9xXJZLIvAlYYy7/dBMSjo6ugBPSxs1+8hUZFxks+YQoPLR5nTU0C0yuhZ9dfg/2VGkCYLsDLYnh1lJj6uQ2VgwfhbwSJC0E9hwYvD7yl6LcmpySbGiyI0cCbK/wWHE8wVw4VBcbuv01f3Cj6F+mo= +cee.test. 3600 IN NSEC erts.test. RRSIG DS +cee.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA= +ENTRY_END + +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +wild.example.test. IN A +ENTRY_END + +; query for the wildcard record. +STEP 30 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +wild.example.test. IN A +ENTRY_END +;REPLY QR RD RA AD DO NXDOMAIN +;SECTION QUESTION +;domain1.test. IN A +;SECTION ANSWER +;wild.example.test. IN A 10.20.30.40 +;wild.example.test. 3600 IN RRSIG A 8 1 3600 20201116135527 20201019135527 55567 example.test. XR1dPkaZmhIXoKRBmVLiDdIROYxlVNuII0kD/Nh/L3QteSvjwdfDBbVvwWGc+y011is0eFZBlFHWxmhw8BXytktlcJ3rZ1GPbcixkX7XPIIZER7jvZiFnKDS2Fwgh2wgpAXdo8KrmMgeUGPjP9scbzbBxLfSV/ja93PTuTSi6VA= +;SECTION AUTHORITY +;un.example.test. 3600 IN NSEC xy.example.test. A RRSIG +;un.example.test. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55567 example.test. rP0p0viq8A3y/RSth9BNkDVAufPRVp8uohX+Wp1lby4naxlOjZCONz3aeLz8c0XgrIUtdU4t2sZZz9gF9jfr/QnAr5JDMDAIpMXKYGx/3dk5mSP/OBRX9sNVuBdr9YuyYy5N9K97aKTSQTRNU8FdTVYx9yjImVlwA8KI+SkztJ4= +;ENTRY_END + +;STEP 40 QUERY +;ENTRY_BEGIN +;REPLY RD DO +;SECTION QUESTION +;domain2.test. IN A +;ENTRY_END +; +;; aggressive cache synthesis, the '*.test' from the wildcard lookup. +;STEP 50 CHECK_ANSWER +;ENTRY_BEGIN +;MATCH all +;REPLY QR RD RA DO SERVFAIL +;SECTION QUESTION +;domain2.test. IN A +;SECTION ANSWER +;ENTRY_END + +STEP 60 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +wild2.example.test. IN DS +ENTRY_END + +; wild2 is for *.test DS +STEP 70 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +wild2.example.test. IN DS +SECTION ANSWER +ENTRY_END + +STEP 80 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +domain3.test. IN A +ENTRY_END + +; aggressive cache synthesis, the '*.test' from the wildcard lookup. +; with '*.test' DS record. +STEP 90 CHECK_ANSWER +ENTRY_BEGIN +MATCH all + +; The bad answer +;REPLY QR RD RA DO NOERROR +;SECTION QUESTION +;domain3.test. IN A +;SECTION ANSWER +;domain3.test. 0 IN A 10.20.30.40 +;domain3.test. 0 IN RRSIG A 8 1 3600 20201116135527 20201019135527 55567 example.test. XR1dPkaZmhIXoKRBmVLiDdIROYxlVNuII0kD/Nh/L3QteSvjwdfDBbVvwWGc+y011is0eFZBlFHWxmhw8BXytktlcJ3rZ1GPbcixkX7XPIIZER7jvZiFnKDS2Fwgh2wgpAXdo8KrmMgeUGPjP9scbzbBxLfSV/ja93PTuTSi6VA= ;{id = 55567} +;SECTION AUTHORITY +;cee.test. 0 IN NSEC erts.test. DS RRSIG +;cee.test. 0 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA= ;{id = 1444} + +; The correct answer +REPLY QR RD RA AD DO NXDOMAIN +SECTION QUESTION +domain3.test. IN A +SECTION AUTHORITY +test. 3600 IN NSEC abc.test. NS SOA DNSKEY RRSIG NSEC +test. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 1444 test. SHU0veyxtCpPvwdJxn2xCEq9xXJZLIvAlYYy7/dBMSjo6ugBPSxs1+8hUZFxks+YQoPLR5nTU0C0yuhZ9dfg/2VGkCYLsDLYnh1lJj6uQ2VgwfhbwSJC0E9hwYvD7yl6LcmpySbGiyI0cCbK/wWHE8wVw4VBcbuv01f3Cj6F+mo= +cee.test. 3600 IN NSEC erts.test. RRSIG DS +cee.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA= +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +ENTRY_END + +SCENARIO_END diff --git a/testdata/serve_expired_respip_cname.rpl b/testdata/serve_expired_respip_cname.rpl new file mode 100644 index 000000000..977836f5a --- /dev/null +++ b/testdata/serve_expired_respip_cname.rpl @@ -0,0 +1,290 @@ +; config options +; The island of trust is at test. +server: + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: no + local-zone: test. nodefault + log-servfail: yes + discard-timeout: 0 + module-config: "respip iterator" + serve-expired: yes + serve-expired-client-timeout: 500 + serve-expired-ttl: 3600 + serve-expired-reply-ttl: 30 + response-ip: 192.0.2.0/24 redirect + response-ip-data: 192.0.2.0/24 "CNAME tgt.far.test." + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test expired response respip rewrite + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +far.test. IN NS +SECTION AUTHORITY +far.test. IN NS ns.far.test. +SECTION ADDITIONAL +ns.far.test. IN A 1.2.3.6 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 20 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 45 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; ns.far.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.6 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +far.test. IN NS +SECTION ANSWER +far.test. IN NS ns.far.test. +SECTION ADDITIONAL +ns.far.test. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.far.test. IN A +SECTION ANSWER +ns.far.test. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.far.test. IN AAAA +SECTION AUTHORITY +far.test. 3600 IN SOA ns.far.test. host.far.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +tgt.far.test. IN A +SECTION ANSWER +tgt.far.test. 1 IN A 10.20.30.40 +ENTRY_END +RANGE_END + +; Put items with TTL 1 in cache. +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +tgt.far.test. IN A +ENTRY_END + +STEP 2 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +tgt.far.test. IN A +SECTION ANSWER +tgt.far.test. 1 IN A 10.20.30.40 +ENTRY_END + +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +STEP 11 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 3600 IN CNAME tgt.far.test. +tgt.far.test. 1 IN A 10.20.30.40 +ENTRY_END + +; Move time to expire the cache entries. +STEP 20 TIME_PASSES ELAPSE 2 + +; the upstream RANGE is removed, so serve-expired has to act. + +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +; for serve expired callback. +STEP 31 TIME_PASSES ELAPSE 2 + +STEP 40 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 3600 IN CNAME tgt.far.test. +tgt.far.test. 1 IN A 10.20.30.40 +ENTRY_END + +; The pending lookup for the data, that was answered with expired to the client. +STEP 50 TRAFFIC + +SCENARIO_END diff --git a/testdata/serve_expired_respip_drop.rpl b/testdata/serve_expired_respip_drop.rpl new file mode 100644 index 000000000..de9eee7be --- /dev/null +++ b/testdata/serve_expired_respip_drop.rpl @@ -0,0 +1,274 @@ +; config options +; The island of trust is at test. +server: + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: no + local-zone: test. nodefault + log-servfail: yes + discard-timeout: 0 + module-config: "respip iterator" + serve-expired: yes + serve-expired-client-timeout: 500 + serve-expired-ttl: 3600 + serve-expired-reply-ttl: 30 + response-ip: 192.0.2.0/24 deny + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test expired response respip drop + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +far.test. IN NS +SECTION AUTHORITY +far.test. IN NS ns.far.test. +SECTION ADDITIONAL +ns.far.test. IN A 1.2.3.6 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 20 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 45 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; ns.far.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.6 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +far.test. IN NS +SECTION ANSWER +far.test. IN NS ns.far.test. +SECTION ADDITIONAL +ns.far.test. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.far.test. IN A +SECTION ANSWER +ns.far.test. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.far.test. IN AAAA +SECTION AUTHORITY +far.test. 3600 IN SOA ns.far.test. host.far.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +tgt.far.test. IN A +SECTION ANSWER +tgt.far.test. 1 IN A 10.20.30.40 +ENTRY_END +RANGE_END + +; Put items with TTL 1 in cache. +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +; Answer is dropped +;STEP 11 CHECK_ANSWER +;ENTRY_BEGIN +;MATCH all +;REPLY QR RD RA DO NOERROR +;SECTION QUESTION +;www.example.test. IN A +;SECTION ANSWER +;www.example.test. 3600 IN CNAME tgt.far.test. +;tgt.far.test. 1 IN A 10.20.30.40 +;ENTRY_END + +; Move time to expire the cache entries. +STEP 20 TIME_PASSES ELAPSE 2 + +; the upstream RANGE is removed, so serve-expired has to act. + +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +; for serve expired callback. +STEP 31 TIME_PASSES ELAPSE 2 + +; Answer is dropped +;STEP 40 CHECK_ANSWER +;ENTRY_BEGIN +;MATCH all +;REPLY QR RD RA DO NOERROR +;SECTION QUESTION +;www.example.test. IN A +;SECTION ANSWER +;www.example.test. 3600 IN CNAME tgt.far.test. +;tgt.far.test. 1 IN A 10.20.30.40 +;ENTRY_END + +; The pending lookup for the data, that was answered with expired to the client. +STEP 50 TRAFFIC + +SCENARIO_END diff --git a/testdata/serve_expired_rpz_drop.rpl b/testdata/serve_expired_rpz_drop.rpl new file mode 100644 index 000000000..ab5d49827 --- /dev/null +++ b/testdata/serve_expired_rpz_drop.rpl @@ -0,0 +1,246 @@ +; config options +; The island of trust is at test. +server: + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: no + local-zone: test. nodefault + log-servfail: yes + discard-timeout: 0 + module-config: "respip iterator" + serve-expired: yes + serve-expired-client-timeout: 500 + serve-expired-ttl: 3600 + serve-expired-reply-ttl: 30 + +rpz: + name: "rpz.example.com." + rpz-log: yes + rpz-log-name: "rpz.example.com" + zonefile: +TEMPFILE_NAME rpz.example.com +TEMPFILE_CONTENTS rpz.example.com +$ORIGIN example.com. +rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( + 1379078166 28800 7200 604800 7200 ) + 3600 IN NS ns1.rpz.example.com. + 3600 IN NS ns2.rpz.example.com. +$ORIGIN rpz.example.com. +24.0.2.0.192.rpz-ip CNAME rpz-drop. +TEMPFILE_END + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test expired response RPZ drop + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 20 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 50 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; Put items with TTL 1 in cache. +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +; answer is dropped. +;STEP 11 CHECK_ANSWER +;ENTRY_BEGIN +;MATCH all +;REPLY QR RD RA DO NXDOMAIN +;SECTION QUESTION +;www.example.test. IN A +;SECTION ANSWER +;ENTRY_END + +; Move time to expire the cache entries. +STEP 20 TIME_PASSES ELAPSE 2 + +; the upstream RANGE is removed, so serve-expired has to act. + +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +; for serve expired callback. +STEP 31 TIME_PASSES ELAPSE 2 + +; answer is dropped +;STEP 40 CHECK_ANSWER +;ENTRY_BEGIN +;MATCH all +;REPLY QR RD RA DO NXDOMAIN +;SECTION QUESTION +;www.example.test. IN A +;SECTION ANSWER +;ENTRY_END + +; The pending lookup for the data, that was answered with expired to the client. +STEP 50 TRAFFIC + +SCENARIO_END diff --git a/testdata/serve_expired_rpz_nx.rpl b/testdata/serve_expired_rpz_nx.rpl new file mode 100644 index 000000000..19956545e --- /dev/null +++ b/testdata/serve_expired_rpz_nx.rpl @@ -0,0 +1,319 @@ +; config options +; The island of trust is at test. +server: + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: no + local-zone: test. nodefault + log-servfail: yes + discard-timeout: 0 + module-config: "respip iterator" + serve-expired: yes + serve-expired-client-timeout: 500 + serve-expired-ttl: 3600 + serve-expired-reply-ttl: 30 + +rpz: + name: "rpz.example.com." + rpz-log: yes + rpz-log-name: "rpz.example.com" + zonefile: +TEMPFILE_NAME rpz.example.com +TEMPFILE_CONTENTS rpz.example.com +$ORIGIN example.com. +rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( + 1379078166 28800 7200 604800 7200 ) + 3600 IN NS ns1.rpz.example.com. + 3600 IN NS ns2.rpz.example.com. +$ORIGIN rpz.example.com. +24.0.2.0.192.rpz-ip CNAME . +TEMPFILE_END + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test expired response RPZ rewrite + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +far.test. IN NS +SECTION AUTHORITY +far.test. IN NS ns.far.test. +SECTION ADDITIONAL +ns.far.test. IN A 1.2.3.6 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 20 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 1 IN A 192.0.2.1 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 20 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR SERVFAIL +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +ENTRY_END +RANGE_END + +; ns.far.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.6 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +far.test. IN NS +SECTION ANSWER +far.test. IN NS ns.far.test. +SECTION ADDITIONAL +ns.far.test. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.far.test. IN A +SECTION ANSWER +ns.far.test. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.far.test. IN AAAA +SECTION AUTHORITY +far.test. 3600 IN SOA ns.far.test. host.far.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +tgt.far.test. IN A +SECTION ANSWER +tgt.far.test. 1 IN A 10.20.30.40 +ENTRY_END +RANGE_END + +; Put items with TTL 1 in cache. +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +tgt.far.test. IN A +ENTRY_END + +STEP 2 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +tgt.far.test. IN A +SECTION ANSWER +tgt.far.test. 1 IN A 10.20.30.40 +ENTRY_END + +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +STEP 11 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NXDOMAIN +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +ENTRY_END + +; Move time to expire the cache entries. +STEP 20 TIME_PASSES ELAPSE 2 + +; the upstream RANGE is removed, so serve-expired has to act. + +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +; for serve expired callback. +STEP 31 TIME_PASSES ELAPSE 2 + +STEP 40 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NXDOMAIN +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +ENTRY_END + +; The pending lookup for the data, that was answered with expired to the client. +STEP 50 TRAFFIC + +SCENARIO_END diff --git a/testdata/serve_expired_wildcard_swap_ad.rpl b/testdata/serve_expired_wildcard_swap_ad.rpl new file mode 100644 index 000000000..9bfd5caaa --- /dev/null +++ b/testdata/serve_expired_wildcard_swap_ad.rpl @@ -0,0 +1,330 @@ +; config options +; The island of trust is at test. +server: + trust-anchor: "test. DS 1444 8 2 8a87d067fd09a5965244fe2e317dd26d182c468e0a7f26ecc4c7b479bf89db9b" + val-override-date: "20201020135527" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: no + local-zone: test. nodefault + log-servfail: yes + serve-expired: yes + serve-expired-client-timeout: 0 + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test serve-expired on wildcard secure from another message + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +alias.other.tld. IN A +SECTION ANSWER +alias.other.tld. IN CNAME www.example.test. +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +test. 3600 IN RRSIG NS 8 1 3600 20201116135527 20201019135527 1444 test. RGCxIO32TbbLTk6xZmTr+fjYPH50hntBxeOQ2DIj2pDsmjALcHYtVkOfpfk2EhOhHZd+9PLuoJPbJh6a9NqLSFeBvr0XZoCZoQ2g0tCHUNHcH5EVjA2TuYBQem6DVYnPLJ3914aRx0uA1j42b8dC2xsam/XkOo7U+dLbUW2Os1s= +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +ns.test. 3600 IN NSEC nz.test. A RRSIG +ns.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. PElArVB3KPg8KHAP7lzcNbhFuXNxTsHNTn1dZVncB5qmWRdIaeKpaXDjpH0JSXMaelGFS+/QhuQ6Hmw9+4VyZFRqMzGhw4agUR/2bxABHcDIG4ZpUwyeSP61ATTfHUkQVxaH2wjCWI/tfmesdP2xVE4GXyUvCIBxU914MkZbULU= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN DNSKEY +SECTION ANSWER +test. 3600 IN DNSKEY 257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b} +test. 3600 IN RRSIG DNSKEY 8 1 3600 20201116135527 20201019135527 1444 test. UmRMS4iG9NBBHZYOtpwFFcJgbEb5SfHSgHd9XRe/8pTWM31WSDayn5ViPOBMqI1T5TXg2amc13dDI574xIM2oKMus3b5cBW72jJLW13jprBtslO6P8BMWb4HNnvLrJtQjwf3ErRirtTxinLmywQtmyr1cdthyG3Gp4N7i90fHSc= +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.test. IN DS +SECTION ANSWER +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 25 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +example.test. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55567 example.test. l1JT0wMlK0YI7/CWHzexf/k0iafUhCgN+BdgjBXIRXmSQNf4HDTiAkbcWL2/15qtnp12nQy9JeiTdSQ3vtPoHAJX4C5uTWaze4ms+Wrrf+n92sLCjacP9x50uuicH3URT6cKb1QCAPwlvlWxIlZjAMYFScSns7+C441NMJT8aE4= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN DNSKEY +SECTION ANSWER +example.test. 3600 IN DNSKEY 257 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55567 (ksk), size = 1024b} +example.test. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g= +ENTRY_END + +; This wildcard exists in the zone. It is signed by example.test. +; *.example.test. 10 IN A 10.20.30.33 +; +; *.example.test. 10 IN A 10.20.30.33 +; *.example.test. 10 IN RRSIG A 8 2 10 20201116135527 20201019135527 55567 example.test. txqAQLRwy7ZdpExOnpLAQ1/xOz7gOp5C3XB/vg3CoTqvUtGqJ2MxEc3H0XtCfhSJJocbIof+lQSleAzs+Y/B0FV7YruCzPoNlZDW7qVaY0fITTwef97ui3AbxkOpNEptVN3xxsH3o5AYKAmh+oePzBsZlxmP4KuF9DoKl9/m52M= + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 10 IN A 10.20.30.40 +www.example.test. 10 IN RRSIG A 8 3 10 20201116135527 20201019135527 55567 example.test. 1by1cfB/FwdGm2gH/TUmn9KYzyIpd1i2iDwHXayd4uOuYC/v4CCHwl1pbhlz4J7WNoetG7QmVNKhXQyH1446BEUOpEe0skYOYb0r+gk3Cv6BwTH+bAzkiseFLUQ/YVbmUmLOXMm0fN1rP6sUM1aDBd+ugIr0UNPQJcbCTMjtvIQ= +ENTRY_END +RANGE_END + +RANGE_BEGIN 25 45 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +; the wildcard put as the www.example.test. +www.example.test. 10 IN A 10.20.30.33 +www.example.test. 10 IN RRSIG A 8 2 10 20201116135527 20201019135527 55567 example.test. txqAQLRwy7ZdpExOnpLAQ1/xOz7gOp5C3XB/vg3CoTqvUtGqJ2MxEc3H0XtCfhSJJocbIof+lQSleAzs+Y/B0FV7YruCzPoNlZDW7qVaY0fITTwef97ui3AbxkOpNEptVN3xxsH3o5AYKAmh+oePzBsZlxmP4KuF9DoKl9/m52M= +; no wildcard NSEC proof +ENTRY_END +RANGE_END + +RANGE_BEGIN 45 65 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 10 IN A 10.20.30.40 +www.example.test. 10 IN RRSIG A 8 3 10 20201116135527 20201019135527 55567 example.test. 1by1cfB/FwdGm2gH/TUmn9KYzyIpd1i2iDwHXayd4uOuYC/v4CCHwl1pbhlz4J7WNoetG7QmVNKhXQyH1446BEUOpEe0skYOYb0r+gk3Cv6BwTH+bAzkiseFLUQ/YVbmUmLOXMm0fN1rP6sUM1aDBd+ugIr0UNPQJcbCTMjtvIQ= +ENTRY_END +RANGE_END + +; query for a message in cache that is going to be expired, +; and then get an RRset replaced. +; The query is for a record not covered by the wildcard in the zone. + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AD DO NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 10 IN A 10.20.30.40 +www.example.test. 10 IN RRSIG A 8 3 10 20201116135527 20201019135527 55567 example.test. 1by1cfB/FwdGm2gH/TUmn9KYzyIpd1i2iDwHXayd4uOuYC/v4CCHwl1pbhlz4J7WNoetG7QmVNKhXQyH1446BEUOpEe0skYOYb0r+gk3Cv6BwTH+bAzkiseFLUQ/YVbmUmLOXMm0fN1rP6sUM1aDBd+ugIr0UNPQJcbCTMjtvIQ= +ENTRY_END + +; wait to expire the message +STEP 20 TIME_PASSES ELAPSE 18 + +; swap the www.example.test. RRset with another. + +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +alias.other.tld. IN A +ENTRY_END + +STEP 40 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +alias.other.tld. IN A +SECTION ANSWER +; the wildcard proof fails here, but it validated the RRSIG over +; wildcard A record. +ENTRY_END + +; the serve expired response +STEP 50 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.test. IN A +ENTRY_END + +STEP 60 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AD DO NOERROR +SECTION QUESTION +www.example.test. IN A +SECTION ANSWER +www.example.test. 10 IN A 10.20.30.40 +www.example.test. 10 IN RRSIG A 8 3 10 20201116135527 20201019135527 55567 example.test. 1by1cfB/FwdGm2gH/TUmn9KYzyIpd1i2iDwHXayd4uOuYC/v4CCHwl1pbhlz4J7WNoetG7QmVNKhXQyH1446BEUOpEe0skYOYb0r+gk3Cv6BwTH+bAzkiseFLUQ/YVbmUmLOXMm0fN1rP6sUM1aDBd+ugIr0UNPQJcbCTMjtvIQ= +ENTRY_END + +SCENARIO_END diff --git a/testdata/stop_nxdomain_label.rpl b/testdata/stop_nxdomain_label.rpl new file mode 100644 index 000000000..b882cf05f --- /dev/null +++ b/testdata/stop_nxdomain_label.rpl @@ -0,0 +1,115 @@ +; config options +server: + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + harden-below-nxdomain: yes + trust-anchor: ". IN DNSKEY 257 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3" + val-override-date: "20070916134226" + fake-sha1: yes + trust-anchor-signaling: no + aggressive-nsec: no + domain-insecure: "under.example.local" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +stub-zone: + name: "under.example.local" + stub-addr: 1.2.3.4 +CONFIG_END + +SCENARIO_BEGIN Test stop cache on nxdomain, with stub under intermediate label + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN DNSKEY +SECTION ANSWER +. 3600 IN DNSKEY 257 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30900 (ksk), size = 512b} +. 3600 IN RRSIG DNSKEY 5 0 3600 20070926134150 20070829134150 30900 . BlVcSh8xSgm7ne+XVCJwNHQKjk5kTJgG4Fa3sOSfp3YUjb2YclmVWyIw7XEHl0/C6CN5gdy18idnM6vT6Hy42A== ;{id = 30900} +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NXDOMAIN +SECTION QUESTION +example.local. IN A +SECTION AUTHORITY +. 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2010111601 1800 900 604800 86400 +. 86400 IN RRSIG SOA 5 0 86400 20070926134150 20070829134150 30900 . bOYbFZZp7vWWC2oxV+kph+YXjoQj2f6QJktlgmzRI7oReFX9jy/LibTPQi/sW0SGHpLaj3G5p4IfIlBibne4DA== ;{id = 30900} +. 86400 IN NSEC ac. NS SOA RRSIG NSEC DNSKEY +. 86400 IN RRSIG NSEC 5 0 86400 20070926134150 20070829134150 30900 . U+/m5+FmczzkosEx1aTP7MK/F3PpcKWct8CzM1jhjwNe2RlnW7qFe0IH8SLzD/elvxDTQMpJSMlKOhUUdapB8g== ;{id = 30900} +lk. 86400 IN NSEC lr. NS DS RRSIG NSEC +lk. 86400 IN RRSIG NSEC 5 1 86400 20070926134150 20070829134150 30900 . j6Pw5Eu9vGHDJcckTSWa8YD1b7FV7c/Z8aVkLfJCH+iPcaa40/LSp784+t2PnAAXL8fgriNL6jF/ve1rti3ANQ== ;{id = 30900} +ENTRY_END +RANGE_END + +; under.example.local +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.under.example.local. IN A +SECTION ANSWER +www.under.example.local. IN A 10.20.30.40 +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +example.local. IN A +ENTRY_END + +; recursion happens here. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NXDOMAIN +SECTION QUESTION +example.local. IN A +SECTION AUTHORITY +. 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2010111601 1800 900 604800 86400 +ENTRY_END + +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.under.example.local. IN A +ENTRY_END + +; this query does not get sent to K-ROOT. +STEP 30 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.under.example.local. IN A +SECTION ANSWER +www.under.example.local. IN A 10.20.30.40 +ENTRY_END + +SCENARIO_END diff --git a/testdata/stop_nxdomain_minimised.rpl b/testdata/stop_nxdomain_minimised.rpl index 0de22edde..d6e881f59 100644 --- a/testdata/stop_nxdomain_minimised.rpl +++ b/testdata/stop_nxdomain_minimised.rpl @@ -7,6 +7,7 @@ server: val-override-date: "20070916134226" fake-sha1: yes trust-anchor-signaling: no + domain-insecure: "anotherexample.local" stub-zone: name: "." @@ -69,7 +70,7 @@ REPLY QR AA NOERROR SECTION QUESTION anotherexample.local. IN TXT SECTION ANSWER -anotherexample.local. 86400 IN TXT "should not resolve this" +anotherexample.local. 86400 IN TXT "stub works" ENTRY_END RANGE_END @@ -95,7 +96,7 @@ STEP 20 QUERY ENTRY_BEGIN REPLY RD SECTION QUESTION -anotherexample.local. IN TXT +anotherexample2.local. IN TXT ENTRY_END ; query should be answered using NXDOMAIN for local in cache @@ -104,9 +105,27 @@ ENTRY_BEGIN MATCH all REPLY QR RD RA NXDOMAIN SECTION QUESTION -anotherexample.local. IN TXT +anotherexample2.local. IN TXT SECTION AUTHORITY . 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2010111601 1800 900 604800 86400 ENTRY_END +STEP 40 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +anotherexample.local. IN TXT +ENTRY_END + +; The stub stops going higher in the negative cache. +STEP 50 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +anotherexample.local. IN TXT +SECTION ANSWER +anotherexample.local. 86400 IN TXT "stub works" +ENTRY_END + SCENARIO_END diff --git a/testdata/val_canon_short_px.rpl b/testdata/val_canon_short_px.rpl new file mode 100644 index 000000000..3dda85fbe --- /dev/null +++ b/testdata/val_canon_short_px.rpl @@ -0,0 +1,215 @@ +; config options +; The island of trust is at test. +server: + trust-anchor: "test. DS 1444 8 2 8a87d067fd09a5965244fe2e317dd26d182c468e0a7f26ecc4c7b479bf89db9b" + val-override-date: "20201020135527" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: yes + local-zone: test. nodefault + log-servfail: yes + ;msg-buffer-size: 4096 + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test validator canonicalize of short PX record. +; The record ends just before the second dname. +; And the message buffer is small, and filled with previous content. + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +test. 3600 IN RRSIG NS 8 1 3600 20201116135527 20201019135527 1444 test. RGCxIO32TbbLTk6xZmTr+fjYPH50hntBxeOQ2DIj2pDsmjALcHYtVkOfpfk2EhOhHZd+9PLuoJPbJh6a9NqLSFeBvr0XZoCZoQ2g0tCHUNHcH5EVjA2TuYBQem6DVYnPLJ3914aRx0uA1j42b8dC2xsam/XkOo7U+dLbUW2Os1s= +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +ns.test. 3600 IN NSEC nz.test. A RRSIG +ns.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. PElArVB3KPg8KHAP7lzcNbhFuXNxTsHNTn1dZVncB5qmWRdIaeKpaXDjpH0JSXMaelGFS+/QhuQ6Hmw9+4VyZFRqMzGhw4agUR/2bxABHcDIG4ZpUwyeSP61ATTfHUkQVxaH2wjCWI/tfmesdP2xVE4GXyUvCIBxU914MkZbULU= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN DNSKEY +SECTION ANSWER +test. 3600 IN DNSKEY 257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b} +test. 3600 IN RRSIG DNSKEY 8 1 3600 20201116135527 20201019135527 1444 test. UmRMS4iG9NBBHZYOtpwFFcJgbEb5SfHSgHd9XRe/8pTWM31WSDayn5ViPOBMqI1T5TXg2amc13dDI574xIM2oKMus3b5cBW72jJLW13jprBtslO6P8BMWb4HNnvLrJtQjwf3ErRirtTxinLmywQtmyr1cdthyG3Gp4N7i90fHSc= +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.test. IN DS +SECTION ANSWER +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +example.test. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55567 example.test. l1JT0wMlK0YI7/CWHzexf/k0iafUhCgN+BdgjBXIRXmSQNf4HDTiAkbcWL2/15qtnp12nQy9JeiTdSQ3vtPoHAJX4C5uTWaze4ms+Wrrf+n92sLCjacP9x50uuicH3URT6cKb1QCAPwlvlWxIlZjAMYFScSns7+C441NMJT8aE4= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN DNSKEY +SECTION ANSWER +example.test. 3600 IN DNSKEY 257 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55567 (ksk), size = 1024b} +example.test. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +px.example.test. IN PX +SECTION ANSWER +; PX with preference 10, first name "." , second name is missing. +px.example.test. 3600 IN PX \# 3 000A00 +; invalid signature +px.example.test. 3600 IN RRSIG PX 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g +ENTRY_END +RANGE_END + +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +px.example.test. IN PX +ENTRY_END + +STEP 20 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +px.example.test. IN PX +SECTION ANSWER +ENTRY_END + +SCENARIO_END diff --git a/testdata/val_global_quota.rpl b/testdata/val_global_quota.rpl new file mode 100644 index 000000000..baeaa5cbb --- /dev/null +++ b/testdata/val_global_quota.rpl @@ -0,0 +1,358 @@ +; config options +; The island of trust is at test. +server: + trust-anchor: "test. DS 1444 8 2 8a87d067fd09a5965244fe2e317dd26d182c468e0a7f26ecc4c7b479bf89db9b" + val-override-date: "20201020135527" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: no + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + iter-scrub-promiscuous: no + aggressive-nsec: yes + local-zone: test. nodefault + log-servfail: yes + max-global-quota: 200 + val-max-restart: 5 + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test global quota with validator + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +test. IN NS +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.test +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN NS +SECTION ANSWER +test. IN NS ns.test +test. 3600 IN RRSIG NS 8 1 3600 20201116135527 20201019135527 1444 test. RGCxIO32TbbLTk6xZmTr+fjYPH50hntBxeOQ2DIj2pDsmjALcHYtVkOfpfk2EhOhHZd+9PLuoJPbJh6a9NqLSFeBvr0XZoCZoQ2g0tCHUNHcH5EVjA2TuYBQem6DVYnPLJ3914aRx0uA1j42b8dC2xsam/XkOo7U+dLbUW2Os1s= +SECTION ADDITIONAL +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN A +SECTION ANSWER +ns.test. IN A 1.2.3.5 +ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.test. IN AAAA +SECTION AUTHORITY +test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600 +test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw= +ns.test. 3600 IN NSEC nz.test. A RRSIG +ns.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. PElArVB3KPg8KHAP7lzcNbhFuXNxTsHNTn1dZVncB5qmWRdIaeKpaXDjpH0JSXMaelGFS+/QhuQ6Hmw9+4VyZFRqMzGhw4agUR/2bxABHcDIG4ZpUwyeSP61ATTfHUkQVxaH2wjCWI/tfmesdP2xVE4GXyUvCIBxU914MkZbULU= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +test. IN DNSKEY +SECTION ANSWER +test. 3600 IN DNSKEY 257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b} +test. 3600 IN RRSIG DNSKEY 8 1 3600 20201116135527 20201019135527 1444 test. UmRMS4iG9NBBHZYOtpwFFcJgbEb5SfHSgHd9XRe/8pTWM31WSDayn5ViPOBMqI1T5TXg2amc13dDI574xIM2oKMus3b5cBW72jJLW13jprBtslO6P8BMWb4HNnvLrJtQjwf3ErRirtTxinLmywQtmyr1cdthyG3Gp4N7i90fHSc= +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.test. IN DS +SECTION ANSWER +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION AUTHORITY +example.test. IN NS ns.example.test. +example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39 +example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.test. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN NS +SECTION ANSWER +example.test. IN NS ns.example.test. +example.test. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55567 example.test. l1JT0wMlK0YI7/CWHzexf/k0iafUhCgN+BdgjBXIRXmSQNf4HDTiAkbcWL2/15qtnp12nQy9JeiTdSQ3vtPoHAJX4C5uTWaze4ms+Wrrf+n92sLCjacP9x50uuicH3URT6cKb1QCAPwlvlWxIlZjAMYFScSns7+C441NMJT8aE4= +SECTION ADDITIONAL +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN A +SECTION ANSWER +ns.example.test. IN A 1.2.3.4 +ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.example.test. IN AAAA +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.test. IN DNSKEY +SECTION ANSWER +example.test. 3600 IN DNSKEY 257 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55567 (ksk), size = 1024b} +example.test. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g= +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +;a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.example.test. IN A +a.a.a.a.a.example.test. IN A +SECTION ANSWER +; unsigned answer +;a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.example.test. 3600 IN A 10.20.30.40 +a.a.a.a.a.example.test. IN A 10.20.30.40 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +a.example.test. IN NSEC \000.a.example.test. NSEC RRSIG TYPE128 +a.example.test. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55567 example.test. IFHxa61iaEHyRiTrez1FNy6TArOerKgaRwkhjwEk8basD2SZ7wP63ZvxfiNJlg3VAKxM8RApT4GIXDLBT2IlAK5I+K2Ti1dxUw9XwhnOpVf7/4WDEEgQKBsYPVrSAGVig9v5eefuEmVQTphHovDAAOkKYd4rCJ50WX+ckLsP658= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.a.example.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +a.a.example.test. IN NSEC \000.a.a.example.test. NSEC RRSIG TYPE128 +a.a.example.test. 3600 IN RRSIG NSEC 8 4 3600 20201116135527 20201019135527 55567 example.test. hqwhNsdny2lWkGnWhF7WaIyWhGDJHBVzJbwO8wZ6e+SIfQtt4AFFqXqCtqOIN9u+jjU7YT8SdABQLEoFm6TN47+lC0689fpO59xx4qOnpSyCRA0sRMDW4AcwVDHLECLGEMzI7xHdCPGFGxYl+abr5lcw+A4sH5RomJ0DTRKbB10= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.a.a.example.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +a.a.a.example.test. IN NSEC \000.a.a.a.example.test. NSEC RRSIG TYPE128 +a.a.a.example.test. 3600 IN RRSIG NSEC 8 5 3600 20201116135527 20201019135527 55567 example.test. afjzouI1IgcLgzkuTUTZC6yBZ2IDhWjV1s7zIRuL9fdf1sKvhooJK7+1mnozoQ4VCbLWFVoD4NX/nKcB5ALxJYjEw28qcAYtMwEme3Hj0FNoe7NR2M/nQonqvGfYo6FAUJBJfvcJaXMROAyw16R8qdlpqBgdecfk8LfEcJ3DcWA= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.a.a.a.example.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +a.a.a.a.example.test. IN NSEC \000.a.a.a.a.example.test. NSEC RRSIG TYPE128 +a.a.a.a.example.test. 3600 IN RRSIG NSEC 8 6 3600 20201116135527 20201019135527 55567 example.test. F9mOk6KyGI6LSDgs7l50fPIWQVz65bO2ONxoZe4BzE0NqCTloznQ7r0QXXMmcI6IAC2W7RjsymsViTexuMI8sLaFvzNoM5jDLnic4KFZFIuUy1oA/2Hd56TwofK/KctbkQQpT8IDKc/pnxp8iXTjwNsV31fzZ5RPWt2YqpMfY4Q= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.a.a.a.a.example.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +a.a.a.a.a.example.test. IN NSEC \000.a.a.a.a.a.example.test. NSEC RRSIG TYPE128 +a.a.a.a.a.example.test. 3600 IN RRSIG NSEC 8 7 3600 20201116135527 20201019135527 55567 example.test. AlEcceF3UARAczJQW7/skNbf0t6gum2LEfFWilZtakpdrnnl+HkIR8LttE/gOjLFv/MWzSWPLDmsj9Be/7PsWWddJwN0hgrskt/W4KBPdYkBhgnrfxOMYm6ZTDY6EUh9iTUAdWP0SDmfG7Zs5UIhIpsYEnxsYF0oRT5HZpYMBq8= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.a.a.a.a.a.example.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.example.test. IN A +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.a.example.test. IN A +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.a.a.example.test. IN A +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.a.a.a.example.test. IN A +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.a.a.a.a.example.test. IN A +SECTION ANSWER +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8= +ENTRY_END + +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.a.a.a.a.example.test. IN A +ENTRY_END + +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +a.a.a.a.a.example.test. IN A +SECTION ANSWER +ENTRY_END + +SCENARIO_END diff --git a/testdata/val_nx_uns_resp.rpl b/testdata/val_nx_uns_resp.rpl new file mode 100644 index 000000000..88dc95567 --- /dev/null +++ b/testdata/val_nx_uns_resp.rpl @@ -0,0 +1,82 @@ +; config options +server: + ; This is the test key 29332 in the testdata. + trust-anchor: ". 3600 IN DS 29332 8 2 b75e26316631b6e37cbc977323a08769f86e36a10fee888676d35f61e2ff4181" + val-override-date: "20201020135527" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: no + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + log-servfail: yes + +forward-zone: + name: "." + forward-addr: 10.5.5.5 +CONFIG_END + +SCENARIO_BEGIN Test nxdomain that gets unsigned response +; and the DS lookup that it makes gets an NSEC NXDOMAIN response. + +; 10.5.5.5 forwarder +RANGE_BEGIN 0 100 + ADDRESS 10.5.5.5 + +; unsigned NXDOMAIN response, from the first forwarder, here it is served +; from the upstream. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NXDOMAIN +SECTION QUESTION +example.veryinvalid. IN TXT +SECTION AUTHORITY +. 3600 IN SOA ns.root. host.root. 1 3600 3600 3600 3600 +ENTRY_END + +; DNSKEY answer, using CSK for test simplicity. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN DNSKEY +SECTION ANSWER +. IN DNSKEY 257 3 8 AwEAAb4WMOTBLTFvmBra5m6SK4VfViOzmvyUAU0qv861ZQXeEFvwlndqNU9rwRsMxrSWAYs5nHErKDn49usC/HyxxW1477iGFHhfgL4mjNreJm9zft2QFB1VLbRbEPYdDMLCn4co0qnG7/KG8W2i8Pym1L7f+aREwbLo+/716AS2PbaKMhfWLKLiq5wnBcUClQMNzCiwhqxDJp1oePqfkVdeUgXOtgi0dYRIKyQFhJ5VWJ22npoi/Gif0XLCADAlAwRLKc8o/yJkCxskzgpHpw5Cki1lclg0aq4ssOuPRQ+ne6IHYCz9D2mwzulblhLFamKdq7aHzNt4NlyxhpANVFiKLD8= ;{id = 29332 (ksk), size = 2048b} +. 3600 IN RRSIG DNSKEY 8 0 3600 20201116135527 20201019135527 29332 . ToK8hJrGa+kNu6y8FpRwZq2FjDPBAk5Ctchia3Vu9yTth2dR7BhK2ALTWVBwAQGwiwxXKoVK9QCxdQM0ti7CVb9x75bejkd2E6UGWVmqyTRPpn3D43qYARm87y3ZVKG7LlWHp8UOf21XLp1H7R+wuipIvBJ1XA+QGXThPdbV9EEz1kKGdprBfdpFkQdcAiuYYrOTa5cJ11z32mGiQ12fWjpb4UUbfcoDD9YOoa/S5a6h7jYBOfm75ZB8UCW3Z/SlsN8KIfYZsg5CZphpf38XH5uNLMmzpaWYhfamJZJve9Isx4eILNmdMLK4E8ESwDFCVNzMIqdf20VRg6Lh7nwQeA== +ENTRY_END + +; answer for DS, from another forwarder, here returned from the test upstream. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NXDOMAIN +SECTION QUESTION +veryinvalid. IN DS +SECTION AUTHORITY +versicherung. 3600 IN NSEC vet. NS DS RRSIG NSEC +versicherung. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 29332 . AVAON9Y7AVwX9YWQK8JPcB6Wk/tEfQT7JrLiCRlBBQA0+mpVYYYtMyrm4aMjkhusqYcnpIZoLGOI/dxJjIwDgnMkd4EqY2oICea3I260f8z2v9e7zNobyUTjkoWsmLPc7VRLtEGKu1XyVpt7DX6ElGoSUhU4JsTx7wkkXU0SGAakL0bhK8K68B92NEVwgKX4D7+kVfpjc0aHaB3rAkhQCM/G0jEFp0RuhTX1aru6IuYrZmjW0dvQ2niec6NaYzvuGnbhMLlFLuXqSmI2B7uIFx894usd1cVWnSRg49bAkuiEv5q04ltRel1huJBGGiZlLEwanS5g53C5DHfq10OUrw== +. 3600 IN NSEC aaa. NS SOA RRSIG NSEC DNSKEY ZONEMD +. 3600 IN RRSIG NSEC 8 0 3600 20201116135527 20201019135527 29332 . E8r6rpFgFBUda2GnFSMzHZLtjy1dT+ZS0wPRE12RNwVK547bo2vByv9EFhOHS6sEIFqX+AmIJotuiEPKnCFUTr6FKscaxtw38dJRZ3wldqV6dmqUiRmz91crDCV5nSL45FIbkWKk1Q+tnXie3sZ4zwBc12kGg2BttMAQ0i4sbMbf6EUNYZGwYzSB0/VhXVJcl8gl+5lfpiVqfWNZI7vTEaHqrC2gBC3UK1cQE9lQOqhJ6H5ThA1FR9j/mZFM9sG5vQ2Mqlzl2iiN2Y6mCptDY1vwfff6AnT0YeDwJ/XwGisMZrSvTCYaiRndb8CUUmCr23AFy5OER1rmeFGkHX5+WQ== +. 3600 IN SOA ns.root. host.root. 1 3600 3600 3600 3600 +. 3600 IN RRSIG SOA 8 0 3600 20201116135527 20201019135527 29332 . tVeReLMXPnl6rk4QX94xy9lCodQ+xc39lokbNkvbXnTURNCOAwtNiMMPlAAJ3/HTpIxo175gPfupACIveBtgajdp85jUIvLMOM5B6lX80+dUPBGZ4gHVjf+8EGnr7q2wnW2+KcJu0OhN2g+YqCV6aPi8pzuAp+AMsBYcMfXqEQq9Lxqv6TL50MUCJN3GPCyBIdjbs/A+ZB7D1EOO1YgdbsMHK/pWKYt4UfBFfekoA6joIGf4vBKKRTWnoo0BcrFob3AW1SyJkoxoqEsN3YAVL9jNkJCkU0/adLypHgDNayLgsWI5/o4Ng8LxN6tNxAilkMhcGY80T5g0uo+ukY7McA== +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +example.veryinvalid. IN TXT +ENTRY_END + +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +example.veryinvalid. IN TXT +SECTION ANSWER +ENTRY_END + +SCENARIO_END diff --git a/util/configparser.y b/util/configparser.y index bc217c765..db6701e76 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -2397,6 +2397,9 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG && strcmp($3, "typetransparent")!=0 && strcmp($3, "always_transparent")!=0 && strcmp($3, "block_a")!=0 + && strcmp($3, "block_aaaa")!=0 + && strcmp($3, "block_a_wdata")!=0 + && strcmp($3, "block_aaaa_wdata")!=0 && strcmp($3, "always_refuse")!=0 && strcmp($3, "always_nxdomain")!=0 && strcmp($3, "always_nodata")!=0 @@ -2409,7 +2412,9 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG yyerror("local-zone type: expected static, deny, " "refuse, redirect, transparent, " "typetransparent, inform, inform_deny, " - "inform_redirect, always_transparent, block_a, " + "inform_redirect, always_transparent, " + "block_a, block_aaaa, " + "block_a_wdata, block_aaaa_wdata, " "always_refuse, always_nxdomain, " "always_nodata, always_deny, always_null, " "noview, nodefault or ipset"); diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 9239f8fe3..f9beb605c 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -687,6 +687,9 @@ calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr) } rdf++; } + /* rdata ended before all _dname_count names were seen */ + if(count != 0) + return 0; /* the rdata is too short. */ } /* remaining rdata */ rr->size += pkt_len; @@ -1030,8 +1033,11 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, break; case LDNS_EDNS_PADDING: - if(!cfg || !cfg->pad_responses || - !c || c->type != comm_tcp ||!c->ssl || padding_seen) + if(!cfg || !cfg->pad_responses || !c || padding_seen) + break; + if(!((c->type == comm_tcp && c->ssl) || + (c->type == comm_http && c->ssl) || + c->type == comm_doq)) break; padding_seen = 1; if(!edns_opt_list_append(&edns->opt_list_out, @@ -1068,13 +1074,13 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, * purposes. It will be overwritten if (re)creation * is needed. */ - if(repinfo->remote_addr.ss_family == AF_INET) { + if(repinfo->client_addr.ss_family == AF_INET) { memcpy(server_cookie + 16, - &((struct sockaddr_in*)&repinfo->remote_addr)->sin_addr, 4); + &((struct sockaddr_in*)&repinfo->client_addr)->sin_addr, 4); } else { cookie_is_v4 = 0; memcpy(server_cookie + 16, - &((struct sockaddr_in6*)&repinfo->remote_addr)->sin6_addr, 16); + &((struct sockaddr_in6*)&repinfo->client_addr)->sin6_addr, 16); } if(cfg->cookie_secret_file && diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c index d28d75761..598d606b4 100644 --- a/util/data/packed_rrset.c +++ b/util/data/packed_rrset.c @@ -198,6 +198,7 @@ get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname, { struct packed_rrset_data* d; size_t len; + if(!rrset) return; if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME) return; @@ -279,7 +280,9 @@ int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i, size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i]; time_t adjust = 0; log_assert(dest_len > 0 && dest); - if(rlen > dest_len) { + /* rlen is the length written into rr, dest_len bounds the output + * string; check both, callers can pass a dest_len over sizeof(rr). */ + if(rlen > dest_len || rlen > sizeof(rr)) { dest[0] = 0; return 0; } diff --git a/util/fptr_wlist.c b/util/fptr_wlist.c index da301c034..88a788a8e 100644 --- a/util/fptr_wlist.c +++ b/util/fptr_wlist.c @@ -612,6 +612,7 @@ int fptr_whitelist_alloc_cleanup(void (*fptr)(void*)) { if(fptr == &worker_alloc_cleanup) return 1; + else if(fptr == &libworker_alloc_cleanup) return 1; return 0; } diff --git a/util/iana_ports.inc b/util/iana_ports.inc index 9bb2fefbe..0d61e948e 100644 --- a/util/iana_ports.inc +++ b/util/iana_ports.inc @@ -4610,6 +4610,7 @@ 7101, 7107, 7121, +7123, 7128, 7129, 7161, diff --git a/util/module.h b/util/module.h index 46eb7c31e..9192c9af5 100644 --- a/util/module.h +++ b/util/module.h @@ -730,6 +730,12 @@ struct module_qstate { /** whether the reply should be dropped */ int is_drop; + /** the global quota that was reached, by one of the modules. + * So that continued counting can go on from that point. */ + int global_quota_reached; + /** the global quota that a query started with, it is a subquery, + * so that calling mesh states can see the increase. */ + int global_quota_started; }; /** diff --git a/util/netevent.c b/util/netevent.c index 37b29bc24..432fead1b 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -1835,7 +1835,6 @@ doq_send_retry(struct comm_point* c, struct doq_pkt_addr* paddr, char host[256], port[32]; struct ngtcp2_cid scid; uint8_t token[NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN]; - ngtcp2_tstamp ts; ngtcp2_ssize tokenlen, ret; if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, @@ -1849,12 +1848,10 @@ doq_send_retry(struct comm_point* c, struct doq_pkt_addr* paddr, scid.datalen = c->doq_socket->sv_scidlen; doq_cid_randfill(&scid, scid.datalen, c->doq_socket->rnd); - ts = doq_get_timestamp_nanosec(); - tokenlen = ngtcp2_crypto_generate_retry_token(token, c->doq_socket->static_secret, c->doq_socket->static_secret_len, hd->version, (void*)&paddr->addr, paddr->addrlen, &scid, - &hd->dcid, ts); + &hd->dcid, doq_get_timestamp_nanosec()); if(tokenlen < 0) { log_err("ngtcp2_crypto_generate_retry_token failed: %s", ngtcp2_strerror(tokenlen)); @@ -1903,13 +1900,11 @@ doq_verify_retry_token(struct comm_point* c, struct doq_pkt_addr* paddr, struct ngtcp2_cid* ocid, struct ngtcp2_pkt_hd* hd) { char host[256], port[32]; - ngtcp2_tstamp ts; if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, sizeof(host), port, sizeof(port))) { log_err("doq_verify_retry_token failed"); return 0; } - ts = doq_get_timestamp_nanosec(); verbose(VERB_ALGO, "doq: verifying retry token from %s %s", host, port); if(ngtcp2_crypto_verify_retry_token(ocid, @@ -1921,7 +1916,7 @@ doq_verify_retry_token(struct comm_point* c, struct doq_pkt_addr* paddr, c->doq_socket->static_secret, c->doq_socket->static_secret_len, hd->version, (void*)&paddr->addr, paddr->addrlen, &hd->dcid, - 10*NGTCP2_SECONDS, ts) != 0) { + 10*NGTCP2_SECONDS, doq_get_timestamp_nanosec()) != 0) { verbose(VERB_ALGO, "doq: could not verify retry token " "from %s %s", host, port); return 0; @@ -1936,13 +1931,11 @@ doq_verify_token(struct comm_point* c, struct doq_pkt_addr* paddr, struct ngtcp2_pkt_hd* hd) { char host[256], port[32]; - ngtcp2_tstamp ts; if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, sizeof(host), port, sizeof(port))) { log_err("doq_verify_token failed"); return 0; } - ts = doq_get_timestamp_nanosec(); verbose(VERB_ALGO, "doq: verifying token from %s %s", host, port); if(ngtcp2_crypto_verify_regular_token( #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN @@ -1952,7 +1945,7 @@ doq_verify_token(struct comm_point* c, struct doq_pkt_addr* paddr, #endif c->doq_socket->static_secret, c->doq_socket->static_secret_len, (void*)&paddr->addr, paddr->addrlen, 3600*NGTCP2_SECONDS, - ts) != 0) { + doq_get_timestamp_nanosec()) != 0) { verbose(VERB_ALGO, "doq: could not verify token from %s %s", host, port); return 0; @@ -2179,6 +2172,7 @@ doq_pickup_timer(struct comm_point* c) { struct doq_timer* t; struct timeval tv; + ngtcp2_tstamp ts = 0; int have_time = 0; memset(&tv, 0, sizeof(tv)); @@ -2188,27 +2182,24 @@ doq_pickup_timer(struct comm_point* c) t->worker_doq_socket == c->doq_socket) { /* pick up this element */ t->worker_doq_socket = c->doq_socket; + memcpy(&tv, &t->time_real, sizeof(tv)); + ts = t->time_mono; have_time = 1; - memcpy(&tv, &t->time, sizeof(tv)); break; } } lock_rw_unlock(&c->doq_socket->table->lock); - + c->doq_socket->marked_time = ts; if(have_time) { struct timeval rel; timeval_subtract(&rel, &tv, c->doq_socket->now_tv); comm_timer_set(c->doq_socket->timer, &rel); - memcpy(&c->doq_socket->marked_time, &tv, - sizeof(c->doq_socket->marked_time)); verbose(VERB_ALGO, "doq pickup timer at %d.%6.6d in %d.%6.6d", (int)tv.tv_sec, (int)tv.tv_usec, (int)rel.tv_sec, (int)rel.tv_usec); } else { if(comm_timer_is_set(c->doq_socket->timer)) comm_timer_disable(c->doq_socket->timer); - memset(&c->doq_socket->marked_time, 0, - sizeof(c->doq_socket->marked_time)); verbose(VERB_ALGO, "doq timer disabled"); } } @@ -2221,13 +2212,14 @@ doq_done_setup_timer_and_write(struct comm_point* c, struct doq_conn* conn) uint8_t cid[NGTCP2_MAX_CIDLEN]; rbnode_type* node; struct timeval new_tv; + ngtcp2_tstamp new_ts; int write_change = 0, timer_change = 0; /* No longer in callbacks, so the pointer to doq_socket is back * to NULL. */ conn->doq_socket = NULL; - if(doq_conn_check_timer(conn, &new_tv)) + if(doq_conn_check_timer(conn, &new_tv, &new_ts)) timer_change = 1; if( (conn->write_interest && !conn->on_write_list) || (!conn->write_interest && conn->on_write_list)) @@ -2273,7 +2265,7 @@ doq_done_setup_timer_and_write(struct comm_point* c, struct doq_conn* conn) } if(timer_change) { doq_timer_set(c->doq_socket->table, &conn->timer, - c->doq_socket, &new_tv); + c->doq_socket, &new_tv, new_ts); } lock_rw_unlock(&c->doq_socket->table->lock); lock_basic_unlock(&conn->lock); @@ -2437,7 +2429,7 @@ doq_write_blocked_pkt(struct comm_point* c) return 1; } -/** doq find a timer that timeouted and return the conn, locked. */ +/** doq find a timer that timed out and return the conn, locked. */ static struct doq_conn* doq_timer_timeout_conn(struct doq_server_socket* doq_socket) { @@ -2450,7 +2442,7 @@ doq_timer_timeout_conn(struct doq_server_socket* doq_socket) conn = t->conn; /* If now < timer then no further timeouts in tree. */ - if(timeval_smaller(doq_socket->now_tv, &t->time)) { + if(timeval_smaller(doq_socket->now_tv, &t->time_real)) { lock_rw_unlock(&doq_socket->table->lock); return NULL; } @@ -2473,11 +2465,11 @@ doq_timer_erase_marker(struct doq_server_socket* doq_socket) { struct doq_timer* t; lock_rw_wrlock(&doq_socket->table->lock); - t = doq_timer_find_time(doq_socket->table, &doq_socket->marked_time); + t = doq_timer_find_time(doq_socket->table, doq_socket->marked_time); if(t && t->worker_doq_socket == doq_socket) t->worker_doq_socket = NULL; lock_rw_unlock(&doq_socket->table->lock); - memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time)); + doq_socket->marked_time = 0; } void @@ -2784,7 +2776,7 @@ doq_server_socket_create(struct doq_table* table, struct ub_randstate* rnd, free(doq_socket); return NULL; } - memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time)); + doq_socket->marked_time = 0; comm_base_timept(base, &doq_socket->now_tt, &doq_socket->now_tv); doq_socket->cfg = cfg; return doq_socket; @@ -3241,7 +3233,7 @@ static void http2_stream_delete(struct http2_session* h2_session, { if(h2_stream->mesh_state) { mesh_state_remove_reply(h2_stream->mesh, h2_stream->mesh_state, - h2_session->c, h2_stream); + h2_session->c, h2_stream, NULL); h2_stream->mesh_state = NULL; } http2_req_stream_clear(h2_stream); @@ -6784,7 +6776,9 @@ comm_point_send_reply(struct comm_reply *repinfo) log_assert(repinfo && repinfo->c); #ifdef USE_DNSCRYPT buffer = repinfo->c->dnscrypt_buffer; - if(!dnsc_handle_uncurved_request(repinfo)) { + if(!dnsc_handle_uncurved_request(repinfo, + repinfo->c->tcp_req_info? + repinfo->c->tcp_req_info->spool_buffer:repinfo->c->buffer)) { return; } #else diff --git a/util/netevent.h b/util/netevent.h index e073b45f2..7d64fac5b 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -189,6 +189,8 @@ struct comm_reply { /** port number for doq */ int doq_srcport; #endif /* HAVE_NGTCP2 */ + /** The doq stream to register mesh states to. */ + struct doq_stream* doq_stream; }; /** @@ -1095,8 +1097,10 @@ struct doq_server_socket { struct doq_pkt_addr* blocked_paddr; /** timer for this worker on this comm_point to wait on. */ struct comm_timer* timer; +#ifdef HAVE_NGTCP2 /** the timer that is marked by the doq_socket as waited on. */ - struct timeval marked_time; + ngtcp2_tstamp marked_time; +#endif /** the current time for use by time functions, time_t. */ time_t* now_tt; /** the current time for use by time functions, timeval. */ diff --git a/validator/autotrust.c b/validator/autotrust.c index f1c4f9efa..fc7897b71 100644 --- a/validator/autotrust.c +++ b/validator/autotrust.c @@ -884,13 +884,16 @@ parse_var_line(char* line, struct val_anchors* anchors, *header_seen = 1; *anchor = parse_id(anchors, line+6); if(!*anchor) return -1; + lock_basic_lock(&(*anchor)->lock); if(*anchor && !(*anchor)->autr->file) { (*anchor)->autr->file = strdup(nm); if(!(*anchor)->autr->file) { + lock_basic_unlock(&(*anchor)->lock); log_err("malloc failure"); return -1; } } + lock_basic_unlock(&(*anchor)->lock); if(*anchor) return 1; } else if(strncmp(line, ";;REVOKED", 9) == 0) { if(tp) { diff --git a/validator/val_neg.c b/validator/val_neg.c index 5835fcbaf..63f380ad9 100644 --- a/validator/val_neg.c +++ b/validator/val_neg.c @@ -938,6 +938,10 @@ void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep) continue; if(!dname_subdomain_c(rep->rrsets[i]->rk.dname, zone->name)) continue; + if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC && + !nsec_nextowner_subdomain(rep->rrsets[i], zone->name)) { + continue; /* nextowner not in zone */ + } /* insert NSEC into this zone's tree */ neg_insert_data(neg, zone, rep->rrsets[i]); } @@ -1022,6 +1026,10 @@ void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep, continue; if(!dname_subdomain_c(rep->rrsets[i]->rk.dname, zone->name)) continue; + if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC && + !nsec_nextowner_subdomain(rep->rrsets[i], zone->name)) { + continue; /* nextowner not in zone */ + } /* insert NSEC into this zone's tree */ neg_insert_data(neg, zone, rep->rrsets[i]); } @@ -1110,12 +1118,14 @@ grab_nsec(struct rrset_cache* rrset_cache, uint8_t* qname, size_t qname_len, * @param rrset_cache: rrset cache * @param now: to check ttl against * @param region: where to alloc result + * @param topname: do not look higher than this name, so that the + * result cannot be taken from a zone above the current trust anchor. * @return rrset or NULL */ static struct ub_packed_rrset_key* neg_find_nsec(struct val_neg_cache* neg_cache, uint8_t* qname, size_t qname_len, uint16_t qclass, struct rrset_cache* rrset_cache, time_t now, - struct regional* region) + struct regional* region, uint8_t* topname) { int labs; uint32_t flags; @@ -1133,6 +1143,11 @@ neg_find_nsec(struct val_neg_cache* neg_cache, uint8_t* qname, size_t qname_len, lock_basic_unlock(&neg_cache->lock); return NULL; } + if(topname && !dname_subdomain_c(zone->name, topname)) { + /* Reject NSEC not within trust anchor's bailiwick */ + lock_basic_unlock(&neg_cache->lock); + return NULL; + } /* NSEC only for now */ if(zone->nsec3_hash) { @@ -1430,7 +1445,7 @@ val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo, /* Get best available NSEC for qname */ nsec = neg_find_nsec(neg, qinfo->qname, qinfo->qname_len, qinfo->qclass, - rrset_cache, now, region); + rrset_cache, now, region, topname); /* Matching NSEC, use to generate No Data answer. Not creating answers * yet for No Data proven using wildcard. */ @@ -1510,7 +1525,7 @@ val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo, * proof */ if(!(wcrr = neg_find_nsec(neg, wc_qinfo.qname, wc_qinfo.qname_len, qinfo->qclass, - rrset_cache, now, region))) + rrset_cache, now, region, topname))) return NULL; nodata_wc = NULL; diff --git a/validator/val_nsec3.c b/validator/val_nsec3.c index 62effde20..d0385be68 100644 --- a/validator/val_nsec3.c +++ b/validator/val_nsec3.c @@ -1248,6 +1248,10 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } if(!param_set_same(&flt, NULL)) return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) @@ -1436,6 +1440,10 @@ nsec3_prove_nodata(struct module_env* env, struct val_env* ve, filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } if(!param_set_same(&flt, NULL)) return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) @@ -1461,6 +1469,10 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } if(!param_set_same(&flt, NULL)) return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) @@ -1565,6 +1577,11 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, *reason = "no NSEC3 records"; return sec_status_bogus; /* no RRs */ } + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + *reason = "NSEC3 name is not b32.signer name"; + return sec_status_bogus; + } if(!param_set_same(&flt, reason)) return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) @@ -1660,6 +1677,10 @@ nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve, filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } if(!param_set_same(&flt, NULL)) return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c index 2ce52a74b..d0d6d73d8 100644 --- a/validator/val_secalgo.c +++ b/validator/val_secalgo.c @@ -745,11 +745,9 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) &&(fake_dsa||fake_sha1)) return sec_status_secure; #endif -#ifndef USE_SHA1 if(fake_sha1 && (algo == LDNS_DSA || algo == LDNS_DSA_NSEC3 || algo == LDNS_RSASHA1 || algo == LDNS_RSASHA1_NSEC3)) return sec_status_secure; -#endif - + if(!setup_key_digest(algo, &evp_key, &digest_type, key, keylen)) { verbose(VERB_QUERY, "verify: failed to setup key"); *reason = "use of key for crypto failed"; diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index 674db9d40..4139cc1fe 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -1107,6 +1107,7 @@ canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset, { uint8_t* datstart = sldns_buffer_current(buf)-len+2; uint8_t* datend = sldns_buffer_current(buf); + size_t firstlen; switch(ntohs(rrset->rk.type)) { case LDNS_RR_TYPE_NXT: case LDNS_RR_TYPE_NS: @@ -1126,8 +1127,9 @@ canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset, case LDNS_RR_TYPE_SOA: /* two names after another */ canon_dname_tolower(datstart, datend); - canon_dname_tolower(datstart + - dname_valid(datstart, len-2), datend); + firstlen = dname_valid(datstart, len-2); + if(firstlen && firstlen < len-2) + canon_dname_tolower(datstart + firstlen, datend); return; case LDNS_RR_TYPE_RT: case LDNS_RR_TYPE_AFSDB: @@ -1154,8 +1156,9 @@ canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset, return; datstart += 2; canon_dname_tolower(datstart, datend); - canon_dname_tolower(datstart + - dname_valid(datstart, len-2-2), datend); + firstlen = dname_valid(datstart, len-2-2); + if(firstlen && firstlen < len-2-2) + canon_dname_tolower(datstart + firstlen, datend); return; case LDNS_RR_TYPE_NAPTR: if(len < 2+4) @@ -1624,6 +1627,30 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; return sec_status_bogus; /* signer name offtree */ } + /* NSEC3, the owner name must be the .signername */ + if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC3 && + rrset->rk.dname_len > 0) { + uint8_t* dnameless = rrset->rk.dname; + size_t dnamelesslen = rrset->rk.dname_len; + dname_remove_label(&dnameless, &dnamelesslen); + if(query_dname_compare(dnameless, signer) != 0) { + verbose(VERB_QUERY, "verify: NSEC3 owner name is not b32.signer name"); + *reason = "NSEC3 owner name is not b32.signer name"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; /* NSEC3 owner not b32.signer */ + } + } + /* NSEC, a next owner that is not under the signer is not allowed.*/ + if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC && + !nsec_nextowner_subdomain(rrset, signer)) { + verbose(VERB_QUERY, "verify: NSEC next owner overreaches signer name"); + *reason = "NSEC next owner overreaches signer name"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; /* nextowner overreaching */ + } + sigblock = (unsigned char*)signer+signer_len; if(siglen < 2+18+signer_len+1) { verbose(VERB_QUERY, "verify: too short, no signature data"); @@ -1681,6 +1708,13 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; return sec_status_bogus; } + if((int)sig[2+3] < dname_signame_label_count(signer)) { + verbose(VERB_QUERY, "verify: RRSIG label count too low for signer"); + *reason = "signature labelcount lower than signature signer"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } /* original ttl, always ok */ diff --git a/validator/val_utils.c b/validator/val_utils.c index 687253412..bfff19126 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -157,7 +157,7 @@ val_classify_response(uint16_t query_flags, struct query_info* origqinf, } /** Get signer name from RRSIG */ -static void +void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen) { /* RRSIG rdata is not allowed to be compressed, it is stored @@ -439,10 +439,15 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, * only improves security status * and bogus is set only once, even if we rechecked the status */ if(sec > d->security) { + int wc_expanded = 0; d->security = sec; - if(sec == sec_status_secure) + if(sec == sec_status_secure) { + uint8_t* wc = NULL; + size_t wclen = 0; d->trust = rrset_trust_validated; - else if(sec == sec_status_bogus) { + if(val_rrset_wildcard(rrset, &wc, &wclen) && wc) + wc_expanded = 1; + } else if(sec == sec_status_bogus) { size_t i; /* update ttl for rrset to fixed value. */ d->ttl = ve->bogus_ttl; @@ -455,7 +460,11 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, lock_basic_unlock(&ve->bogus_lock); } /* if status updated - store in cache for reuse */ - rrset_update_sec_status(env->rrset_cache, rrset, *env->now); + /* For a wildcard rrset, that is secure, do not store this + * into the cache, because it changes proofs around the + * item. */ + if(!wc_expanded) + rrset_update_sec_status(env->rrset_cache, rrset, *env->now); } return sec; @@ -1314,6 +1323,20 @@ int val_has_signed_nsecs(struct reply_info* rep, char** reason) return 0; } +void val_has_auth_nsecs(struct reply_info* rep, int* has_nsec, int* has_nsec3) +{ + size_t i, num_nsec = 0, num_nsec3 = 0; + for(i=rep->an_numrrsets; ian_numrrsets+rep->ns_numrrsets; i++) { + if(rep->rrsets[i]->rk.type == htons(LDNS_RR_TYPE_NSEC)) + num_nsec++; + else if(rep->rrsets[i]->rk.type == htons(LDNS_RR_TYPE_NSEC3)) + num_nsec3++; + else continue; + } + *has_nsec = (num_nsec != 0); + *has_nsec3 = (num_nsec3 != 0); +} + struct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t c, struct regional* region, uint8_t* topname) @@ -1375,3 +1398,20 @@ int derive_cname_from_dname(struct ub_packed_rrset_key* cname, memmove(out+prefix_len, dname_target, dname_target_len); return 1; } + +int nsec_nextowner_subdomain(struct ub_packed_rrset_key* rrset, uint8_t* name) +{ + struct packed_rrset_data* d; + uint8_t* next; + size_t nextlen; + if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_NSEC) + return 0; + d = (struct packed_rrset_data*)rrset->entry.data; + if(!d || d->count == 0) + return 0; + next = d->rr_data[0]+2; + nextlen = dname_valid(next, d->rr_len[0]-2); + if(nextlen == 0) + return 0; /* malformed */ + return dname_subdomain_c(next, name); +} diff --git a/validator/val_utils.h b/validator/val_utils.h index afa38b9c7..f05ff1d94 100644 --- a/validator/val_utils.h +++ b/validator/val_utils.h @@ -410,6 +410,14 @@ void val_blacklist(struct sock_list** blacklist, struct regional* region, */ int val_has_signed_nsecs(struct reply_info* rep, char** reason); +/** + * See if there are NSECs, or NSEC3s in the authority section. + * @param rep: reply to check + * @param has_nsec: returned true if it has nsecs. + * @param has_nsec3: returned true if it has nsec3s. + */ +void val_has_auth_nsecs(struct reply_info* rep, int* has_nsec, int* has_nsec3); + /** * Return algo number for favorite (best) algorithm that we support in DS. * @param ds_rrset: the DSes in this rrset are inspected and best algo chosen. @@ -448,4 +456,11 @@ struct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, int derive_cname_from_dname(struct ub_packed_rrset_key* cname, struct ub_packed_rrset_key* dname, uint8_t* out, size_t outlen); +/** Get signer name from RRSIG, sname is NULL if malformed. */ +void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, + size_t* slen); + +/** See if the NSEC nextowner name is a subdomain of the name. */ +int nsec_nextowner_subdomain(struct ub_packed_rrset_key* rrset, uint8_t* name); + #endif /* VALIDATOR_VAL_UTILS_H */ diff --git a/validator/validator.c b/validator/validator.c index 5e07abb29..3634e3215 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -520,6 +520,14 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name, /* add our blacklist to the query blacklist */ sock_list_merge(&(*newq)->blacklist, (*newq)->region, vq->chain_blacklist); + /* start its global quota counter where this one is. */ + if(qstate->global_quota_reached > + (*newq)->global_quota_reached) { + (*newq)->global_quota_started = + qstate->global_quota_reached; + (*newq)->global_quota_reached = + qstate->global_quota_reached; + } } qstate->ext_state[id] = module_wait_subquery; return 1; @@ -1069,7 +1077,14 @@ validate_positive_response(struct module_env* env, struct val_env* ve, uint8_t* wc = NULL; size_t wl; int wc_cached = 0; + int wc_to_cache = 0; + uint8_t* cache_wc = NULL; + size_t cache_wl = 0; + struct ub_packed_rrset_key* cache_s = NULL; int wc_NSEC_ok = 0; + /* This is used to update the RRset cache, with the combination + * of the dname expansion and this wildcard, for security status. */ + struct ub_packed_rrset_key* wc_rrset = NULL; int nsec3s_seen = 0; size_t i; struct ub_packed_rrset_key* s; @@ -1088,14 +1103,20 @@ validate_positive_response(struct module_env* env, struct val_env* ve, ntohs(s->rk.type), ntohs(s->rk.rrset_class)); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } if(wc && !wc_cached && env->cfg->aggressive_nsec) { - rrset_cache_update_wildcard(env->rrset_cache, s, wc, wl, - env->alloc, *env->now); + /* Postpone cache adjust until proof has succeeded. */ + wc_to_cache = 1; + cache_wc = wc; + cache_wl = wl; + cache_s = s; wc_cached = 1; } - + if(wc) wc_rrset = s; } /* validate the AUTHORITY section as well - this will generally be @@ -1152,8 +1173,15 @@ validate_positive_response(struct module_env* env, struct val_env* ve, "did not exist"); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } + if(wc_to_cache) { + rrset_cache_update_wildcard(env->rrset_cache, cache_s, + cache_wc, cache_wl, env->alloc, *env->now); + } verbose(VERB_ALGO, "Successfully validated positive response"); chase_reply->security = sec_status_secure; @@ -1553,6 +1581,16 @@ validate_any_response(struct module_env* env, struct val_env* ve, "did not exist"); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + /* Make the expanded name and wildcard RRSIG rrsets bogus */ + for(i=0; ian_numrrsets; i++) { + uint8_t* cwc = NULL; + size_t cwl = 0; + s = chase_reply->rrsets[i]; + if(val_rrset_wildcard(s, &cwc, &cwl) && cwc) { + ((struct packed_rrset_data*)s-> + entry.data)->security = sec_status_bogus; + } + } return; } @@ -1590,6 +1628,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve, uint8_t* wc = NULL; size_t wl; int wc_NSEC_ok = 0; + /* This is used to update the RRset cache, with the combination + * of the dname expansion and this wildcard, for security status. */ + struct ub_packed_rrset_key* wc_rrset = NULL; int nsec3s_seen = 0; size_t i; struct ub_packed_rrset_key* s; @@ -1610,6 +1651,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve, update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); return; } + if(wc) wc_rrset = s; /* Refuse wildcarded DNAMEs rfc 4597. * Do not follow a wildcarded DNAME because @@ -1621,6 +1663,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve, ntohs(s->rk.type), ntohs(s->rk.rrset_class)); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } @@ -1685,6 +1730,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve, "did not exist"); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } @@ -3068,6 +3116,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, case sec_status_unchecked: default: /* NSEC proof did not work, try next */ + verbose(VERB_ALGO, "NSEC proof did not prove insecure delegation, try NSEC3"); break; } @@ -3103,6 +3152,25 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, *ke = NULL; return 0; case sec_status_bogus: + /* It could be that the NSEC proof failed, + * and, then tried NSEC3. */ + { + int has_nsec=0, has_nsec3=0; + val_has_auth_nsecs(msg->rep, &has_nsec, + &has_nsec3); + if(!has_nsec3 && has_nsec) { + /* The NSECs are the cause, mention that in the error message. */ + verbose(VERB_DETAIL, "NSECs for the " + "referral did not prove no DS."); + errinf_ede(qstate, "NSECs for the referral did not prove no DS", LDNS_EDE_DNSSEC_BOGUS); + goto return_bogus; + } + if(!has_nsec3 && !has_nsec) { + verbose(VERB_DETAIL, "absence of NSECs and NSEC3s when attempting to prove no DS."); + errinf_ede(qstate, "no NSECs or NSEC3s when attempting to prove no DS", LDNS_EDE_DNSSEC_BOGUS); + goto return_bogus; + } + } verbose(VERB_DETAIL, "NSEC3s for the " "referral did not prove no DS."); errinf_ede(qstate, reason, reason_bogus); @@ -3565,6 +3633,11 @@ val_inform_super(struct module_qstate* qstate, int id, verbose(VERB_ALGO, "super: has no validator state"); return; } + /* Pick up the global quota limit from the subquery. */ + if(qstate->global_quota_reached > qstate->global_quota_started) { + super->global_quota_reached += qstate->global_quota_reached - + qstate->global_quota_started; + } if(vq->wait_prime_ta) { vq->wait_prime_ta = 0; process_prime_response(super, vq, id, qstate->return_rcode,