diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1f514b5d0..000000000 --- a/.travis.yml +++ /dev/null @@ -1,380 +0,0 @@ -language: c - -git: - depth: 5 - -addons: - apt: - packages: - - libssl-dev - - libevent-dev - - libexpat-dev - - clang - homebrew: - packages: - - openssl - - libevent - - expat - # homebrew update takes 20min or hangs, so disable update - #update: true - -jobs: - include: - - os: linux - name: GCC on Linux, Amd64 - compiler: gcc - arch: amd64 - env: - - CONFIG_OPTS="--enable-debug --disable-flto" - - os: linux - name: Clang on Linux, Amd64, clang-analysis - compiler: clang - arch: amd64 - env: - - CONFIG_OPTS="--enable-debug --disable-flto" - - TEST_ANALYZER=yes - - os: osx - osx_image: xcode12.2 - name: Clang on OS X, Amd64, clang-analysis - compiler: clang - arch: amd64 - env: - - TEST_OSX=yes - - CONFIG_OPTS="--enable-debug --disable-flto --with-ssl=/usr/local/opt/openssl --with-libexpat=/usr/local/opt/expat" - - TEST_ANALYZER=yes - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: linux - name: Libevent, GCC on Linux, Amd64 - compiler: gcc - arch: amd64 - env: - - TEST_LIBEVENT=yes - - CONFIG_OPTS="--with-libevent" - - os: linux - name: Libevent, Clang on Linux, Amd64 - compiler: clang - arch: amd64 - env: - - TEST_LIBEVENT=yes - - CONFIG_OPTS="--with-libevent" - - os: osx - osx_image: xcode12.2 - name: Libevent, Clang on OS X, Amd64 - compiler: clang - arch: amd64 - env: - - TEST_OSX=yes - - TEST_LIBEVENT=yes - - CONFIG_OPTS="--disable-flto --with-ssl=/usr/local/opt/openssl --with-libevent=/usr/local/opt/libevent --with-libexpat=/usr/local/opt/expat" - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: linux - name: UBsan, GCC on Linux, Amd64 - compiler: gcc - arch: amd64 - dist: bionic - env: - - TEST_UBSAN=yes - - os: linux - name: UBsan, Clang on Linux, Amd64 - compiler: clang - arch: amd64 - dist: bionic - env: - - TEST_UBSAN=yes - - os: linux - name: Asan, GCC on Linux, Amd64 - compiler: gcc - arch: amd64 - dist: bionic - env: - - TEST_ASAN=yes - - os: linux - name: Asan, Clang on Linux, Amd64 - compiler: clang - arch: amd64 - dist: bionic - env: - - TEST_ASAN=yes - - os: linux - name: GCC on Linux, Aarch64 - compiler: gcc - arch: arm64 - dist: bionic - env: - - CONFIG_OPTS="--enable-debug --disable-flto" - - os: linux - name: Clang on Linux, Aarch64 - compiler: clang - arch: arm64 - dist: bionic - env: - - CONFIG_OPTS="--enable-debug --disable-flto" - - os: linux - name: GCC on Linux, PowerPC64 - compiler: gcc - arch: ppc64le - dist: bionic - env: - - CONFIG_OPTS="--enable-debug --disable-flto" - - os: linux - name: Clang on Linux, PowerPC64 - compiler: clang - arch: ppc64le - dist: bionic - env: - - CONFIG_OPTS="--enable-debug --disable-flto" - - os: linux - name: GCC on Linux, s390x - compiler: gcc - arch: s390x - dist: bionic - env: - - CONFIG_OPTS="--enable-debug --disable-flto" - - os: linux - name: Clang on Linux, s390x - compiler: clang - arch: s390x - dist: bionic - env: - - CONFIG_OPTS="--enable-debug --disable-flto" - - os: osx - osx_image: xcode12.2 - name: Apple iPhone on iOS, armv7 - compiler: clang - env: - - TEST_IOS=yes - - AUTOTOOLS_HOST=armv7-apple-ios - - OPENSSL_HOST=ios-cross - - IOS_SDK=iPhoneOS - - IOS_CPU=armv7s - - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU" - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: osx - osx_image: xcode12.2 - name: Apple iPhone on iOS, arm64 - compiler: clang - env: - - TEST_IOS=yes - - AUTOTOOLS_HOST=aarch64-apple-ios - - OPENSSL_HOST=ios64-cross - - IOS_SDK=iPhoneOS - - IOS_CPU=arm64 - - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU" - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: osx - osx_image: xcode12.2 - name: Apple TV on iOS, arm64 - compiler: clang - env: - - TEST_IOS=yes - - AUTOTOOLS_HOST=aarch64-apple-ios - - OPENSSL_HOST=ios64-cross - - IOS_SDK=AppleTVOS - - IOS_CPU=arm64 - - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU" - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: osx - osx_image: xcode12.2 - name: Apple Watch on iOS, armv7 - compiler: clang - env: - - TEST_IOS=yes - - AUTOTOOLS_HOST=armv7-apple-ios - - OPENSSL_HOST=ios-cross - - IOS_SDK=WatchOS - - IOS_CPU=armv7k - - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU" - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: osx - osx_image: xcode12.2 - name: iPhoneSimulator on OS X, i386 - env: - - TEST_IOS=yes - - AUTOTOOLS_HOST=i386-apple-ios - - OPENSSL_HOST=iphoneos-cross - - IOS_CPU=i386 - - IOS_SDK=iPhoneSimulator - - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU" - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: osx - osx_image: xcode12.2 - name: iPhoneSimulator on OS X, x86_64 - env: - - TEST_IOS=yes - - AUTOTOOLS_HOST=x86_64-apple-ios - - OPENSSL_HOST=iphoneos-cross - - IOS_CPU=x86_64 - - IOS_SDK=iPhoneSimulator - - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU" - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: osx - osx_image: xcode12.2 - name: AppleTVSimulator on OS X, x86_64 - env: - - TEST_IOS=yes - - AUTOTOOLS_HOST=x86_64-apple-ios - - OPENSSL_HOST=iphoneos-cross - - IOS_CPU=x86_64 - - IOS_SDK=AppleTVSimulator - - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU" - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: osx - osx_image: xcode12.2 - name: WatchSimulator on OS X, i386 - env: - - TEST_IOS=yes - - AUTOTOOLS_HOST=i386-apple-ios - - OPENSSL_HOST=iphoneos-cross - - IOS_CPU=i386 - - IOS_SDK=WatchSimulator - - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU" - - HOMEBREW_NO_AUTO_UPDATE=1 - - os: linux - name: Android armv7a, Linux, Amd64 - compiler: clang - arch: amd64 - dist: bionic - env: - - TEST_ANDROID=yes - - AUTOTOOLS_HOST=armv7a-linux-androideabi - - OPENSSL_HOST=android-arm - - ANDROID_CPU=armv7a - - ANDROID_API=23 - - ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU" - - ANDROID_SDK_ROOT="$HOME/android-sdk" - - ANDROID_NDK_ROOT="$HOME/android-ndk" - - os: linux - name: Android aarch64, Linux, Amd64 - compiler: clang - arch: amd64 - dist: bionic - env: - - TEST_ANDROID=yes - - AUTOTOOLS_HOST=aarch64-linux-android - - OPENSSL_HOST=android-arm64 - - ANDROID_CPU=aarch64 - - ANDROID_API=23 - - ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU" - - ANDROID_SDK_ROOT="$HOME/android-sdk" - - ANDROID_NDK_ROOT="$HOME/android-ndk" - - os: linux - name: Android x86, Linux, Amd64 - compiler: clang - arch: amd64 - dist: bionic - env: - - TEST_ANDROID=yes - - AUTOTOOLS_HOST=i686-linux-android - - OPENSSL_HOST=android-x86 - - ANDROID_CPU=x86 - - ANDROID_API=23 - - ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU" - - ANDROID_SDK_ROOT="$HOME/android-sdk" - - ANDROID_NDK_ROOT="$HOME/android-ndk" - - os: linux - name: Android x86_64, Linux, Amd64 - compiler: clang - arch: amd64 - dist: bionic - env: - - TEST_ANDROID=yes - - AUTOTOOLS_HOST=x86_64-linux-android - - OPENSSL_HOST=android-x86_64 - - ANDROID_CPU=x86_64 - - ANDROID_API=23 - - ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU" - - ANDROID_SDK_ROOT="$HOME/android-sdk" - - ANDROID_NDK_ROOT="$HOME/android-ndk" - - allow_failures: - - os: osx - name: Apple iPhone on iOS, armv7 - - os: osx - name: Apple iPhone on iOS, arm64 - - os: osx - name: Apple TV on iOS, arm64 - - os: osx - name: Apple Watch on iOS, armv7 - - os: osx - name: iPhoneSimulator on OS X, i386 - - os: osx - name: iPhoneSimulator on OS X, x86_64 - - os: osx - name: AppleTVSimulator on OS X, x86_64 - - os: osx - name: WatchSimulator on OS X, i386 - - os: linux - name: Android armv7a, Linux, Amd64 - - os: linux - name: Android aarch64, Linux, Amd64 - - os: linux - name: Android x86, Linux, Amd64 - - os: linux - name: Android x86_64, Linux, Amd64 - -before_script: - - | - if [ "$TEST_ANDROID" = "yes" ]; then - ./contrib/android/install_tools.sh - elif [ "$TEST_IOS" = "yes" ]; then - ./contrib/ios/install_tools.sh - fi - -# The Travis docs say to avoid calling exit in the script. It leads to -# some code duplication to avoid failures in cross-compiles. Also see -# https://docs.travis-ci.com/user/job-lifecycle/ in the Travis docs. -script: - - | - export MAKE_TEST="yes" - if [ "$TEST_UBSAN" = "yes" ]; then - export CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=undefined -fno-sanitize-recover=all" - elif [ "$TEST_ASAN" = "yes" ]; then - export CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=address" - fi - - | - if [ "$TEST_IOS" = "yes" ]; then - export AUTOTOOLS_BUILD="$(./config.guess)" - export PKG_CONFIG_PATH="$IOS_PREFIX/lib/pkgconfig" - source ./contrib/ios/setenv_ios.sh - ./contrib/ios/install_openssl.sh - ./contrib/ios/install_expat.sh - export CONFIG_OPTS="\ - --build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST \ - --prefix=$IOS_PREFIX \ - --with-ssl=$IOS_PREFIX --disable-gost \ - --with-libexpat=$IOS_PREFIX " - echo CONFIG_OPTS ${CONFIG_OPTS} - export MAKE_TEST=no - export TEST_INSTALL=yes - fi - - | - if [ "$TEST_ANDROID" = "yes" ]; then - export AUTOTOOLS_BUILD="$(./config.guess)" - export PKG_CONFIG_PATH="$ANDROID_PREFIX/lib/pkgconfig" - ./contrib/android/install_ndk.sh - source ./contrib/android/setenv_android.sh - ./contrib/android/install_openssl.sh - ./contrib/android/install_expat.sh - export CONFIG_OPTS="\ - --build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST \ - --prefix=$ANDROID_PREFIX \ - --with-ssl=$ANDROID_PREFIX --disable-gost \ - --with-libexpat=$ANDROID_PREFIX " - echo CONFIG_OPTS ${CONFIG_OPTS} - export MAKE_TEST=no - export TEST_INSTALL=yes - fi - - ./configure ${CONFIG_OPTS} - - make -j 2 - - | - if [ "$MAKE_TEST" = "yes" ]; then - make test - fi - - | - if [ "$TEST_INSTALL" = "yes" ]; then - make install - fi - - | - if [ "$TEST_ANALYZER" = "yes" ]; then - (cd testdata/clang-analysis.tdir; bash clang-analysis.test) - fi diff --git a/configure b/configure index 699d67006..66255fc2d 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.26.1. +# Generated by GNU Autoconf 2.71 for unbound 1.26.2. # # Report bugs to . # @@ -622,8 +622,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.26.1' -PACKAGE_STRING='unbound 1.26.1' +PACKAGE_VERSION='1.26.2' +PACKAGE_STRING='unbound 1.26.2' 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.26.1 to adapt to many kinds of systems. +\`configure' configures unbound 1.26.2 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.26.1:";; + short | recursive ) echo "Configuration of unbound 1.26.2:";; 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.26.1 +unbound configure 1.26.2 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.26.1, which was +It was created by unbound $as_me 1.26.2, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -3253,11 +3253,11 @@ UNBOUND_VERSION_MAJOR=1 UNBOUND_VERSION_MINOR=26 -UNBOUND_VERSION_MICRO=1 +UNBOUND_VERSION_MICRO=2 LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=40 +LIBUNBOUND_REVISION=41 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -3365,6 +3365,7 @@ LIBUNBOUND_AGE=1 # 1.25.2 had 9:38:1 # 1.26.0 had 9:39:1 # 1.26.1 had 9:40:1 +# 1.26.2 had 9:41:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -25712,7 +25713,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h -version=1.26.1 +version=1.26.2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5 printf %s "checking for build time... " >&6; } @@ -26242,7 +26243,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.26.1, which was +This file was extended by unbound $as_me 1.26.2, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -26310,7 +26311,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.26.1 +unbound config.status 1.26.2 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index afedb889e..788202e28 100644 --- a/configure.ac +++ b/configure.ac @@ -12,14 +12,14 @@ sinclude(dnscrypt/dnscrypt.m4) # must be numbers. ac_defun because of later processing m4_define([VERSION_MAJOR],[1]) m4_define([VERSION_MINOR],[26]) -m4_define([VERSION_MICRO],[1]) +m4_define([VERSION_MICRO],[2]) 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=40 +LIBUNBOUND_REVISION=41 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -127,6 +127,7 @@ LIBUNBOUND_AGE=1 # 1.25.2 had 9:38:1 # 1.26.0 had 9:39:1 # 1.26.1 had 9:40:1 +# 1.26.2 had 9:41:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary diff --git a/daemon/cachedump.c b/daemon/cachedump.c index 3fc2081d8..d3a29c8f5 100644 --- a/daemon/cachedump.c +++ b/daemon/cachedump.c @@ -554,7 +554,7 @@ move_into_cache(struct ub_packed_rrset_key* k, ref.key = ak; ref.id = ak->id; - (void)rrset_cache_update(worker->env.rrset_cache, &ref, + rrset_cache_update_unlock(worker->env.rrset_cache, &ref, worker->alloc, *worker->env.now); return 1; diff --git a/daemon/remote.c b/daemon/remote.c index 2ec4e1c5c..467e422aa 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -6285,6 +6285,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg, COPY_VAR_int(harden_referral_path); COPY_VAR_int(harden_algo_downgrade); COPY_VAR_int(harden_unknown_additional); + COPY_VAR_int(harden_cname_follow); COPY_VAR_int(use_caps_bits_for_id); COPY_VAR_ptr(caps_whitelist); COPY_VAR_ptr(private_address); @@ -6521,6 +6522,8 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg, COPY_VAR_ptr(ipset_name_v6); #endif COPY_VAR_int(ede); + COPY_VAR_int(val_validation_attempts); + COPY_VAR_int(val_hash_attempts); COPY_VAR_int(iter_scrub_ns); COPY_VAR_int(iter_scrub_cname); COPY_VAR_int(iter_scrub_rrsig); diff --git a/daemon/worker.c b/daemon/worker.c index 5cc586442..ac0748cd5 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -95,8 +95,6 @@ #include "winrc/win_svc.h" #endif -/** Size of an UDP datagram */ -#define NORMAL_UDP_SIZE 512 /* bytes */ /** ratelimit for error responses */ #define ERROR_RATELIMIT 100 /* qps */ @@ -863,7 +861,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, "validation"); goto bail_out; /* need to validate cache entry first */ } else if(rep->security == sec_status_secure) { - if(reply_all_rrsets_secure(rep)) { + if(reply_an_ns_rrsets_secure(rep)) { *is_secure_answer = 1; } else { if(must_validate) { @@ -1706,6 +1704,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } memset(&reply_edns, 0, sizeof(reply_edns)); reply_edns.edns_present = 1; + reply_edns.edns_version = EDNS_ADVERTISED_VERSION; + reply_edns.udp_size = EDNS_ADVERTISED_SIZE; error_encode(c->buffer, ret, &qinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns); diff --git a/dns64/dns64.c b/dns64/dns64.c index 8f9dba82f..9c6de9d12 100644 --- a/dns64/dns64.c +++ b/dns64/dns64.c @@ -968,6 +968,7 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super) if(answer) { answer->rk.dname = super->qinfo.qname; answer->rk.dname_len = super->qinfo.qname_len; + answer->entry.hash = rrset_key_hash(&answer->rk); } } diff --git a/doc/Changelog b/doc/Changelog index 39936295d..5e8e699d7 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,135 @@ +2 October 2026: Yorgos + - Document libunbound's context lifetime during an async callback. + Thanks to Omar Mousa for the suggestion. + +28 September 2026: Wouter + - Fix to log the errno for trust anchor write close fail. + - Merge #1518 from nshopik: rrset: rehash copies after + changing the key. + - Fix to allow for large (64Kb) packets with testbound. + +22 September 2026: Yorgos + - Fix #1514: [FR] do-not-query-localhost is not including + 0.0.0.0/8 and ‘::’ in the man page. + - Fix #1513: [FR] Size of harden-large-queries in the man page. + - Move NORMAL_UDP_SIZE around. + - Clarify man page text for harden-short-bufsize. + - Update generated man pages. + +21 September 2026: Yorgos + - Merge #1510 from Andy Warner: Move unlink of temp file to before + fatal exit. + +16 September 2026: Wouter + - Release of 1.26.1 with the following security fixes. + - Fix CVE-2026-81642, Heap buffer overflow and possible Remote Code + Execution when digesting DNSKEY. Thanks to Yuqi Qiu and Xiang Li + from Nankai University, AOSP Lab for the report. + - Fix CVE-2026-81634, Possible heap buffer overflow during DNSSEC + canonicalization. Thanks to Vlatko Kosturjak with Marlink Cyber, + for the report. + - Fix CVE-2026-82717, CNAME synthesis could lead to heap corruption. + Thanks to Ben Morris from Anthropic for the report. + - Fix CVE-2026-77955, Possible ZONEMD verification bypass window. + Thanks to Yuqi Qiu and Xiang Li from Nankai University, AOSP Lab, + for the report. In addition, thanks to Qifan Zhang from Palo Alto + Networks for also reporting this issue. + - Fix CVE-2026-78227, Use-after-free in DoQ stream output buffer on + reset re-transmission. Thanks to Yuqi Qiu and Xiang Li from Nankai + University, AOSP Lab for the report. + - Fix CVE-2026-80225, Possible degradation of service from continuous + queries on the same TCP/DoT connection. Thanks to Qifan Zhang from + Palo Alto Networks for the report. + - Fix CVE-2026-82720, Use-after-free in DoH stream cleanup code path. + Thanks to Yuqi Qiu and Xiang Li from Nankai University, AOSP Lab, + for the report. + - Fix CVE-2026-85501, Retrap: Novel Vulnerabilities to launch + Algorithmic Complexity Attacks on DNSSEC. Thanks to Zuyao Xu and + Xiang Li from Nankai University, AOSP Lab for the report. In + addition, thanks to Qifan Zhang from Palo Alto Networks for a + complimentary report. + - Fix CVE-2026-77860, 'serve-expired' can bypass Unbound 'wait-limit'. + Thanks to Xuanchao Xie, Lutong Chen, and Kaiping Xue from the + University of Science and Technology of China (USTC) for the + report. + - The code repository continues with 1.26.2 under development, + that includes the changes from before the 1.26.1 commits. + - Unit test for CVE-2026-81642. + - Unit test for CVE-2026-82717. + - Unit test for CVE-2026-85501. + +15 September 2026: Wouter + - For #1507: TOCTOU race in store_rrsets() can return a + CNAME chain whose target owns no address. + +10 September 2026: Wouter + - Fix to construct the delegation point during DS NS find + as a child side delegation point if that was the response. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix to error on missing close parenthesis for zone file + read and for url content read. Thanks to Qifan Zhang, Palo + Alto Networks, for the report. + +8 September 2026: Wouter + - Fix to elevate the diagnostic for no matches for a wildcard + trusted-keys-file, make it more descriptive, and more man + page content for it. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + +4 September 2026: Wouter + - Fix to make rpz_config leave the rpz with correct set up + on failure. The struct is not half configured on exit. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix to not change the action override in rpz_config, before + the cname override has succeeded. + +3 September 2026: Wouter + - Fix to match NSEC3 hash length to the NSEC3 algorithm, + this stops negative cache overdeletion. It also contrains + the hash label length and checks if the NSEC nextowner + is valid. Thanks to Yuqi Qiu & Xiang Li (Nankai University, + AOSP Lab). + - Remove unused .travis.yml for ci integration. + - Fix to reorder SVCB and HTTPS svcparams for unknown RR form + zonefile input. If it can not be parsed it is leniently + accepted, much like as a secondary it leniently accepts it. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that when extended EDNS RCODE does not fit, at short + udpsize, the reply is truncated with TC and fix for the + rcode in that short reply to be a sensible rcode. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that when a partial EDNS option is in a query, the + response is a more RFC conformant FORMERR, since the EDNS + option is malformed. Also fix to have an EDNS size for + the reply error encoding for failed EDNS parse of the query. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + +2 September 2026: Wouter + - Fix to not commit to have_zone at apply AXFR time for auth + zone transfers, so that later failure rolls back to not. + The have_zone value is set later when the SOA is retrieved. + Also fix to clear the zone data when a transfer does not + have a valid SOA record in the zone for it. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + +1 September 2026: Wouter + - Fix to allow block_a and other local-zone types in a view. + - Fix LOC RR parse to avoid double to uint32 cast overflow. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + +26 August 2026: Wouter + - Fix notify for auth-zone during initial start up. It + performs the transfer and not only lookup. + +24 August 2026: Wouter + - Fix #132: Add `harden-cname-follow: yes` config option, that + can be used to disable cname scrubbing. That can be useful + for when the traffic is on localhost only. + +21 August 2026: Wouter + - Fix to defend against double event deletion, that could cause + event corruption and use after free, for comm_timer_disable. + 11 August 2026: Wouter - Fix #1492 from zacek: Data race in log_init() on key_created/log_lock when calling ub_ctx_create() diff --git a/doc/example.conf.in b/doc/example.conf.in index c5e4e242e..e35eb25d5 100644 --- a/doc/example.conf.in +++ b/doc/example.conf.in @@ -203,6 +203,12 @@ server: # protects against poison attempts. # iter-scrub-promiscuous: yes + # Limit on number of DNSSEC validation attempts for a query. + # val-validation-attempts: 32 + + # Limit on number of DNSSEC hash attempts for a query. + # val-hash-attempts: 32 + # msec for waiting for an unknown server to reply. Increase if you # are behind a slow satellite link, to eg. 1128. # unknown-server-time-limit: 376 @@ -582,6 +588,9 @@ server: # additional section. # harden-unknown-additional: no + # Harden CNAME redirections by following them. + # harden-cname-follow: yes + # Sent minimum amount of information to upstream servers to enhance # privacy. Only sent minimum required labels of the QNAME and set QTYPE # to A when possible. @@ -728,7 +737,7 @@ server: # non-secure data. Useful to shield the users of this validator from # potential bogus data in the additional section. All unsigned data # in the additional section is removed from secure messages. - # val-clean-additional: yes + # val-clean-additional: no # Turn permissive mode on to permit bogus messages. Thus, messages # for which security checks failed will be returned to clients, diff --git a/doc/libunbound.3.in b/doc/libunbound.3.in index a4fa56d38..153e2ac24 100644 --- a/doc/libunbound.3.in +++ b/doc/libunbound.3.in @@ -331,6 +331,8 @@ void my_callback_function(void* my_arg, int err, The \fBasync_id\fP is returned so you can (at your option) decide to track it and cancel the request if needed. If you pass a NULL pointer the \fBasync_id\fP is not returned. +The context, created via \fBub_ctx_create\fP, is in use during but also +after the callback and it cannot be deleted during a callback. .TP .B ub_cancel Cancel an async query in progress. diff --git a/doc/libunbound.rst b/doc/libunbound.rst index 97883dc55..1d0d44f8c 100644 --- a/doc/libunbound.rst +++ b/doc/libunbound.rst @@ -408,6 +408,8 @@ Functions The **async_id** is returned so you can (at your option) decide to track it and cancel the request if needed. If you pass a NULL pointer the **async_id** is not returned. + The context, created via **ub_ctx_create**, is in use during but also + after the callback and it cannot be deleted during a callback. ub_cancel Cancel an async query in progress. diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in index 54116af23..1642f0a93 100644 --- a/doc/unbound.conf.5.in +++ b/doc/unbound.conf.5.in @@ -2070,7 +2070,8 @@ Default: \(dq3 2 1 0 0\(dq .INDENT 0.0 .TP .B harden\-short\-bufsize: \fI\fP -Very small EDNS buffer sizes from queries are ignored. +Very small EDNS buffer sizes from queries are ignored and are instead +set to the normal UDP packet size (512 bytes). .sp Default: yes (per \fI\%RFC 6891\fP) .UNINDENT @@ -2078,6 +2079,7 @@ Default: yes (per \fI\%RFC 6891\fP) .TP .B harden\-large\-queries: \fI\fP Very large queries are ignored. +The cutoff value is chosen to be the normal UDP packet size (512 bytes). Default is no, since it is legal protocol wise to send these, and could be necessary for operation if TSIG or EDNS payload is very large. .sp @@ -2201,6 +2203,18 @@ Default: no .UNINDENT .INDENT 0.0 .TP +.B harden\-cname\-follow: \fI\fP +Harden CNAME redirections by following them. +If no, then upstream CNAME and DNAME redirections are allowed in a +response without checking with further messages if those are valid. +It can only really be disabled safely on localhost net or encrypted +connectivity. +Default is on to protect the cache integrity. +.sp +Default: yes +.UNINDENT +.INDENT 0.0 +.TP .B use\-caps\-for\-id: \fI\fP Use 0x20\-encoded random bits in the query to foil spoof attempts. This perturbs the lowercase and uppercase of query names sent to authority @@ -2336,7 +2350,10 @@ Default: (none) .B do\-not\-query\-localhost: \fI\fP If yes, localhost is added to the \fI\%do\-not\-query\-address\fP entries, -both IPv6 \fB::1\fP and IPv4 \fB127.0.0.1/8\fP\&. +both IPv4 \fB127.0.0.1/8\fP (also \fB::ffff:127.0.0.0/104\fP) and IPv6 \fB::1\fP\&. +Additionally, the zero subnets \fB0.0.0.0/8\fP (also \fB::ffff:0:0/96\fP) and +\fB::\fP are added to the list since on some systems they route to +localhost as well. If no, then localhost can be used to send queries to. .sp Default: yes @@ -2504,6 +2521,9 @@ Format is BIND\-9 style format, the \fBtrusted\-keys { name flag proto algo It is possible to use wildcards with this statement, the wildcard is expanded on start and on reload. .sp +A wildcard that matches no files is not an error: the entry loads no +trust anchors, and the condition is logged at operational verbosity. +.sp Default: \(dq\(dq (no trusted keys file) .UNINDENT .INDENT 0.0 @@ -2613,7 +2633,7 @@ affected. Use this setting to protect the users that rely on this validator for authentication from potentially bad data in the additional section. .sp -Default: yes +Default: no .UNINDENT .INDENT 0.0 .TP @@ -3879,6 +3899,28 @@ Default: yes .UNINDENT .INDENT 0.0 .TP +.B val\-validation\-attempts: \fI\fP +Limit on the number of DNSSEC validation attempts for a query. +This protects against too large numbers of cryptographic operations, +like for a deep delegation chain. +This counts attempts to validate RRSIGs. +When it is exceeded, the query fails. +.sp +Default: 32 +.UNINDENT +.INDENT 0.0 +.TP +.B val\-hash\-attempts: \fI\fP +Limit on the number of DNSSEC hash attempts for a query. +This protects against too large numbers of cryptographic operations, +like for a deep delegation chain. +This counts DS hash attempts to match DNSKEYs. +When it is exceeded, the query fails. +.sp +Default: 32 +.UNINDENT +.INDENT 0.0 +.TP .B fast\-server\-permil: \fI\fP Specify how many times out of 1000 to pick from the set of fastest servers. 0 turns the feature off. diff --git a/doc/unbound.conf.rst b/doc/unbound.conf.rst index e341c516f..74f242acb 100644 --- a/doc/unbound.conf.rst +++ b/doc/unbound.conf.rst @@ -1838,13 +1838,15 @@ These options are part of the ``server:`` section. @@UAHL@unbound.conf@harden-short-bufsize@@: ** - Very small EDNS buffer sizes from queries are ignored. + Very small EDNS buffer sizes from queries are ignored and are instead + set to the normal UDP packet size (512 bytes). Default: yes (per :rfc:`6891`) @@UAHL@unbound.conf@harden-large-queries@@: ** Very large queries are ignored. + The cutoff value is chosen to be the normal UDP packet size (512 bytes). Default is no, since it is legal protocol wise to send these, and could be necessary for operation if TSIG or EDNS payload is very large. @@ -1952,6 +1954,17 @@ These options are part of the ``server:`` section. Default: no +@@UAHL@unbound.conf@harden-cname-follow@@: ** + Harden CNAME redirections by following them. + If no, then upstream CNAME and DNAME redirections are allowed in a + response without checking with further messages if those are valid. + It can only really be disabled safely on localhost net or encrypted + connectivity. + Default is on to protect the cache integrity. + + Default: yes + + @@UAHL@unbound.conf@use-caps-for-id@@: ** Use 0x20-encoded random bits in the query to foil spoof attempts. This perturbs the lowercase and uppercase of query names sent to authority @@ -2077,7 +2090,10 @@ These options are part of the ``server:`` section. @@UAHL@unbound.conf@do-not-query-localhost@@: ** If yes, localhost is added to the :ref:`do-not-query-address` entries, - both IPv6 ``::1`` and IPv4 ``127.0.0.1/8``. + both IPv4 ``127.0.0.1/8`` (also ``::ffff:127.0.0.0/104``) and IPv6 ``::1``. + Additionally, the zero subnets ``0.0.0.0/8`` (also ``::ffff:0:0/96``) and + ``::`` are added to the list since on some systems they route to + localhost as well. If no, then localhost can be used to send queries to. Default: yes @@ -2226,6 +2242,9 @@ These options are part of the ``server:`` section. It is possible to use wildcards with this statement, the wildcard is expanded on start and on reload. + A wildcard that matches no files is not an error: the entry loads no + trust anchors, and the condition is logged at operational verbosity. + Default: "" (no trusted keys file) @@ -2320,7 +2339,7 @@ These options are part of the ``server:`` section. Use this setting to protect the users that rely on this validator for authentication from potentially bad data in the additional section. - Default: yes + Default: no @@UAHL@unbound.conf@val-log-level@@: ** @@ -3358,6 +3377,26 @@ These options are part of the ``server:`` section. Default: yes +@@UAHL@unbound.conf@val-validation-attempts@@: ** + Limit on the number of DNSSEC validation attempts for a query. + This protects against too large numbers of cryptographic operations, + like for a deep delegation chain. + This counts attempts to validate RRSIGs. + When it is exceeded, the query fails. + + Default: 32 + + +@@UAHL@unbound.conf@val-hash-attempts@@: ** + Limit on the number of DNSSEC hash attempts for a query. + This protects against too large numbers of cryptographic operations, + like for a deep delegation chain. + This counts DS hash attempts to match DNSKEYs. + When it is exceeded, the query fails. + + Default: 32 + + @@UAHL@unbound.conf@fast-server-permil@@: ** Specify how many times out of 1000 to pick from the set of fastest servers. 0 turns the feature off. diff --git a/iterator/iter_resptype.c b/iterator/iter_resptype.c index f16520b3e..18501ff6a 100644 --- a/iterator/iter_resptype.c +++ b/iterator/iter_resptype.c @@ -46,6 +46,7 @@ #include "services/cache/dns.h" #include "util/net_help.h" #include "util/data/dname.h" +#include "util/config_file.h" #include "sldns/rrdef.h" #include "sldns/pkthdr.h" @@ -107,7 +108,8 @@ response_type_from_cache(struct dns_msg* msg, enum response_type response_type_from_server(int rdset, struct dns_msg* msg, struct query_info* request, struct delegpt* dp, - int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral) + int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral, + struct config_file* cfg) { uint8_t* origzone = (uint8_t*)"\000"; /* the default */ struct ub_packed_rrset_key* s; @@ -130,6 +132,16 @@ response_type_from_server(int rdset, if( (msg->rep->flags&BIT_RA) && !(msg->rep->flags&BIT_AA) && !rdset) return RESPONSE_TYPE_REC_LAME; + if(!cfg->harden_cname_follow /* follow CNAME chain */) { + /* If the CNAME chain is allowed, see if there is a + * SOA record, if so, the chain is complete to the + * end of it, otherwise it could be a partial chain.*/ + for(i=msg->rep->an_numrrsets; irep->an_numrrsets+msg->rep->ns_numrrsets; i++) { + s = msg->rep->rrsets[i]; + if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA) + return RESPONSE_TYPE_ANSWER; + } + } /* it could be a CNAME with NXDOMAIN rcode */ for(i=0; irep->an_numrrsets; i++) { s = msg->rep->rrsets[i]; @@ -162,6 +174,7 @@ response_type_from_server(int rdset, if(msg->rep->an_numrrsets > 0) { uint8_t* mname = request->qname; size_t mname_len = request->qname_len; + int sawanswer = 0; /* Now look at the answer section first. 3 states: our * answer is there directly, our answer is there after @@ -197,6 +210,7 @@ response_type_from_server(int rdset, * the answer, we only provisionally say * 'ANSWER' -- it very well could be a * REFERRAL. */ + sawanswer = 1; break; } @@ -214,6 +228,10 @@ response_type_from_server(int rdset, * still got to here, then it is a CNAME response. * (This is regardless of the AA bit at this point) */ if(mname != request->qname) { + if(!cfg->harden_cname_follow /* allow CNAMEs */ && + sawanswer /* The last was not CNAME, and + there is an answer RRset. */ ) + return RESPONSE_TYPE_ANSWER; return RESPONSE_TYPE_CNAME; } } diff --git a/iterator/iter_resptype.h b/iterator/iter_resptype.h index 73719abda..b6ebfe8d8 100644 --- a/iterator/iter_resptype.h +++ b/iterator/iter_resptype.h @@ -45,6 +45,7 @@ struct dns_msg; struct query_info; struct delegpt; +struct config_file; /** * The response type is used to interpret the response. @@ -115,7 +116,7 @@ enum response_type response_type_from_cache(struct dns_msg* msg, * detection, mostly). * * @param rdset: if RD bit was sent in query sent by unbound. - * @param msg: the message from the cache. + * @param msg: the message. * @param request: the request that generated the response. * @param dp: The delegation point that was being queried * when the response was returned. @@ -124,10 +125,12 @@ enum response_type response_type_from_cache(struct dns_msg* msg, * is lame, before it became empty. * @param msg_lame_referral: returned true if the reply has a referral before * scrub. + * @param cfg: config with options. * @return the response type (CNAME or ANSWER). */ enum response_type response_type_from_server(int rdset, struct dns_msg* msg, struct query_info* request, struct delegpt* dp, - int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral); + int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral, + struct config_file* cfg); #endif /* ITERATOR_ITER_RESPTYPE_H */ diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c index f2f20a5c1..ebc5144a3 100644 --- a/iterator/iter_scrub.c +++ b/iterator/iter_scrub.c @@ -294,7 +294,14 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias, if(ttl_t > MAX_TTL) ttl_t = MAX_TTL; ttl = (uint32_t)ttl_t; sldns_write_uint32(cn->rr_first->ttl_data, ttl); - sldns_write_uint32(rrset->rr_first->ttl_data, ttl); + /* Do NOT write the clamp back into the packet buffer: + * parse_packet already sized every name from the original + * bytes and rdata_copy re-walks them trusting those sizes; + * mutating packet bytes between the walks breaks that + * invariant (compression pointers can target these TTL + * bytes). The DNAME rrset receives the same clamp at store + * time in rdata_copy, so the DNAME and the synthesized + * CNAME still carry equal TTLs in the cache. */ } sldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen); memmove(cn->rr_first->ttl_data+6, alias, aliaslen); @@ -517,7 +524,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, * server, scrub down the length to something * shorter. This deletes everything after the limit * is reached. The iterator is going to look up - * the content one by one anyway. */ + * the content one by one, if harden-cname-follow . */ remove_rrset("normalize: removing because too many cnames:", pkt, msg, prev, &rrset); continue; @@ -648,6 +655,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, if(rrset->type == LDNS_RR_TYPE_NS && rrset->rr_count > env->cfg->iter_scrub_ns) { shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); + } else if(rrset->type == LDNS_RR_TYPE_DS && + rrset->rr_count > env->cfg->iter_scrub_ns) { + shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); } prev = rrset; rrset = rrset->rrset_all_next; @@ -667,6 +677,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, if(rrset->type == LDNS_RR_TYPE_NS && rrset->rr_count > env->cfg->iter_scrub_ns) { shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); + } else if(rrset->type == LDNS_RR_TYPE_DS && + rrset->rr_count > env->cfg->iter_scrub_ns) { + shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); } /* Mark the additional names from relevant rrset as OK. */ @@ -791,6 +804,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); } } + } else if(rrset->type==LDNS_RR_TYPE_DS) { + if(rrset->rr_count > env->cfg->iter_scrub_ns) { + shorten_rrset(pkt, rrset, + env->cfg->iter_scrub_ns); + } } /* if this is type DS and we query for type DS we just got * a referral answer for our type DS query, fix packet */ @@ -893,8 +911,8 @@ store_rrset(sldns_buffer* pkt, struct msg_parse* msg, struct module_env* env, packed_rrset_ttl_add(d, now); ref.key = k; ref.id = k->id; - /*ignore ret: it was in the cache, ref updated */ - (void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, now); + /* if it was in the cache, ref updated */ + rrset_cache_update_unlock(env->rrset_cache, &ref, env->alloc, now); } /** @@ -1021,6 +1039,8 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg, uint8_t* ns_rrset_dname = NULL; int added_rrlen_ede = 0; struct rrset_parse* rrset, *prev; + uint8_t* sname = qinfo->qname; + size_t snamelen = qinfo->qname_len; prev = NULL; rrset = msg->rrset_first; @@ -1028,6 +1048,7 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg, * it can be used from the cache. After normalization, an initial * DNAME will have a correctly synthesized CNAME after it. */ if(rrset && rrset->type == LDNS_RR_TYPE_DNAME && + env->cfg->harden_cname_follow /* CNAME chain is cut off, one DNAME is allowed here. */ && rrset->section == LDNS_SECTION_ANSWER && pkt_strict_sub(pkt, qinfo->qname, rrset->dname) && pkt_sub(pkt, rrset->dname, zonename)) { @@ -1043,12 +1064,33 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg, * ANY queries get query name in answer section. * Remainders of CNAME chains are cut off and resolved by iterator. */ while(rrset && rrset->section == LDNS_SECTION_ANSWER) { - if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) != 0) { + if(!env->cfg->harden_cname_follow /* CNAME chain is allowed to stay */ && + rrset->type == LDNS_RR_TYPE_DNAME && + pkt_strict_sub(pkt, sname, rrset->dname) && + pkt_sub(pkt, rrset->dname, zonename)) { + /* This DNAME is allowed to stay, the synthesized + * CNAME follows next. */ + prev = rrset; + rrset = rrset->rrset_all_next; + continue; + } + if(dname_pkt_compare(pkt, sname, rrset->dname) != 0) { if(has_additional(rrset->type)) del_addi = 1; remove_rrset("sanitize: removing extraneous answer " "RRset:", pkt, msg, prev, &rrset); continue; } + if(!env->cfg->harden_cname_follow /* CNAME chain is allowed to stay */ && + qinfo->qtype != LDNS_RR_TYPE_ANY && + rrset->type == LDNS_RR_TYPE_CNAME && + dname_pkt_compare(pkt, sname, rrset->dname) == 0) { + /* Follow the CNAME chain, and allow the elements + * that match the CNAME chain. Also allow a DNAME + * in front. */ + if(!parse_get_cname_target(rrset, &sname, &snamelen, + pkt)) + return 0; + } prev = rrset; rrset = rrset->rrset_all_next; } diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index e848e83ba..b8cdcc471 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -1215,8 +1215,8 @@ iter_store_parentside_rrset(struct module_env* env, rrset->entry.hash = rrset_key_hash(&rrset->rk); ref.key = rrset; ref.id = rrset->id; - /* ignore ret: if it was in the cache, ref updated */ - (void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, *env->now); + /* if it was in the cache, ref updated */ + rrset_cache_update_unlock(env->rrset_cache, &ref, env->alloc, *env->now); } /** fetch NS record from reply, if any */ @@ -1712,3 +1712,28 @@ deleg_port_number(struct module_env* env) return env->cfg->ssl_port; return -1; } + +void +shorten_answer_cname(struct reply_info* rep, uint8_t* cutoff) +{ + size_t i, found = 0, removenum; + uint8_t* sname = NULL; + size_t snamelen = 0; + for(i=0; ian_numrrsets; i++) { + if(query_dname_compare(rep->rrsets[i]->rk.dname, cutoff) == 0) { + found = 1; + removenum = i; + break; + } + if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME) { + get_cname_target(rep->rrsets[i], &sname, &snamelen); + if(query_dname_compare(sname, cutoff) == 0) { + found = 1; + removenum = i+1; + break; + } + } + } + if(!found) return; /* not found */ + val_reply_remove_answers(rep, removenum, rep->an_numrrsets-removenum); +} diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 9fb361ab5..e5daca016 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -486,4 +486,7 @@ void iter_make_minimal(struct reply_info* rep); /** See if we need a different port number */ int deleg_port_number(struct module_env* env); +/** Shorten reply CNAME chain to cutoff, cutoff is excluded. */ +void shorten_answer_cname(struct reply_info* rep, uint8_t* cutoff); + #endif /* ITERATOR_ITER_UTILS_H */ diff --git a/iterator/iterator.c b/iterator/iterator.c index cadb95ebd..52cbe762e 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -3189,7 +3189,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, type = response_type_from_server( (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd), iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found, - iq->msg_lame_empty, iq->msg_lame_referral); + iq->msg_lame_empty, iq->msg_lame_referral, qstate->env->cfg); iq->chase_to_rd = 0; /* remove TC flag, if this is erroneously set by TCP upstream */ iq->response->rep->flags &= ~BIT_TC; @@ -3302,6 +3302,47 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, * to send another query with a new qtype. */ type = RESPONSE_TYPE_ANSWER; } + if(type == RESPONSE_TYPE_ANSWER && + !qstate->env->cfg->harden_cname_follow /* cname chain from upstream is allowed */ && + qstate->env->auth_zones && + /* Check for CNAMEs in answer and RPZ after the CNAME. */ + reply_find_rrset_section_an( + iq->response->rep, iq->qchase.qname, + iq->qchase.qname_len, LDNS_RR_TYPE_CNAME, + iq->qchase.qclass) != NULL) { + /* If this is an answer with CNAMEs in front, and + * RPZ wants to modify after CNAME(s), cut off, the + * remainder, and treat as the CNAME response */ + size_t i; + uint8_t* origname = iq->qchase.qname; + size_t orignamelen = iq->qchase.qname_len; + for(i=0; iresponse->rep->an_numrrsets; i++) { + struct dns_msg* forged_response; + if(ntohs(iq->response->rep->rrsets[i]->rk.type) == + LDNS_RR_TYPE_DNAME) { + continue; + } + if(ntohs(iq->response->rep->rrsets[i]->rk.type) != + LDNS_RR_TYPE_CNAME) { + break; + } + get_cname_target(iq->response->rep->rrsets[i], + &iq->qchase.qname, &iq->qchase.qname_len); + forged_response = rpz_callback_from_iterator_cname(qstate, iq); + if(forged_response) { + /* Cut off the answer section at this point. + * RPZ is going to make an answer, in the + * processInit after the CNAME(s) in front + * are handled. */ + shorten_answer_cname(iq->response->rep, + iq->qchase.qname); + type = RESPONSE_TYPE_CNAME; + break; + } + } + iq->qchase.qname = origname; + iq->qchase.qname_len = orignamelen; + } /* handle each of the type cases */ if(type == RESPONSE_TYPE_ANSWER) { @@ -3804,7 +3845,7 @@ processPrimeResponse(struct module_qstate* qstate, int id) type = response_type_from_server( (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd), iq->response, &iq->qchase, iq->dp, NULL, iq->msg_lame_empty, - iq->msg_lame_referral); + iq->msg_lame_referral, qstate->env->cfg); if(type == RESPONSE_TYPE_ANSWER) { qstate->return_rcode = LDNS_RCODE_NOERROR; qstate->return_msg = iq->response; @@ -3954,15 +3995,32 @@ processDSNSResponse(struct module_qstate* qstate, int id, struct module_qstate* forq) { struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id]; + int sec_an = 0, sec_ns = 0; /* if the finished (iq->response) query has no NS set: continue * up to look for the right dp; nothing to change, do DPNSstate */ if(qstate->return_rcode != LDNS_RCODE_NOERROR) return; /* seek further */ /* find the NS RRset (without allowing CNAMEs) */ - if(!reply_find_rrset(qstate->return_msg->rep, qstate->qinfo.qname, - qstate->qinfo.qname_len, LDNS_RR_TYPE_NS, - qstate->qinfo.qclass)){ + /* Usually, the response has a NS in the answer section, since that + * was the query type. And it is then the child side part of the NS + * set. This child side part would be used if next up a delegation + * point was constructed from cache, for example. But now it uses that + * child side part for constructing a delegation point for the DS + * lookup. + * If that is not there, we can pick up the NS from the authority + * section as well, like from a referral. */ + if(reply_find_rrset_section_an(qstate->return_msg->rep, + qstate->qinfo.qname, qstate->qinfo.qname_len, + LDNS_RR_TYPE_NS, qstate->qinfo.qclass)) + sec_an = 1; + if(!sec_an && reply_find_rrset_section_ns(qstate->return_msg->rep, + qstate->qinfo.qname, qstate->qinfo.qname_len, + LDNS_RR_TYPE_NS, qstate->qinfo.qclass)) + sec_ns = 1; + if(!sec_an && !sec_ns) { + /* We probably hit an intermediate label, without a type NS + * record there. To find the nameservers, it must go up more.*/ return; /* seek further */ } @@ -3975,6 +4033,11 @@ processDSNSResponse(struct module_qstate* qstate, int id, errinf(qstate, "malloc failure, in DS search"); return; /* dp==NULL in QUERYTARGETS makes SERVFAIL */ } + if(sec_an) { + /* The NS is in the answer section, this is not a parent side, + * but a child side response for it. */ + foriq->dp->has_parent_side_NS = 0; + } /* success, go query the querytargets in the new dp (and go down) */ } diff --git a/makedist.sh b/makedist.sh index 07b097738..49006f25a 100755 --- a/makedist.sh +++ b/makedist.sh @@ -409,7 +409,7 @@ if [ "$DOWIN" = "yes" ]; then info "git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound" git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound || error_cleanup "git clone failed" cd unbound || error_cleanup "Unbound not exported correctly from git" - rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information" + rm -rf .git .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information" # on a re-configure the cache may no longer be valid... if test -f mingw32-config.cache; then rm mingw32-config.cache; fi @@ -603,7 +603,7 @@ info "git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound" git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound || error_cleanup "git clone failed" cd unbound || error_cleanup "Unbound not exported correctly from git" -rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information" +rm -rf .git .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information" info "Adding libtool utils (libtoolize)." libtoolize -c --install || libtoolize -c || error_cleanup "Libtoolize failed." diff --git a/respip/respip.c b/respip/respip.c index fc9de4c01..3840fe1dd 100644 --- a/respip/respip.c +++ b/respip/respip.c @@ -734,6 +734,7 @@ respip_data_answer(enum respip_action action, if(!new_rep) return -1; rp->rk.flags |= PACKED_RRSET_FIXEDTTL; /* avoid adjusting TTL */ + rp->entry.hash = rrset_key_hash(&rp->rk); new_rep->rrsets[rrset_id] = rp; *redirect_rrsetp = rp; diff --git a/services/authzone.c b/services/authzone.c index 5ca4e4dba..30c33f71f 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -397,6 +397,20 @@ auth_data_del(rbnode_type* n, void* ATTR_UNUSED(arg)) auth_data_delete(z); } +/** delete chunklist */ +static void +auth_chunk_list_delete(struct auth_chunk* first) +{ + struct auth_chunk* c, *cn; + c = first; + while(c) { + cn = c->next; + free(c->data); + free(c); + c = cn; + } +} + /** delete an auth zone structure (tree remove must be done elsewhere) */ static void auth_zone_delete(struct auth_zone* z, struct auth_zones* az) @@ -418,6 +432,7 @@ auth_zone_delete(struct auth_zone* z, struct auth_zones* az) } if(z->rpz) rpz_delete(z->rpz); + auth_chunk_list_delete(z->perform_write_chunk_list); free(z->name); free(z->zonefile); free(z); @@ -2374,14 +2389,7 @@ static void auth_chunks_delete(struct auth_transfer* at) { if(at->chunks_first) { - struct auth_chunk* c, *cn; - c = at->chunks_first; - while(c) { - cn = c->next; - free(c->data); - free(c); - c = cn; - } + auth_chunk_list_delete(at->chunks_first); } at->chunks_first = NULL; at->chunks_last = NULL; @@ -3598,7 +3606,13 @@ int auth_zones_lookup(struct auth_zones* az, struct query_info* qinfo, *fallback = 1; return 0; } - if(z->zone_expired) { + if(z->zone_expired || (z->zonemd_check && z->zonemd_callback_env)) { + /* Do not serve from a zonemd-check zone while its ZONEMD + * verification is still pending: the content is not yet known + * to pass the configured check. The pending marker + * (zonemd_callback_env) is set under z->lock when the async + * lookup is spawned and cleared by the callback under z->lock, + * so this test is race-free. */ *fallback = z->fallback_enabled; lock_rw_unlock(&z->lock); return 0; @@ -3700,7 +3714,10 @@ int auth_zones_downstream_answer(struct auth_zones* az, struct module_env* env, lock_rw_unlock(&z->lock); return 0; } - if(z->zone_expired) { + if(z->zone_expired || (z->zonemd_check && z->zonemd_callback_env)) { + /* see auth_zones_lookup: a pending ZONEMD verification is + * treated like expiry - the zone content is not yet known + * to pass the configured check. */ if(z->fallback_enabled) { lock_rw_unlock(&z->lock); return 0; @@ -3916,6 +3933,12 @@ xfr_process_notify(struct auth_xfer* xfr, struct module_env* env, return; } /* start new probe with this addr src, or note serial */ + if(xfr->task_probe->worker == NULL && xfr->task_probe->only_lookup) { + /* Perform transfer, not just lookup this notify. + * The only_lookup could be set during initial start up + * when the timer sets it for address lookup. */ + xfr->task_probe->only_lookup = 0; + } if(!xfr_start_probe(xfr, env, fromhost)) { /* not started because already in progress, note the serial */ xfr_note_notify_serial(xfr, has_serial, serial); @@ -4513,7 +4536,7 @@ check_packet_ok(sldns_buffer* pkt, uint16_t qtype, struct auth_xfer* xfr, /** read one line from chunks into buffer at current position */ static int chunkline_get_line(struct auth_chunk** chunk, size_t* chunk_pos, - sldns_buffer* buf) + sldns_buffer* buf, int* eof) { int readsome = 0; while(*chunk) { @@ -4542,6 +4565,7 @@ chunkline_get_line(struct auth_chunk** chunk, size_t* chunk_pos, } /* no more text */ if(readsome) return 1; + *eof = 1; return 0; } @@ -4619,13 +4643,13 @@ chunkline_is_comment_line_or_empty(sldns_buffer* buf) /** find a line with ( ) collated */ static int chunkline_get_line_collated(struct auth_chunk** chunk, size_t* chunk_pos, - sldns_buffer* buf) + sldns_buffer* buf, int* eof) { size_t pos; int parens = 0; sldns_buffer_clear(buf); pos = sldns_buffer_position(buf); - if(!chunkline_get_line(chunk, chunk_pos, buf)) { + if(!chunkline_get_line(chunk, chunk_pos, buf, eof)) { if(sldns_buffer_position(buf) < sldns_buffer_limit(buf)) sldns_buffer_write_u8_at(buf, sldns_buffer_position(buf), 0); else sldns_buffer_write_u8_at(buf, sldns_buffer_position(buf)-1, 0); @@ -4636,11 +4660,16 @@ chunkline_get_line_collated(struct auth_chunk** chunk, size_t* chunk_pos, while(parens > 0) { chunkline_remove_trailcomment(buf, pos); pos = sldns_buffer_position(buf); - if(!chunkline_get_line(chunk, chunk_pos, buf)) { + if(!chunkline_get_line(chunk, chunk_pos, buf, eof)) { if(sldns_buffer_position(buf) < sldns_buffer_limit(buf)) sldns_buffer_write_u8_at(buf, sldns_buffer_position(buf), 0); else sldns_buffer_write_u8_at(buf, sldns_buffer_position(buf)-1, 0); sldns_buffer_flip(buf); + if(eof) { + verbose(VERB_ALGO, "http chunkline: " + "missing closing parenthesis"); + *eof = 0; /* It is an error instead of EOF */ + } return 0; } parens += chunkline_count_parens(buf, pos); @@ -4649,6 +4678,8 @@ chunkline_get_line_collated(struct auth_chunk** chunk, size_t* chunk_pos, if(sldns_buffer_remaining(buf) < 1) { verbose(VERB_ALGO, "http chunkline: " "line too long"); + /* null terminate for safety */ + sldns_buffer_write_u8_at(buf, sldns_buffer_capacity(buf)-1, 0); return 0; } sldns_buffer_write_u8_at(buf, sldns_buffer_position(buf), 0); @@ -4717,8 +4748,8 @@ static int chunkline_non_comment_RR(struct auth_chunk** chunk, size_t* chunk_pos, sldns_buffer* buf, struct sldns_file_parse_state* pstate) { - int ret; - while(chunkline_get_line_collated(chunk, chunk_pos, buf)) { + int ret, eof = 0; + while(chunkline_get_line_collated(chunk, chunk_pos, buf, &eof)) { chunkline_newline_removal(buf); if(chunkline_is_comment_line_or_empty(buf)) { /* a comment, go to next line */ @@ -4736,6 +4767,7 @@ chunkline_non_comment_RR(struct auth_chunk** chunk, size_t* chunk_pos, } return 1; } + if(!eof) return 0; /* no noncomments, fail */ return 0; } @@ -5280,7 +5312,7 @@ xfr_apply_http(uint8_t* name, size_t namelen, const char* host, struct sldns_file_parse_state pstate; struct auth_chunk* chunk; size_t chunk_pos; - int ret; + int ret, eof=0; memset(&pstate, 0, sizeof(pstate)); pstate.default_ttl = 3600; if(namelen < sizeof(pstate.origin)) { @@ -5293,7 +5325,8 @@ xfr_apply_http(uint8_t* name, size_t namelen, const char* host, chunk = chunk_list; chunk_pos = 0; pstate.lineno = 0; - while(chunkline_get_line_collated(&chunk, &chunk_pos, scratch_buffer)) { + while(chunkline_get_line_collated(&chunk, &chunk_pos, scratch_buffer, + &eof)) { /* process this line */ pstate.lineno++; chunkline_newline_removal(scratch_buffer); @@ -5330,6 +5363,13 @@ xfr_apply_http(uint8_t* name, size_t namelen, const char* host, return 0; } } + if(!eof) { + verbose(VERB_ALGO, "error parsing line [%s:%d] %s", + xfr->task_transfer->master->file, + pstate.lineno, + sldns_buffer_begin(scratch_buffer)); + return 0; + } return 1; } @@ -5357,7 +5397,7 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z, /** write http chunks to zonefile to create downloaded file */ static int -auth_zone_write_chunks(struct auth_xfer* xfr, const char* fname) +auth_zone_write_chunks(struct auth_chunk* chunk_list, const char* fname) { FILE* out; struct auth_chunk* p; @@ -5366,7 +5406,7 @@ auth_zone_write_chunks(struct auth_xfer* xfr, const char* fname) log_err("could not open %s: %s", fname, strerror(errno)); return 0; } - for(p = xfr->task_transfer->chunks_first; p ; p = p->next) { + for(p = chunk_list; p ; p = p->next) { if(!write_out(out, (char*)p->data, p->len)) { log_err("could not write http download to %s", fname); fclose(out); @@ -5377,14 +5417,91 @@ auth_zone_write_chunks(struct auth_xfer* xfr, const char* fname) return 1; } -/** write to zonefile after zone has been updated */ +/** write to zonefile after zone has been updated, z has rdlock by caller. */ static void -xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env) +zone_write_after_update(struct auth_zone* z, struct module_env* env, + struct auth_chunk* chunk_list) { struct config_file* cfg = env->cfg; - struct auth_zone* z; char tmpfile[1024]; char* zfilename; + + if(z->zonefile == NULL || z->zonefile[0] == 0) { + /* no write needed, no zonefile set */ + auth_chunk_list_delete(chunk_list); + return; + } + zfilename = z->zonefile; + if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(zfilename, + cfg->chrootdir, strlen(cfg->chrootdir)) == 0) + zfilename += strlen(cfg->chrootdir); + if(verbosity >= VERB_ALGO) { + char nm[LDNS_MAX_DOMAINLEN]; + dname_str(z->name, nm); + verbose(VERB_ALGO, "write zonefile %s for %s", zfilename, nm); + } + + /* write to tempfile first */ + if((size_t)strlen(zfilename) + 16 > sizeof(tmpfile)) { + verbose(VERB_ALGO, "tmpfilename too long, cannot update " + " zonefile %s", zfilename); + auth_chunk_list_delete(chunk_list); + return; + } + snprintf(tmpfile, sizeof(tmpfile), "%s.tmp%u", zfilename, + (unsigned)getpid()); + if(chunk_list) { + /* use the stored chunk list to write them */ + if(!auth_zone_write_chunks(chunk_list, tmpfile)) { + unlink(tmpfile); + auth_chunk_list_delete(chunk_list); + return; + } + auth_chunk_list_delete(chunk_list); + } else if(!auth_zone_write_file(z, tmpfile)) { + unlink(tmpfile); + return; + } +#ifdef UB_ON_WINDOWS + (void)unlink(zfilename); /* windows does not replace file with rename() */ +#endif + if(rename(tmpfile, zfilename) < 0) { + log_err("could not rename(%s, %s): %s", tmpfile, zfilename, + strerror(errno)); + unlink(tmpfile); + return; + } +} + +/** write to zonefile after zone has updated, reacquires z readlock. */ +static void +zone_write_after_update_reacq(uint8_t* bakname, size_t baknamelen, + uint16_t bakdclass, struct module_env* env, + struct auth_chunk* chunk_list) +{ + struct auth_zone* z; + /* get lock again, so it is a readlock and concurrently queries + * can be answered */ + lock_rw_rdlock(&env->auth_zones->lock); + z = auth_zone_find(env->auth_zones, bakname, baknamelen, bakdclass); + if(!z) { + lock_rw_unlock(&env->auth_zones->lock); + /* the zone is gone, ignore xfr results */ + return; + } + lock_rw_rdlock(&z->lock); + lock_rw_unlock(&env->auth_zones->lock); + + zone_write_after_update(z, env, chunk_list); + lock_rw_unlock(&z->lock); +} + +/** write to zonefile after zone has been updated */ +static void +xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env, + struct auth_chunk* chunk_list) +{ + struct auth_zone* z; lock_basic_unlock(&xfr->lock); /* get lock again, so it is a readlock and concurrently queries @@ -5402,52 +5519,7 @@ xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env) lock_basic_lock(&xfr->lock); lock_rw_unlock(&env->auth_zones->lock); - if(z->zonefile == NULL || z->zonefile[0] == 0) { - lock_rw_unlock(&z->lock); - /* no write needed, no zonefile set */ - return; - } - zfilename = z->zonefile; - if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(zfilename, - cfg->chrootdir, strlen(cfg->chrootdir)) == 0) - zfilename += strlen(cfg->chrootdir); - if(verbosity >= VERB_ALGO) { - char nm[LDNS_MAX_DOMAINLEN]; - dname_str(z->name, nm); - verbose(VERB_ALGO, "write zonefile %s for %s", zfilename, nm); - } - - /* write to tempfile first */ - if((size_t)strlen(zfilename) + 16 > sizeof(tmpfile)) { - verbose(VERB_ALGO, "tmpfilename too long, cannot update " - " zonefile %s", zfilename); - lock_rw_unlock(&z->lock); - return; - } - snprintf(tmpfile, sizeof(tmpfile), "%s.tmp%u", zfilename, - (unsigned)getpid()); - if(xfr->task_transfer->master->http) { - /* use the stored chunk list to write them */ - if(!auth_zone_write_chunks(xfr, tmpfile)) { - unlink(tmpfile); - lock_rw_unlock(&z->lock); - return; - } - } else if(!auth_zone_write_file(z, tmpfile)) { - unlink(tmpfile); - lock_rw_unlock(&z->lock); - return; - } -#ifdef UB_ON_WINDOWS - (void)unlink(zfilename); /* windows does not replace file with rename() */ -#endif - if(rename(tmpfile, zfilename) < 0) { - log_err("could not rename(%s, %s): %s", tmpfile, zfilename, - strerror(errno)); - unlink(tmpfile); - lock_rw_unlock(&z->lock); - return; - } + zone_write_after_update(z, env, chunk_list); lock_rw_unlock(&z->lock); } @@ -5480,6 +5552,8 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env, int* ixfr_fail) { struct auth_zone* z; + int zonemd_in_progress; + struct auth_chunk* current_chunk_list = NULL; /* obtain locks and structures */ lock_basic_unlock(&xfr->lock); @@ -5520,6 +5594,7 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env, xfr->zone_expired = 0; z->zone_expired = 0; if(!xfr_find_soa(z, xfr)) { + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); verbose(VERB_ALGO, "xfr from %s: no SOA in zone after update" " (or malformed RR)", xfr->task_transfer->master->host); @@ -5563,6 +5638,25 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env, if(z->rpz) rpz_finish_config(z->rpz); + if(z->zonemd_check && z->zonemd_callback_env) { + zonemd_in_progress = 1; + z->zonemd_callback_perform_write = 1; + auth_chunk_list_delete(z->perform_write_chunk_list); + z->perform_write_chunk_list = NULL; + if(xfr->task_transfer->master->http) { + z->perform_write_chunk_list = xfr->task_transfer->chunks_first; + xfr->task_transfer->chunks_first = NULL; + auth_chunks_delete(xfr->task_transfer); + } + } else { + zonemd_in_progress = 0; + z->zonemd_callback_perform_write = 0; + if(xfr->task_transfer->master->http) { + current_chunk_list = xfr->task_transfer->chunks_first; + xfr->task_transfer->chunks_first = NULL; + auth_chunks_delete(xfr->task_transfer); + } + } /* unlock */ lock_rw_unlock(&z->lock); @@ -5573,7 +5667,9 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env, (unsigned)xfr->serial); } /* see if we need to write to a zonefile */ - xfr_write_after_update(xfr, env); + if(!zonemd_in_progress) { + xfr_write_after_update(xfr, env, current_chunk_list); + } return 1; } @@ -8415,7 +8511,8 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z, "zonemd: verify %s RRset with DNSKEY", typestr); } sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL, - LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, reasonlen); + LDNS_SECTION_ANSWER, NULL, NULL, &verified, reasonbuf, + reasonlen); if(sec == sec_status_secure) { return 1; } @@ -8764,8 +8861,8 @@ zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env, auth_zone_log(z->name, VERB_QUERY, "zonemd: verify DNSKEY RRset with trust anchor"); sec = val_verify_DNSKEY_with_TA(env, ve, keystorage, anchor->ds_rrset, - anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, reasonbuf, - reasonlen); + anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, NULL, + reasonbuf, reasonlen); regional_free_all(env->scratch); if(sec == sec_status_secure) { /* success */ @@ -8825,7 +8922,7 @@ auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z, keystorage->rk.rrset_class = htons(z->dclass); auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS"); sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg, - why_bogus, NULL, NULL, reasonbuf, reasonlen); + why_bogus, NULL, NULL, NULL, reasonbuf, reasonlen); regional_free_all(env->scratch); if(sec == sec_status_secure) { /* success */ @@ -8854,9 +8951,13 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf, char reasonbuf[256]; char* reason = NULL, *ds_bogus = NULL, *typestr="DNSKEY"; struct ub_packed_rrset_key* dnskey = NULL, *ds = NULL; - int is_insecure = 0, downprot; + int is_insecure = 0, downprot, perform_write = 0; struct ub_packed_rrset_key keystorage; uint8_t sigalg[ALGO_NEEDS_MAX+1]; + uint8_t bakname[LDNS_MAX_DOMAINLEN]; + size_t baknamelen; + uint16_t bakdclass; + struct auth_chunk* chunk_list = NULL; lock_rw_wrlock(&z->lock); env = z->zonemd_callback_env; @@ -8979,7 +9080,37 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf, auth_zone_verify_zonemd_with_key(z, env, &env->mesh->mods, dnskey, is_insecure, NULL, downprot?sigalg:NULL); regional_free_all(env->scratch); + + if(z->zonemd_callback_perform_write) { + if(!z->zone_expired) { + /* Write to zonefile if the ZONEMD is okay. */ + perform_write = 1; + /* copy the key to lookup the z structure. + * The new lookup is readonly so concurrent + * queries can continue. */ + if(z->namelen > sizeof(bakname)) { + perform_write = 0; + auth_chunk_list_delete(z->perform_write_chunk_list); + z->perform_write_chunk_list = NULL; + } else { + memcpy(bakname, z->name, z->namelen); + baknamelen = z->namelen; + bakdclass = z->dclass; + chunk_list = z->perform_write_chunk_list; + z->perform_write_chunk_list = NULL; + } + } else { + auth_chunk_list_delete(z->perform_write_chunk_list); + z->perform_write_chunk_list = NULL; + } + z->zonemd_callback_perform_write = 0; + } lock_rw_unlock(&z->lock); + + if(perform_write) { + zone_write_after_update_reacq(bakname, baknamelen, bakdclass, + env, chunk_list); + } } /** lookup DNSKEY for ZONEMD verification */ @@ -9047,6 +9178,9 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env) &auth_zonemd_dnskey_lookup_callback, z, 0, &z->zonemd_callback_unique_info)) { lock_rw_wrlock(&z->lock); + /* no callback will run; do not leave the pending + * marker set */ + z->zonemd_callback_env = NULL; log_err("out of memory lookup of %s for zonemd", (fetch_ds?"DS":"DNSKEY")); return 0; diff --git a/services/authzone.h b/services/authzone.h index 8a964db92..c34538c38 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -147,6 +147,10 @@ struct auth_zone { uint16_t zonemd_callback_qtype; /** for the zonemd callback, the unique info */ void* zonemd_callback_unique_info; + /** if the zonemd callback should write to file */ + int zonemd_callback_perform_write; + /** chunklist to write for chunked transfer. */ + struct auth_chunk* perform_write_chunk_list; /** zone has been deleted */ int zone_deleted; /** deletelist pointer, unused normally except during delete */ diff --git a/services/cache/dns.c b/services/cache/dns.c index 04d5ae2d6..b621195c2 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -95,7 +95,8 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now, case 2: /* ref updated, cache is superior */ if(region) { struct ub_packed_rrset_key* ck; - lock_rw_rdlock(&rep->ref[i].key->entry.lock); + /* the entry is already readlocked from the + * check in rrset_cache_update. */ /* if deleted rrset, do not copy it */ if(rep->ref[i].key->id == 0 || rep->ref[i].id != rep->ref[i].key->id) @@ -116,6 +117,8 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now, qrep->serve_expired_ttl = qrep->ttl + SERVE_EXPIRED_TTL; } } + } else { + lock_rw_unlock(&rep->ref[i].key->entry.lock); } /* no break: also copy key item */ /* the line below is matched by gcc regex and silences @@ -677,7 +680,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, rrset_array_unlock(r->ref, r->rrset_count); return NULL; } - if(r->security == sec_status_secure && !reply_all_rrsets_secure(r)) { + if(r->security == sec_status_secure && !reply_an_ns_rrsets_secure(r)) { /* message rrsets have changed status, revalidate */ rrset_array_unlock(r->ref, r->rrset_count); return NULL; @@ -1208,9 +1211,9 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf, rep->rrsets[i]->entry.data, *env->now); ref.key = rep->rrsets[i]; ref.id = rep->rrsets[i]->id; - /*ignore ret: it was in the cache, ref updated */ + /* if it was in the cache, ref updated */ /* no leeway for typeNS */ - (void)rrset_cache_update(env->rrset_cache, &ref, + rrset_cache_update_unlock(env->rrset_cache, &ref, env->alloc, ((ntohs(ref.key->rk.type)==LDNS_RR_TYPE_NS && !pside) ? qstarttime:*env->now + leeway)); diff --git a/services/cache/rrset.c b/services/cache/rrset.c index 9b0319140..3600d7974 100644 --- a/services/cache/rrset.c +++ b/services/cache/rrset.c @@ -239,9 +239,13 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, 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 */ + if(equal) { + ub_packed_rrset_parsedelete(k, alloc); + /* return readlocked item. */ + return 2; + } lock_rw_unlock(&e->lock); ub_packed_rrset_parsedelete(k, alloc); - if(equal) return 2; return 1; } lock_rw_unlock(&e->lock); @@ -269,6 +273,15 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, return 0; } +void rrset_cache_update_unlock(struct rrset_cache* r, struct rrset_ref* ref, + struct alloc_cache* alloc, time_t timenow) +{ + int ret = rrset_cache_update(r, ref, alloc, timenow); + if(ret == 2) { + lock_rw_unlock(&ref->key->entry.lock); + } +} + /** See if the name is a within signer authority */ static int dname_subdomain_rrsig_signers(uint8_t* dname, @@ -333,8 +346,8 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache, rrset->entry.hash = rrset_key_hash(&rrset->rk); ref.key = rrset; ref.id = rrset->id; - /* ignore ret: if it was in the cache, ref updated */ - (void)rrset_cache_update(rrset_cache, &ref, alloc, timenow); + /* if it was in the cache, ref updated */ + rrset_cache_update_unlock(rrset_cache, &ref, alloc, timenow); } /** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache). diff --git a/services/cache/rrset.h b/services/cache/rrset.h index 6db79d90f..06b720a32 100644 --- a/services/cache/rrset.h +++ b/services/cache/rrset.h @@ -129,10 +129,16 @@ void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key, * 1: reference updated, item is inserted in cache. * 2: reference updated, item in cache is considered superior. * also the rdata is equal (but other parameters in cache are superior). + * In case 2 the item is returned under a readlock. The caller must + * unlock. */ int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, struct alloc_cache* alloc, time_t timenow); +/** The rrset_cache_update routine that unlocks at end */ +void rrset_cache_update_unlock(struct rrset_cache* r, struct rrset_ref* ref, + struct alloc_cache* alloc, time_t timenow); + /** * Update or add an rrset in the rrset cache using a wildcard dname. * Generates wildcard dname by prepending the wildcard label to the closest diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 7da23126e..347bbe29d 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -2151,7 +2151,7 @@ void listen_start_accept(struct listen_dnsport* listen) } struct tcp_req_info* -tcp_req_info_create(struct sldns_buffer* spoolbuf) +tcp_req_info_create(struct comm_base* base, struct sldns_buffer* spoolbuf) { struct tcp_req_info* req = (struct tcp_req_info*)malloc(sizeof(*req)); if(!req) { @@ -2159,6 +2159,12 @@ tcp_req_info_create(struct sldns_buffer* spoolbuf) return NULL; } memset(req, 0, sizeof(*req)); + req->read_again_timer = comm_timer_create(base, tcp_read_again_cb, req); + if(!req->read_again_timer) { + log_err("malloc failure"); + free(req); + return NULL; + } req->spool_buffer = spoolbuf; return req; } @@ -2168,6 +2174,7 @@ tcp_req_info_delete(struct tcp_req_info* req) { if(!req) return; tcp_req_info_clear(req); + comm_timer_delete(req->read_again_timer); /* cp is pointer back to commpoint that owns this struct and * called delete on us */ /* spool_buffer is shared udp buffer, not deleted here */ @@ -2207,6 +2214,9 @@ void tcp_req_info_clear(struct tcp_req_info* req) req->done_req_list = NULL; req->num_done_req = 0; req->read_is_closed = 0; + + if(comm_timer_is_set(req->read_again_timer)) + comm_timer_disable(req->read_again_timer); } void @@ -4522,7 +4532,7 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id, "unknown stream %d", (int)stream_id); return 0; } - if(!doq_stream_close(doq_conn, stream, 0)) + if(!doq_stream_close(doq_conn, stream, 1)) return NGTCP2_ERR_CALLBACK_FAILURE; return 0; } diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index ae0463468..4aeb6aa70 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -347,6 +347,10 @@ struct tcp_req_info { int num_done_req; /** list of pending writable result packets, malloced one at a time */ struct tcp_req_done_item* done_req_list; + /** the read again timer, when the number of pipelined TCP queries + * is large, it waits, zero time, for a new event loop to service + * the remainder of the TCP traffic on the fd. */ + struct comm_timer* read_again_timer; }; /** @@ -377,10 +381,12 @@ struct tcp_req_done_item { * Create tcp request info structure that keeps track of open * requests on the TCP channel that are resolved at the same time, * and the pending results that have to get written back to that client. + * @param base: comm base for read again timer. * @param spoolbuf: shared buffer * @return new structure or NULL on alloc failure. */ -struct tcp_req_info* tcp_req_info_create(struct sldns_buffer* spoolbuf); +struct tcp_req_info* tcp_req_info_create(struct comm_base* base, + struct sldns_buffer* spoolbuf); /** * Delete tcp request structure. Called by owning commpoint. diff --git a/services/mesh.c b/services/mesh.c index add773b88..04dedd329 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -373,7 +373,7 @@ mesh_serve_expired_lookup(struct module_qstate* qstate, "validation"); goto bail_out; /* need to validate cache entry first */ } else if(msg->rep->security == sec_status_secure && - !reply_all_rrsets_secure(msg->rep) && must_validate) { + !reply_an_ns_rrsets_secure(msg->rep) && must_validate) { verbose(VERB_ALGO, "Serve expired: secure entry" " changed status"); goto bail_out; /* rrset changed, re-verify */ @@ -1097,6 +1097,18 @@ mesh_state_make_unique(struct mesh_state* mstate) mstate->unique = mstate; } +/** pop a reply from the reply list, if there are any. */ +static struct mesh_reply* +mesh_reply_list_pop_first(struct mesh_state* mstate) +{ + if(mstate->reply_list) { + struct mesh_reply* r = mstate->reply_list; + mstate->reply_list = r->next; + return r; + } + return NULL; +} + void mesh_state_cleanup(struct mesh_state* mstate) { @@ -1112,15 +1124,30 @@ mesh_state_cleanup(struct mesh_state* mstate) } /* drop unsent replies */ if(!mstate->replies_sent) { - struct mesh_reply* rep = mstate->reply_list; + struct mesh_reply* rep; struct mesh_cb* cb; - /* in tcp_req_info, the mstates linked are removed, but - * the reply_list is now NULL, so the remove-from-empty-list - * takes no time and also it does not do the mesh accounting */ - mstate->reply_list = NULL; - for(; rep; rep=rep->next) { + /* Pop items from the list, that means there is no iterator. + * And then items can be removed from the reply list, from + * like comm_point_drop_reply and comm_point_close calls. + * As the tcp_req_info and http2 code drops the entire + * connection. That could delete mesh_reply items previous and + * after the current state. The previous items are already + * popped. And the next items can be altered, like to when a + * connection has more replies on the reply list. + * The current item is also popped so the code needs to + * remove its references. */ + while((rep = mesh_reply_list_pop_first(mstate)) != NULL) { infra_wait_limit_dec(mesh->env->infra_cache, &rep->query_reply, mesh->env->cfg); + if(rep->query_reply.c->tcp_req_info) + tcp_req_info_remove_mesh_state( + rep->query_reply.c->tcp_req_info, + mstate); + else if(rep->query_reply.c->use_h2) + http2_stream_remove_mesh_state(rep->h2_stream); + else if(rep->query_reply.doq_stream) + doq_stream_remove_mesh_state( + rep->query_reply.doq_stream); comm_point_drop_reply(&rep->query_reply); log_assert(mesh->num_reply_addrs > 0); mesh->num_reply_addrs--; @@ -1484,12 +1511,6 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, struct timeval end_time; struct timeval duration; int secure; - /* briefly set the replylist to null in case the - * meshsendreply calls tcpreqinfo sendreply that - * comm_point_drops because of size, and then the - * null stops the mesh state remove and thus - * reply_list modification and accounting */ - struct mesh_reply* rlist = m->reply_list; /* rpz: apply actions */ rcode = mesh_is_udp(r) && mesh_is_rpz_respip_tcponly_action(m) @@ -1546,9 +1567,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, sldns_buffer_write_at(r_buffer, 0, &r->qid, sizeof(uint16_t)); sldns_buffer_write_at(r_buffer, 12, r->qname, m->s.qinfo.qname_len); - m->reply_list = NULL; comm_point_send_reply(&r->query_reply); - m->reply_list = rlist; } else if(rcode) { m->s.qinfo.qname = r->qname; m->s.qinfo.local_alias = r->local_alias; @@ -1570,9 +1589,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, } error_encode(r_buffer, rcode, &m->s.qinfo, r->qid, r->qflags, &r->edns); - m->reply_list = NULL; comm_point_send_reply(&r->query_reply); - m->reply_list = rlist; } else { size_t udp_size = r->edns.udp_size; r->edns.edns_version = EDNS_ADVERTISED_VERSION; @@ -1608,9 +1625,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, error_encode(r_buffer, LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, r->qflags, &r->edns); } - m->reply_list = NULL; comm_point_send_reply(&r->query_reply); - m->reply_list = rlist; } infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply, m->s.env->cfg); @@ -1762,6 +1777,7 @@ void mesh_query_done(struct mesh_state* mstate) struct reply_info* rep = (mstate->s.return_msg? mstate->s.return_msg->rep:NULL); struct timeval tv = {0, 0}; + struct mesh_area* mesh = mstate->s.env->mesh; int i = 0; /* No need for the serve expired timer anymore; we are going to reply. */ if(mstate->s.serve_expired_data) { @@ -1786,7 +1802,18 @@ void mesh_query_done(struct mesh_state* mstate) && (!rep || rep->security != sec_status_secure)) dns_error_reporting(&mstate->s, rep); - for(r = mstate->reply_list; r; r = r->next) { + while((r = mesh_reply_list_pop_first(mstate)) != NULL) { + + /* it was not detached (because it had a reply list), could be now */ + if(!mstate->reply_list && !mstate->cb_list + && mstate->super_set.count == 0) { + mesh->num_detached_states++; + } + /* if not replies any more in mstate, it is no longer a reply_state */ + if(!mstate->reply_list && !mstate->cb_list) { + log_assert(mesh->num_reply_states > 0); + mesh->num_reply_states--; + } if(mesh_is_udp(r)) { /* For UDP queries, the old replies are discarded. * This stops a large volume of old replies from @@ -1801,22 +1828,18 @@ void mesh_query_done(struct mesh_state* mstate) ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > mstate->s.env->cfg->discard_timeout) { /* Drop the reply, it is too old */ - /* briefly set the reply_list to NULL, so that the - * tcp req info cleanup routine that calls the mesh - * to deregister the meshstate for it is not done - * because the list is NULL and also accounting is not - * done there, but instead we do that here. */ - struct mesh_reply* reply_list = mstate->reply_list; verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); infra_wait_limit_dec(mstate->s.env->infra_cache, &r->query_reply, mstate->s.env->cfg); - mstate->reply_list = NULL; - if(r->query_reply.c->use_h2) + if(r->query_reply.c->tcp_req_info) + tcp_req_info_remove_mesh_state( + r->query_reply.c->tcp_req_info, + mstate); + else 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++; @@ -1841,22 +1864,17 @@ void mesh_query_done(struct mesh_state* mstate) /* if this query is determined to be dropped during the * mesh processing, this is the point to take that action. */ if(mstate->s.is_drop) { - /* briefly set the reply_list to NULL, so that the - * tcp req info cleanup routine that calls the mesh - * to deregister the meshstate for it is not done - * because the list is NULL and also accounting is not - * done there, but instead we do that here. */ - struct mesh_reply* reply_list = mstate->reply_list; infra_wait_limit_dec(mstate->s.env->infra_cache, &r->query_reply, mstate->s.env->cfg); - mstate->reply_list = NULL; - if(r->query_reply.c->use_h2) { + if(r->query_reply.c->tcp_req_info) { + tcp_req_info_remove_mesh_state( + r->query_reply.c->tcp_req_info, mstate); + } else 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--; } else { @@ -1897,18 +1915,6 @@ void mesh_query_done(struct mesh_state* mstate) } } - /* Mesh area accounting */ - if(mstate->reply_list) { - mstate->reply_list = NULL; - if(!mstate->reply_list && !mstate->cb_list) { - /* was a reply state, not anymore */ - log_assert(mstate->s.env->mesh->num_reply_states > 0); - mstate->s.env->mesh->num_reply_states--; - } - if(!mstate->reply_list && !mstate->cb_list && - mstate->super_set.count == 0) - mstate->s.env->mesh->num_detached_states++; - } mstate->replies_sent = 1; while((c = mstate->cb_list) != NULL) { @@ -2498,7 +2504,6 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, } } - static int apply_respip_action(struct module_qstate* qstate, const struct query_info* qinfo, struct respip_client_info* cinfo, @@ -2631,7 +2636,18 @@ mesh_serve_expired_callback(void* arg) if(verbosity >= VERB_ALGO) log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep); - for(r = mstate->reply_list; r; r = r->next) { + while((r = mesh_reply_list_pop_first(mstate)) != NULL) { + + /* it was not detached (because it had a reply list), could be now */ + if(!mstate->reply_list && !mstate->cb_list + && mstate->super_set.count == 0) { + mesh->num_detached_states++; + } + /* if not replies any more in mstate, it is no longer a reply_state */ + if(!mstate->reply_list && !mstate->cb_list) { + log_assert(mesh->num_reply_states > 0); + mesh->num_reply_states--; + } if(mesh_is_udp(r)) { struct timeval old; timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); @@ -2639,22 +2655,17 @@ mesh_serve_expired_callback(void* arg) ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > mstate->s.env->cfg->discard_timeout) { /* Drop the reply, it is too old */ - /* briefly set the reply_list to NULL, so that the - * tcp req info cleanup routine that calls the mesh - * to deregister the meshstate for it is not done - * because the list is NULL and also accounting is not - * done there, but instead we do that here. */ - struct mesh_reply* reply_list = mstate->reply_list; verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); infra_wait_limit_dec(mstate->s.env->infra_cache, &r->query_reply, mstate->s.env->cfg); - mstate->reply_list = NULL; - if(r->query_reply.c->use_h2) + if(r->query_reply.c->tcp_req_info) + tcp_req_info_remove_mesh_state( + r->query_reply.c->tcp_req_info, mstate); + else 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++; @@ -2692,8 +2703,7 @@ mesh_serve_expired_callback(void* arg) if(r->query_reply.c->tcp_req_info) tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); /* mesh_send_reply removed mesh state from http2_stream. */ - infra_wait_limit_dec(mstate->s.env->infra_cache, - &r->query_reply, mstate->s.env->cfg); + /* mesh_send_reply decremented wait_limit. */ prev = r; prev_buffer = r_buffer; } @@ -2712,18 +2722,6 @@ mesh_serve_expired_callback(void* arg) } } - /* Mesh area accounting */ - if(mstate->reply_list) { - mstate->reply_list = NULL; - if(!mstate->reply_list && !mstate->cb_list) { - log_assert(mesh->num_reply_states > 0); - mesh->num_reply_states--; - if(mstate->super_set.count == 0) { - mesh->num_detached_states++; - } - } - } - while((c = mstate->cb_list) != NULL) { /* take this cb off the list; so that the list can be * changed, eg. by adds from the callback routine */ diff --git a/services/rpz.c b/services/rpz.c index 1a23e52a0..f5a9b34e9 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -506,24 +506,37 @@ delete_cname_override(struct rpz* r) static int rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p) { + enum rpz_action action_override; if(p->rpz_taglist && p->rpz_taglistlen) { - r->taglistlen = p->rpz_taglistlen; - r->taglist = memdup(p->rpz_taglist, r->taglistlen); - if(!r->taglist) { + uint8_t* taglist = memdup(p->rpz_taglist, p->rpz_taglistlen); + if(!taglist) { log_err("malloc failure on RPZ taglist alloc"); return 0; } + if(r->taglist) + free(r->taglist); + r->taglist = taglist; + r->taglistlen = p->rpz_taglistlen; + } else { + /* free taglist, if any */ + if(r->taglist) { + free(r->taglist); + r->taglist = NULL; + r->taglistlen = 0; + } } if(p->rpz_action_override) { - r->action_override = rpz_config_to_action(p->rpz_action_override); + action_override = rpz_config_to_action(p->rpz_action_override); } else - r->action_override = RPZ_NO_OVERRIDE_ACTION; + action_override = RPZ_NO_OVERRIDE_ACTION; - if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) { + if(action_override == RPZ_CNAME_OVERRIDE_ACTION) { uint8_t nm[LDNS_MAX_DOMAINLEN+1]; size_t nmlen = sizeof(nm); + struct regional* newr; + struct ub_packed_rrset_key* cname_override; if(!p->rpz_cname) { log_err("rpz: override with cname action found, but no " @@ -536,18 +549,40 @@ rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p) p->rpz_cname); return 0; } - r->cname_override = new_cname_override(r->region, nm, nmlen); - if(!r->cname_override) { + newr = regional_create_custom(sizeof(struct regional)); + if(!newr) { + log_err("malloc failure on RPZ cname override region"); return 0; } + cname_override = new_cname_override(newr, nm, nmlen); + if(!cname_override) { + regional_destroy(newr); + return 0; + } + regional_destroy(r->region); + r->region = newr; + r->cname_override = cname_override; + } else { + delete_cname_override(r); } + r->action_override = action_override; r->log = p->rpz_log; r->signal_nxdomain_ra = p->rpz_signal_nxdomain_ra; if(p->rpz_log_name) { - if(!(r->log_name = strdup(p->rpz_log_name))) { + char* log_name = strdup(p->rpz_log_name); + if(!log_name) { log_err("malloc failure on RPZ log_name strdup"); return 0; } + if(r->log_name) + free(r->log_name); + r->log_name = log_name; + } else { + /* free logname, if any */ + if(r->log_name) { + free(r->log_name); + r->log_name = NULL; + } } return 1; } @@ -616,22 +651,6 @@ rpz_config(struct rpz* r, struct config_auth* p) { /* If the zonefile changes, it is read later, after which * rpz_clear and rpz_finish_config is called. */ - - /* free taglist, if any */ - if(r->taglist) { - free(r->taglist); - r->taglist = NULL; - r->taglistlen = 0; - } - - /* free logname, if any */ - if(r->log_name) { - free(r->log_name); - r->log_name = NULL; - } - - delete_cname_override(r); - if(!rpz_apply_cfg_elements(r, p)) return 0; return 1; @@ -2078,6 +2097,7 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs * actual data. So that the actual network data and fake data * are kept track of separately. */ rp->rk.flags |= PACKED_RRSET_RPZ; + rp->entry.hash = rrset_key_hash(&rp->rk); new_reply_info->rrsets[0] = rp; msg->rep = new_reply_info; if(!rpz_add_soa(msg->rep, ms, az)) @@ -2243,6 +2263,7 @@ rpz_synthesize_cname_override_msg(struct rpz* r, struct module_qstate* ms, * actual data. So that the actual network data and fake data * are kept track of separately. */ rp->rk.flags |= PACKED_RRSET_RPZ; + rp->entry.hash = rrset_key_hash(&rp->rk); new_reply_info->rrsets[0] = rp; msg->rep = new_reply_info; diff --git a/sldns/parse.c b/sldns/parse.c index 8ea084661..e76c38601 100644 --- a/sldns/parse.c +++ b/sldns/parse.c @@ -197,6 +197,8 @@ sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l } *t = '\0'; if (c == EOF) { + if(p != 0 || quoted) + return -1; return (ssize_t)i; } diff --git a/sldns/str2wire.c b/sldns/str2wire.c index d2c44980c..37c656106 100644 --- a/sldns/str2wire.c +++ b/sldns/str2wire.c @@ -842,8 +842,7 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len, sldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10)); *rr_len = rr_cur_len; /* SVCB/HTTPS handling */ - if ((rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) - && !was_unknown_rr_format) { + if (rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) { size_t rdata_len = rr_cur_len - dname_len - 10; uint8_t *rdata = rr+dname_len + 10; @@ -875,7 +874,14 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len, rdata_len -= 1; rdata += 1; - return sldns_str2wire_check_svcbparams(rdata, rdata_len); + status = sldns_str2wire_check_svcbparams(rdata, rdata_len); + /* For RFC3597 generic-form input, preserve unprintable records. + * Those could have appeared due to secondary zones, and also + * unbound writing invalid-format records out in generic form. + * If it can be parsed, it fixes the svcparam ordering. */ + if(was_unknown_rr_format && status != LDNS_WIREPARSE_ERR_OK) + status = LDNS_WIREPARSE_ERR_OK; + return status; } return LDNS_WIREPARSE_ERR_OK; @@ -2304,6 +2310,8 @@ int sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len) if (isdigit((unsigned char) *my_str)) { s = strtod(my_str, &my_str); + if(s > 60.0) + return LDNS_WIREPARSE_ERR_SYNTAX; } /* skip blanks before northerness */ @@ -2362,6 +2370,8 @@ north: if (isdigit((unsigned char) *my_str)) { s = strtod(my_str, &my_str); + if(s > 60.0) + return LDNS_WIREPARSE_ERR_SYNTAX; } /* skip blanks before easterness */ @@ -2394,8 +2404,17 @@ east: longitude = equator - longitude; } - altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 + - 10000000.0 + 0.5); + while (isblank((unsigned char) *my_str)) { + my_str++; + } + + /* altitude */ + if(!(isdigit((unsigned char) *my_str) || *my_str == '-')) + return LDNS_WIREPARSE_ERR_SYNTAX; + s = strtod(my_str, &my_str); + if(s < -100000.0 || s > 42849672.95) + return LDNS_WIREPARSE_ERR_SYNTAX; + altitude = (uint32_t)(s*100.0 + 10000000.0 + 0.5); if (*my_str == 'm' || *my_str == 'M') { my_str++; } diff --git a/testcode/testbound.c b/testcode/testbound.c index dbdb2b319..7397bc2f9 100644 --- a/testcode/testbound.c +++ b/testcode/testbound.c @@ -789,3 +789,13 @@ size_t doq_table_quic_size_get(struct doq_table* ATTR_UNUSED(table)) return 0; } #endif + +void tcp_read_again_cb(void* ATTR_UNUSED(arg)) +{ + /* nothing */ +} + +void tcp_more_read_again_cb(void* ATTR_UNUSED(arg)) +{ + /* nothing */ +} diff --git a/testcode/testpkts.c b/testcode/testpkts.c index 93f2add94..cb993b19b 100644 --- a/testcode/testpkts.c +++ b/testcode/testpkts.c @@ -387,7 +387,7 @@ hex_buffer2wire(sldns_buffer *data_buffer) uint8_t *wire = (uint8_t*)malloc(MAX_PACKETLEN); if(!wire) error("out of memory"); - hexbuf = (uint8_t*)malloc(MAX_PACKETLEN); + hexbuf = (uint8_t*)malloc(MAX_PACKETLEN * 2); if(!hexbuf) error("out of memory"); for (data_buf_pos = 0; data_buf_pos < sldns_buffer_position(data_buffer); data_buf_pos++) { c = (int) data_wire[data_buf_pos]; @@ -402,7 +402,7 @@ hex_buffer2wire(sldns_buffer *data_buffer) (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) { - if (hexbufpos >= MAX_PACKETLEN) { + if (hexbufpos >= MAX_PACKETLEN * 2) { error("buffer overflow"); free(hexbuf); return 0; @@ -422,7 +422,7 @@ hex_buffer2wire(sldns_buffer *data_buffer) } break; case 2: - if (hexbufpos >= MAX_PACKETLEN) { + if (hexbufpos >= MAX_PACKETLEN * 2) { error("buffer overflow"); free(hexbuf); return 0; @@ -433,13 +433,13 @@ hex_buffer2wire(sldns_buffer *data_buffer) } } - if (hexbufpos >= MAX_PACKETLEN) { + if (hexbufpos >= MAX_PACKETLEN * 2) { /*verbose("packet size reached\n");*/ } /* lenient mode: length must be multiple of 2 */ if (hexbufpos % 2 != 0) { - if (hexbufpos >= MAX_PACKETLEN) { + if (hexbufpos >= MAX_PACKETLEN * 2) { error("buffer overflow"); free(hexbuf); return 0; @@ -630,7 +630,7 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate, add_section = LDNS_SECTION_ADDITIONAL; else error("%s line %d: bad section %s", name, pstate->lineno, parse); } else if(str_keyword(&parse, "HEX_ANSWER_BEGIN")) { - hex_data_buffer = sldns_buffer_new(MAX_PACKETLEN); + hex_data_buffer = sldns_buffer_new(MAX_PACKETLEN*2); reading_hex = 1; } else if(str_keyword(&parse, "HEX_ANSWER_END")) { if(!reading_hex) { @@ -643,7 +643,7 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate, } else if(reading_hex) { sldns_buffer_printf(hex_data_buffer, "%s", line); } else if(str_keyword(&parse, "HEX_EDNSDATA_BEGIN")) { - hex_ednsdata_buffer = sldns_buffer_new(MAX_PACKETLEN); + hex_ednsdata_buffer = sldns_buffer_new(MAX_PACKETLEN*2); reading_hex_ednsdata = 1; } else if(str_keyword(&parse, "HEX_EDNSDATA_END")) { if (!reading_hex_ednsdata) { diff --git a/testcode/unitverify.c b/testcode/unitverify.c index fcf2e2ffe..ea991faac 100644 --- a/testcode/unitverify.c +++ b/testcode/unitverify.c @@ -196,7 +196,7 @@ verifytest_rrset(struct module_env* env, struct val_env* ve, setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */ /* ok to give null as qstate here, won't be used for answer section. */ sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason, - NULL, LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, + NULL, LDNS_SECTION_ANSWER, NULL, NULL, &verified, reasonbuf, sizeof(reasonbuf)); if(vsig) { printf("verify outcome is: %s %s\n", sec_status_to_string(sec), @@ -510,6 +510,146 @@ nsec3_hash_test(const char* fname) sldns_buffer_free(buf); } +/** Test the rrset_canonicalize_to_buffer function to see if the + * size of canon_owner name is properly checked for. */ +static void +canon_owner_buf_test(void) +{ + struct regional* region; + sldns_buffer* buf; + struct ub_packed_rrset_key k; + struct packed_rrset_data d; + size_t rr_len[2]; + time_t rr_ttl[2]; + uint8_t* rr_data[2]; + int ret; + unit_show_func("validator/val_sigcrypt.c", + "rrset_canonicalize_to_buffer"); + region = regional_create(); + if(!region) + fatal_exit("out of memory"); + /* Purposefully a very small buffer, to overflow it */ + buf = sldns_buffer_new(28); + if(!buf) + fatal_exit("out of memory"); + + /* An RRset to canonicalize. The buffer is made smaller, so + * it can fail on bounds checks. */ + memset(&d, 0, sizeof(d)); + d.ttl = 3600; + d.count = 1; + d.rrsig_count = 1; + d.rr_len = rr_len; + d.rr_ttl = rr_ttl; + d.rr_data = rr_data; + rr_len[0] = 18; + rr_len[1] = 36; + rr_ttl[0] = 3600; + rr_ttl[1] = 3600; + rr_data[0] = (uint8_t*)"\x00\x10\x0Fzzaaaaaaaaaaaaa"; + rr_data[1] = (uint8_t*)"\x00\x24\x00\x06\x08\x3\x01\x02\x03\x04\x01\x02\x03\x04\x01\x02\x03\x04\x12\x34\x03zzz\x00zzaaaaaaaaaaa"; + + memset(&k, 0, sizeof(k)); + k.rk.dname = (uint8_t*) "\x0f" "aaaaaaaaaaaaaaa" "\x00"; + k.rk.dname_len = 17; + k.rk.type = htons(LDNS_RR_TYPE_TXT); + k.rk.rrset_class = htons(LDNS_RR_CLASS_IN); + k.entry.data = &d; + + /* There should be no buffer overflow, assertion failure, here */ + ret = rrset_canonicalize_to_buffer(region, buf, &k); + unit_assert(ret == 0); + + regional_destroy(region); + sldns_buffer_free(buf); +} + +/** Test if ds_digest_match_dnskey that calls ds_create_dnskey_digest, + * checks the buffer size. */ +static void +dnskey_ds_digest_test(void) +{ + struct regional* region; + sldns_buffer* buf; + struct module_env env; + struct ub_packed_rrset_key k1, k2; + struct packed_rrset_data d1, d2; + size_t rr_len1[1], rr_len2[1]; + time_t rr_ttl1[1], rr_ttl2[1]; + uint8_t* rr_rdata1[1], *rr_rdata2[1]; + int ret; + unit_show_func("validator/val_sigcrypt.c", "ds_digest_match_dnskey"); + region = regional_create(); + if(!region) + fatal_exit("out of memory"); + /* Purposefully a very small buffer, to overflow it */ + buf = sldns_buffer_new(28); + if(!buf) + fatal_exit("out of memory"); + memset(&env, 0, sizeof(env)); + env.scratch = region; + env.scratch_buffer = buf; + + /* A DNSKEY and DS RRset to match together. The buffer is made + * smaller, so it can fail on bounds checks. */ + memset(&d1, 0, sizeof(d1)); + d1.ttl = 3600; + d1.count = 1; + d1.rr_len = rr_len1; + d1.rr_ttl = rr_ttl1; + d1.rr_data = rr_rdata1; + rr_len1[0] = 38; + rr_ttl1[0] = 3600; + /* DS rdata has: keytag (2bytes), algorithm (1byte), + * digesttype (1byte), digest (remainder). */ + rr_rdata1[0] = (uint8_t*)"\x00\x24" + "\x12\x34" + "\x08" /* RSASHA256 */ + "\x02" /* SHA256 */ + "0123456789abcdef0123456789abcdef"; /* 32 bytes */ + ; + + memset(&k1, 0, sizeof(k1)); + k1.rk.dname = (uint8_t*) "\x03" "foo" "\x00"; + k1.rk.dname_len = 5; + k1.rk.type = htons(LDNS_RR_TYPE_DS); + k1.rk.rrset_class = htons(LDNS_RR_CLASS_IN); + k1.entry.data = &d1; + + memset(&d2, 0, sizeof(d2)); + d2.ttl = 3600; + d2.count = 1; + d2.rr_len = rr_len2; + d2.rr_ttl = rr_ttl2; + d2.rr_data = rr_rdata2; + rr_len2[0] = 38; + rr_ttl2[0] = 3600; + /* DNSKEY rdata has: flags (2bytes), protocol (1byte), + * algorithm (1byte), publickey (remainder). */ + rr_rdata2[0] = (uint8_t*)"\x00\x24" + "\x01\x01" /* KSK */ + "\x03" /* DNSSEC_KEYPROTO */ + "\x08" /* RSASHA256 */ + "0123456789abcdef0123456789abcdef"; /* 32 bytes of content */ + ; + + memset(&k2, 0, sizeof(k2)); + k2.rk.dname = (uint8_t*) "\x03" "foo" "\x00"; + k2.rk.dname_len = 5; + k2.rk.type = htons(LDNS_RR_TYPE_DNSKEY); + k2.rk.rrset_class = htons(LDNS_RR_CLASS_IN); + k2.entry.data = &d2; + /* 36 byte rdata length for DNSKEY (38-2), and dname length of 5, + * exceeds the (small) buffer size. */ + + /* There should be no buffer overflow, assertion failure, here */ + ret = ds_digest_match_dnskey(&env, &k2, 0, &k1, 0); + unit_assert(ret == 0); + + regional_destroy(region); + sldns_buffer_free(buf); +} + #define xstr(s) str(s) #define str(s) #s @@ -724,4 +864,6 @@ verify_test(void) #endif nsectest(); nsec3_hash_test(SRCDIRSTR "/testdata/test_nsec3_hash.1"); + dnskey_ds_digest_test(); + canon_owner_buf_test(); } diff --git a/testdata/03-testbound.tdir/03-testbound.test b/testdata/03-testbound.tdir/03-testbound.test index b9fdf214d..dd75b061d 100644 --- a/testdata/03-testbound.tdir/03-testbound.test +++ b/testdata/03-testbound.tdir/03-testbound.test @@ -85,6 +85,15 @@ for input in $PRE/testdata/*.rpl $PRE/testdata/*.crpl; do fi fi + # detect if ECDSA is needed + if echo $cleaninput | grep ecdsa >/dev/null 2>&1; then + if $PRE/testbound -e >/dev/null 2>&1; then + : # ECDSA is supported + else + continue + fi + fi + # detect if CLIENT_SUBNET is needed if echo $cleaninput | grep subnet >/dev/null 2>&1; then if $PRE/testbound -c >/dev/null 2>&1; then diff --git a/testdata/auth_xfr_notifyinitiallookup.rpl b/testdata/auth_xfr_notifyinitiallookup.rpl new file mode 100644 index 000000000..06e217bf0 --- /dev/null +++ b/testdata/auth_xfr_notifyinitiallookup.rpl @@ -0,0 +1,236 @@ +; config options +server: + target-fetch-policy: "0 0 0 0 0" + +auth-zone: + name: "example.com." + master: 1.2.3.44 + for-downstream: yes + for-upstream: yes + ## fallback-enabled: no + allow-notify: 127.0.0.1/32 + + ## this line generates zonefile: \n"/tmp/xxx.example.com"\n + zonefile: +TEMPFILE_NAME example.com + ## this is the inline file /tmp/xxx.example.com + ## the tempfiles are deleted when the testrun is over. +TEMPFILE_CONTENTS example.com +example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +example.com. 3600 IN NS ns.example.net. +www.example.com. 3600 IN A 1.2.3.4 +TEMPFILE_END + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test authority zone with NOTIFY during initial lookup + +; 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 +com. IN NS +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END +RANGE_END + +; a.gtld-servers.net. +RANGE_BEGIN 0 100 + ADDRESS 192.5.6.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION ANSWER +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION AUTHORITY +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.44 +ENTRY_END +RANGE_END + +; ns.example.net. +RANGE_BEGIN 0 45 + ADDRESS 1.2.3.44 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.net. IN NS +SECTION ANSWER +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +ns.example.net. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN A +SECTION ANSWER +ns.example.net. IN A 1.2.3.44 +SECTION AUTHORITY +example.net. IN NS ns.example.net. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.net. IN AAAA +SECTION AUTHORITY +example.net. IN NS ns.example.net. +SECTION ADDITIONAL +www.example.net. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +example.com. IN NS ns.example.net. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN SOA +SECTION ANSWER +; serial, refresh, retry, expire, minimum +example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname serial=1 +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +example.com. IN IXFR +SECTION ANSWER +example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600 +example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +add.example.com. IN A 1.2.3.5 +example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 20 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 1.2.3.4 +ENTRY_END + +; NOTIFY example.com +STEP 30 QUERY +ENTRY_BEGIN +REPLY NOTIFY +SECTION QUESTION +example.com. IN SOA +ENTRY_END +; notify reply +STEP 40 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RA NOTIFY NOERROR +SECTION QUESTION +example.com. IN SOA +SECTION ANSWER +ENTRY_END + +STEP 45 TRAFFIC + +STEP 50 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +add.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 60 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA NOERROR +SECTION QUESTION +add.example.com. IN A +SECTION ANSWER +add.example.com. IN A 1.2.3.5 +ENTRY_END + +; the zonefile was updated with new contents +STEP 70 CHECK_TEMPFILE example.com +FILE_BEGIN +example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600 +example.com. 3600 IN NS ns.example.net. +add.example.com. 3600 IN A 1.2.3.5 +www.example.com. 3600 IN A 1.2.3.4 +FILE_END + +SCENARIO_END diff --git a/testdata/auth_zonemd_xfr_chain_fail.rpl b/testdata/auth_zonemd_xfr_chain_fail.rpl index 3e09c9e8e..76a989f75 100644 --- a/testdata/auth_zonemd_xfr_chain_fail.rpl +++ b/testdata/auth_zonemd_xfr_chain_fail.rpl @@ -283,39 +283,9 @@ www.example.com. IN A SECTION ANSWER ENTRY_END -; the zonefile was updated with new contents +; the zonefile was not updated with new contents, due to zonemd failure STEP 70 CHECK_TEMPFILE example.com FILE_BEGIN -example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 200154054 28800 7200 604800 3600 -example.com. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55566 example.com. gcFHT/Q4iDZ78CK6fyY2HZr8sRtgH2Rna9fEs06RW0gqMnfDntweoIaBamOZ7NlAP84aY2bZeanmEccmkHexByUpodCoKQ4NzVXctLr0TO4PVoFyfUfj62fjhM56SF8ioDxsoDQcPtYXcjNQjwfntWofMqHCMxrb9LzbgePzhOM= -example.com. 3600 IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55566 example.com. X+V3XsbJbBi9OsHpjMkGCox8RLY/uXp/XX/O/flTrIre9fMDWm9ZGnewtuQFpLgGc6hUTi0eLsuRWRA5fZXEKUBhmoR2Ph01KgE1gvlL7v6zPWQwXVcBRUr3mOSbYdNNkHkXEjiDBGEhNkfqR216zNgw563eEGXOkLUFNIx5Zpg= -example.com. 3600 IN NSEC bar.example.com. NS SOA RRSIG NSEC DNSKEY ZONEMD -example.com. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 55566 example.com. ufLrlOQprAqjnH85Rt3T0Mxd3ZB0mBeeNIr84eFJ8Rk6WiWEPm0Y1R7GRufNI24Mj7iqLcL4nJM6KK6B7dJqjqu73jw1acuYNnbsoV2BNDRXRFP2FNWTpctVdi+955f3FzgsmEJXfGiSUG0YXAEcZmdCPCn5ii2jk8mk7r6KKYo= -example.com. 3600 IN DNSKEY 256 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55566} -example.com. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55566 example.com. fsdnVg38PKQTH2mDOwkXL6Jre7JP7Gf8WI3CvIbmeYQUJtAlpcSbZkS3wInm3kKMxOuT55BWzndQzpfmpo91OqJjG27W0k9301NMLUwFprA6b9HK+iPAT0JpYPDPzcm1bQdarLzLS+eD/GPwmyVSX7Gze+08VfE8m8sOW2r7UjA= -example.com. 3600 IN ZONEMD 200154054 1 2 58F7620F93204BBB31B44F795B3409CC4ABD9EF5601DECC15675BD7751213152984EDDCE0626E6062E744B03B3E47711202FBB79E4A2EB8BC5CF46741B5CAE6F -example.com. 3600 IN RRSIG ZONEMD 8 2 3600 20201116135527 20201019135527 55566 example.com. orn8ZF/yqj9u4WrhiO6gtEcTaVsnZSWWZLfXhcIOiWSB8kKCxtZl5cG17dD3Du1NllUwMRqkp0KleLhIoUS9xeQ/0x05u+CYLrfQ62oAiD7q54ZQzpXJIH52aQzKV70ZnO03CZowhQBnetmIoKX6xLogKo8pt+BdQbo3oVHxV8Y= -bar.example.com. 3600 IN A 1.2.3.55 -bar.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. NYhmRicF4C9+YxpWeQrepy4ALM1CM0USoDuGi3W5Xtp4/+YpCJfSIdR9vlJaJ2WayYuZrz9Ai2ci7oWwE1Fn3oywGwCKvGo9m0c3mC2eEtphE19wrop6pWu6um4RiFhmzYS1voraA3PAdYzze9U4NHzlk0+sb5vNZW9dSZS30Ds= -bar.example.com. 3600 IN NSEC ding.example.com. A RRSIG NSEC -bar.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. VhsGuBx20DXQZNU8ITAMnasn6NVyEjN9xtB8msH5xJn80UCuaqvFBURzcPWN3aHnykEvGfdPF/9P3WvlON0cMikWkqSLy6Q9bpvgAq13HWYh+ZcDoqLtICaB7RkBQc+6aHAqZFyQbD8/m8Kxt5eVJtV6rEuf+yPX0+3aXHhsRg0= -ding.example.com. 3600 IN A 1.2.3.4 -ding.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. OERsruISkpd1s68ute8Xm8YXisBCTkkiDMt34K+0dVqvySOJq63d3qN18BeUxZxLyHDB1eR3nZZKqEdkTqrv2r98skhWhjnOECpFbu5gKjtN/KPexbbJ+rxC0QqciuWOC7M6YE0cvI17/RB9KhVRy5rqY2X4Gt2wk2CNeD1dAko= -ding.example.com. 3600 IN NSEC foo.example.com. A RRSIG NSEC -ding.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. nb1W2aaKrU5iAQiY8gMsoMOejID19JMTEwY2rRoe+KsvzMs0rE0ifEkqit4blXaU0tfy0foJ70uqdJFqBoGz1NcSwZ6GNk/iNfGvG3XpxZ/zqEe7kkIucqqei794G7z9psqV94yZ3WaT+IswPpWrSaWv1w41RtcWufPhe4fOAmU= -foo.example.com. 3600 IN A 1.2.3.4 -foo.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. ZcUngb2pUejwnsshbJN/Dfr+Bzu8fcZXyqLArQ+10Bw1IPHyfx7yyUJ43V5tTYVHPSEsJzTnaWj+olVrNhVZxq5e0pgzSYPfGln2FEItEvMIOn33j8yKTpPW2MLyuFF5ZkXhosG20EUwRMvMmRHRz9mIZfwWoMbSGPukmLh8zMA= -foo.example.com. 3600 IN NSEC ns.example.com. A RRSIG NSEC -foo.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. fUZEpkEULRWDntN5Z7Kr8M83Hjhf08ECMKRpo6IBoBc3ayenj+YMgWAvFXC825wjENPYYWNGag0d32U83zCZxqgv+8uXZd3B7QDpTbL41aWZdc++s5YWTkYjyOWwJ1XHOv4nL3qEnJBXVzo/E1gbSKhTFuG97i+7J1MFd9MsC5s= -ns.example.com. 3600 IN A 127.0.0.1 -ns.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. SiuxuPtN/ITd+Z20j8UNUHJWbLHirE8zQOWMv5fAZ1rPKpAidrZgUL8J417GdrTwkueU2ywAJ7EzFJSwNTa7o/wUnq7svmOR6Ze6UQsKuZFZGEfqPNDRp4YuF86LU5jChuo+f/IRpydHrxVwGxDPCR9KarDM+ewfW+yI5bZeZcg= -ns.example.com. 3600 IN NSEC www.example.com. A RRSIG NSEC -ns.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. 0upKNYjiow4NDJm3I1RbUddE9GGuFYEVKswww5BAc/6WHuukupncL30lskvcSKGpByDssP2Hi2CufyEtYeGWh6q1TxtOFRqFBX1p6Q5b3tBlCtvv4h31dQR9uqLvq+GkGS5MR+0LO5kWagIpZmnI8YY5plVdXEtNbp2Ar8zvz/A= -www.example.com. 3600 IN A 127.0.0.1 -www.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. AaIeICaPjV50TDrpbyOn94+hs8EYIMTmN4pYqj7e8GIGimqQIk5jgpwSx6SOoOF+uOqkf9GKHkQTn5YVGaeXwEQleg7mPTmMYKAOk06Y7MFUO1Vwt1Vt7Wo+Cpa3x2a1CmEkfFOi4WqP43VJnUtjjKmXoKRz3VUmqByyJYUAGbQ= -www.example.com. 3600 IN NSEC example.com. A RRSIG NSEC -www.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. meg/t6nIBqQZ0d5/dT7uu/3CuP4vE+HxqFQaj2fjUNceA/6C7QIQnqQ5Kyblg+XijDkQX0yvyFNHYdgF16UDgFT7tlNUCHk1SpF5BWzV4c4tBEhxASTz7UQo111O3Tyd6CldPzO/Se15Ud0/ZYltHEqWTfY5nJoXC/OJD9V2QOI= FILE_END SCENARIO_END diff --git a/testdata/dname_pkt_alter.rpl b/testdata/dname_pkt_alter.rpl new file mode 100644 index 000000000..7c1e0d372 --- /dev/null +++ b/testdata/dname_pkt_alter.rpl @@ -0,0 +1,206 @@ +; config options +; The island of trust is at test. +server: + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: no + minimal-responses: no + local-zone: test. nodefault + log-servfail: yes + cache-max-ttl: 86400 + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test DNAME for post parse packet alteration + +; 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 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. +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 +a.d.example.test. IN CNAME +SECTION ANSWER +HEX_ANSWER_BEGIN +00 00 84 00 ; QR AA +00 01 00 02 00 01 00 00 ; QDCOUNT=1, ANCOUNT=2, NSCOUNT=1, ARCOUNT=0. +; a.d.example.test. IN CNAME +01 61 01 64 07 6578616d706c65 04 74657374 00 00 05 00 01 +; answer d.example.test. DNAME IN TTL=.. e.example.test. +01 64 07 6578616d706c65 04 74657374 00 00 27 00 01 FF 00 12 34 +00 10 01 65 07 6578616d706c65 04 74657374 00 +; . TXT len to have space. +00 00 10 00 01 00 00 00 15 +00 10 +0F 000102030405060708090A0B0C0D0E +; auth SOA, with rdata compression pointer that points to the +; DNAME TTL value. That gets clamped with max-ttl. +; example.test. SOA IN ttl +07 6578616d706c65 04 74657374 00 00 06 00 01 00 00 00 15 +00 18 +; DNAME TTL is at 36 +c0 37 +c0 0c +00 00 00 01 +00 00 00 02 +00 00 00 03 +00 00 00 04 +00 00 00 05 +HEX_ANSWER_END +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +a.e.example.test. IN A +SECTION AUTHORITY +example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600 +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +a.d.example.test. IN CNAME +ENTRY_END + +; The query is for type CNAME, so that the DNAME redirect is not followed, +; but we get the processed answer from that DNAME reply. +; The packet alteration would have changed the domain name in the SOA rdata. +; but it should not have happened, the check below has the correct outcome, +; where the packet data has not been altered, from its already awkward +; contents. +; The TXT RR has been scrubbed from the reply. +; The malformed rdata would read something like: +; example.test. 5 IN SOA . \001e\007example\004test\000. 1048577 21 1052416 16909060 84281096 + +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +a.d.example.test. IN CNAME +SECTION ANSWER +d.example.test. 21 IN DNAME e.example.test. +a.d.example.test. 21 IN CNAME a.e.example.test. +SECTION AUTHORITY +example.test. 3600 IN SOA . a.d.example.test. 1 2 3 4 5 +ENTRY_END + +SCENARIO_END diff --git a/testdata/dsloop_dupds_ecdsa.crpl b/testdata/dsloop_dupds_ecdsa.crpl new file mode 100644 index 000000000..98dae77cc --- /dev/null +++ b/testdata/dsloop_dupds_ecdsa.crpl @@ -0,0 +1,436 @@ +; config options +; The island of trust is at example.com +server: + trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b" + val-override-date: "20070916134226" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + ede: yes + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test validator with DS loop with duplicate DS records. +; the DS records match digest. + +; 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 +com. IN NS +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END +RANGE_END + +; a.gtld-servers.net. +RANGE_BEGIN 0 100 + ADDRESS 192.5.6.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION ANSWER +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION AUTHORITY +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.com. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN DNSKEY +SECTION ANSWER +example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b} +example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854} +SECTION AUTHORITY +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +sub1.example.com. IN A +SECTION ANSWER +SECTION AUTHORITY +sub1.example.com. IN NS ns.sub1.example.com. +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 + +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 + +sub1.example.com. 3600 IN RRSIG DS 3 3 3600 20070926134150 20070829134150 2854 example.com. AA2wcVQsxCw2VQcgrSp2zjxYP5ElbMVNMMdc/pMU77k5VkMThtZKygE= +SECTION ADDITIONAL +ns.sub1.example.com. IN A 1.2.3.5 +ENTRY_END +RANGE_END + +; ns.sub1.example.com. +; 24 DSes and 24 DNSKEYs +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.sub1.example.com. IN AAAA +SECTION ANSWER +SECTION AUTHORITY +sub1.example.com. IN SOA a. b. 3600 3600 3600 3600 3600 +sub1.example.com. 3600 IN RRSIG SOA 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. PyHa+O9jyNBtKuVilpPoqQGDKHdMCrfhm6A7GDj0+ZPXZAax/+hl10CVIUhl5YqCS3xGc3Zae/WNbD+1w3cIUQ== +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +sub1.example.com. IN DNSKEY +SECTION ANSWER +sub1.example.com. IN DNSKEY 257 3 13 n2P99SKaAUDt50U/cToH/0TmGJKG8+Pbiwl1WY/f5EVWZD/auO5QEyY6Tm9kLHzAEOcjWR701V74ZgyFPirxIA== ;{id = 20 (ksk), size = 256b} +; invalid signatures There is AAAA01 in it. +sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQAAAA01== +sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQAAAA02== +sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQAAAA03== +sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQAAAA04== +sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQAAAA05== +sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQAAAA06== +sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQAAAA07== +sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQAAAA08== +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.sub1.example.com. IN A +SECTION ANSWER +www.sub1.example.com. IN A 10.20.30.41 +www.sub1.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 20 sub1.example.com. utG2+wuHSbmyQCaIjL7ElDe3DJCMqZGrPqsOEyJj8ljGGa5JaTY+KdYvZ6oGmprV7utRPNyRormou1zRWoG8ew== +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AD DO NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} +ENTRY_END + +; sub1.example.com. +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.sub1.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 30 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ede=6 +;ednsdata +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +www.sub1.example.com. IN A +SECTION ANSWER +;www.sub1.example.com. IN A 10.20.30.41 +;SECTION ADDITIONAL +;HEX_EDNSDATA_BEGIN +;; EDE: DNSSEC Bogus "validation failure : DS verify has too many tag matches from 1.2.3.5 for key sub1.example.com. while building chain of trust" +;000F009A000676616C69646174696F6E206661696C757265203C7777772E737562312E +;6578616D706C652E636F6D2E204120494E3E3A20445320766572696679206861732074 +;6F6F206D616E7920746167206D6174636865732066726F6D20312E322E332E3520666F +;72206B657920737562312E6578616D706C652E636F6D2E207768696C65206275696C64 +;696E6720636861696E206F66207472757374 +;HEX_EDNSDATA_END +ENTRY_END + +SCENARIO_END diff --git a/testdata/edns_downstream_cookie_short.rpl b/testdata/edns_downstream_cookie_short.rpl new file mode 100644 index 000000000..22fd6e6fa --- /dev/null +++ b/testdata/edns_downstream_cookie_short.rpl @@ -0,0 +1,74 @@ +; config options +server: + answer-cookie: yes + cookie-secret: "000102030405060708090a0b0c0d0e0f" + access-control: 127.0.0.1 allow_cookie + access-control: 1.2.3.4 allow + local-data: "test. TXT test" + harden-short-bufsize: no + +CONFIG_END + +SCENARIO_BEGIN Test downstream DNS Cookies with short bufsize + +; Note: When a valid hash was required, it was generated by running this test +; with an invalid one and checking the output for the valid one. +; Actual hash generation is tested with unit tests. + +; Query without a client cookie ... +; There is no space in udpsize for the EDE. +STEP 0 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +test. IN TXT +SECTION ADDITIONAL +. 0 CLASS20 OPT \# 00 +ENTRY_END +; ... get TC and refused +STEP 1 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA TC REFUSED +SECTION QUESTION +test. IN TXT +ENTRY_END + +; Query with only a client cookie ... +; The OPT udpsize is short so the reply EDNS OPT does not fit. +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +test. IN TXT +SECTION ADDITIONAL +. 0 CLASS24 OPT \# 12 00 0a 00 08 31 32 33 34 35 36 37 38 +ENTRY_END +; ... the BADCOOKIE and a new cookie, does not fit. +STEP 21 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA TC SERVFAIL +SECTION QUESTION +test. IN TXT +ENTRY_END + +; Check an EDNS option with a too short content +; The EDNS OPT rdata is too short, for the option opt_len. +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +test. IN TXT +SECTION ADDITIONAL +. 32768 CLASS1230 OPT \# 04 00 0a 00 08 +ENTRY_END +STEP 31 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO FORMERR +SECTION QUESTION +test. IN TXT +ENTRY_END + +SCENARIO_END diff --git a/testdata/fwd_cname_follow.rpl b/testdata/fwd_cname_follow.rpl new file mode 100644 index 000000000..b3aae17c6 --- /dev/null +++ b/testdata/fwd_cname_follow.rpl @@ -0,0 +1,137 @@ +; This is a comment. +; config options go here. +server: + # allow cname chains from the upstream. + harden-cname-follow: no + +forward-zone: name: "." forward-addr: 216.0.0.1 +CONFIG_END + +SCENARIO_BEGIN Forward and follow CNAME chain. +RANGE_BEGIN 0 100 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +SECTION AUTHORITY +www.example.com. IN NS ns.example.com. +www.example.com. IN NS ns.example.com. +www.example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 10.20.30.50 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR RD RA NOERROR +SECTION QUESTION +www2.example.com. IN A +SECTION ANSWER +www2.example.com. IN CNAME b.ex2.com. +b.ex2.com. IN A 10.20.30.42 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR RD RA NOERROR +SECTION QUESTION +www3.example.com. IN A +SECTION ANSWER +www3.example.com. IN CNAME b.ex2.com. +b.ex2.com. IN CNAME b.ex3.com. +b.ex3.com. IN A 10.20.30.43 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR RD RA NOERROR +SECTION QUESTION +www4.example.com. IN A +SECTION ANSWER +www4.example.com. IN CNAME b4.ex2.com. +b4.ex2.com. IN CNAME b4.ex3.com. +b4.ex3.com. IN CNAME b4.ex4.com. +b4.ex4.com. IN A 10.20.30.44 +ENTRY_END + +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +STEP 4 CHECK_ANSWER +ENTRY_BEGIN +MATCH opcode qname qtype +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +ENTRY_END + +STEP 11 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www2.example.com. IN A +ENTRY_END + +STEP 14 CHECK_ANSWER +ENTRY_BEGIN +MATCH opcode qname qtype +SECTION QUESTION +www2.example.com. IN A +SECTION ANSWER +www2.example.com. IN CNAME b.ex2.com. +b.ex2.com. IN A 10.20.30.42 +ENTRY_END + +STEP 21 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www3.example.com. IN A +ENTRY_END + +STEP 24 CHECK_ANSWER +ENTRY_BEGIN +MATCH opcode qname qtype +SECTION QUESTION +www3.example.com. IN A +SECTION ANSWER +www3.example.com. IN CNAME b.ex2.com. +b.ex2.com. IN CNAME b.ex3.com. +b.ex3.com. IN A 10.20.30.43 +ENTRY_END + +STEP 31 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www4.example.com. IN A +ENTRY_END + +STEP 34 CHECK_ANSWER +ENTRY_BEGIN +MATCH opcode qname qtype +SECTION QUESTION +www4.example.com. IN A +SECTION ANSWER +www4.example.com. IN CNAME b4.ex2.com. +b4.ex2.com. IN CNAME b4.ex3.com. +b4.ex3.com. IN CNAME b4.ex4.com. +b4.ex4.com. IN A 10.20.30.44 +ENTRY_END + +SCENARIO_END diff --git a/testdata/iter_ds_locate_ns_midns.rpl b/testdata/iter_ds_locate_ns_midns.rpl new file mode 100644 index 000000000..adb7ba5dd --- /dev/null +++ b/testdata/iter_ds_locate_ns_midns.rpl @@ -0,0 +1,506 @@ +; config options +server: + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: no + local-zone: test. nodefault + +stub-zone: + name: "." + stub-addr: 193.0.14.129 +CONFIG_END + +SCENARIO_BEGIN Test locate of DS NS records when middle NS is another server. +; There are several zones hosted on one server. The DS lookup needs to +; locate the NS for one of the middle zones. That middle zone has an NS +; record where the child-data does not precisely match the parent referral. +; Even though that parent referral is not visible due to the zones that are +; on one server. The DS lookup fetches the child-side NS record. +; And then should lookup the DS with it. +; +; In foo2.test there is an actual referral, the server host the upper and +; lower zone, but not the middle, so it gives a referral instead of the +; child side data when queried for the middle NS record. +; +; In foo3.test the zone is co-hosted, also the middle zone, and the glue +; is correct, there is no mismatch with the NS record. It points to the +; same server. That server answers from the lower zone for qtype DS, +; that is from the wrong zone if that server supported DNSSEC for qtype DS. +; +; In foo4.test the zone is co-hosted and the server supports DNSSEC for +; qtype DS, and so uses the correct middle zone, answering the query. +; And DSNS find is not used. + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 200 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA 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 A +SECTION AUTHORITY +test. IN NS ns.test. +SECTION ADDITIONAL +ns.test. IN A 192.5.0.1 +ENTRY_END +RANGE_END + +; ns.test. +RANGE_BEGIN 0 200 + ADDRESS 192.5.0.1 +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +foo.test. IN A +SECTION AUTHORITY +foo.test. IN NS ns.foo.test. +SECTION ADDITIONAL +ns.foo.test. IN A 192.5.0.2 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +ex2.test. IN A +SECTION AUTHORITY +ex2.test. IN NS ns.ex2.test. +SECTION ADDITIONAL +ns.ex2.test. IN A 192.5.0.3 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +foo2.test. IN A +SECTION AUTHORITY +foo2.test. IN NS ns.foo2.test. +SECTION ADDITIONAL +ns.foo2.test. IN A 192.5.0.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +ex3.test. IN A +SECTION AUTHORITY +ex3.test. IN NS ns.ex3.test. +SECTION ADDITIONAL +ns.ex3.test. IN A 192.5.0.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +foo3.test. IN A +SECTION AUTHORITY +foo3.test. IN NS ns.foo3.test. +SECTION ADDITIONAL +ns.foo3.test. IN A 192.5.0.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +foo4.test. IN A +SECTION AUTHORITY +foo4.test. IN NS ns.foo4.test. +SECTION ADDITIONAL +ns.foo4.test. IN A 192.5.0.7 +ENTRY_END +RANGE_END + +; ns.foo.test. +; This server hosts a number of zones. +; foo.test +; mid.foo.test +; x.mid.foo.test +RANGE_BEGIN 0 200 + ADDRESS 192.5.0.2 + +; This answer is too low, for the DS query, it should have been answered +; from a higher zone. This starts DSNS find. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +x.mid.foo.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +x.mid.foo.test. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +; The server is also authoriative for mid.foo.test and that +; has a mismatching NS record, that lists another server than ns.foo.test. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +mid.foo.test. IN NS +SECTION ANSWER +mid.foo.test. IN NS ns2.ex2.test. +SECTION AUTHORITY +ENTRY_END + +; If it goes up further, this is the answer for the foo.test NS. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +foo.test. IN NS +SECTION ANSWER +foo.test. IN NS ns.foo.test. +SECTION AUTHORITY +SECTION ADDITIONAL +ns.foo.test. IN A 192.5.0.2 +ENTRY_END +RANGE_END + +; ns.ex2.test. +RANGE_BEGIN 0 200 + ADDRESS 192.5.0.3 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns2.ex2.test. IN A +SECTION ANSWER +; it is on this same server for ex2.test. +ns2.ex2.test. IN A 192.5.0.3 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns2.ex2.test. IN AAAA +SECTION AUTHORITY +ex2.test. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +x.mid.foo.test. IN DS +SECTION ANSWER +; The DS and RRSIG content are for the test. Not actually DNSSEC valid, +; but supposedly the zone is signed, and has a signed DS to the lower zone. +x.mid.foo.test. IN DS 30899 5 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3 +x.mid.foo.test. IN RRSIG DS 3 4 3600 20070926134150 20070829134150 2854 mid.foo.test. MCwCFCW3ix0GD4BSvNLWIbROCJt5DAW9AhRt/kg9kBKJ20UBUdumrBUHqnskdA== +SECTION AUTHORITY +ENTRY_END +RANGE_END + +; ns.foo2.test. +; This server hosts a number of zones. +; foo2.test +; x.mid.foo2.test +; but not: mid.foo2.test +RANGE_BEGIN 0 200 + ADDRESS 192.5.0.4 + +; This answer is too low, for the DS query, it should have been answered +; from a higher zone. This starts DSNS find. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +x.mid.foo2.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +x.mid.foo2.test. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +; The server has a referral for mid.foo2.test. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +mid.foo2.test. IN NS +SECTION AUTHORITY +mid.foo2.test. IN NS ns.ex3.test. +ENTRY_END + +; If it goes up further, this is the answer for the foo2.test NS. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +foo2.test. IN NS +SECTION ANSWER +foo2.test. IN NS ns.foo2.test. +SECTION AUTHORITY +SECTION ADDITIONAL +ns.foo2.test. IN A 192.5.0.4 +ENTRY_END +RANGE_END + +; ns.ex3.test. +RANGE_BEGIN 0 200 + ADDRESS 192.5.0.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.ex3.test. IN A +SECTION ANSWER +ns.ex3.test. IN A 192.5.0.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.ex3.test. IN AAAA +SECTION AUTHORITY +ex3.test. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +mid.foo2.test. IN NS +SECTION ANSWER +mid.foo2.test. IN NS ns.ex3.test. +; Not actually valid signature, but content is here for the test. +mid.foo2.test. IN RRSIG NS 3 3 3600 20070926134150 20070829134150 2854 mid.foo2.test. MCwCFCW3ix0GD4BSvNLWIbROCJt5DAW9AhRt/kg9kBKJ20UBUdumrBUHqnskdA== +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +x.mid.foo2.test. IN DS +SECTION ANSWER +; The DS and RRSIG content are for the test. Not actually DNSSEC valid, +; but supposedly the zone is signed, and has a signed DS to the lower zone. +x.mid.foo2.test. IN DS 30899 5 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3 +x.mid.foo2.test. IN RRSIG DS 3 4 3600 20070926134150 20070829134150 2854 mid.foo2.test. MCwCFCW3ix0GD4BSvNLWIbROCJt5DAW9AhRt/kg9kBKJ20UBUdumrBUHqnskdA== +SECTION AUTHORITY +ENTRY_END +RANGE_END + +; ns.foo3.test. +; This server hosts a number of zones. +; foo3.test +; mid.foo3.test +; x.mid.foo3.test +RANGE_BEGIN 0 200 + ADDRESS 192.5.0.6 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.foo3.test. IN A +SECTION ANSWER +ns.foo3.test. IN A 192.5.0.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.foo3.test. IN AAAA +SECTION AUTHORITY +foo3.test. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +; This answer is too low, for the DS query, it should have been answered +; from a higher zone. This starts DSNS find. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +x.mid.foo3.test. IN DS +SECTION ANSWER +SECTION AUTHORITY +x.mid.foo3.test. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +; The middle zone is actually hosted on this server, and this is its +; child side NS record. +; But since this nameserver gives the wrong answer, from the wrong zone +; for qtype DS, it is not going to resolve the DS lookup from mid.foo3.test, +; but from x.mid.foo3.test instead. This can happen for a server that does +; not support DNSSEC, and qtype DS then has lookup in the zone for it. +; Servers that support DNSSEC are supposed to pick the right zone for the +; qtype DS lookup in the multiple zone situation. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +mid.foo3.test. IN NS +SECTION ANSWER +mid.foo3.test. IN NS ns.foo3.test. +ENTRY_END +RANGE_END + +; ns.foo4.test. +; This server hosts a number of zones. +; foo4.test +; mid.foo4.test +; x.mid.foo4.test +RANGE_BEGIN 0 200 + ADDRESS 192.5.0.7 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.foo4.test. IN A +SECTION ANSWER +ns.foo4.test. IN A 192.5.0.7 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.foo4.test. IN AAAA +SECTION AUTHORITY +foo4.test. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +; The server supports DNSSEC, it hosts the correct zone for the answer, +; and it uses the mid.foo4.test zone for the qtype DS answer. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +x.mid.foo4.test. IN DS +SECTION ANSWER +x.mid.foo4.test. IN DS 30899 5 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3 +x.mid.foo4.test. IN RRSIG DS 3 4 3600 20070926134150 20070829134150 2854 mid.foo4.test. MCwCFCW3ix0GD4BSvNLWIbROCJt5DAW9AhRt/kg9kBKJ20UBUdumrBUHqnskdA== +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +x.mid.foo.test. IN DS +ENTRY_END + +; recursion happens here. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +x.mid.foo.test. IN DS +SECTION ANSWER +x.mid.foo.test. IN DS 30899 5 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3 +x.mid.foo.test. IN RRSIG DS 3 4 3600 20070926134150 20070829134150 2854 mid.foo.test. MCwCFCW3ix0GD4BSvNLWIbROCJt5DAW9AhRt/kg9kBKJ20UBUdumrBUHqnskdA== +ENTRY_END +RANGE_END + +; to resolve pending messages for nameserver lookups. +STEP 20 TRAFFIC + +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +x.mid.foo2.test. IN DS +ENTRY_END + +STEP 40 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +x.mid.foo2.test. IN DS +SECTION ANSWER +x.mid.foo2.test. IN DS 30899 5 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3 +x.mid.foo2.test. IN RRSIG DS 3 4 3600 20070926134150 20070829134150 2854 mid.foo2.test. MCwCFCW3ix0GD4BSvNLWIbROCJt5DAW9AhRt/kg9kBKJ20UBUdumrBUHqnskdA== +ENTRY_END + +; to resolve pending messages for nameserver lookups. +STEP 50 TRAFFIC + +STEP 60 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +x.mid.foo3.test. IN DS +ENTRY_END + +STEP 70 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +x.mid.foo3.test. IN DS +SECTION AUTHORITY +x.mid.foo3.test. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +; to resolve pending messages for nameserver lookups. +STEP 80 TRAFFIC + +STEP 90 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +x.mid.foo4.test. IN DS +ENTRY_END + +STEP 100 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +x.mid.foo4.test. IN DS +SECTION ANSWER +x.mid.foo4.test. IN DS 30899 5 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3 +x.mid.foo4.test. IN RRSIG DS 3 4 3600 20070926134150 20070829134150 2854 mid.foo4.test. MCwCFCW3ix0GD4BSvNLWIbROCJt5DAW9AhRt/kg9kBKJ20UBUdumrBUHqnskdA== +ENTRY_END + +SCENARIO_END diff --git a/testdata/nsec3_wipeout_neg.rpl b/testdata/nsec3_wipeout_neg.rpl new file mode 100644 index 000000000..32a778160 --- /dev/null +++ b/testdata/nsec3_wipeout_neg.rpl @@ -0,0 +1,215 @@ +; EXP testbound scenario for +; Tests: malicious NSEC3 in referral response triggers wipeout over-deletion +; +; Scenario: +; 1. Query www.sub.example.com (A) - triggers referral from example.com +; 2. The referral includes a malicious NSEC3 with oversized next owner +; (200 'v' chars = 125 bytes raw, > 63 LDNS_MAX_LABELLEN) +; 3. The malicious NSEC3 enters val_neg_addreferral -> neg_insert_data -> wipeout +; 4. wipeout over-deletes existing neg cache entries +; 5. The query still resolves (the referral is valid), but the neg cache +; is now corrupted + +server: + trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b" + val-override-date: "20070916134226" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + module-config: "validator iterator" + aggressive-nsec: yes + +stub-zone: + name: "." + stub-addr: 193.0.14.129 +CONFIG_END + +SCENARIO_BEGIN EXP: malicious NSEC3 in referral triggers wipeout + +; 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 +www.sub.example.com. IN A +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END +RANGE_END + +; a.gtld-servers.net. +RANGE_BEGIN 0 100 + ADDRESS 192.5.6.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION ANSWER +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.sub.example.com. IN A +SECTION AUTHORITY +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.com. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN DNSKEY +SECTION ANSWER +example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b} +example.com. 3600 IN RRSIG DNSKEY DSA 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFBQRtlR4BEv9ohi+PGFjp+AHsJuHAhRCvz0shggvnvI88DFnBDCczHUcVA== ;{id = 2854} +SECTION AUTHORITY +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} +ENTRY_END + +; DS query response: no DS for sub.example.com (NODATA with NSEC3 proof) +; This is a separate query from the validator to verify the delegation +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +sub.example.com. IN DS +SECTION AUTHORITY +example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000 +example.com. 3600 IN RRSIG SOA 3 2 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCM6lsu9byZIQ1yYjJmyYfFWM2RWAIUcR5t84r2La824oWCkLjmHXRQlco= ;{id = 2854} +; NODATA response with NSEC3 proof +; H(sub.example.com.) = kg19n32806c832kijdnglq8p9m2r5mdj +kg19n32806c832kijdnglq8p9m2r5mdj.example.com. 3600 IN NSEC3 1 0 0 - kg19n32806c832kijdnglq8p9m2r5mdk NS RRSIG +kg19n32806c832kijdnglq8p9m2r5mdj.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926134150 20070829134150 2854 example.com. AD1ed7zhMyd/S4fTCwip94DwMbiDV1lF+11zFI/yeR4R7k/n0Hh7GcE= +ENTRY_END + +; REFERRAL response with MALICIOUS NSEC3 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.sub.example.com. IN A +SECTION ANSWER +SECTION AUTHORITY +sub.example.com. IN NS ns.sub.example.com. +; MALICIOUS NSEC3: next owner = vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv (125 bytes, all 0xFF) +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com. 3600 IN NSEC3 1 0 0 - vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv NS RRSIG +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926134150 20070829134150 2854 example.com. AC8XUZo1he4odxG32SfOzFznQn83N4/gJv8AWE0wzrbPO+bbO80+0pg= + +SECTION ADDITIONAL +ns.sub.example.com. IN A 1.2.3.6 +ENTRY_END + +RANGE_END + +; ns.sub.example.com. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.6 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +sub.example.com. IN NS +SECTION ANSWER +sub.example.com. IN NS ns.sub.example.com. +SECTION ADDITIONAL +ns.sub.example.com. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +sub.example.com. IN DNSKEY +SECTION ANSWER +sub.example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b} +sub.example.com. 3600 IN RRSIG DNSKEY 3 3 3600 20070926135752 20070829135752 2854 sub.example.com. MCwCFBznBTYM/SrdUnjQdBnLtRO79KAaAhQReG5nRuL7Xsdf6D0KKwPa1GpWyQ== ;{id = 2854} +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.sub.example.com. IN A +SECTION ANSWER +www.sub.example.com. IN A 11.11.11.11 +www.sub.example.com. 3600 IN RRSIG A 3 4 3600 20070926135752 20070829135752 2854 sub.example.com. MC0CFEExteiCsLkRi/md6o5K8BhRJAKFAhUAgg2tkvwaDn8Xbm9q+5xnjvgIB8k= ;{id = 2854} +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.sub.example.com. IN A +ENTRY_END + +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO NOERROR +SECTION QUESTION +www.sub.example.com. IN A +SECTION ANSWER +www.sub.example.com. 3600 IN A 11.11.11.11 +www.sub.example.com. 3600 IN RRSIG A 3 4 3600 20070926135752 20070829135752 2854 sub.example.com. MC0CFEExteiCsLkRi/md6o5K8BhRJAKFAhUAgg2tkvwaDn8Xbm9q+5xnjvgIB8k= ;{id = 2854} +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END + +SCENARIO_END diff --git a/testdata/svcb.tdir/svcb.test-vectors-pf.zone b/testdata/svcb.tdir/svcb.test-vectors-pf.zone index d2cb5087b..5f32cc0e7 100644 --- a/testdata/svcb.tdir/svcb.test-vectors-pf.zone +++ b/testdata/svcb.tdir/svcb.test-vectors-pf.zone @@ -90,3 +90,11 @@ v18 HTTPS 16 foo.example.org. (alpn=h2,h3-19 mandatory=ipv4hint,alpn v19 HTTPS 16 foo.example.org. alpn="f\\\\oo\\,bar,h2" v20 HTTPS 16 foo.example.org. alpn=f\\\092oo\092,bar,h2 +; This vector is out-of-order in the wireformat encoding. That could come +; from an upstream when this is the secondary zone. To leniently accept such +; content as a secondary, it has to be able to be written and read back in. +v21 HTTPS 1 . alpn="h3" port=7777 + +; If the server can leniently accept broken svcparams, then it should be able +; to write and read them back in. This svcparam is broken, it is truncated. +v22 HTTPS \# 8 000100000300021e diff --git a/testdata/svcb.tdir/svcb.test-vectors-wf.zone b/testdata/svcb.tdir/svcb.test-vectors-wf.zone index bf47ab75c..53d21452c 100644 --- a/testdata/svcb.tdir/svcb.test-vectors-wf.zone +++ b/testdata/svcb.tdir/svcb.test-vectors-wf.zone @@ -230,3 +230,11 @@ v20 HTTPS \# 35 ( 68 32 ; alpn value ) +; This vector is out-of-order in the wireformat encoding. That could come +; from an upstream when this is the secondary zone. To leniently accept such +; content as a secondary, it has to be able to be written and read back in. +v21 HTTPS \# 16 000100000300021e6100010003026833 + +; If the server can leniently accept broken svcparams, then it should be able +; to write and read them back in. This svcparam is broken, it is truncated. +v22 HTTPS \# 8 000100000300021e diff --git a/testdata/tagtrap_limit_2_shortends_ecdsa.crpl b/testdata/tagtrap_limit_2_shortends_ecdsa.crpl new file mode 100644 index 000000000..8d625cb68 --- /dev/null +++ b/testdata/tagtrap_limit_2_shortends_ecdsa.crpl @@ -0,0 +1,602 @@ +; config options +; The island of trust is at example.com +server: + trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b" + val-override-date: "20070916134226" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: "no" + fake-sha1: yes + trust-anchor-signaling: no + minimal-responses: no + ede: yes + # this is not the limit that is tested here. + val-hash-attempts: 128 + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test validator with too many tag matches + +; 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 +com. IN NS +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END +RANGE_END + +; a.gtld-servers.net. +RANGE_BEGIN 0 100 + ADDRESS 192.5.6.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION ANSWER +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION AUTHORITY +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.com. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN DNSKEY +SECTION ANSWER +example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b} +example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854} +SECTION AUTHORITY +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +sub1.example.com. IN A +SECTION ANSWER +SECTION AUTHORITY +sub1.example.com. IN NS ns.sub1.example.com. + +sub1.example.com. IN DS 20 13 2 c3bd4c6000cff93b4ce8ca6c934d7f46ab1f2bb7283e40493798395627c9ca41 +sub1.example.com. IN DS 3539 13 2 2e33e1da915795ab2412fa116cab8b219707135aa6bcc48a5f8b1ca097c5a297 +sub1.example.com. IN DS 12688 13 2 87a10b8df44945b7dae0c12c98f82d04992587a8e0a2ed823b0789dd48fe889f +sub1.example.com. IN DS 13058 13 2 e8f15b542b537cb7b4a2370575988d5e6dc58c495fe695961fc482be580396fa +sub1.example.com. IN DS 18006 13 2 2a35a6f7d086c11493d34712ac819f74baaa674399d5d478fd056d0227c17b83 +sub1.example.com. IN DS 18279 13 2 4a4c9053b35a89d4ba1453fb8c0df658c6f473aa9042dabc9269f00e888751be +sub1.example.com. IN DS 20669 13 2 6958b937ef837d76361e03eb11e780de5ee65e44faac5ec19daecdb9e4722b0d +sub1.example.com. IN DS 25106 13 2 56bbbbaee440eb3649afebdd6a806105bdc345613bffa156b9b5f708cddb44cf +sub1.example.com. IN DS 25932 13 2 76c6e7506e9b7306e547913d35e4cc9162c2cf3000b9b62cc0acb21c5e85b960 +sub1.example.com. IN DS 27845 13 2 ed630a116a6049eb5ccdd3f46aa09228bde76a0f3c43ac40731d3ebcdb65c161 +sub1.example.com. IN DS 29183 13 2 2a573047cd9945ec15aa6278dc3cd908d59732fa253ebffed6b35485e4e3d6f9 +sub1.example.com. IN DS 30380 13 2 a1dac7f7185404ca826ce62c5ec57b50f5584ee86e762c809af3f5ebc207f0a8 +sub1.example.com. IN DS 31753 13 2 c811dca5f7cfb8d82be1c145b1bf0f5f6275bed42f31ffdec45fb7ba54d76564 +sub1.example.com. IN DS 32621 13 2 4ba7774dbfa9115c6a188dce790b6b45480e0aa5c39602be08ccc139c68492de +sub1.example.com. IN DS 33127 13 2 d45c3cbcc4cb71d53c80374efe2b6081e9d1add53bae66fb6bf61028b68d3cf9 +sub1.example.com. IN DS 37404 13 2 2480a04461a7425a5d897921eb6b493428abaf46ed6809f3fac53fd1465415ab +sub1.example.com. IN DS 38693 13 2 ad6a97280b20cf4eac60c9e70db9712a5357d12166993f55c201b91d2b4c1ff5 +sub1.example.com. IN DS 40580 13 2 93ace4ec403fd790d1debb05f539f58797822fc75ac3dd0d7e2f8b1d3fdb126d +sub1.example.com. IN DS 43985 13 2 2c8f7712ebd5fd18df7e6e58995b13d8204b258322078f473d5c28a76c03b8d7 +sub1.example.com. IN DS 44725 13 2 9e6631ddbc09355f8891c7713d8703c4e213d8c51b1126826d31c05a4b7991be +sub1.example.com. IN DS 44975 13 2 4ea12a0336c18766537d195c608ce76a7ab7cbb5cce873a65fe0d9a662fcd9aa +sub1.example.com. IN DS 49819 13 2 c7f1a7b39c26ffab7ff3775624a2e40aa73af44c84ebd80442c52cdb1abb991e +sub1.example.com. IN DS 56088 13 2 653cff8afa5cda5d6efda676c2a73eccc3301f7e32437bff72a8b761fa1b6379 +sub1.example.com. IN DS 58926 13 2 39000f49e8914dee8602795fd559ac2b0b4d434da4c8d1908936e9acc0e42485 +sub1.example.com. 3600 IN RRSIG DS 3 3 3600 20070926134150 20070829134150 2854 example.com. AA2wcVQsxCw2VQcgrSp2zjxYP5ElbMVNMMdc/pMU77k5VkMThtZKygE= +SECTION ADDITIONAL +ns.sub1.example.com. IN A 1.2.3.5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +sub2.example.com. IN A +SECTION ANSWER +SECTION AUTHORITY +sub2.example.com. IN NS ns.sub2.example.com. + +; With this one DS record it works for sub2.example.com, since not that +; many DNSKEY to RRSIG attempts are made. +;sub2.example.com. 3600 IN RRSIG DS 3 3 3600 20070926134150 20070829134150 2854 example.com. AHyR2q4kMaOs9/SFLRgftMXPMu0CQRjRk8z2+3M7VAcnKzIck7VAcl0= +; Here with 8 DS records, that match. +sub2.example.com. 3600 IN DS 3539 13 2 e94cf5357bdb8ce5423a0a5eacf564105ea1935fbf813c76bcc13eb34594167c +sub2.example.com. 3600 IN DS 12688 13 2 73d5613cba9bfe510ffa8241c20277d78b57a28d9b1d3c8ad23c2032fbe86a78 +sub2.example.com. 3600 IN DS 13058 13 2 12e107e5a4c72620cfcdfe7c4186eccaf1b46501afb7bb3ca9e395a083e16fea +sub2.example.com. 3600 IN DS 18006 13 2 7a3525ee9385e36a2819a3b0e650f0aff4788b787d6ef7870d4956692b1d6feb +sub2.example.com. 3600 IN DS 18279 13 2 8a900772c1ff65553343920868996b2cf3be2dc5bdf182e962cb996dbd3f1682 +sub2.example.com. 3600 IN DS 20669 13 2 54ad32be8029ce48cb6d45ffbdba918c11e70fbd416c2f3501321a4fcc2692c8 +sub2.example.com. 3600 IN DS 25106 13 2 a6c125c2be2f301888e16255405d994c1b31ccc3ca72217399ae2a16c721cbeb +sub2.example.com. 3600 IN DS 20 13 2 87f0229abc95a9a463e15e572c52869224ac07098e72ec7bacf0b3e358e44674 +sub2.example.com. 3600 IN RRSIG DS 3 3 3600 20070926134150 20070829134150 2854 example.com. AFluwWeqE8NSEI+u1S+pDZBfgdBvbXBeGez5Wf35ojP0HIW+MIFCWL4= + +SECTION ADDITIONAL +ns.sub2.example.com. IN A 1.2.3.6 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +sub3.example.com. IN A +SECTION ANSWER +SECTION AUTHORITY +sub3.example.com. IN NS ns.sub3.example.com. +sub3.example.com. 3600 IN DS 20 13 2 64d2a1243b619ba0b1f14912fd560f3e9d27b0ae6f4df35625c74fe3015fb1d3 +sub3.example.com. 3600 IN RRSIG DS 3 3 3600 20070926134150 20070829134150 2854 example.com. AE7A38rpBCyGBEkqyQVqLHwFnjSmoIwOVEm5oh9bErGhqdB0fIF2ddw= +SECTION ADDITIONAL +ns.sub3.example.com. IN A 1.2.3.7 +ENTRY_END +RANGE_END + +; ns.sub1.example.com. +; 24 DSes and 24 DNSKEYs +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.5 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.sub1.example.com. IN AAAA +SECTION ANSWER +SECTION AUTHORITY +sub1.example.com. IN SOA a. b. 3600 3600 3600 3600 3600 +sub1.example.com. 3600 IN RRSIG SOA 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. PyHa+O9jyNBtKuVilpPoqQGDKHdMCrfhm6A7GDj0+ZPXZAax/+hl10CVIUhl5YqCS3xGc3Zae/WNbD+1w3cIUQ== +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +sub1.example.com. IN DNSKEY +SECTION ANSWER +; These keys actually match the DS record, but to have more match attempts they +; are altered, below. +;sub1.example.com. IN DNSKEY 257 3 13 n2P99SKaAUDt50U/cToH/0TmGJKG8+Pbiwl1WY/f5EVWZD/auO5QEyY6Tm9kLHzAEOcjWR701V74ZgyFPirxIA== ;{id = 20 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 2biK+rkC8P/MV/UMDbksGCov08Tya5wrtrjeDOSez5W1qFqqPKXzxuMxecGSXIYgNM8Y/m8XdlwOd8Q6vUuw5A== ;{id = 3539 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 UeL+mKovo+r7+B3egif1JxCHPfmbR4SU4m3s0Fp42ozze0FiMzEwRM85O4aYViPOmu0AKgfwuRjEM5aEM1pBug== ;{id = 12688 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 iFe//OnLHLGXpE9i+4y3H+NefdDTZAEwYzDv0U+OIzs37lnOEMYTVqBxkLA82JDKMtnjupCOtSXMoru7lQcckw== ;{id = 13058 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 0/lAWEpW94Rkjion6aUxepvCO6MxoRRJ5aIX9fdEPjUJXCGeHviFLmeDnNzTB0egvC5CgthSnQfyxqMqbbuMAQ== ;{id = 18006 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 P1rwuvxZ8tQOxtOHsbzHAIpMNkleGRtg7gynoesq2gSJT+NAmYRrk+BzEGvHWTHKWd5KnusSt2BpBBlWw5pLiw== ;{id = 18279 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 WraqJ/JvyS8xQZOKpVscbAUuYU8lVCiuEHjekR0kADMP/eWOvdJkaPZ++REeHclBejqXp+NcP0dnyweObnZDsA== ;{id = 20669 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 /fci65ankZ0cKOPdJAJBIyXHYGzjngEyqGbBVmeDk2RwAqxmyUB5OORRmlPMY80ipMU+e8Pt3itKpglwpT7qSA== ;{id = 25106 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 MEfZQnvjQI/L/0QlglQ2YrxSCQ6fRruKF2aQ+nD5JV9ecE1AhA/RujbKkg9UrG4ScjqC7f0fhCW+eUqsSoUcTg== ;{id = 25932 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 KbKK1C8ZtHNsBicJnjrvTB56BoTTjL9pvNEbRVwCKIcWYdNP8l3dpsvVEAZ/ujxmKRA/ToA7ua4/IBDtALFWvg== ;{id = 27845 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 G3I9nIlyTOrn12D8luAgZR4ZTK+iNegzz9UG8b5YsC9IV4UtgbdZkoEDRsH2uu429qvezzlUsjTzR+fu/74Saw== ;{id = 29183 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 fBgVewGRqRmvJUVm/ZQqPLynt1lM6ilPdENMd9uESPh30CzUsi8Q7tbGZoH52CJjpcb17z3zSjJv40ASVEBhNw== ;{id = 30380 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 3LbmoAShX4cKq4qyIqHLI7+UH4/EVOaXCF7AhJHaRJsgbyCEwn4Ofjh6l15Pxbk/UH851tR8MBaaOz8+ROcL2A== ;{id = 31753 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 xMfArWljU25/0ePkuncQHH8U+/NMLIqy3IpJ7IqcOKRXmR7hrY2dQ6MgBN1rUBW8Q7Uq3mFbozdJbr3oDeZcdQ== ;{id = 32621 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 YsXykW60iTTY+1DY7CG9izDd+RAzx+oPUk2UBiHBPengMUmu3R9rgsJHYfjwWgYWB60sy0CPcdAeu+jD2tB4eA== ;{id = 33127 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 wzS1uBaSWR+bTTYgtLm3jNxNnLSNv6abvnHABXQD5yDFs17rGqDCdvkk6JM3qI4BJ+npNLdADJZt118PWlQ7eQ== ;{id = 37404 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 9nDuSJ9wRTsvFYubQ7KQyOmzlY+UzG1cESD8NK9eOj9VMX1O71d5GxBwzc4UtBs+kZBi49BLjZIV5qWbD9FbXQ== ;{id = 38693 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 EFDgOhEi43zsVaJdytsq3HjtAh6dVDaAnR0PY7O0S4q/svucxOVxmJsG/2rXYMHTej9jRTg/qWWbW4gdReDoSQ== ;{id = 40580 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 wq8UI3DydI9svWJEQ1G0JHGVHykgo3YXFF8CRG055gshZAVyfIiTRwCemG0mbziuobOeZSpCtK05KGp20NHRTA== ;{id = 43985 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 wRMENWFMd+9c4p9agfd/3qLnum1SS555CP9lgJKtU0t7Q689SrAUwBJP7ymXTDGtWSjlFBzbts6SUARX47SK1Q== ;{id = 44725 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 zeWh2eFjuwp9K9yaJq16XMVNC8Ys0TOk91eYkGa0Dgez59aG/PvPYV1qi9pxbmG/c4tuXcRV9Z9cxcVev9DdYw== ;{id = 44975 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 O/y794Mc/kIwRltqnqj+puIS1ejFQeE9Xmjz1NVU82x+UyEvx2InNpwaU2TFNKaT7aned72CE1u//CahV6zeEg== ;{id = 49819 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 edr2Ai2uObWeVfFjvCF01Xa9SQD706baatsttcUuI4MblMTNG4blOSN1pMpZJ/wymkqt4c7eQSCETlD/mPeWPQ== ;{id = 56088 (ksk), size = 256b} +;sub1.example.com. IN DNSKEY 257 3 13 PlfsudScPXH3VdDVv6nnuBEXQpP6coF6F2w99u4Es5VbJHZrgFhvxL9os0jnfiGCL6VJ0Q+bNKnzfoP3ByP1Kg== ;{id = 58926 (ksk), size = 256b} +;sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQbqA7tA== + +; The altered keys, with 'AAAA' at the end. +sub1.example.com. IN DNSKEY 257 3 13 n2P99SKaAUDt50U/cToH/0TmGJKG8+Pbiwl1WY/f5EVWZD/auO5QEyY6Tm9kLHzAEOcjWR701V74ZgyFPiAAAA== ;{id = 20 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 2biK+rkC8P/MV/UMDbksGCov08Tya5wrtrjeDOSez5W1qFqqPKXzxuMxecGSXIYgNM8Y/m8XdlwOd8Q6vAAAAA== ;{id = 3539 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 UeL+mKovo+r7+B3egif1JxCHPfmbR4SU4m3s0Fp42ozze0FiMzEwRM85O4aYViPOmu0AKgfwuRjEM5aEM1AAAA== ;{id = 12688 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 iFe//OnLHLGXpE9i+4y3H+NefdDTZAEwYzDv0U+OIzs37lnOEMYTVqBxkLA82JDKMtnjupCOtSXMoru7lQAAAA== ;{id = 13058 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 0/lAWEpW94Rkjion6aUxepvCO6MxoRRJ5aIX9fdEPjUJXCGeHviFLmeDnNzTB0egvC5CgthSnQfyxqMqbbAAAA== ;{id = 18006 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 P1rwuvxZ8tQOxtOHsbzHAIpMNkleGRtg7gynoesq2gSJT+NAmYRrk+BzEGvHWTHKWd5KnusSt2BpBBlWw5AAAA== ;{id = 18279 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 WraqJ/JvyS8xQZOKpVscbAUuYU8lVCiuEHjekR0kADMP/eWOvdJkaPZ++REeHclBejqXp+NcP0dnyweObnAAAA== ;{id = 20669 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 /fci65ankZ0cKOPdJAJBIyXHYGzjngEyqGbBVmeDk2RwAqxmyUB5OORRmlPMY80ipMU+e8Pt3itKpglwpTAAAA== ;{id = 25106 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 MEfZQnvjQI/L/0QlglQ2YrxSCQ6fRruKF2aQ+nD5JV9ecE1AhA/RujbKkg9UrG4ScjqC7f0fhCW+eUqsSoAAAA== ;{id = 25932 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 KbKK1C8ZtHNsBicJnjrvTB56BoTTjL9pvNEbRVwCKIcWYdNP8l3dpsvVEAZ/ujxmKRA/ToA7ua4/IBDtALAAAA== ;{id = 27845 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 G3I9nIlyTOrn12D8luAgZR4ZTK+iNegzz9UG8b5YsC9IV4UtgbdZkoEDRsH2uu429qvezzlUsjTzR+fu/7AAAA== ;{id = 29183 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 fBgVewGRqRmvJUVm/ZQqPLynt1lM6ilPdENMd9uESPh30CzUsi8Q7tbGZoH52CJjpcb17z3zSjJv40ASVEAAAA== ;{id = 30380 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 3LbmoAShX4cKq4qyIqHLI7+UH4/EVOaXCF7AhJHaRJsgbyCEwn4Ofjh6l15Pxbk/UH851tR8MBaaOz8+ROAAAA== ;{id = 31753 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 xMfArWljU25/0ePkuncQHH8U+/NMLIqy3IpJ7IqcOKRXmR7hrY2dQ6MgBN1rUBW8Q7Uq3mFbozdJbr3oDeAAAA== ;{id = 32621 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 YsXykW60iTTY+1DY7CG9izDd+RAzx+oPUk2UBiHBPengMUmu3R9rgsJHYfjwWgYWB60sy0CPcdAeu+jD2tAAAA== ;{id = 33127 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 wzS1uBaSWR+bTTYgtLm3jNxNnLSNv6abvnHABXQD5yDFs17rGqDCdvkk6JM3qI4BJ+npNLdADJZt118PWlAAAA== ;{id = 37404 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 9nDuSJ9wRTsvFYubQ7KQyOmzlY+UzG1cESD8NK9eOj9VMX1O71d5GxBwzc4UtBs+kZBi49BLjZIV5qWbD9AAAA== ;{id = 38693 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 EFDgOhEi43zsVaJdytsq3HjtAh6dVDaAnR0PY7O0S4q/svucxOVxmJsG/2rXYMHTej9jRTg/qWWbW4gdReAAAA== ;{id = 40580 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 wq8UI3DydI9svWJEQ1G0JHGVHykgo3YXFF8CRG055gshZAVyfIiTRwCemG0mbziuobOeZSpCtK05KGp20NAAAA== ;{id = 43985 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 wRMENWFMd+9c4p9agfd/3qLnum1SS555CP9lgJKtU0t7Q689SrAUwBJP7ymXTDGtWSjlFBzbts6SUARX47AAAA== ;{id = 44725 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 zeWh2eFjuwp9K9yaJq16XMVNC8Ys0TOk91eYkGa0Dgez59aG/PvPYV1qi9pxbmG/c4tuXcRV9Z9cxcVev9AAAA== ;{id = 44975 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 O/y794Mc/kIwRltqnqj+puIS1ejFQeE9Xmjz1NVU82x+UyEvx2InNpwaU2TFNKaT7aned72CE1u//CahV6AAAA== ;{id = 49819 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 edr2Ai2uObWeVfFjvCF01Xa9SQD706baatsttcUuI4MblMTNG4blOSN1pMpZJ/wymkqt4c7eQSCETlD/mPAAAA== ;{id = 56088 (ksk), size = 256b} +sub1.example.com. IN DNSKEY 257 3 13 PlfsudScPXH3VdDVv6nnuBEXQpP6coF6F2w99u4Es5VbJHZrgFhvxL9os0jnfiGCL6VJ0Q+bNKnzfoP3ByAAAA== ;{id = 58926 (ksk), size = 256b} +sub1.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub1.example.com. p6ScxBgybYLIhpD9SVDSquhPsytpehEUVncg2zRoXTxkuKXUsQIDKUuLhZxgeHNAnkKQn8e3xnoDWCGQbqA7tA== +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.sub1.example.com. IN A +SECTION ANSWER +www.sub1.example.com. IN A 10.20.30.41 +www.sub1.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 20 sub1.example.com. utG2+wuHSbmyQCaIjL7ElDe3DJCMqZGrPqsOEyJj8ljGGa5JaTY+KdYvZ6oGmprV7utRPNyRormou1zRWoG8ew== +ENTRY_END +RANGE_END + +; ns.sub2.example.com. +; 24 DNSKEYs with 24 RRSIGs on DNSKEY, that works with one DS. +; 8 DS with 24 DNSKEYs with 40 RRSIGs on DNSKEY. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.6 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.sub2.example.com. IN AAAA +SECTION ANSWER +SECTION AUTHORITY +sub2.example.com. IN SOA a. b. 3600 3600 3600 3600 3600 +sub2.example.com. 3600 IN RRSIG SOA 13 3 3600 20070926134150 20070829134150 20 sub2.example.com. Uzdsj01UwK807QiRzTxZffHYpd7uEDEfPwbH4XsVilR238gk/fObaNBVij8Y2HiZHmch8I7GeNqB6RXpKQKU1w== +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +sub2.example.com. IN DNSKEY +SECTION ANSWER +sub2.example.com. IN DNSKEY 257 3 13 n2P99SKaAUDt50U/cToH/0TmGJKG8+Pbiwl1WY/f5EVWZD/auO5QEyY6Tm9kLHzAEOcjWR701V74ZgyFPirxIA== ;{id = 20 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 2biK+rkC8P/MV/UMDbksGCov08Tya5wrtrjeDOSez5W1qFqqPKXzxuMxecGSXIYgNM8Y/m8XdlwOd8Q6vUuw5A== ;{id = 3539 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 UeL+mKovo+r7+B3egif1JxCHPfmbR4SU4m3s0Fp42ozze0FiMzEwRM85O4aYViPOmu0AKgfwuRjEM5aEM1pBug== ;{id = 12688 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 iFe//OnLHLGXpE9i+4y3H+NefdDTZAEwYzDv0U+OIzs37lnOEMYTVqBxkLA82JDKMtnjupCOtSXMoru7lQcckw== ;{id = 13058 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 0/lAWEpW94Rkjion6aUxepvCO6MxoRRJ5aIX9fdEPjUJXCGeHviFLmeDnNzTB0egvC5CgthSnQfyxqMqbbuMAQ== ;{id = 18006 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 P1rwuvxZ8tQOxtOHsbzHAIpMNkleGRtg7gynoesq2gSJT+NAmYRrk+BzEGvHWTHKWd5KnusSt2BpBBlWw5pLiw== ;{id = 18279 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 WraqJ/JvyS8xQZOKpVscbAUuYU8lVCiuEHjekR0kADMP/eWOvdJkaPZ++REeHclBejqXp+NcP0dnyweObnZDsA== ;{id = 20669 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 /fci65ankZ0cKOPdJAJBIyXHYGzjngEyqGbBVmeDk2RwAqxmyUB5OORRmlPMY80ipMU+e8Pt3itKpglwpT7qSA== ;{id = 25106 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 MEfZQnvjQI/L/0QlglQ2YrxSCQ6fRruKF2aQ+nD5JV9ecE1AhA/RujbKkg9UrG4ScjqC7f0fhCW+eUqsSoUcTg== ;{id = 25932 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 KbKK1C8ZtHNsBicJnjrvTB56BoTTjL9pvNEbRVwCKIcWYdNP8l3dpsvVEAZ/ujxmKRA/ToA7ua4/IBDtALFWvg== ;{id = 27845 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 G3I9nIlyTOrn12D8luAgZR4ZTK+iNegzz9UG8b5YsC9IV4UtgbdZkoEDRsH2uu429qvezzlUsjTzR+fu/74Saw== ;{id = 29183 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 fBgVewGRqRmvJUVm/ZQqPLynt1lM6ilPdENMd9uESPh30CzUsi8Q7tbGZoH52CJjpcb17z3zSjJv40ASVEBhNw== ;{id = 30380 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 3LbmoAShX4cKq4qyIqHLI7+UH4/EVOaXCF7AhJHaRJsgbyCEwn4Ofjh6l15Pxbk/UH851tR8MBaaOz8+ROcL2A== ;{id = 31753 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 xMfArWljU25/0ePkuncQHH8U+/NMLIqy3IpJ7IqcOKRXmR7hrY2dQ6MgBN1rUBW8Q7Uq3mFbozdJbr3oDeZcdQ== ;{id = 32621 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 YsXykW60iTTY+1DY7CG9izDd+RAzx+oPUk2UBiHBPengMUmu3R9rgsJHYfjwWgYWB60sy0CPcdAeu+jD2tB4eA== ;{id = 33127 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 wzS1uBaSWR+bTTYgtLm3jNxNnLSNv6abvnHABXQD5yDFs17rGqDCdvkk6JM3qI4BJ+npNLdADJZt118PWlQ7eQ== ;{id = 37404 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 9nDuSJ9wRTsvFYubQ7KQyOmzlY+UzG1cESD8NK9eOj9VMX1O71d5GxBwzc4UtBs+kZBi49BLjZIV5qWbD9FbXQ== ;{id = 38693 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 EFDgOhEi43zsVaJdytsq3HjtAh6dVDaAnR0PY7O0S4q/svucxOVxmJsG/2rXYMHTej9jRTg/qWWbW4gdReDoSQ== ;{id = 40580 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 wq8UI3DydI9svWJEQ1G0JHGVHykgo3YXFF8CRG055gshZAVyfIiTRwCemG0mbziuobOeZSpCtK05KGp20NHRTA== ;{id = 43985 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 wRMENWFMd+9c4p9agfd/3qLnum1SS555CP9lgJKtU0t7Q689SrAUwBJP7ymXTDGtWSjlFBzbts6SUARX47SK1Q== ;{id = 44725 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 zeWh2eFjuwp9K9yaJq16XMVNC8Ys0TOk91eYkGa0Dgez59aG/PvPYV1qi9pxbmG/c4tuXcRV9Z9cxcVev9DdYw== ;{id = 44975 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 O/y794Mc/kIwRltqnqj+puIS1ejFQeE9Xmjz1NVU82x+UyEvx2InNpwaU2TFNKaT7aned72CE1u//CahV6zeEg== ;{id = 49819 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 edr2Ai2uObWeVfFjvCF01Xa9SQD706baatsttcUuI4MblMTNG4blOSN1pMpZJ/wymkqt4c7eQSCETlD/mPeWPQ== ;{id = 56088 (ksk), size = 256b} +sub2.example.com. IN DNSKEY 257 3 13 PlfsudScPXH3VdDVv6nnuBEXQpP6coF6F2w99u4Es5VbJHZrgFhvxL9os0jnfiGCL6VJ0Q+bNKnzfoP3ByP1Kg== ;{id = 58926 (ksk), size = 256b} + +; 44 invalid signatures, modified with different tags. +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 22 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 23 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 24 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 25 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 26 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 27 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 28 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 29 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 30 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 31 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 32 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 33 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 34 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 35 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 36 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 37 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 38 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 39 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 40 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 41 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 42 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 43 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 44 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 45 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== + +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 46 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 47 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 48 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 49 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 50 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 51 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 52 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 53 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 54 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 55 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 56 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 57 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 58 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 59 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 60 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 61 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 62 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 63 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 64 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 65 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== + +; this signature is valid +sub2.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub2.example.com. fu5MNWhUdr7xd3u3PENBOdg3sZiaOo+TAoj+ZIc2E+6p4SMZYya64a/gdppEqd2kCCPsW0FyxhUlfi9mGmgjcw== +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.sub2.example.com. IN A +SECTION ANSWER +www.sub2.example.com. IN A 10.20.30.42 +www.sub2.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 20 sub2.example.com. VCy6Ggk2HZ+fQ8Bube9UIVDXfF6iWo6Gm5MFRVikWdgqTNizrP5F/z2HzgYFPd+K9WNzsWbi4n+9m4sgYRHAnA== +ENTRY_END +RANGE_END + +; ns.sub3.example.com. +; 24 DNSKEYs and 24 RRSIGs on A +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.7 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +ns.sub3.example.com. IN AAAA +SECTION ANSWER +SECTION AUTHORITY +sub3.example.com. IN SOA a. b. 3600 3600 3600 3600 3600 +sub3.example.com. 3600 IN RRSIG SOA 13 3 3600 20070926134150 20070829134150 20 sub3.example.com. ghR8Y1uUeoJaADEVdXMkNTE2/LtCBt/lmnTX5TOYZSWsT2+Ut6RclRrR9gi771T8IihYwvcf3ZsNyfjfEENSfw== +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +sub3.example.com. IN DNSKEY +SECTION ANSWER +sub3.example.com. IN DNSKEY 257 3 13 n2P99SKaAUDt50U/cToH/0TmGJKG8+Pbiwl1WY/f5EVWZD/auO5QEyY6Tm9kLHzAEOcjWR701V74ZgyFPirxIA== ;{id = 20 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 2biK+rkC8P/MV/UMDbksGCov08Tya5wrtrjeDOSez5W1qFqqPKXzxuMxecGSXIYgNM8Y/m8XdlwOd8Q6vUuw5A== ;{id = 3539 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 UeL+mKovo+r7+B3egif1JxCHPfmbR4SU4m3s0Fp42ozze0FiMzEwRM85O4aYViPOmu0AKgfwuRjEM5aEM1pBug== ;{id = 12688 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 iFe//OnLHLGXpE9i+4y3H+NefdDTZAEwYzDv0U+OIzs37lnOEMYTVqBxkLA82JDKMtnjupCOtSXMoru7lQcckw== ;{id = 13058 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 0/lAWEpW94Rkjion6aUxepvCO6MxoRRJ5aIX9fdEPjUJXCGeHviFLmeDnNzTB0egvC5CgthSnQfyxqMqbbuMAQ== ;{id = 18006 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 P1rwuvxZ8tQOxtOHsbzHAIpMNkleGRtg7gynoesq2gSJT+NAmYRrk+BzEGvHWTHKWd5KnusSt2BpBBlWw5pLiw== ;{id = 18279 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 WraqJ/JvyS8xQZOKpVscbAUuYU8lVCiuEHjekR0kADMP/eWOvdJkaPZ++REeHclBejqXp+NcP0dnyweObnZDsA== ;{id = 20669 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 /fci65ankZ0cKOPdJAJBIyXHYGzjngEyqGbBVmeDk2RwAqxmyUB5OORRmlPMY80ipMU+e8Pt3itKpglwpT7qSA== ;{id = 25106 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 MEfZQnvjQI/L/0QlglQ2YrxSCQ6fRruKF2aQ+nD5JV9ecE1AhA/RujbKkg9UrG4ScjqC7f0fhCW+eUqsSoUcTg== ;{id = 25932 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 KbKK1C8ZtHNsBicJnjrvTB56BoTTjL9pvNEbRVwCKIcWYdNP8l3dpsvVEAZ/ujxmKRA/ToA7ua4/IBDtALFWvg== ;{id = 27845 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 G3I9nIlyTOrn12D8luAgZR4ZTK+iNegzz9UG8b5YsC9IV4UtgbdZkoEDRsH2uu429qvezzlUsjTzR+fu/74Saw== ;{id = 29183 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 fBgVewGRqRmvJUVm/ZQqPLynt1lM6ilPdENMd9uESPh30CzUsi8Q7tbGZoH52CJjpcb17z3zSjJv40ASVEBhNw== ;{id = 30380 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 3LbmoAShX4cKq4qyIqHLI7+UH4/EVOaXCF7AhJHaRJsgbyCEwn4Ofjh6l15Pxbk/UH851tR8MBaaOz8+ROcL2A== ;{id = 31753 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 xMfArWljU25/0ePkuncQHH8U+/NMLIqy3IpJ7IqcOKRXmR7hrY2dQ6MgBN1rUBW8Q7Uq3mFbozdJbr3oDeZcdQ== ;{id = 32621 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 YsXykW60iTTY+1DY7CG9izDd+RAzx+oPUk2UBiHBPengMUmu3R9rgsJHYfjwWgYWB60sy0CPcdAeu+jD2tB4eA== ;{id = 33127 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 wzS1uBaSWR+bTTYgtLm3jNxNnLSNv6abvnHABXQD5yDFs17rGqDCdvkk6JM3qI4BJ+npNLdADJZt118PWlQ7eQ== ;{id = 37404 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 9nDuSJ9wRTsvFYubQ7KQyOmzlY+UzG1cESD8NK9eOj9VMX1O71d5GxBwzc4UtBs+kZBi49BLjZIV5qWbD9FbXQ== ;{id = 38693 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 EFDgOhEi43zsVaJdytsq3HjtAh6dVDaAnR0PY7O0S4q/svucxOVxmJsG/2rXYMHTej9jRTg/qWWbW4gdReDoSQ== ;{id = 40580 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 wq8UI3DydI9svWJEQ1G0JHGVHykgo3YXFF8CRG055gshZAVyfIiTRwCemG0mbziuobOeZSpCtK05KGp20NHRTA== ;{id = 43985 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 wRMENWFMd+9c4p9agfd/3qLnum1SS555CP9lgJKtU0t7Q689SrAUwBJP7ymXTDGtWSjlFBzbts6SUARX47SK1Q== ;{id = 44725 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 zeWh2eFjuwp9K9yaJq16XMVNC8Ys0TOk91eYkGa0Dgez59aG/PvPYV1qi9pxbmG/c4tuXcRV9Z9cxcVev9DdYw== ;{id = 44975 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 O/y794Mc/kIwRltqnqj+puIS1ejFQeE9Xmjz1NVU82x+UyEvx2InNpwaU2TFNKaT7aned72CE1u//CahV6zeEg== ;{id = 49819 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 edr2Ai2uObWeVfFjvCF01Xa9SQD706baatsttcUuI4MblMTNG4blOSN1pMpZJ/wymkqt4c7eQSCETlD/mPeWPQ== ;{id = 56088 (ksk), size = 256b} +sub3.example.com. IN DNSKEY 257 3 13 PlfsudScPXH3VdDVv6nnuBEXQpP6coF6F2w99u4Es5VbJHZrgFhvxL9os0jnfiGCL6VJ0Q+bNKnzfoP3ByP1Kg== ;{id = 58926 (ksk), size = 256b} +sub3.example.com. 3600 IN RRSIG DNSKEY 13 3 3600 20070926134150 20070829134150 20 sub3.example.com. bHMk1YyEhCSaG4zvIeEyy0CKrMVKx+LctpKLCGWhfFGmItIlEdsT/GPwpWUPrTpp990tSSzUFvxkRc+unavAVA== +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.sub3.example.com. IN A +SECTION ANSWER +www.sub3.example.com. IN A 10.20.30.43 +; invalid signatures, with wrong keytag. +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 22 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 23 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 24 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 25 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 26 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 27 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 28 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 29 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 30 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 31 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 32 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 33 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 34 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 35 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 36 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 37 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 38 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 39 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 40 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 41 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 42 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 43 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 44 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 45 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== + +; valid signature. +www.sub3.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 20 sub3.example.com. mqnO7+cyQw79Lt+TwcZhvt5ybNidAjIaap2/NuNnYZeJhluveSoiwzyT+vvLLluD97nuGHym6+d4vrdFLaFYFw== + +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AD DO NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} +ENTRY_END + +; sub1.example.com. +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.sub1.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 30 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ednsdata +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +www.sub1.example.com. IN A +SECTION ANSWER +;www.sub1.example.com. IN A 10.20.30.41 +SECTION ADDITIONAL +HEX_EDNSDATA_BEGIN +; EDE: DNSSEC Bogus "validation failure : DS verify has too many tag matches from 1.2.3.5 for key sub1.example.com. while building chain of trust" +000F009A000676616C69646174696F6E206661696C757265203C7777772E737562312E +6578616D706C652E636F6D2E204120494E3E3A20445320766572696679206861732074 +6F6F206D616E7920746167206D6174636865732066726F6D20312E322E332E3520666F +72206B657920737562312E6578616D706C652E636F6D2E207768696C65206275696C64 +696E6720636861696E206F66207472757374 +HEX_EDNSDATA_END +ENTRY_END + +; sub2.example.com. +STEP 40 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.sub2.example.com. IN A +ENTRY_END + +STEP 50 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ede=6 +;ednsdata +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +www.sub2.example.com. IN A +SECTION ANSWER +;www.sub2.example.com. IN A 10.20.30.42 +;www.sub2.example.com. 3600 IN RRSIG A 13 4 3600 20070926134150 20070829134150 20 sub2.example.com. VCy6Ggk2HZ+fQ8Bube9UIVDXfF6iWo6Gm5MFRVikWdgqTNizrP5F/z2HzgYFPd+K9WNzsWbi4n+9m4sgYRHAnA== +SECTION ADDITIONAL +;HEX_EDNSDATA_BEGIN +;; EDE: DNSSEC Bogus "validation failure : DS verify has too many DNSKEY to RRSIG tag matches from 1.2.3.6 for key sub2.example.com. while building chain of trust" +;000F00AA000676616C69646174696F6E206661696C757265203C7777772E737562322E +;6578616D706C652E636F6D2E204120494E3E3A20445320766572696679206861732074 +;6F6F206D616E7920444E534B455920746F20525253494720746167206D617463686573 +;2066726F6D20312E322E332E3620666F72206B657920737562322E6578616D706C652E +;636F6D2E207768696C65206275696C64696E6720636861696E206F66207472757374 +;HEX_EDNSDATA_END +ENTRY_END + +; sub3.example.com. +STEP 60 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.sub3.example.com. IN A +ENTRY_END + +STEP 70 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ede=9 +;ednsdata +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +www.sub3.example.com. IN A +SECTION ANSWER +;www.sub3.example.com. IN A 10.20.30.43 +SECTION ADDITIONAL +;HEX_EDNSDATA_BEGIN +;; EDE: DNSSEC Bogus "validation failure : too many tag matches from 1.2.3.7" +;000F0054000676616C69646174696F6E206661696C757265203C7777772E737562332E +;6578616D706C652E636F6D2E204120494E3E3A20746F6F206D616E7920746167206D61 +;74636865732066726F6D20312E322E332E37 +;HEX_EDNSDATA_END +ENTRY_END + +SCENARIO_END diff --git a/testdata/val_refer_unsignadd.rpl b/testdata/val_refer_unsignadd.rpl index 22f15d21a..6e3418ceb 100644 --- a/testdata/val_refer_unsignadd.rpl +++ b/testdata/val_refer_unsignadd.rpl @@ -11,6 +11,7 @@ server: trust-anchor-signaling: no iter-scrub-promiscuous: no rrset-roundrobin: no + val-clean-additional: yes stub-zone: name: "." diff --git a/testdata/val_referglue.rpl b/testdata/val_referglue.rpl index 3ca0c0e80..c14bad17f 100644 --- a/testdata/val_referglue.rpl +++ b/testdata/val_referglue.rpl @@ -12,6 +12,7 @@ server: minimal-responses: no iter-scrub-promiscuous: no rrset-roundrobin: no + val-clean-additional: yes stub-zone: name: "." diff --git a/util/config_file.c b/util/config_file.c index e4a2f681e..5c7e0d979 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -253,6 +253,7 @@ config_create(void) cfg->harden_referral_path = 0; cfg->harden_algo_downgrade = 0; cfg->harden_unknown_additional = 0; + cfg->harden_cname_follow = 1; cfg->use_caps_bits_for_id = 0; cfg->caps_whitelist = NULL; cfg->private_address = NULL; @@ -279,7 +280,7 @@ config_create(void) cfg->val_sig_skew_min = 3600; /* at least daylight savings trouble */ cfg->val_sig_skew_max = 86400; /* at most timezone settings trouble */ cfg->val_max_restart = 5; - cfg->val_clean_additional = 1; + cfg->val_clean_additional = 0; /* off to protect against much data. */ cfg->val_log_level = 0; cfg->val_log_squelch = 0; cfg->val_permissive_mode = 0; @@ -430,6 +431,8 @@ config_create(void) cfg->iter_scrub_rrsig = 8; cfg->iter_scrub_promiscuous = 1; cfg->max_global_quota = 200; + cfg->val_validation_attempts = 32; + cfg->val_hash_attempts = 32; return cfg; error_exit: config_delete(cfg); @@ -739,6 +742,7 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_YNO("harden-referral-path:", harden_referral_path) else S_YNO("harden-algo-downgrade:", harden_algo_downgrade) else S_YNO("harden-unknown-additional:", harden_unknown_additional) + else S_YNO("harden-cname-follow:", harden_cname_follow) else S_YNO("use-caps-for-id:", use_caps_bits_for_id) else S_STRLIST("caps-whitelist:", caps_whitelist) else S_SIZET_OR_ZERO("unwanted-reply-threshold:", unwanted_threshold) @@ -788,6 +792,8 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_NUMBER_OR_ZERO("iter-scrub-rrsig:", iter_scrub_rrsig) else S_YNO("iter-scrub-promiscuous:", iter_scrub_promiscuous) else S_NUMBER_OR_ZERO("max-global-quota:", max_global_quota) + else S_NUMBER_OR_ZERO("val-validation-attempts:", val_validation_attempts) + else S_NUMBER_OR_ZERO("val-hash-attempts:", val_hash_attempts) else S_YNO("serve-original-ttl:", serve_original_ttl) else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations) else S_YNO("zonemd-permissive-mode:", zonemd_permissive_mode) @@ -1243,6 +1249,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_YNO(opt, "harden-referral-path", harden_referral_path) else O_YNO(opt, "harden-algo-downgrade", harden_algo_downgrade) else O_YNO(opt, "harden-unknown-additional", harden_unknown_additional) + else O_YNO(opt, "harden-cname-follow", harden_cname_follow) else O_YNO(opt, "use-caps-for-id", use_caps_bits_for_id) else O_LST(opt, "caps-whitelist", caps_whitelist) else O_DEC(opt, "unwanted-reply-threshold", unwanted_threshold) @@ -1268,6 +1275,8 @@ config_get_option(struct config_file* cfg, const char* opt, else O_DEC(opt, "iter-scrub-rrsig", iter_scrub_rrsig) else O_YNO(opt, "iter-scrub-promiscuous", iter_scrub_promiscuous) else O_DEC(opt, "max-global-quota", max_global_quota) + else O_DEC(opt, "val-validation-attempts", val_validation_attempts) + else O_DEC(opt, "val-hash-attempts", val_hash_attempts) else O_YNO(opt, "serve-original-ttl", serve_original_ttl) else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations) else O_YNO(opt, "zonemd-permissive-mode", zonemd_permissive_mode) @@ -3091,3 +3100,40 @@ file_get_mtime(const char* file, time_t* mtime, long* ns, int* nonexist) #endif return 1; } + +int cfg_local_zone_type_value_check(const char* str) +{ + if(strcmp(str, "static")!=0 && strcmp(str, "deny")!=0 && + strcmp(str, "refuse")!=0 && strcmp(str, "redirect")!=0 && + strcmp(str, "transparent")!=0 && strcmp(str, "nodefault")!=0 + && strcmp(str, "typetransparent")!=0 + && strcmp(str, "always_transparent")!=0 + && strcmp(str, "block_a")!=0 + && strcmp(str, "block_aaaa")!=0 + && strcmp(str, "block_a_wdata")!=0 + && strcmp(str, "block_aaaa_wdata")!=0 + && strcmp(str, "always_refuse")!=0 + && strcmp(str, "always_nxdomain")!=0 + && strcmp(str, "always_nodata")!=0 + && strcmp(str, "always_deny")!=0 + && strcmp(str, "always_null")!=0 + && strcmp(str, "noview")!=0 + && strcmp(str, "inform")!=0 && strcmp(str, "inform_deny")!=0 + && strcmp(str, "inform_redirect") != 0 + && strcmp(str, "ipset") != 0) + return 0; + return 1; +} + +const char* cfg_local_zone_type_list(void) +{ + return "static, deny, " + "refuse, redirect, transparent, " + "typetransparent, inform, inform_deny, " + "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/config_file.h b/util/config_file.h index 0a41563ba..f6da7c953 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -313,6 +313,8 @@ struct config_file { /** harden against unknown records in the authority section and in * the additional section */ int harden_unknown_additional; + /** harden to follow cname redirections */ + int harden_cname_follow; /** use 0x20 bits in query as random ID bits */ int use_caps_bits_for_id; /** 0x20 whitelist, domains that do not use capsforid */ @@ -800,6 +802,10 @@ struct config_file { int iter_scrub_rrsig; /** limit on upstream queries for an incoming query and subqueries. */ int max_global_quota; + /** limit on validator validation attempts. */ + int val_validation_attempts; + /** limit on validator hash attempts. */ + int val_hash_attempts; /** Should the iterator scrub promiscuous NS rrsets, from positive * answers. */ int iter_scrub_promiscuous; @@ -1519,4 +1525,10 @@ void cfg_tls_protocols_allowed(const char* tls_protocols, int* allow12, int* all /** get the file mtime stat (or error, with errno and nonexist) */ int file_get_mtime(const char* file, time_t* mtime, long* ns, int* nonexist); +/** check local-zone type for correctness */ +int cfg_local_zone_type_value_check(const char* str); + +/** the list of local-zone types, for error printout. */ +const char* cfg_local_zone_type_list(void); + #endif /* UTIL_CONFIG_FILE_H */ diff --git a/util/configlexer.lex b/util/configlexer.lex index 4881d760f..4be467b47 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -323,6 +323,7 @@ harden-below-nxdomain{COLON} { YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) } harden-referral-path{COLON} { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) } harden-algo-downgrade{COLON} { YDVAR(1, VAR_HARDEN_ALGO_DOWNGRADE) } harden-unknown-additional{COLON} { YDVAR(1, VAR_HARDEN_UNKNOWN_ADDITIONAL) } +harden-cname-follow{COLON} { YDVAR(1, VAR_HARDEN_CNAME_FOLLOW) } use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) } caps-whitelist{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) } caps-exempt{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) } @@ -609,6 +610,8 @@ iter-scrub-ns{COLON} { YDVAR(1, VAR_ITER_SCRUB_NS) } iter-scrub-cname{COLON} { YDVAR(1, VAR_ITER_SCRUB_CNAME) } iter-scrub-rrsig{COLON} { YDVAR(1, VAR_ITER_SCRUB_RRSIG) } max-global-quota{COLON} { YDVAR(1, VAR_MAX_GLOBAL_QUOTA) } +val-validation-attempts{COLON} { YDVAR(1, VAR_VAL_VALIDATION_ATTEMPTS) } +val-hash-attempts{COLON} { YDVAR(1, VAR_VAL_HASH_ATTEMPTS) } max-transfer-size{COLON} { YDVAR(1, VAR_MAX_TRANSFER_SIZE) } max-transfer-time{COLON} { YDVAR(1, VAR_MAX_TRANSFER_TIME) } iter-scrub-promiscuous{COLON} { YDVAR(1, VAR_ITER_SCRUB_PROMISCUOUS) } diff --git a/util/configparser.y b/util/configparser.y index db6701e76..68a750c2c 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -219,7 +219,9 @@ extern struct config_parser_state* cfg_parser; %token VAR_ITER_SCRUB_RRSIG %token VAR_MAX_TRANSFER_SIZE VAR_MAX_TRANSFER_TIME %token VAR_MAX_GLOBAL_QUOTA VAR_HARDEN_UNVERIFIED_GLUE VAR_LOG_TIME_ISO +%token VAR_VAL_VALIDATION_ATTEMPTS VAR_VAL_HASH_ATTEMPTS %token VAR_ITER_SCRUB_PROMISCUOUS VAR_LOG_THREAD_ID +%token VAR_HARDEN_CNAME_FOLLOW %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -362,8 +364,10 @@ content_server: server_num_threads | server_verbosity | server_port | server_harden_unknown_additional | server_disable_edns_do | server_log_destaddr | server_cookie_secret_file | server_iter_scrub_ns | server_iter_scrub_cname | server_max_global_quota | - server_iter_scrub_rrsig | - server_harden_unverified_glue | server_log_time_iso | server_iter_scrub_promiscuous + server_val_validation_attempts | + server_val_hash_attempts | server_iter_scrub_rrsig | + server_harden_unverified_glue | server_log_time_iso | server_iter_scrub_promiscuous | + server_harden_cname_follow ; stub_clause: stubstart contents_stub { @@ -1949,6 +1953,16 @@ server_harden_unknown_additional: VAR_HARDEN_UNKNOWN_ADDITIONAL STRING_ARG free($2); } ; +server_harden_cname_follow: VAR_HARDEN_CNAME_FOLLOW STRING_ARG + { + OUTYY(("P(server_harden_cname_follow:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->harden_cname_follow = + (strcmp($2, "yes")==0); + free($2); + } + ; server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG { OUTYY(("P(server_use_caps_for_id:%s)\n", $2)); @@ -2391,33 +2405,9 @@ server_neg_cache_size: VAR_NEG_CACHE_SIZE STRING_ARG server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG { OUTYY(("P(server_local_zone:%s %s)\n", $2, $3)); - if(strcmp($3, "static")!=0 && strcmp($3, "deny")!=0 && - strcmp($3, "refuse")!=0 && strcmp($3, "redirect")!=0 && - strcmp($3, "transparent")!=0 && strcmp($3, "nodefault")!=0 - && 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 - && strcmp($3, "always_deny")!=0 - && strcmp($3, "always_null")!=0 - && strcmp($3, "noview")!=0 - && strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0 - && strcmp($3, "inform_redirect") != 0 - && strcmp($3, "ipset") != 0) { - yyerror("local-zone type: expected static, deny, " - "refuse, redirect, transparent, " - "typetransparent, inform, inform_deny, " - "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"); + if(!cfg_local_zone_type_value_check($3)) { + ub_c_error_msg("local-zone type: expected %s", + cfg_local_zone_type_list()); free($2); free($3); } else if(strcmp($3, "nodefault")==0) { @@ -3383,27 +3373,9 @@ view_name: VAR_NAME STRING_ARG view_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG { OUTYY(("P(view_local_zone:%s %s)\n", $2, $3)); - if(strcmp($3, "static")!=0 && strcmp($3, "deny")!=0 && - strcmp($3, "refuse")!=0 && strcmp($3, "redirect")!=0 && - strcmp($3, "transparent")!=0 && strcmp($3, "nodefault")!=0 - && strcmp($3, "typetransparent")!=0 - && strcmp($3, "always_transparent")!=0 - && strcmp($3, "always_refuse")!=0 - && strcmp($3, "always_nxdomain")!=0 - && strcmp($3, "always_nodata")!=0 - && strcmp($3, "always_deny")!=0 - && strcmp($3, "always_null")!=0 - && strcmp($3, "noview")!=0 - && strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0 - && strcmp($3, "inform_redirect") != 0 - && strcmp($3, "ipset") != 0) { - yyerror("local-zone type: expected static, deny, " - "refuse, redirect, transparent, " - "typetransparent, inform, inform_deny, " - "inform_redirect, always_transparent, " - "always_refuse, always_nxdomain, " - "always_nodata, always_deny, always_null, " - "noview, nodefault or ipset"); + if(!cfg_local_zone_type_value_check($3)) { + ub_c_error_msg("local-zone type: expected %s", + cfg_local_zone_type_list()); free($2); free($3); } else if(strcmp($3, "nodefault")==0) { @@ -4328,6 +4300,24 @@ server_iter_scrub_promiscuous: VAR_ITER_SCRUB_PROMISCUOUS STRING_ARG free($2); } ; +server_val_validation_attempts: VAR_VAL_VALIDATION_ATTEMPTS STRING_ARG + { + OUTYY(("P(server_val_validation_attempts:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->val_validation_attempts = atoi($2); + free($2); + } + ; +server_val_hash_attempts: VAR_VAL_HASH_ATTEMPTS STRING_ARG + { + OUTYY(("P(server_val_hash_attempts:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->val_hash_attempts = atoi($2); + free($2); + } + ; ipsetstart: VAR_IPSET { OUTYY(("\nP(ipset:)\n")); diff --git a/util/data/dname.c b/util/data/dname.c index 5370aa6f9..9fbbe1092 100644 --- a/util/data/dname.c +++ b/util/data/dname.c @@ -192,34 +192,34 @@ pkt_dname_len(sldns_buffer* pkt) while(1) { /* read next label */ if(sldns_buffer_remaining(pkt) < 1) - return 0; + goto fail; labellen = sldns_buffer_read_u8(pkt); if(LABEL_IS_PTR(labellen)) { /* compression ptr */ uint16_t ptr; if(sldns_buffer_remaining(pkt) < 1) - return 0; + goto fail; ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt)); if(ptrcount++ > MAX_COMPRESS_PTRS) - return 0; /* loop! */ + goto fail; /* loop! */ if(sldns_buffer_limit(pkt) <= ptr) - return 0; /* out of bounds! */ + goto fail; /* out of bounds! */ if(!endpos) endpos = sldns_buffer_position(pkt); sldns_buffer_set_position(pkt, ptr); } else { /* label contents */ if(labellen > 0x3f) - return 0; /* label too long */ + goto fail; /* label too long */ len += 1 + labellen; if(len > LDNS_MAX_DOMAINLEN) - return 0; + goto fail; if(labellen == 0) { /* end of dname */ break; } if(sldns_buffer_remaining(pkt) < labellen) - return 0; + goto fail; sldns_buffer_skip(pkt, (ssize_t)labellen); } } @@ -227,6 +227,13 @@ pkt_dname_len(sldns_buffer* pkt) sldns_buffer_set_position(pkt, endpos); return len; +fail: + /* Restore the position on failure too: callers (rdata_copy) compute + * the consumed field length from the buffer position and must not + * see a partial walk of a name that failed to parse. */ + if(endpos) + sldns_buffer_set_position(pkt, endpos); + return 0; } int diff --git a/util/data/msgencode.c b/util/data/msgencode.c index 8e55e13f1..cc78a40b4 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -1166,6 +1166,12 @@ extended_error_encode(sldns_buffer* buf, uint16_t rcode, edns_opt_list_remove(&es.opt_list_inplace_cb_out, LDNS_EDNS_EDE); edns_opt_list_remove(&es.opt_list_out, LDNS_EDNS_EDE); attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); + } else { + LDNS_TC_SET(sldns_buffer_begin(buf)); + if(es.ext_rcode != 0) { + LDNS_RCODE_SET(sldns_buffer_begin(buf), + LDNS_RCODE_SERVFAIL); + } } } } diff --git a/util/data/msgparse.c b/util/data/msgparse.c index f9beb605c..e00f570c7 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -974,7 +974,6 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, } /* while still more options, and have code+len to read */ - /* ignores partial content (i.e. rdata len 3) */ while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) { uint16_t opt_code = sldns_read_uint16(rdata_ptr); uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); @@ -984,8 +983,10 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, rdata_ptr += 4; rdata_len -= 4; - if(opt_len > rdata_len) - break; /* option code partial */ + if(opt_len > rdata_len) { + /* option code partial */ + return LDNS_RCODE_FORMERR; + } /* handle parse time edns options here */ switch(opt_code) { @@ -1160,6 +1161,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, rdata_len -= opt_len; i++; } + /* partial content (i.e. rdata len 3) is FORMERR */ + if(rdata_len > 0 && rdata_len <= 3) + return LDNS_RCODE_FORMERR; return LDNS_RCODE_NOERROR; } @@ -1240,6 +1244,8 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg, rdata_len -= 4; if(opt_len > rdata_len) break; /* option code partial */ + /* This is lenient for partially broken messages + * from upstream. With a partial EDNS option. */ if(!edns_opt_list_append(&edns->opt_list_in, opt_code, opt_len, rdata_ptr, region)) { diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 0beb893c3..86193a671 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -248,6 +248,7 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, sldns_pkt_section section) { uint16_t pkt_len; + size_t tolen; uint32_t ttl; const sldns_rr_descriptor* desc; @@ -293,9 +294,13 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t))); /* insert decompressed size into rdata len stored in memory */ /* -2 because rdatalen bytes are not included. */ + tolen = rr->size; + if(tolen < 2) + return 0; pkt_len = htons(rr->size - 2); memmove(to, &pkt_len, sizeof(uint16_t)); to += 2; + tolen -= 2; /* read packet rdata len */ pkt_len = sldns_buffer_read_u16(pkt); if(sldns_buffer_remaining(pkt) < pkt_len) @@ -304,16 +309,29 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, if(pkt_len > 0 && desc && desc->_dname_count > 0) { int count = (int)desc->_dname_count; int rdf = 0; - size_t len; - size_t oldpos; + size_t len, dlen; + size_t oldpos, newpos; /* decompress dnames. */ while(pkt_len > 0 && count) { switch(desc->_wireformat[rdf]) { case LDNS_RDF_TYPE_DNAME: oldpos = sldns_buffer_position(pkt); - dname_pkt_copy(pkt, to, + dlen = pkt_dname_len(pkt); + if(dlen == 0) + return 0; /* malformed */ + if(dlen > tolen) + return 0; /* alloc mismatch */ + newpos = sldns_buffer_position(pkt); + if(oldpos > newpos) + return 0; /* should have moved forward*/ + sldns_buffer_set_position(pkt, oldpos); + dname_pkt_copy(pkt, to, sldns_buffer_current(pkt)); - to += pkt_dname_len(pkt); + sldns_buffer_set_position(pkt, newpos); + to += dlen; + tolen -= dlen; + if(sldns_buffer_position(pkt)-oldpos > pkt_len) + return 0; /* malformed: walks diverged */ pkt_len -= sldns_buffer_position(pkt)-oldpos; count--; len = 0; @@ -326,9 +344,12 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, break; } if(len) { + if(len > tolen) + return 0; /* alloc mismatch */ log_assert(len <= pkt_len); memmove(to, sldns_buffer_current(pkt), len); to += len; + tolen -= len; sldns_buffer_skip(pkt, (ssize_t)len); pkt_len -= len; } @@ -336,8 +357,11 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, } } /* copy remaining rdata */ - if(pkt_len > 0) + if(pkt_len > 0) { + if(pkt_len > tolen) + return 0; /* alloc mismatch */ memmove(to, sldns_buffer_current(pkt), pkt_len); + } return 1; } @@ -1115,6 +1139,17 @@ reply_all_rrsets_secure(struct reply_info* rep) return 1; } +int reply_an_ns_rrsets_secure(struct reply_info* rep) +{ + size_t i; + for(i=0; ian_numrrsets+rep->ns_numrrsets; i++) { + if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) + ->security != sec_status_secure ) + return 0; + } + return 1; +} + struct reply_info* parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region, struct query_info* qi) diff --git a/util/data/msgreply.h b/util/data/msgreply.h index e7c688e97..e4476660d 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -494,6 +494,9 @@ int reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep); */ int reply_all_rrsets_secure(struct reply_info* rep); +/** Check status of answer and authority section RRs. */ +int reply_an_ns_rrsets_secure(struct reply_info* rep); + /** * Find answer rrset in reply, the one matching qinfo. Follows CNAMEs, so the * result may have a different owner name. diff --git a/util/fptr_wlist.c b/util/fptr_wlist.c index 88a788a8e..252969e89 100644 --- a/util/fptr_wlist.c +++ b/util/fptr_wlist.c @@ -142,6 +142,8 @@ fptr_whitelist_comm_timer(void (*fptr)(void*)) #ifdef UB_ON_WINDOWS else if(fptr == &wsvc_cron_cb) return 1; #endif + else if(fptr == &tcp_read_again_cb) return 1; + else if(fptr == &tcp_more_read_again_cb) return 1; else if(fptr == &auth_xfer_timer) return 1; else if(fptr == &auth_xfer_probe_timer_callback) return 1; else if(fptr == &auth_xfer_transfer_timer_callback) return 1; diff --git a/util/netevent.c b/util/netevent.c index 432fead1b..b9f4611f9 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -122,6 +122,10 @@ #define NUM_UDP_PER_SELECT 1 #endif +/** The number of TCP queries over a TCP connection, per read indication + * from select. */ +#define NUM_TCP_PER_SELECT 100 + /** timeout in millisec to wait for write to unblock, packets dropped after.*/ #define SEND_BLOCKED_WAIT_TIMEOUT 200 /** max number of times to wait for write to unblock, packets dropped after.*/ @@ -3226,6 +3230,26 @@ static int http2_submit_settings(struct http2_session* h2_session) } #endif /* HAVE_NGHTTP2 */ +/** Clear http2 stream mesh states */ +static void http2_session_clear_meshstate(struct http2_session* h2_session) +{ +#ifdef HAVE_NGHTTP2 + /* Since the session gets closed, remove the mesh state references. */ + struct http2_stream* h2_stream; + for(h2_stream = h2_session->first_stream; h2_stream; + h2_stream = h2_stream->next) { + if(h2_stream->mesh_state) { + mesh_state_remove_reply(h2_stream->mesh, + h2_stream->mesh_state, h2_session->c, + h2_stream, NULL); + h2_stream->mesh_state = NULL; + } + } +#else + (void)h2_session; +#endif /* HAVE_NGHTTP2 */ +} + #ifdef HAVE_NGHTTP2 /** Delete http2 stream. After session delete or stream close callback */ static void http2_stream_delete(struct http2_session* h2_session, @@ -4621,6 +4645,10 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c) static int tcp_req_info_read_again(int fd, struct comm_point* c) { + /* One event-loop visit drains at most this many pipelined queries; + * the rest is re-queued, so that other file descriptors get + * serviced in between. */ + int budget = NUM_TCP_PER_SELECT; while(c->tcp_req_info->read_again) { int r; c->tcp_req_info->read_again = 0; @@ -4637,6 +4665,16 @@ tcp_req_info_read_again(int fd, struct comm_point* c) } return 0; } + if(--budget <= 0 && c->tcp_req_info->read_again) { + /* Defer the rest of the drain to the next loop turn. + * This uses a zero delay timer. For TLS the undrained + * remainder sits in OpenSSL's user-space buffer. */ + struct timeval tv; + memset(&tv, 0, sizeof(tv)); + verbose(VERB_ALGO, "Defer tcp_req_info read again"); + comm_timer_set(c->tcp_req_info->read_again_timer, &tv); + return 1; + } } return 1; } @@ -4650,6 +4688,7 @@ tcp_more_read_again(int fd, struct comm_point* c) /* this continues until the read routines get EAGAIN or so, * and thus does not call the callback, and the bool is 0 */ int* moreread = c->tcp_more_read_again; + int budget = NUM_TCP_PER_SELECT; while(moreread && *moreread) { *moreread = 0; if(!comm_point_tcp_handle_read(fd, c, 0)) { @@ -4662,6 +4701,30 @@ tcp_more_read_again(int fd, struct comm_point* c) } return; } + if(--budget <= 0 && *moreread) { + /* Defer the rest of the drain to the next loop turn. + * This uses a zero delay timer. For TLS the undrained + * remainder sits in OpenSSL's user-space buffer. */ + struct timeval tv; + memset(&tv, 0, sizeof(tv)); + if(!c->tcp_more_read_again_timer) { + c->tcp_more_read_again_timer = comm_timer_create(c->ev->base, tcp_more_read_again_cb, c); + if(!c->tcp_more_read_again_timer) { + log_err("out of memory for tcp more read again timer"); + reclaim_tcp_handler(c); + if(!c->tcp_do_close) { + fptr_ok(fptr_whitelist_comm_point( + c->callback)); + (void)(*c->callback)(c, c->cb_arg, + NETEVENT_CLOSED, NULL); + } + return; + } + } + verbose(VERB_ALGO, "Defer more read again"); + comm_timer_set(c->tcp_more_read_again_timer, &tv); + return; + } } } @@ -4689,6 +4752,23 @@ tcp_more_write_again(int fd, struct comm_point* c) } } +void +tcp_read_again_cb(void* arg) +{ + struct tcp_req_info* req = (struct tcp_req_info*)arg; + verbose(VERB_ALGO, "tcp_read_again_cb"); + if(!tcp_req_info_read_again(req->cp->fd, req->cp)) + return; +} + +void +tcp_more_read_again_cb(void* arg) +{ + struct comm_point* c = (struct comm_point*)arg; + verbose(VERB_ALGO, "tcp_more_read_again_cb"); + tcp_more_read_again(c->fd, c); +} + void comm_point_tcp_handle_callback(int fd, short event, void* arg) { @@ -6131,7 +6211,7 @@ comm_point_create_tcp_handler(struct comm_base *base, c->pp2_enabled = parent->pp2_enabled; c->pp2_header_state = pp2_header_none; if(spoolbuf) { - c->tcp_req_info = tcp_req_info_create(spoolbuf); + c->tcp_req_info = tcp_req_info_create(base, spoolbuf); if(!c->tcp_req_info) { log_err("could not create tcp commpoint"); sldns_buffer_free(c->buffer); @@ -6232,8 +6312,8 @@ comm_point_create_http_handler(struct comm_base *base, c->http_min_version = http_version_2; c->http2_stream_max_qbuffer_size = bufsize; - if(harden_large_queries && bufsize > 512) - c->http2_stream_max_qbuffer_size = 512; + if(harden_large_queries && bufsize > NORMAL_UDP_SIZE) + c->http2_stream_max_qbuffer_size = NORMAL_UDP_SIZE; c->http2_max_streams = http_max_streams; if(!(c->http_endpoint = strdup(http_endpoint))) { log_err("could not strdup http_endpoint"); @@ -6693,6 +6773,9 @@ comm_point_close(struct comm_point* c) *c->tcp_more_read_again = 0; if(c->tcp_more_write_again && *c->tcp_more_write_again) *c->tcp_more_write_again = 0; + if(c->tcp_more_read_again_timer && + comm_timer_is_set(c->tcp_more_read_again_timer)) + comm_timer_disable(c->tcp_more_read_again_timer); /* close fd after removing from event lists, or epoll.. is messed up */ if(c->fd != -1 && !c->do_not_close) { @@ -6732,6 +6815,7 @@ comm_point_delete(struct comm_point* c) free(c->tcp_handlers); } free(c->timeout); + comm_timer_delete(c->tcp_more_read_again_timer); if(c->type == comm_tcp || c->type == comm_local || c->type == comm_http) { sldns_buffer_free(c->buffer); #ifdef USE_DNSCRYPT @@ -6872,6 +6956,7 @@ comm_point_drop_reply(struct comm_reply* repinfo) if(repinfo->c->type == comm_http) { if(repinfo->c->h2_session) { repinfo->c->h2_session->is_drop = 1; + http2_session_clear_meshstate(repinfo->c->h2_session); if(!repinfo->c->h2_session->postpone_drop) reclaim_http_handler(repinfo->c); return; @@ -7036,8 +7121,12 @@ comm_timer_disable(struct comm_timer* timer) { if(!timer) return; - ub_timer_del(timer->ev_timer->ev); - timer->ev_timer->enabled = 0; + /* The event backend can not always deal with event del if it was not + * added before. For that, there is a check if it was added here.*/ + if(timer->ev_timer->enabled) { + ub_timer_del(timer->ev_timer->ev); + timer->ev_timer->enabled = 0; + } } void diff --git a/util/netevent.h b/util/netevent.h index 7d64fac5b..e9a34406f 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -118,6 +118,9 @@ typedef int comm_point_callback_type(struct comm_point*, void*, int, /** for doq, the maximum dcid length, in ngtcp2 it is 20. */ #define DOQ_MAX_CIDLEN 24 +/** Size of an UDP datagram */ +#define NORMAL_UDP_SIZE 512 /* bytes */ + /** * A communication point dispatcher. Thread specific. */ @@ -384,6 +387,9 @@ struct comm_point { * Or leave NULL if it is not used at all. */ int* tcp_more_write_again; + /** resume timer for tcp_more_read_again */ + struct comm_timer* tcp_more_read_again_timer; + /** if set, read/write completes: read/write state of tcp is toggled. buffer reset/bytecount reset. @@ -1133,6 +1139,12 @@ void doq_send_pkt(struct comm_point* c, struct doq_pkt_addr* paddr, /** doq timer callback function. */ void doq_timer_cb(void* arg); +/** tcp read again callback function. For tcp req info listen. */ +void tcp_read_again_cb(void* arg); + +/** tcp more read again callback function. For outside network. */ +void tcp_more_read_again_cb(void* arg); + /** * This routine is published for checks and tests, and is only used internally. * handle libevent callback for timer comm. diff --git a/validator/autotrust.c b/validator/autotrust.c index fc7897b71..0da4188ef 100644 --- a/validator/autotrust.c +++ b/validator/autotrust.c @@ -1275,9 +1275,10 @@ void autr_write_file(struct module_env* env, struct trust_anchor* tp) FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out))); #endif if(fclose(out) != 0) { - fatal_exit("could not complete write: %s: %s", - fname, strerror(errno)); + int err = errno; unlink(tempf); + fatal_exit("could not complete write: %s: %s", + fname, strerror(err)); return; } /* success; overwrite actual file */ @@ -1297,12 +1298,13 @@ void autr_write_file(struct module_env* env, struct trust_anchor* tp) * @param tp: trust point to verify with * @param rrset: DNSKEY rrset to verify. * @param qstate: qstate with region. + * @param vq: validator query state. * @return false on failure, true if verification successful. */ static int verify_dnskey(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* rrset, - struct module_qstate* qstate) + struct module_qstate* qstate, struct val_qstate* vq) { char reasonbuf[256]; char* reason = NULL; @@ -1310,7 +1312,7 @@ verify_dnskey(struct module_env* env, struct val_env* ve, int downprot = env->cfg->harden_algo_downgrade; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason, - NULL, qstate, reasonbuf, sizeof(reasonbuf)); + NULL, qstate, vq, reasonbuf, sizeof(reasonbuf)); /* sigalg is ignored, it returns algorithms signalled to exist, but * in 5011 there are no other rrsets to check. if downprot is * enabled, then it checks that the DNSKEY is signed with all @@ -1350,16 +1352,18 @@ min_expiry(struct module_env* env, struct packed_rrset_data* dd) static int rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, size_t i, - struct module_qstate* qstate) + struct module_qstate* qstate, struct val_qstate* vq) { enum sec_status sec; char* reason = NULL; + size_t num_tagmatches = 0; verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d", (int)i); /* no algorithm downgrade protection necessary, if it is selfsigned * revoked it can be removed. */ sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i, - &reason, NULL, LDNS_SECTION_ANSWER, qstate); + &reason, NULL, LDNS_SECTION_ANSWER, qstate, vq, + &num_tagmatches); return (sec == sec_status_secure); } @@ -1575,7 +1579,7 @@ init_events(struct trust_anchor* tp) static void check_contains_revoked(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, - int* changed, struct module_qstate* qstate) + int* changed, struct module_qstate* qstate, struct val_qstate* vq) { struct packed_rrset_data* dd = (struct packed_rrset_data*) dnskey_rrset->entry.data; @@ -1595,7 +1599,8 @@ check_contains_revoked(struct module_env* env, struct val_env* ve, } if(!ta) continue; /* key not found */ - if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) { + if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate, + vq)) { /* checked if there is an rrsig signed by this key. */ /* same keytag, but stored can be revoked already, so * compare keytags, with +0 or +128(REVOKE flag) */ @@ -2209,7 +2214,7 @@ autr_tp_remove(struct module_env* env, struct trust_anchor* tp, int autr_process_prime(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, - struct module_qstate* qstate) + struct module_qstate* qstate, struct val_qstate* vq) { int changed = 0; log_assert(tp && tp->autr); @@ -2250,7 +2255,7 @@ int autr_process_prime(struct module_env* env, struct val_env* ve, return 1; /* trust point exists */ } /* check for revoked keys to remove immediately */ - check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate); + check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate, vq); if(changed) { verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble"); if(!autr_assemble(tp)) { @@ -2266,7 +2271,7 @@ int autr_process_prime(struct module_env* env, struct val_env* ve, } } /* verify the dnskey rrset and see if it is valid. */ - if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) { + if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate, vq)) { verbose(VERB_ALGO, "autotrust: dnskey did not verify."); /* only increase failure count if this is not the first prime, * this means there was a previous successful probe */ diff --git a/validator/autotrust.h b/validator/autotrust.h index 057f2b68a..2e2f92668 100644 --- a/validator/autotrust.h +++ b/validator/autotrust.h @@ -50,6 +50,7 @@ struct module_env; struct module_qstate; struct val_env; struct sldns_buffer; +struct val_qstate; /** Autotrust anchor states */ typedef enum { @@ -190,13 +191,14 @@ void autr_point_delete(struct trust_anchor* tp); * @param dnskey_rrset: DNSKEY rrset probed (can be NULL if bad prime result). * allocated in a region. Has not been validated yet. * @param qstate: qstate with region. + * @param vq: validator query state. * @return false if trust anchor was revoked completely. * Otherwise logs errors to log, does not change return value. * On errors, likely the trust point has been unchanged. */ int autr_process_prime(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, - struct module_qstate* qstate); + struct module_qstate* qstate, struct val_qstate* vq); /** * Debug printout of rfc5011 tracked anchors diff --git a/validator/val_anchor.c b/validator/val_anchor.c index af42d53c7..ca50446d0 100644 --- a/validator/val_anchor.c +++ b/validator/val_anchor.c @@ -829,8 +829,9 @@ anchor_read_bind_file_wild(struct val_anchors* anchors, sldns_buffer* buffer, if(r) { /* some error */ if(r == GLOB_NOMATCH) { - verbose(VERB_QUERY, "trusted-keys-file: " - "no matches for %s", pat); + verbose(VERB_OPS, "trusted-keys-file: " + "no matches for %s; " + "no trust anchors loaded from it", pat); return 1; } else if(r == GLOB_NOSPACE) { log_err("wildcard trusted-keys-file %s: " diff --git a/validator/val_neg.c b/validator/val_neg.c index 63f380ad9..74ef3d3b3 100644 --- a/validator/val_neg.c +++ b/validator/val_neg.c @@ -42,12 +42,6 @@ * from cached NSEC records. */ #include "config.h" -#ifdef HAVE_OPENSSL_SSL_H -#include -#define NSEC3_SHA_LEN SHA_DIGEST_LENGTH -#else -#define NSEC3_SHA_LEN 20 -#endif #include "validator/val_neg.h" #include "validator/val_nsec.h" #include "validator/val_nsec3.h" @@ -694,6 +688,8 @@ static void wipeout(struct val_neg_cache* neg, struct val_neg_zone* zone, if(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC) { end = d->rr_data[0]+2; end_len = dname_valid(end, d->rr_len[0]-2); + if(!end_len) + return; end_labs = dname_count_labels(end); } else { /* NSEC3 */ @@ -1515,6 +1511,7 @@ val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo, lock_rw_unlock(&cache_wc->entry.lock); wcrr->rk.dname = qinfo->qname; wcrr->rk.dname_len = qinfo->qname_len; + wcrr->entry.hash = rrset_key_hash(&wcrr->rk); if(!dns_msg_ansadd(msg, region, wcrr, 0)) return NULL; /* No SOA needed for wildcard synthesised diff --git a/validator/val_nsec.c b/validator/val_nsec.c index becd42b4d..a7f49d6e1 100644 --- a/validator/val_nsec.c +++ b/validator/val_nsec.c @@ -177,7 +177,8 @@ static int nsec_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen) { struct packed_rrset_data* d = (struct packed_rrset_data*) nsec->entry.data; @@ -189,7 +190,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve, if(d->security == sec_status_secure) return 1; d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason, - reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified, + reason_bogus, LDNS_SECTION_AUTHORITY, qstate, vq, &verified, reasonbuf, reasonlen); if(d->security == sec_status_secure) { rrset_update_sec_status(env->rrset_cache, nsec, *env->now); @@ -203,7 +204,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, struct query_info* qinfo, struct reply_info* rep, struct key_entry_key* kkey, time_t* proof_ttl, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns( rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC, @@ -221,7 +222,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, * 2) this is not a delegation point */ if(nsec) { if(!nsec_verify_rrset(env, ve, nsec, kkey, reason, - reason_bogus, qstate, reasonbuf, reasonlen)) { + reason_bogus, qstate, vq, reasonbuf, reasonlen)) { verbose(VERB_ALGO, "NSEC RRset for the " "referral did not verify."); return sec_status_bogus; @@ -258,7 +259,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC)) continue; if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason, - reason_bogus, qstate, reasonbuf, reasonlen)) { + reason_bogus, qstate, vq, reasonbuf, reasonlen)) { verbose(VERB_ALGO, "NSEC for empty non-terminal " "did not verify."); *reason = "NSEC for empty non-terminal " diff --git a/validator/val_nsec.h b/validator/val_nsec.h index c1d45314a..a9002b78a 100644 --- a/validator/val_nsec.h +++ b/validator/val_nsec.h @@ -52,6 +52,7 @@ struct ub_packed_rrset_key; struct reply_info; struct query_info; struct key_entry_key; +struct val_qstate; /** * Check DS absence. @@ -68,6 +69,7 @@ struct key_entry_key; * @param reason: string explaining why bogus. * @param reason_bogus: relevant EDE code for validation failure. * @param qstate: qstate with region. + * @param vq: validator qstate. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return security status. @@ -80,7 +82,8 @@ enum sec_status val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, struct query_info* qinfo, struct reply_info* rep, struct key_entry_key* kkey, time_t* proof_ttl, char** reason, sldns_ede_code* reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen); + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen); /** * nsec typemap check, takes an NSEC-type bitmap as argument, checks for type. diff --git a/validator/val_nsec3.c b/validator/val_nsec3.c index d0385be68..23589e330 100644 --- a/validator/val_nsec3.c +++ b/validator/val_nsec3.c @@ -265,6 +265,8 @@ size_t nsec3_hash_to_b32(uint8_t* hash, size_t hashlen, uint8_t* zone, ret = sldns_b32_ntop_extended_hex(hash, hashlen, (char*)buf+1, max-1); if(ret < 1) return 0; + if(ret > LDNS_MAX_LABELLEN) + return 0; /* label length too long */ buf[0] = (uint8_t)ret; /* length of b32 label */ ret++; if(max - ret < zonelen) @@ -273,13 +275,30 @@ size_t nsec3_hash_to_b32(uint8_t* hash, size_t hashlen, uint8_t* zone, return zonelen+(size_t)ret; } +/** Check that the hash length corresponds to the nsec3 algo */ +static int +nsec3_algo_has_hashlen(int algo, size_t hlen) +{ + if(algo == NSEC3_HASH_SHA1) { + if(hlen != NSEC3_SHA_LEN) + return 0; /* wrong hash length for this algo */ + } else { + return 0; /* unknown algo */ + } + return 1; +} + size_t nsec3_get_nextowner_b32(struct ub_packed_rrset_key* rrset, int r, uint8_t* buf, size_t max) { uint8_t* nm, *zone; size_t nmlen, zonelen; + int algo; if(!nsec3_get_nextowner(rrset, r, &nm, &nmlen)) return 0; + algo = nsec3_get_algo(rrset, r); + if(!nsec3_algo_has_hashlen(algo, nmlen)) + return 0; /* wrong hash length for this algo */ /* append zone name; the owner name must be .zone */ zone = rrset->rk.dname; zonelen = rrset->rk.dname_len; @@ -1521,7 +1540,8 @@ static int list_is_secure(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen) { struct packed_rrset_data* d; size_t i; @@ -1537,7 +1557,7 @@ list_is_secure(struct module_env* env, struct val_env* ve, continue; d->security = val_verify_rrset_entry(env, ve, list[i], kkey, reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate, - &verified, reasonbuf, reasonlen); + vq, &verified, reasonbuf, reasonlen); if(d->security != sec_status_secure) { verbose(VERB_ALGO, "NSEC3 did not verify"); return 0; @@ -1552,7 +1572,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, struct nsec3_cache_table* ct, char* reasonbuf, + size_t reasonlen) { struct nsec3_filter flt; struct ce_response ce; @@ -1568,7 +1589,7 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, return sec_status_bogus; /* no valid NSEC3s, bogus */ } if(!list_is_secure(env, ve, list, num, kkey, reason, reason_bogus, - qstate, reasonbuf, reasonlen)) { + qstate, vq, reasonbuf, reasonlen)) { *reason = "not all NSEC3 records secure"; return sec_status_bogus; /* not all NSEC3 records secure */ } diff --git a/validator/val_nsec3.h b/validator/val_nsec3.h index a13e92991..286ffaf53 100644 --- a/validator/val_nsec3.h +++ b/validator/val_nsec3.h @@ -78,6 +78,7 @@ struct reply_info; struct query_info; struct key_entry_key; struct sldns_buffer; +struct val_qstate; /** * 0 1 2 3 4 5 6 7 @@ -104,6 +105,9 @@ struct sldns_buffer; */ #define MAX_NSEC3_CALCULATIONS 8 +/** Length of the hash in bytes for the NSEC3 algorithm SHA1 */ +#define NSEC3_SHA_LEN 20 + /** * Cache table for NSEC3 hashes. * It keeps a *pointer* to the region its items are allocated. @@ -215,6 +219,7 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, * @param reason: string for bogus result. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate. * @param ct: cached hashes table. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. @@ -230,7 +235,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, struct nsec3_cache_table* ct, char* reasonbuf, + size_t reasonlen); /** * Prove NXDOMAIN or NODATA. diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index 4139cc1fe..3b0dce6da 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -82,6 +82,8 @@ /** Maximum number of RRSIG validations for an RRset. */ #define MAX_VALIDATE_RRSIGS 8 +/** Maximum number of NSEC validations for a message. */ +#define MAX_VALIDATE_NSECS 8 /** return number of rrs in an rrset */ static size_t @@ -305,6 +307,8 @@ ds_create_dnskey_digest(struct module_env* env, * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA); * DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */ sldns_buffer_clear(b); + if(!sldns_buffer_available(b, dnskey_rrset->rk.dname_len + dnskey_len-2)) + return 0; /* buffer too small */ sldns_buffer_write(b, dnskey_rrset->rk.dname, dnskey_rrset->rk.dname_len); query_dname_tolower(sldns_buffer_begin(b)); @@ -546,8 +550,10 @@ int algo_needs_missing(struct algo_needs* n) * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param numverified: incremented when the number of RRSIG validations * increases. + * @param num_tagmatches: incremented for tag matches. * @return secure if any key signs *this* signature. bogus if no key signs it, * unchecked on error, or indeterminate if all keys are not supported by * the crypto library (openssl3+ only). @@ -559,7 +565,7 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, struct rbtree_type** sortree, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* numverified) + struct val_qstate* vq, int* numverified, size_t* num_tagmatches) { /* find matching keys and check them */ enum sec_status sec = sec_status_bogus; @@ -578,6 +584,14 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, } for(i=0; i MAX_TAG_MATCHES) { + *reason = "too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "verify sig: too many tag matches, " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } /* see if key matches keytag and algo */ if(algo != dnskey_get_algo(dnskey, i) || tag != dnskey_calc_keytag(dnskey, i)) @@ -585,6 +599,26 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, numchecked ++; (*numverified)++; + if(vq && vq->num_validation_attempts++ > env->cfg->val_validation_attempts) { + *reason = "too many validation attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "verify sig: too many validation attempts, " + "val-validation-attempts (%d); bogus", env->cfg->val_validation_attempts); + return sec_status_bogus; + } + if(vq && (ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC || + ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC3) && + vq->num_nsec_attempts++ > MAX_VALIDATE_NSECS) { + *reason = "too many NSEC or NSEC3 validation attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "verify sig: too many NSEC or NSEC3 validation attempts, " + "(%d); bogus", MAX_VALIDATE_NSECS); + vq->num_nsec_attempts_exceeded = 1; + return sec_status_bogus; + } + /* see if key verifies */ sec = dnskey_verify_rrset_sig(env->scratch, env->scratch_buffer, ve, now, rrset, dnskey, i, @@ -624,11 +658,12 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate, int* verified, - char* reasonbuf, size_t reasonlen) + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen) { enum sec_status sec; - size_t i, num; + size_t i, num, num_tagmatches = 0; rbtree_type* sortree = NULL; /* make sure that for all DNSKEY algorithms there are valid sigs */ struct algo_needs needs; @@ -656,9 +691,19 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, } } for(i=0; i MAX_TAG_MATCHES) { + *reason = "too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many tag matches, " + "MAX_TAG_MATCHES (%d)", MAX_TAG_MATCHES); + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset, dnskey, i, &sortree, reason, reason_bogus, - section, qstate, verified); + section, qstate, vq, verified, &num_tagmatches); /* see which algorithm has been fixed up */ if(sec == sec_status_secure) { if(!sigalg) @@ -707,7 +752,8 @@ enum sec_status dnskey_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate) + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, size_t* num_tagmatches) { enum sec_status sec; size_t i, num, numchecked = 0, numindeterminate = 0; @@ -728,9 +774,26 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve, } for(i=0; i MAX_TAG_MATCHES) { + *reason = "too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many tag matches, " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } if(algo != rrset_get_sig_algo(rrset, i) || tag != rrset_get_sig_keytag(rrset, i)) continue; + if(vq && vq->num_validation_attempts++ > env->cfg->val_validation_attempts) { + *reason = "too many validation attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many validation attempts, " + "val-validation-attempts (%d); bogus", env->cfg->val_validation_attempts); + return sec_status_bogus; + } + buf_canon = 0; sec = dnskey_verify_rrset_sig(env->scratch, env->scratch_buffer, ve, *env->now, rrset, @@ -1308,15 +1371,32 @@ rrset_canonical(struct regional* region, sldns_buffer* buf, } sldns_buffer_clear(buf); + if(sldns_buffer_remaining(buf) < siglen || siglen < 18+1) { + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } sldns_buffer_write(buf, sig, siglen); /* canonicalize signer name */ canon_dname_tolower(sldns_buffer_begin(buf)+18, sldns_buffer_current(buf)); + + if(sldns_buffer_remaining(buf) < k->rk.dname_len+2) { + /* Check if the first can_owner name can fit in the buffer. + * The length is k->rk.dname_len or k->rk.dname_len+2 + * if it has '*.' in prefixed. Checks the upper bound, + * also realistically the rest of the rrtype, rrclass, origttl, + * rdata and so on has to be inserted, so that extra space has + * to be there. */ + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } RBTREE_FOR(walk, struct canon_rr*, (*sortree)) { /* see if there is enough space left in the buffer */ if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + d->rr_len[walk->rr_idx]) { - log_err("verify: failed to canonicalize, " + verbose(VERB_ALGO, "verify: failed to canonicalize, " "rrset too big"); return 0; } @@ -1325,6 +1405,13 @@ rrset_canonical(struct regional* region, sldns_buffer* buf, sldns_buffer_write(buf, can_owner, can_owner_len); else insert_can_owner(buf, k, sig, &can_owner, &can_owner_len); + /* Check again, if the rdata can fit in the buffer */ + if(sldns_buffer_remaining(buf) < 2 + 2 + 4 + + d->rr_len[walk->rr_idx]) { + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } sldns_buffer_write(buf, &k->rk.type, 2); sldns_buffer_write(buf, &k->rk.rrset_class, 2); sldns_buffer_write(buf, sig+4, 4); @@ -1345,6 +1432,7 @@ rrset_canonical(struct regional* region, sldns_buffer* buf, return 0; k->rk.dname = new_dname; k->rk.dname_len = can_owner_len; + k->entry.hash = rrset_key_hash(&k->rk); } @@ -1376,11 +1464,17 @@ rrset_canonicalize_to_buffer(struct regional* region, sldns_buffer* buf, canonical_sort(k, d, sortree, rrs); sldns_buffer_clear(buf); + if(sldns_buffer_remaining(buf) < k->rk.dname_len) { + /* Check if the first can_owner name can fit in the buffer. */ + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } RBTREE_FOR(walk, struct canon_rr*, sortree) { /* see if there is enough space left in the buffer */ if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + d->rr_len[walk->rr_idx]) { - log_err("verify: failed to canonicalize, " + verbose(VERB_ALGO, "verify: failed to canonicalize, " "rrset too big"); return 0; } @@ -1393,6 +1487,13 @@ rrset_canonicalize_to_buffer(struct regional* region, sldns_buffer* buf, query_dname_tolower(can_owner); can_owner_len = k->rk.dname_len; } + /* Check again, if the rdata can fit in the buffer */ + if(sldns_buffer_remaining(buf) < 2 + 2 + 4 + + d->rr_len[walk->rr_idx]) { + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } sldns_buffer_write(buf, &k->rk.type, 2); sldns_buffer_write(buf, &k->rk.rrset_class, 2); sldns_buffer_write_u32(buf, d->rr_ttl[walk->rr_idx]); diff --git a/validator/val_sigcrypt.h b/validator/val_sigcrypt.h index c1e2658e4..b2cfae96d 100644 --- a/validator/val_sigcrypt.h +++ b/validator/val_sigcrypt.h @@ -53,6 +53,7 @@ struct ub_packed_rrset_key; struct rbtree_type; struct regional; struct sldns_buffer; +struct val_qstate; /** number of entries in algorithm needs array */ #define ALGO_NEEDS_MAX 256 @@ -262,6 +263,7 @@ uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx); * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param verified: if not NULL the number of RRSIG validations is returned. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. @@ -273,8 +275,9 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate, int* verified, - char* reasonbuf, size_t reasonlen); + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen); /** * verify rrset against one specific dnskey (from rrset) @@ -287,13 +290,16 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env, * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. + * @param num_tagmatches: incremented to keep track of tag matches. * @return secure if *this* key signs any of the signatures on rrset. * unchecked on error or and bogus on bad signature. */ enum sec_status dnskey_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate); + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, size_t* num_tagmatches); /** * verify rrset, with specific dnskey(from set), for a specific rrsig diff --git a/validator/val_utils.c b/validator/val_utils.c index bfff19126..5ccc52acd 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -406,7 +406,8 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int *verified, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, int *verified, char* reasonbuf, + size_t reasonlen) { enum sec_status sec; struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> @@ -431,7 +432,8 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname, ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class)); sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason, - reason_bogus, section, qstate, verified, reasonbuf, reasonlen); + reason_bogus, section, qstate, vq, verified, reasonbuf, + reasonlen); verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec)); regional_free_all(env->scratch); @@ -475,7 +477,8 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* verified, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen) { /* temporary dnskey rrset-key */ struct ub_packed_rrset_key dnskey; @@ -489,7 +492,8 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve, dnskey.entry.key = &dnskey; dnskey.entry.data = kd->rrset_data; sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason, - reason_bogus, section, qstate, verified, reasonbuf, reasonlen); + reason_bogus, section, qstate, vq, verified, reasonbuf, + reasonlen); return sec; } @@ -499,13 +503,20 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - int *nonechecked, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, int *nonechecked, char* reasonbuf, + size_t reasonlen, size_t* num_tagmatches, + size_t* num_tagmatches_dnskeysig) { enum sec_status sec = sec_status_bogus; size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0; num = rrset_get_count(dnskey_rrset); *nonechecked = 0; for(i=0; i MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS match attempt reached " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } /* Skip DNSKEYs that don't match the basic criteria. */ if(ds_get_key_algo(ds_rrset, ds_idx) != dnskey_get_algo(dnskey_rrset, i) @@ -518,6 +529,15 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, ds_get_key_algo(ds_rrset, ds_idx), ds_get_keytag(ds_rrset, ds_idx)); + if(vq && vq->num_hash_attempts++ > env->cfg->val_hash_attempts) { + *reason = "too many hash attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many hash attempts, " + "val-hash-attempts (%d); bogus", env->cfg->val_hash_attempts); + return sec_status_bogus; + } + /* Convert the candidate DNSKEY into a hash using the * same DS hash algorithm. */ if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset, @@ -541,8 +561,14 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, /* Otherwise, we have a match! Make sure that the DNSKEY * verifies *with this key* */ + if(*num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS that matched has too many DNSKEY to RRSIG tag matches " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, - i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate); + i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate, + vq, num_tagmatches_dnskeysig); if(sec == sec_status_secure) { return sec; } @@ -586,14 +612,14 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { /* as long as this is false, we can consider this DS rrset to be * equivalent to no DS rrset. */ int has_useful_ds = 0, digest_algo, alg, has_algo_refusal = 0, nonechecked, has_checked_ds = 0; struct algo_needs needs; - size_t i, num; + size_t i, num, num_tagmatches = 0, num_tagmatches_dnskeysig = 0; enum sec_status sec; if(dnskey_rrset->rk.dname_len != ds_rrset->rk.dname_len || @@ -615,6 +641,13 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, } num = rrset_get_count(ds_rrset); for(i=0; i MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS verify attempt reached " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "DS verify has too many tag matches"; + return sec_status_bogus; + } + /* Check to see if we can understand this DS. * And check it is the strongest digest */ if(!ds_digest_algo_is_supported(ds_rrset, i) || @@ -623,9 +656,16 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, continue; } + if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS verify attempt reached " + "DNSKEY to RRSIG MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "DS verify has too many DNSKEY to RRSIG tag matches"; + return sec_status_bogus; + } sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, - ds_rrset, i, reason, reason_bogus, qstate, - &nonechecked, reasonbuf, reasonlen); + ds_rrset, i, reason, reason_bogus, qstate, vq, + &nonechecked, reasonbuf, reasonlen, &num_tagmatches, + &num_tagmatches_dnskeysig); if(sec == sec_status_insecure) { /* DNSKEY too large unsupported or algo refused by * crypto lib. */ @@ -687,12 +727,12 @@ val_verify_new_DNSKEYs(struct regional* region, struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { uint8_t sigalg[ALGO_NEEDS_MAX+1]; enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve, dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason, - reason_bogus, qstate, reasonbuf, reasonlen); + reason_bogus, qstate, vq, reasonbuf, reasonlen); if(sec == sec_status_secure) { return key_entry_create_rrset(region, @@ -718,14 +758,14 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* ta_ds, struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { /* as long as this is false, we can consider this anchor to be * equivalent to no anchor. */ int has_useful_ta = 0, digest_algo = 0, alg, has_algo_refusal = 0, nonechecked, has_checked_ds = 0; struct algo_needs needs; - size_t i, num; + size_t i, num, num_tagmatches = 0, num_tagmatches_dnskeysig = 0; enum sec_status sec; if(ta_ds && (dnskey_rrset->rk.dname_len != ta_ds->rk.dname_len || @@ -761,6 +801,15 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, if(ta_ds) { num = rrset_get_count(ta_ds); for(i=0; i MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "anchor DS verify attempt reached " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "anchor DS verify has too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } + /* Check to see if we can understand this DS. * And check it is the strongest digest */ if(!ds_digest_algo_is_supported(ta_ds, i) || @@ -768,9 +817,18 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, ds_get_digest_algo(ta_ds, i) != digest_algo) continue; + if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "anchor DS verify has too many DNSKEY to RRSIG tag matches " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "anchor DS verify has too many DNSKEY to RRSIG tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, - ta_ds, i, reason, reason_bogus, qstate, &nonechecked, - reasonbuf, reasonlen); + ta_ds, i, reason, reason_bogus, qstate, vq, + &nonechecked, reasonbuf, reasonlen, &num_tagmatches, + &num_tagmatches_dnskeysig); if(sec == sec_status_insecure) { has_algo_refusal = 1; continue; @@ -813,8 +871,16 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, /* we saw a useful TA */ has_useful_ta = 1; + if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "anchor DS that matched has too many DNSKEY to RRSIG tag matches " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "anchor DS that matched has too many DNSKEY to RRSIG tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } sec = dnskey_verify_rrset(env, ve, dnskey_rrset, - ta_dnskey, i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate); + ta_dnskey, i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate, vq, &num_tagmatches_dnskeysig); if(sec == sec_status_secure) { if(!sigalg || algo_needs_set_secure(&needs, (uint8_t)dnskey_get_algo(ta_dnskey, i))) { @@ -862,12 +928,13 @@ val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env, struct ub_packed_rrset_key* ta_ds_rrset, struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen) { uint8_t sigalg[ALGO_NEEDS_MAX+1]; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset, - downprot?sigalg:NULL, reason, reason_bogus, qstate, + downprot?sigalg:NULL, reason, reason_bogus, qstate, vq, reasonbuf, reasonlen); if(sec == sec_status_secure) { diff --git a/validator/val_utils.h b/validator/val_utils.h index f05ff1d94..d92896ebf 100644 --- a/validator/val_utils.h +++ b/validator/val_utils.h @@ -55,6 +55,11 @@ struct regional; struct val_anchors; struct rrset_cache; struct sock_list; +struct val_qstate; + +/** Maximum number of matches with key tag and algorithm, for DNSKEY to + * RRSIG and DS to DNSKEY. Since the number is O(N*N), there is a limit. */ +#define MAX_TAG_MATCHES 256 /** * Response classifications for the validator. The different types of proofs. @@ -124,6 +129,7 @@ void val_find_signer(enum val_classification subtype, * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param verified: if not NULL, the number of RRSIG validations is returned. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. @@ -133,7 +139,8 @@ enum sec_status val_verify_rrset_entry(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* verified, char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen); /** * Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but @@ -148,6 +155,7 @@ enum sec_status val_verify_rrset_entry(struct module_env* env, * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return: sec_status_secure if a DS matches. @@ -158,7 +166,7 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS @@ -174,6 +182,7 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env, * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return: sec_status_secure if a DS matches. @@ -185,7 +194,7 @@ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env, struct ub_packed_rrset_key* ta_ds, struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Verify new DNSKEYs with DS rrset. The DS contains hash values that should @@ -202,6 +211,7 @@ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env, * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return a KeyEntry. This will either contain the now trusted @@ -219,7 +229,7 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Verify rrset with trust anchor: DS and DNSKEY rrset. @@ -235,6 +245,7 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region, * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return a KeyEntry. This will either contain the now trusted @@ -253,7 +264,7 @@ struct key_entry_key* val_verify_new_DNSKEYs_with_ta(struct regional* region, struct ub_packed_rrset_key* ta_ds_rrset, struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Determine if DS rrset is usable for validator or not. diff --git a/validator/validator.c b/validator/validator.c index 3634e3215..7e9cd311a 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -350,13 +350,17 @@ static void val_restart(struct val_qstate* vq) { struct comm_timer* temp_timer; - int restart_count; + int restart_count, num_validation_attempts, num_hash_attempts; if(!vq) return; temp_timer = vq->suspend_timer; restart_count = vq->restart_count+1; + num_validation_attempts = vq->num_validation_attempts; + num_hash_attempts = vq->num_hash_attempts; memset(vq, 0, sizeof(*vq)); vq->suspend_timer = temp_timer; vq->restart_count = restart_count; + vq->num_validation_attempts = num_validation_attempts; + vq->num_hash_attempts = num_hash_attempts; vq->state = VAL_INIT_STATE; } @@ -455,6 +459,24 @@ already_validated(struct dns_msg* ret_msg) return 0; } +/** If it is possible to restart the validation state */ +static int +val_can_restart(struct module_qstate* qstate, struct val_qstate* vq, + struct val_env* ve) +{ + /* For validation failures that are limits exceeded on the amount + * of work that the DNSSEC validator is willing to do, the restart + * is not allowed. A restart would increase the amount of effort + * spent even further. */ + if(vq->restart_count < ve->max_restart && + vq->num_validation_attempts <= qstate->env->cfg->val_validation_attempts && + vq->num_hash_attempts <= qstate->env->cfg->val_hash_attempts && + !vq->num_nsec_attempts_exceeded) + return 1; + (void)qstate; + return 0; +} + /** * Generate a request for DNS data. * @@ -763,8 +785,8 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq, /* Verify the answer rrset */ sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, - &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified, - reasonbuf, sizeof(reasonbuf)); + &reason_bogus, LDNS_SECTION_ANSWER, qstate, vq, + &verified, reasonbuf, sizeof(reasonbuf)); /* If the (answer) rrset failed to validate, then this * message is BAD. */ if(sec != sec_status_secure) { @@ -808,7 +830,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq, continue; s = chase_reply->rrsets[i]; sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, - &reason_bogus, LDNS_SECTION_AUTHORITY, qstate, + &reason_bogus, LDNS_SECTION_AUTHORITY, qstate, vq, &verified, reasonbuf, sizeof(reasonbuf)); /* If anything in the authority section fails to be secure, * we have a bad message. */ @@ -855,7 +877,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq, if(sname && query_dname_compare(sname, key_entry->name)==0) (void)val_verify_rrset_entry(env, ve, s, key_entry, &reason, NULL, LDNS_SECTION_ADDITIONAL, qstate, - &verified, reasonbuf, sizeof(reasonbuf)); + vq, &verified, reasonbuf, sizeof(reasonbuf)); /* the additional section can fail to be secure, * it is optional, check signature in case we need * to clean the additional section later. */ @@ -1433,16 +1455,20 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve, * trusted DNSKEY rrset that signs this response must already have been * completed. * + * @param env: module env. * @param chase_reply: answer to validate. */ static void -validate_referral_response(struct reply_info* chase_reply) +validate_referral_response(struct module_env* env, struct reply_info* chase_reply) { - size_t i; + size_t i, count; enum sec_status s; /* message security equals lowest rrset security */ chase_reply->security = sec_status_secure; - for(i=0; irrset_count; i++) { + if(env->cfg->val_clean_additional) + count = chase_reply->rrset_count; + else count = chase_reply->an_numrrsets+chase_reply->ns_numrrsets; + for(i=0; irrsets[i] ->entry.data)->security; if(s < chase_reply->security) @@ -2309,7 +2335,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, key_entry_get_reason_bogus(vq->key_entry)); errinf_ede(qstate, "while building chain of trust", key_entry_get_reason_bogus(vq->key_entry)); - if(vq->restart_count >= ve->max_restart) + if(!val_can_restart(qstate, vq, ve)) key_cache_insert(ve->kcache, vq->key_entry, qstate->env->cfg->val_log_level >= 2); return 1; @@ -2457,7 +2483,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, case VAL_CLASS_REFERRAL: verbose(VERB_ALGO, "Validating a referral response"); - validate_referral_response(vq->chase_reply); + validate_referral_response(qstate->env, vq->chase_reply); verbose(VERB_DETAIL, "validate(referral): %s", sec_status_to_string( vq->chase_reply->security)); @@ -2531,15 +2557,17 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, } if(subtype == VAL_CLASS_REFERRAL) { - /* for a referral, move to next unchecked rrset and check it*/ - vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep, - vq->rrset_skip); - if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) { - /* and restart for this rrset */ - verbose(VERB_ALGO, "validator: go to next rrset"); - vq->chase_reply->security = sec_status_unchecked; - vq->state = VAL_INIT_STATE; - return 1; + if(qstate->env->cfg->val_clean_additional) { + /* for a referral, move to next unchecked rrset and check it*/ + vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep, + vq->rrset_skip); + if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) { + /* and restart for this rrset */ + verbose(VERB_ALGO, "validator: go to next rrset"); + vq->chase_reply->security = sec_status_unchecked; + vq->state = VAL_INIT_STATE; + return 1; + } } /* referral chase is done */ } @@ -2584,7 +2612,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, struct msgreply_entry* e; /* see if we can try again to fetch data */ - if(vq->restart_count < ve->max_restart) { + if(val_can_restart(qstate, vq, ve)) { verbose(VERB_ALGO, "validation failed, " "blacklist and retry to fetch data"); val_blacklist(&qstate->blacklist, qstate->region, @@ -2876,6 +2904,7 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id, * (this rrset is allocated in the wrong region, not the qstate). * @param ta: trust anchor. * @param qstate: qstate that needs key. + * @param vq: validator qstate. * @param id: module id. * @param sub_qstate: the sub query state, that is the lookup that fetched * the trust anchor data, it contains error information for the answer. @@ -2886,8 +2915,8 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id, */ static struct key_entry_key* primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, - struct trust_anchor* ta, struct module_qstate* qstate, int id, - struct module_qstate* sub_qstate) + struct trust_anchor* ta, struct module_qstate* qstate, + struct val_qstate* vq, int id, struct module_qstate* sub_qstate) { struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; struct key_entry_key* kkey = NULL; @@ -2927,7 +2956,8 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, /* attempt to verify with trust anchor DS and DNSKEY */ kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve, dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot, - &reason, &reason_bogus, qstate, reasonbuf, sizeof(reasonbuf)); + &reason, &reason_bogus, qstate, vq, reasonbuf, + sizeof(reasonbuf)); if(!kkey) { log_err("out of memory: verifying prime TA"); return NULL; @@ -3040,7 +3070,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, * bogus, then we are done. */ sec = val_verify_rrset_entry(qstate->env, ve, ds, vq->key_entry, &reason, &reason_bogus, - LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf, + LDNS_SECTION_ANSWER, qstate, vq, &verified, reasonbuf, sizeof(reasonbuf)); if(sec != sec_status_secure) { verbose(VERB_DETAIL, "DS rrset in DS response did " @@ -3091,7 +3121,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, /* Try to prove absence of the DS with NSEC */ sec = val_nsec_prove_nodata_dsreply( qstate->env, ve, qinfo, msg->rep, vq->key_entry, - &proof_ttl, &reason, &reason_bogus, qstate, + &proof_ttl, &reason, &reason_bogus, qstate, vq, reasonbuf, sizeof(reasonbuf)); switch(sec) { case sec_status_secure: @@ -3130,7 +3160,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, sec = nsec3_prove_nods(qstate->env, ve, msg->rep->rrsets + msg->rep->an_numrrsets, msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason, - &reason_bogus, qstate, &vq->nsec3_cache_table, + &reason_bogus, qstate, vq, &vq->nsec3_cache_table, reasonbuf, sizeof(reasonbuf)); switch(sec) { case sec_status_insecure: @@ -3217,7 +3247,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, } sec = val_verify_rrset_entry(qstate->env, ve, cname, vq->key_entry, &reason, &reason_bogus, - LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf, + LDNS_SECTION_ANSWER, qstate, vq, &verified, reasonbuf, sizeof(reasonbuf)); if(sec == sec_status_secure) { /* Check for wildcard expansion */ @@ -3338,6 +3368,7 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq, uint8_t* olds = vq->empty_DS_name; int ret; *suspend = 0; + vq->num_nsec_attempts = 0; vq->empty_DS_name = NULL; if(sub_qstate && sub_qstate->rpz_applied) { verbose(VERB_ALGO, "rpz was applied to the DS lookup, " @@ -3349,6 +3380,8 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq, } ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske, sub_qstate); + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; if(ret != 0) { switch(ret) { case 1: @@ -3390,7 +3423,7 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq, vq->chain_blacklist = NULL; /* fresh blacklist for next part*/ /* Keep the forState.state on FINDKEY. */ } else if(key_entry_isbad(dske) - && vq->restart_count < ve->max_restart) { + && val_can_restart(qstate, vq, ve)) { vq->empty_DS_name = olds; val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3440,6 +3473,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, char* reason = NULL; sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + vq->num_nsec_attempts = 0; if(sub_qstate && sub_qstate->rpz_applied) { verbose(VERB_ALGO, "rpz was applied to the DNSKEY lookup, " "make it insecure"); @@ -3459,7 +3493,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to " "DNSKEY query."); - if(vq->restart_count < ve->max_restart) { + if(val_can_restart(qstate, vq, ve)) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3496,7 +3530,9 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, downprot = qstate->env->cfg->harden_algo_downgrade; vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env, ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, - qstate, reasonbuf, sizeof(reasonbuf)); + qstate, vq, reasonbuf, sizeof(reasonbuf)); + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; if(!vq->key_entry) { log_err("out of memory in verify new DNSKEYs"); @@ -3507,7 +3543,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, * state. */ if(!key_entry_isgood(vq->key_entry)) { if(key_entry_isbad(vq->key_entry)) { - if(vq->restart_count < ve->max_restart) { + if(val_can_restart(qstate, vq, ve)) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3559,6 +3595,7 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq, struct trust_anchor* ta = anchor_find(qstate->env->anchors, vq->trust_anchor_name, vq->trust_anchor_labs, vq->trust_anchor_len, vq->qchase.qclass); + vq->num_nsec_attempts = 0; if(!ta) { /* trust anchor revoked, restart with less anchors */ vq->state = VAL_INIT_STATE; @@ -3577,19 +3614,23 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq, if(ta->autr) { if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset, - qstate)) { + qstate, vq)) { + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; /* trust anchor revoked, restart with less anchors */ vq->state = VAL_INIT_STATE; vq->trust_anchor_name = NULL; return; } } - vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id, + vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, vq, id, sub_qstate); lock_basic_unlock(&ta->lock); + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; if(vq->key_entry) { if(key_entry_isbad(vq->key_entry) - && vq->restart_count < ve->max_restart) { + && val_can_restart(qstate, vq, ve)) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; diff --git a/validator/validator.h b/validator/validator.h index e04fad572..f7bc3550a 100644 --- a/validator/validator.h +++ b/validator/validator.h @@ -231,6 +231,19 @@ struct val_qstate { struct comm_timer* suspend_timer; /** Number of suspends */ int suspend_count; + + /** Number of DNSKEY RRSIG validation attempts. This is the number of + * cryptographic operations done for the mesh state. */ + int num_validation_attempts; + /** Number of DS hash verification attempts. This is the number of + * hash operations done for the mesh state. + * It does not count NSEC3 hashes. */ + int num_hash_attempts; + /** Number of NSEC validations. And NSEC3 too. This is reset per + * answer. */ + int num_nsec_attempts; + /** The nsec attempts have been exceeded. */ + int num_nsec_attempts_exceeded; }; /**