The branch releng/13.3 has been updated by cy:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=c6edb21e3763b55b4102cb08d62a51abcf3cbd4c

commit c6edb21e3763b55b4102cb08d62a51abcf3cbd4c
Author:     Cy Schubert <c...@freebsd.org>
AuthorDate: 2023-11-13 19:44:16 +0000
Commit:     Cy Schubert <c...@freebsd.org>
CommitDate: 2024-02-18 04:00:01 +0000

    unbound: Vendor import 1.19.1
    
    Release notes at
        https://www.nlnetlabs.nl/news/2024/Feb/13/unbound-1.19.1-released/
    
    Security:       CVE-2023-50387, CVE-2023-50868
    Approved by:    re (cperciva)
    
    (cherry picked from commit b76ef9a7cb8a7c62d10ae8101f41014f34819174)
    (cherry picked from commit abe4ced2b9de0a3dd44d7e2068cfd7fa2b428c16)
---
 contrib/unbound/config.guess                  |  11 +-
 contrib/unbound/config.sub                    |  29 +-
 contrib/unbound/configure                     |  25 +-
 contrib/unbound/configure.ac                  |   5 +-
 contrib/unbound/doc/README                    |   2 +-
 contrib/unbound/doc/example.conf.in           |   2 +-
 contrib/unbound/doc/libunbound.3.in           |   4 +-
 contrib/unbound/doc/unbound-anchor.8.in       |   2 +-
 contrib/unbound/doc/unbound-checkconf.8.in    |   2 +-
 contrib/unbound/doc/unbound-control.8.in      |   2 +-
 contrib/unbound/doc/unbound-host.1.in         |   2 +-
 contrib/unbound/doc/unbound.8.in              |   4 +-
 contrib/unbound/doc/unbound.conf.5.in         |   2 +-
 contrib/unbound/services/authzone.c           |   3 +-
 contrib/unbound/services/cache/dns.c          |  22 ++
 contrib/unbound/services/cache/dns.h          |   9 +
 contrib/unbound/testdata/val_any_negcache.rpl |   3 +
 contrib/unbound/util/fptr_wlist.c             |   1 +
 contrib/unbound/validator/val_nsec.c          |   3 +-
 contrib/unbound/validator/val_nsec3.c         | 316 ++++++++++++----
 contrib/unbound/validator/val_nsec3.h         |  60 +++-
 contrib/unbound/validator/val_sigcrypt.c      |  37 +-
 contrib/unbound/validator/val_sigcrypt.h      |   3 +-
 contrib/unbound/validator/val_utils.c         |  22 +-
 contrib/unbound/validator/val_utils.h         |   4 +-
 contrib/unbound/validator/validator.c         | 499 ++++++++++++++++++++++----
 contrib/unbound/validator/validator.h         |  18 +
 usr.sbin/unbound/config.h                     |   4 +-
 28 files changed, 889 insertions(+), 207 deletions(-)

diff --git a/contrib/unbound/config.guess b/contrib/unbound/config.guess
index cdfc4392047c..f6d217a49f8f 100755
--- a/contrib/unbound/config.guess
+++ b/contrib/unbound/config.guess
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2023 Free Software Foundation, Inc.
+#   Copyright 1992-2024 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2023-08-22'
+timestamp='2024-01-01'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2023 Free Software Foundation, Inc.
+Copyright 1992-2024 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -165,6 +165,8 @@ Linux|GNU|GNU/*)
        LIBC=dietlibc
        #elif defined(__GLIBC__)
        LIBC=gnu
+       #elif defined(__LLVM_LIBC__)
+       LIBC=llvm
        #else
        #include <stdarg.h>
        /* First heuristic to detect musl libc.  */
@@ -1593,6 +1595,9 @@ EOF
     *:Unleashed:*:*)
        GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
        ;;
+    *:Ironclad:*:*)
+       GUESS=$UNAME_MACHINE-unknown-ironclad
+       ;;
 esac
 
 # Do we have a guess based on uname results?
diff --git a/contrib/unbound/config.sub b/contrib/unbound/config.sub
index defe52c0c874..2c6a07ab3c34 100755
--- a/contrib/unbound/config.sub
+++ b/contrib/unbound/config.sub
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2023 Free Software Foundation, Inc.
+#   Copyright 1992-2024 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2023-09-19'
+timestamp='2024-01-01'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -76,7 +76,7 @@ Report bugs and patches to <config-patc...@gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2023 Free Software Foundation, Inc.
+Copyright 1992-2024 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -1222,6 +1222,7 @@ case $cpu-$vendor in
                        | moxie \
                        | mt \
                        | msp430 \
+                       | nanomips* \
                        | nds32 | nds32le | nds32be \
                        | nfp \
                        | nios | nios2 | nios2eb | nios2el \
@@ -1253,6 +1254,7 @@ case $cpu-$vendor in
                        | ubicom32 \
                        | v70 | v850 | v850e | v850e1 | v850es | v850e2 | 
v850e2v3 \
                        | vax \
+                       | vc4 \
                        | visium \
                        | w65 \
                        | wasm32 | wasm64 \
@@ -1597,7 +1599,7 @@ case $cpu-$vendor in
                os=
                obj=elf
                ;;
-       mips*-*)
+       mips*-*|nanomips*-*)
                os=
                obj=elf
                ;;
@@ -1721,7 +1723,7 @@ fi
 
 case $os in
        # Sometimes we do "kernel-libc", so those need to count as OSes.
-       musl* | newlib* | relibc* | uclibc*)
+       llvm* | musl* | newlib* | relibc* | uclibc*)
                ;;
        # Likewise for "kernel-abi"
        eabi* | gnueabi*)
@@ -1766,12 +1768,19 @@ case $os in
             | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
             | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
             | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
-            | fiwix* | mlibc* | cos* | mbr* )
+            | fiwix* | mlibc* | cos* | mbr* | ironclad* )
                ;;
        # This one is extra strict with allowed versions
        sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
                # Don't forget version if it is 3.2v4 or newer.
                ;;
+       # This refers to builds using the UEFI calling convention
+       # (which depends on the architecture) and PE file format.
+       # Note that this is both a different calling convention and
+       # different file format than that of GNU-EFI
+       # (x86_64-w64-mingw32).
+       uefi)
+               ;;
        none)
                ;;
        kernel* | msvc* )
@@ -1818,8 +1827,9 @@ esac
 # As a final step for OS-related things, validate the OS-kernel combination
 # (given a valid OS), if there is a kernel.
 case $kernel-$os-$obj in
-       linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \
-                  | linux-musl*- | linux-relibc*- | linux-uclibc*- | 
linux-mlibc*- )
+       linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \
+                   | linux-mlibc*- | linux-musl*- | linux-newlib*- \
+                   | linux-relibc*- | linux-uclibc*- )
                ;;
        uclinux-uclibc*- )
                ;;
@@ -1827,7 +1837,8 @@ case $kernel-$os-$obj in
                ;;
        windows*-msvc*-)
                ;;
-       -dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- )
+       -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \
+                   | -uclibc*- )
                # These are just libc implementations, not actual OSes, and thus
                # require a kernel.
                echo "Invalid configuration '$1': libc '$os' needs explicit 
kernel." 1>&2
diff --git a/contrib/unbound/configure b/contrib/unbound/configure
index fbe6f8697742..c87c669c8435 100755
--- a/contrib/unbound/configure
+++ b/contrib/unbound/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for unbound 1.19.0.
+# Generated by GNU Autoconf 2.69 for unbound 1.19.1.
 #
 # Report bugs to <unbound-b...@nlnetlabs.nl or 
https://github.com/NLnetLabs/unbound/issues>.
 #
@@ -591,8 +591,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='unbound'
 PACKAGE_TARNAME='unbound'
-PACKAGE_VERSION='1.19.0'
-PACKAGE_STRING='unbound 1.19.0'
+PACKAGE_VERSION='1.19.1'
+PACKAGE_STRING='unbound 1.19.1'
 PACKAGE_BUGREPORT='unbound-b...@nlnetlabs.nl or 
https://github.com/NLnetLabs/unbound/issues'
 PACKAGE_URL=''
 
@@ -1477,7 +1477,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.19.0 to adapt to many kinds of systems.
+\`configure' configures unbound 1.19.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1543,7 +1543,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of unbound 1.19.0:";;
+     short | recursive ) echo "Configuration of unbound 1.19.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1785,7 +1785,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-unbound configure 1.19.0
+unbound configure 1.19.1
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2494,7 +2494,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.19.0, which was
+It was created by unbound $as_me 1.19.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2846,11 +2846,11 @@ UNBOUND_VERSION_MAJOR=1
 
 UNBOUND_VERSION_MINOR=19
 
-UNBOUND_VERSION_MICRO=0
+UNBOUND_VERSION_MICRO=1
 
 
 LIBUNBOUND_CURRENT=9
-LIBUNBOUND_REVISION=23
+LIBUNBOUND_REVISION=24
 LIBUNBOUND_AGE=1
 # 1.0.0 had 0:12:0
 # 1.0.1 had 0:13:0
@@ -2941,6 +2941,7 @@ LIBUNBOUND_AGE=1
 # 1.17.1 had 9:21:1
 # 1.18.0 had 9:22:1
 # 1.19.0 had 9:23:1
+# 1.19.1 had 9:24:1
 
 #   Current  -- the number of the binary API that we're implementing
 #   Revision -- which iteration of the implementation of the binary
@@ -21894,7 +21895,7 @@ _ACEOF
 
 
 
-version=1.19.0
+version=1.19.1
 
 date=`date +'%b %e, %Y'`
 
@@ -22413,7 +22414,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.19.0, which was
+This file was extended by unbound $as_me 1.19.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -22479,7 +22480,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-unbound config.status 1.19.0
+unbound config.status 1.19.1
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/contrib/unbound/configure.ac b/contrib/unbound/configure.ac
index 1b999596d09a..70fc7e7fdf49 100644
--- a/contrib/unbound/configure.ac
+++ b/contrib/unbound/configure.ac
@@ -11,14 +11,14 @@ sinclude(dnscrypt/dnscrypt.m4)
 # must be numbers. ac_defun because of later processing
 m4_define([VERSION_MAJOR],[1])
 m4_define([VERSION_MINOR],[19])
-m4_define([VERSION_MICRO],[0])
+m4_define([VERSION_MICRO],[1])
 
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-b...@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=23
+LIBUNBOUND_REVISION=24
 LIBUNBOUND_AGE=1
 # 1.0.0 had 0:12:0
 # 1.0.1 had 0:13:0
@@ -109,6 +109,7 @@ LIBUNBOUND_AGE=1
 # 1.17.1 had 9:21:1
 # 1.18.0 had 9:22:1
 # 1.19.0 had 9:23:1
+# 1.19.1 had 9:24:1
 
 #   Current  -- the number of the binary API that we're implementing
 #   Revision -- which iteration of the implementation of the binary
diff --git a/contrib/unbound/doc/README b/contrib/unbound/doc/README
index 592a9f4ae8d2..eef91ce02836 100644
--- a/contrib/unbound/doc/README
+++ b/contrib/unbound/doc/README
@@ -1,4 +1,4 @@
-README for Unbound 1.19.0
+README for Unbound 1.19.1
 Copyright 2007 NLnet Labs
 http://unbound.net
 
diff --git a/contrib/unbound/doc/example.conf.in 
b/contrib/unbound/doc/example.conf.in
index fe0dde69fa19..fcfb1da815db 100644
--- a/contrib/unbound/doc/example.conf.in
+++ b/contrib/unbound/doc/example.conf.in
@@ -1,7 +1,7 @@
 #
 # Example configuration file.
 #
-# See unbound.conf(5) man page, version 1.19.0.
+# See unbound.conf(5) man page, version 1.19.1.
 #
 # this is a comment.
 
diff --git a/contrib/unbound/doc/libunbound.3.in 
b/contrib/unbound/doc/libunbound.3.in
index fa090d58186f..4a55eaa9e2ca 100644
--- a/contrib/unbound/doc/libunbound.3.in
+++ b/contrib/unbound/doc/libunbound.3.in
@@ -1,4 +1,4 @@
-.TH "libunbound" "3" "Nov  8, 2023" "NLnet Labs" "unbound 1.19.0"
+.TH "libunbound" "3" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1"
 .\"
 .\" libunbound.3 -- unbound library functions manual
 .\"
@@ -44,7 +44,7 @@
 .B ub_ctx_zone_remove,
 .B ub_ctx_data_add,
 .B ub_ctx_data_remove
-\- Unbound DNS validating resolver 1.19.0 functions.
+\- Unbound DNS validating resolver 1.19.1 functions.
 .SH "SYNOPSIS"
 .B #include <unbound.h>
 .LP
diff --git a/contrib/unbound/doc/unbound-anchor.8.in 
b/contrib/unbound/doc/unbound-anchor.8.in
index a108db9faa72..fee56e9dfa51 100644
--- a/contrib/unbound/doc/unbound-anchor.8.in
+++ b/contrib/unbound/doc/unbound-anchor.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-anchor" "8" "Nov  8, 2023" "NLnet Labs" "unbound 1.19.0"
+.TH "unbound-anchor" "8" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1"
 .\"
 .\" unbound-anchor.8 -- unbound anchor maintenance utility manual
 .\"
diff --git a/contrib/unbound/doc/unbound-checkconf.8.in 
b/contrib/unbound/doc/unbound-checkconf.8.in
index b80c723cd3f0..9a14ef06bc3d 100644
--- a/contrib/unbound/doc/unbound-checkconf.8.in
+++ b/contrib/unbound/doc/unbound-checkconf.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-checkconf" "8" "Nov  8, 2023" "NLnet Labs" "unbound 1.19.0"
+.TH "unbound-checkconf" "8" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1"
 .\"
 .\" unbound-checkconf.8 -- unbound configuration checker manual
 .\"
diff --git a/contrib/unbound/doc/unbound-control.8.in 
b/contrib/unbound/doc/unbound-control.8.in
index 44e73c93dfd5..e747ec47e25a 100644
--- a/contrib/unbound/doc/unbound-control.8.in
+++ b/contrib/unbound/doc/unbound-control.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-control" "8" "Nov  8, 2023" "NLnet Labs" "unbound 1.19.0"
+.TH "unbound-control" "8" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1"
 .\"
 .\" unbound-control.8 -- unbound remote control manual
 .\"
diff --git a/contrib/unbound/doc/unbound-host.1.in 
b/contrib/unbound/doc/unbound-host.1.in
index 36f22ee9b6d1..9c9e9e2bf4a0 100644
--- a/contrib/unbound/doc/unbound-host.1.in
+++ b/contrib/unbound/doc/unbound-host.1.in
@@ -1,4 +1,4 @@
-.TH "unbound\-host" "1" "Nov  8, 2023" "NLnet Labs" "unbound 1.19.0"
+.TH "unbound\-host" "1" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1"
 .\"
 .\" unbound-host.1 -- unbound DNS lookup utility
 .\"
diff --git a/contrib/unbound/doc/unbound.8.in b/contrib/unbound/doc/unbound.8.in
index 3d56b7bfa190..4967a22d328c 100644
--- a/contrib/unbound/doc/unbound.8.in
+++ b/contrib/unbound/doc/unbound.8.in
@@ -1,4 +1,4 @@
-.TH "unbound" "8" "Nov  8, 2023" "NLnet Labs" "unbound 1.19.0"
+.TH "unbound" "8" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1"
 .\"
 .\" unbound.8 -- unbound manual
 .\"
@@ -9,7 +9,7 @@
 .\"
 .SH "NAME"
 .B unbound
-\- Unbound DNS validating resolver 1.19.0.
+\- Unbound DNS validating resolver 1.19.1.
 .SH "SYNOPSIS"
 .B unbound
 .RB [ \-h ]
diff --git a/contrib/unbound/doc/unbound.conf.5.in 
b/contrib/unbound/doc/unbound.conf.5.in
index ac8fa7953f3c..79ca04904c96 100644
--- a/contrib/unbound/doc/unbound.conf.5.in
+++ b/contrib/unbound/doc/unbound.conf.5.in
@@ -1,4 +1,4 @@
-.TH "unbound.conf" "5" "Nov  8, 2023" "NLnet Labs" "unbound 1.19.0"
+.TH "unbound.conf" "5" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1"
 .\"
 .\" unbound.conf.5 -- unbound.conf manual
 .\"
diff --git a/contrib/unbound/services/authzone.c 
b/contrib/unbound/services/authzone.c
index 87844870a25a..761bcc6d9a75 100644
--- a/contrib/unbound/services/authzone.c
+++ b/contrib/unbound/services/authzone.c
@@ -7774,6 +7774,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
        enum sec_status sec;
        struct val_env* ve;
        int m;
+       int verified = 0;
        m = modstack_find(mods, "validator");
        if(m == -1) {
                auth_zone_log(z->name, VERB_ALGO, "zonemd dnssec verify: have "
@@ -7797,7 +7798,7 @@ 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);
+               LDNS_SECTION_ANSWER, NULL, &verified);
        if(sec == sec_status_secure) {
                return 1;
        }
diff --git a/contrib/unbound/services/cache/dns.c 
b/contrib/unbound/services/cache/dns.c
index 9b4ad5888721..7bc1b7b47bf1 100644
--- a/contrib/unbound/services/cache/dns.c
+++ b/contrib/unbound/services/cache/dns.c
@@ -690,6 +690,28 @@ tomsg(struct module_env* env, struct query_info* q, struct 
reply_info* r,
        return msg;
 }
 
+struct dns_msg*
+dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region)
+{
+       size_t i;
+       struct dns_msg* res = NULL;
+       res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count);
+       if(!res) return NULL;
+       *res->rep = *origin->rep;
+       if(origin->rep->reason_bogus_str) {
+               res->rep->reason_bogus_str = regional_strdup(region,
+                       origin->rep->reason_bogus_str);
+       }
+       for(i=0; i<res->rep->rrset_count; i++) {
+               res->rep->rrsets[i] = packed_rrset_copy_region(
+                       origin->rep->rrsets[i], region, 0);
+               if(!res->rep->rrsets[i]) {
+                       return NULL;
+               }
+       }
+       return res;
+}
+
 /** synthesize RRset-only response from cached RRset item */
 static struct dns_msg*
 rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region, 
diff --git a/contrib/unbound/services/cache/dns.h 
b/contrib/unbound/services/cache/dns.h
index 147f992cbc74..c2bf23c6de54 100644
--- a/contrib/unbound/services/cache/dns.h
+++ b/contrib/unbound/services/cache/dns.h
@@ -164,6 +164,15 @@ struct dns_msg* tomsg(struct module_env* env, struct 
query_info* q,
        struct reply_info* r, struct regional* region, time_t now,
        int allow_expired, struct regional* scratch);
 
+/**
+ * Deep copy a dns_msg to a region.
+ * @param origin: the dns_msg to copy.
+ * @param region: the region to copy all the data to.
+ * @return the new dns_msg or NULL on malloc error.
+ */
+struct dns_msg* dns_msg_deepcopy_region(struct dns_msg* origin,
+       struct regional* region);
+
 /** 
  * Find cached message 
  * @param env: module environment with the DNS cache.
diff --git a/contrib/unbound/testdata/val_any_negcache.rpl 
b/contrib/unbound/testdata/val_any_negcache.rpl
index 77aacba8cc13..8800a2140219 100644
--- a/contrib/unbound/testdata/val_any_negcache.rpl
+++ b/contrib/unbound/testdata/val_any_negcache.rpl
@@ -199,6 +199,9 @@ SECTION QUESTION
 example.com. IN ANY
 ENTRY_END
 
+; Allow validation resuming for the RRSIGs
+STEP 21 TIME_PASSES ELAPSE 0.05
+
 ; recursion happens here.
 STEP 30 CHECK_ANSWER
 ENTRY_BEGIN
diff --git a/contrib/unbound/util/fptr_wlist.c 
b/contrib/unbound/util/fptr_wlist.c
index 43d38dc3797d..a792a3429549 100644
--- a/contrib/unbound/util/fptr_wlist.c
+++ b/contrib/unbound/util/fptr_wlist.c
@@ -131,6 +131,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
        else if(fptr == &pending_udp_timer_delay_cb) return 1;
        else if(fptr == &worker_stat_timer_cb) return 1;
        else if(fptr == &worker_probe_timer_cb) return 1;
+       else if(fptr == &validate_suspend_timer_cb) return 1;
 #ifdef UB_ON_WINDOWS
        else if(fptr == &wsvc_cron_cb) return 1;
 #endif
diff --git a/contrib/unbound/validator/val_nsec.c 
b/contrib/unbound/validator/val_nsec.c
index 17c90d83f594..d0cc67ff5d0b 100644
--- a/contrib/unbound/validator/val_nsec.c
+++ b/contrib/unbound/validator/val_nsec.c
@@ -181,6 +181,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* 
ve,
 {
        struct packed_rrset_data* d = (struct packed_rrset_data*)
                nsec->entry.data;
+       int verified = 0;
        if(!d) return 0;
        if(d->security == sec_status_secure)
                return 1;
@@ -188,7 +189,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);
+               reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified);
        if(d->security == sec_status_secure) {
                rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
                return 1;
diff --git a/contrib/unbound/validator/val_nsec3.c 
b/contrib/unbound/validator/val_nsec3.c
index a2b3794f6019..95d1e4d7e4fe 100644
--- a/contrib/unbound/validator/val_nsec3.c
+++ b/contrib/unbound/validator/val_nsec3.c
@@ -57,6 +57,19 @@
 /* we include nsec.h for the bitmap_has_type function */
 #include "validator/val_nsec.h"
 #include "sldns/sbuffer.h"
+#include "util/config_file.h"
+
+/**
+ * Max number of NSEC3 calculations at once, suspend query for later.
+ * 8 is low enough and allows for cases where multiple proofs are needed.
+ */
+#define MAX_NSEC3_CALCULATIONS 8
+/**
+ * When all allowed NSEC3 calculations at once resulted in error treat as
+ * bogus. NSEC3 hash errors are not cached and this helps breaks loops with
+ * erroneous data.
+ */
+#define MAX_NSEC3_ERRORS -1
 
 /** 
  * This function we get from ldns-compat or from base system 
@@ -532,6 +545,17 @@ nsec3_hash_cmp(const void* c1, const void* c2)
        return memcmp(s1, s2, s1len);
 }
 
+int
+nsec3_cache_table_init(struct nsec3_cache_table* ct, struct regional* region)
+{
+       if(ct->ct) return 1;
+       ct->ct = (rbtree_type*)regional_alloc(region, sizeof(*ct->ct));
+       if(!ct->ct) return 0;
+       ct->region = region;
+       rbtree_init(ct->ct, &nsec3_hash_cmp);
+       return 1;
+}
+
 size_t
 nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, 
        size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max)
@@ -646,7 +670,7 @@ nsec3_hash_name(rbtree_type* table, struct regional* 
region, sldns_buffer* buf,
        c = (struct nsec3_cached_hash*)rbtree_search(table, &looki);
        if(c) {
                *hash = c;
-               return 1;
+               return 2;
        }
        /* create a new entry */
        c = (struct nsec3_cached_hash*)regional_alloc(region, sizeof(*c));
@@ -658,10 +682,10 @@ nsec3_hash_name(rbtree_type* table, struct regional* 
region, sldns_buffer* buf,
        c->dname_len = dname_len;
        r = nsec3_calc_hash(region, buf, c);
        if(r != 1)
-               return r;
+               return r;  /* returns -1 or 0 */
        r = nsec3_calc_b32(region, buf, c);
        if(r != 1)
-               return r;
+               return r;  /* returns 0 */
 #ifdef UNBOUND_DEBUG
        n =
 #else
@@ -704,6 +728,7 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt,
        struct nsec3_cached_hash* hash, struct ub_packed_rrset_key* s)
 {
        uint8_t* nm = s->rk.dname;
+       if(!hash) return 0; /* please clang */
        /* compare, does hash of name based on params in this NSEC3
         * match the owner name of this NSEC3? 
         * name must be: <hashlength>base32 . zone name 
@@ -730,34 +755,50 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt,
  * @param nmlen: length of name.
  * @param rrset: nsec3 that matches is returned here.
  * @param rr: rr number in nsec3 rrset that matches.
+ * @param calculations: current hash calculations.
  * @return true if a matching NSEC3 is found, false if not.
  */
 static int
 find_matching_nsec3(struct module_env* env, struct nsec3_filter* flt,
-       rbtree_type* ct, uint8_t* nm, size_t nmlen, 
-       struct ub_packed_rrset_key** rrset, int* rr)
+       struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen,
+       struct ub_packed_rrset_key** rrset, int* rr,
+       int* calculations)
 {
        size_t i_rs;
        int i_rr;
        struct ub_packed_rrset_key* s;
        struct nsec3_cached_hash* hash = NULL;
        int r;
+       int calc_errors = 0;
 
        /* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */
        for(s=filter_first(flt, &i_rs, &i_rr); s; 
                s=filter_next(flt, &i_rs, &i_rr)) {
+               /* check if we are allowed more calculations */
+               if(*calculations >= MAX_NSEC3_CALCULATIONS) {
+                       if(calc_errors == *calculations) {
+                               *calculations = MAX_NSEC3_ERRORS;
+                       }
+                       break;
+               }
                /* get name hashed for this NSEC3 RR */
-               r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer,
+               r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer,
                        s, i_rr, nm, nmlen, &hash);
                if(r == 0) {
                        log_err("nsec3: malloc failure");
                        break; /* alloc failure */
-               } else if(r != 1)
-                       continue; /* malformed NSEC3 */
-               else if(nsec3_hash_matches_owner(flt, hash, s)) {
-                       *rrset = s; /* rrset with this name */
-                       *rr = i_rr; /* matches hash with these parameters */
-                       return 1;
+               } else if(r < 0) {
+                       /* malformed NSEC3 */
+                       calc_errors++;
+                       (*calculations)++;
+                       continue;
+               } else {
+                       if(r == 1) (*calculations)++;
+                       if(nsec3_hash_matches_owner(flt, hash, s)) {
+                               *rrset = s; /* rrset with this name */
+                               *rr = i_rr; /* matches hash with these 
parameters */
+                               return 1;
+                       }
                }
        }
        *rrset = NULL;
@@ -775,6 +816,7 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
        if(!nsec3_get_nextowner(rrset, rr, &next, &nextlen))
                return 0; /* malformed RR proves nothing */
 
+       if(!hash) return 0; /* please clang */
        /* check the owner name is a hashed value . apex
         * base32 encoded values must have equal length. 
         * hash_value and next hash value must have equal length. */
@@ -823,35 +865,51 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* 
hash,
  * @param nmlen: length of name.
  * @param rrset: covering NSEC3 rrset is returned here.
  * @param rr: rr of cover is returned here.
+ * @param calculations: current hash calculations.
  * @return true if a covering NSEC3 is found, false if not.
  */
 static int
 find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt,
-        rbtree_type* ct, uint8_t* nm, size_t nmlen, 
-       struct ub_packed_rrset_key** rrset, int* rr)
+       struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen,
+       struct ub_packed_rrset_key** rrset, int* rr,
+       int* calculations)
 {
        size_t i_rs;
        int i_rr;
        struct ub_packed_rrset_key* s;
        struct nsec3_cached_hash* hash = NULL;
        int r;
+       int calc_errors = 0;
 
        /* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */
        for(s=filter_first(flt, &i_rs, &i_rr); s; 
                s=filter_next(flt, &i_rs, &i_rr)) {
+               /* check if we are allowed more calculations */
+               if(*calculations >= MAX_NSEC3_CALCULATIONS) {
+                       if(calc_errors == *calculations) {
+                               *calculations = MAX_NSEC3_ERRORS;
+                       }
+                       break;
+               }
                /* get name hashed for this NSEC3 RR */
-               r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer,
+               r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer,
                        s, i_rr, nm, nmlen, &hash);
                if(r == 0) {
                        log_err("nsec3: malloc failure");
                        break; /* alloc failure */
-               } else if(r != 1)
-                       continue; /* malformed NSEC3 */
-               else if(nsec3_covers(flt->zone, hash, s, i_rr, 
-                       env->scratch_buffer)) {
-                       *rrset = s; /* rrset with this name */
-                       *rr = i_rr; /* covers hash with these parameters */
-                       return 1;
+               } else if(r < 0) {
+                       /* malformed NSEC3 */
+                       calc_errors++;
+                       (*calculations)++;
+                       continue;
+               } else {
+                       if(r == 1) (*calculations)++;
+                       if(nsec3_covers(flt->zone, hash, s, i_rr,
+                               env->scratch_buffer)) {
+                               *rrset = s; /* rrset with this name */
+                               *rr = i_rr; /* covers hash with these 
parameters */
+                               return 1;
+                       }
                }
        }
        *rrset = NULL;
@@ -869,11 +927,13 @@ find_covering_nsec3(struct module_env* env, struct 
nsec3_filter* flt,
  * @param ct: cached hashes table.
  * @param qinfo: query that is verified for.
  * @param ce: closest encloser information is returned in here.
+ * @param calculations: current hash calculations.
  * @return true if a closest encloser candidate is found, false if not.
  */
 static int
-nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt, 
-       rbtree_type* ct, struct query_info* qinfo, struct ce_response* ce)
+nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
+       struct nsec3_cache_table* ct, struct query_info* qinfo,
+       struct ce_response* ce, int* calculations)
 {
        uint8_t* nm = qinfo->qname;
        size_t nmlen = qinfo->qname_len;
@@ -888,8 +948,12 @@ nsec3_find_closest_encloser(struct module_env* env, struct 
nsec3_filter* flt,
         * may be the case. */
 
        while(dname_subdomain_c(nm, flt->zone)) {
+               if(*calculations >= MAX_NSEC3_CALCULATIONS ||
+                       *calculations == MAX_NSEC3_ERRORS) {
+                       return 0;
+               }
                if(find_matching_nsec3(env, flt, ct, nm, nmlen, 
-                       &ce->ce_rrset, &ce->ce_rr)) {
+                       &ce->ce_rrset, &ce->ce_rr, calculations)) {
                        ce->ce = nm;
                        ce->ce_len = nmlen;
                        return 1;
@@ -933,22 +997,38 @@ next_closer(uint8_t* qname, size_t qnamelen, uint8_t* ce,
  *     If set true, and the return value is true, then you can be 
  *     certain that the ce.nc_rrset and ce.nc_rr are set properly.
  * @param ce: closest encloser information is returned in here.
+ * @param calculations: pointer to the current NSEC3 hash calculations.
  * @return bogus if no closest encloser could be proven.
  *     secure if a closest encloser could be proven, ce is set.
  *     insecure if the closest-encloser candidate turns out to prove
  *             that an insecure delegation exists above the qname.
+ *     unchecked if no more hash calculations are allowed at this point.
  */
 static enum sec_status
-nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, 
-       rbtree_type* ct, struct query_info* qinfo, int prove_does_not_exist,
-       struct ce_response* ce)
+nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
+       struct nsec3_cache_table* ct, struct query_info* qinfo,
+       int prove_does_not_exist, struct ce_response* ce, int* calculations)
 {
        uint8_t* nc;
        size_t nc_len;
        /* robust: clean out ce, in case it gets abused later */
        memset(ce, 0, sizeof(*ce));
 
-       if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce)) {
+       if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce, calculations)) 
{
+               if(*calculations == MAX_NSEC3_ERRORS) {
+                       verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
+                               "not find a candidate for the closest "
+                               "encloser; all attempted hash calculations "
+                               "were erroneous; bogus");
+                       return sec_status_bogus;
+               } else if(*calculations >= MAX_NSEC3_CALCULATIONS) {
+                       verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
+                               "not find a candidate for the closest "
+                               "encloser; reached MAX_NSEC3_CALCULATIONS "
+                               "(%d); unchecked still",
+                               MAX_NSEC3_CALCULATIONS);
+                       return sec_status_unchecked;
+               }
                verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
                        "not find a candidate for the closest encloser.");
                return sec_status_bogus;
@@ -989,9 +1069,23 @@ nsec3_prove_closest_encloser(struct module_env* env, 
struct nsec3_filter* flt,
        /* Otherwise, we need to show that the next closer name is covered. */
        next_closer(qinfo->qname, qinfo->qname_len, ce->ce, &nc, &nc_len);
        if(!find_covering_nsec3(env, flt, ct, nc, nc_len, 
-               &ce->nc_rrset, &ce->nc_rr)) {
+               &ce->nc_rrset, &ce->nc_rr, calculations)) {
+               if(*calculations == MAX_NSEC3_ERRORS) {
+                       verbose(VERB_ALGO, "nsec3: Could not find proof that 
the "
+                               "candidate encloser was the closest encloser; "
+                               "all attempted hash calculations were "
+                               "erroneous; bogus");
+                       return sec_status_bogus;
+               } else if(*calculations >= MAX_NSEC3_CALCULATIONS) {
+                       verbose(VERB_ALGO, "nsec3: Could not find proof that 
the "
+                               "candidate encloser was the closest encloser; "
+                               "reached MAX_NSEC3_CALCULATIONS (%d); "
+                               "unchecked still",
+                               MAX_NSEC3_CALCULATIONS);
+                       return sec_status_unchecked;
+               }
                verbose(VERB_ALGO, "nsec3: Could not find proof that the "
-                         "candidate encloser was the closest encloser");
+                       "candidate encloser was the closest encloser");
                return sec_status_bogus;
        }
        return sec_status_secure;
@@ -1019,8 +1113,8 @@ nsec3_ce_wildcard(struct regional* region, uint8_t* ce, 
size_t celen,
 
 /** Do the name error proof */
 static enum sec_status
-nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, 
-       rbtree_type* ct, struct query_info* qinfo)
+nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
+       struct nsec3_cache_table* ct, struct query_info* qinfo, int* calc)
 {
        struct ce_response ce;
        uint8_t* wc;
@@ -1032,11 +1126,15 @@ nsec3_do_prove_nameerror(struct module_env* env, struct 
nsec3_filter* flt,
        /* First locate and prove the closest encloser to qname. We will 
         * use the variant that fails if the closest encloser turns out 
         * to be qname. */
-       sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce);
+       sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce, calc);
        if(sec != sec_status_secure) {
                if(sec == sec_status_bogus)
                        verbose(VERB_ALGO, "nsec3 nameerror proof: failed "
                                "to prove a closest encloser");
+               else if(sec == sec_status_unchecked)
+                       verbose(VERB_ALGO, "nsec3 nameerror proof: will "
+                               "continue proving closest encloser after "
+                               "suspend");
                else    verbose(VERB_ALGO, "nsec3 nameerror proof: closest "
                                "nsec3 is an insecure delegation");
                return sec;
@@ -1046,9 +1144,27 @@ nsec3_do_prove_nameerror(struct module_env* env, struct 
nsec3_filter* flt,
        /* At this point, we know that qname does not exist. Now we need 
         * to prove that the wildcard does not exist. */
        log_assert(ce.ce);
-       wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen);
-       if(!wc || !find_covering_nsec3(env, flt, ct, wc, wclen, 
-               &wc_rrset, &wc_rr)) {
+       wc = nsec3_ce_wildcard(ct->region, ce.ce, ce.ce_len, &wclen);
+       if(!wc) {
+               verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
+                       "that the applicable wildcard did not exist.");
+               return sec_status_bogus;
+       }
+       if(!find_covering_nsec3(env, flt, ct, wc, wclen, &wc_rrset, &wc_rr, 
calc)) {
+               if(*calc == MAX_NSEC3_ERRORS) {
+                       verbose(VERB_ALGO, "nsec3 nameerror proof: could not 
prove "
+                               "that the applicable wildcard did not exist; "
+                               "all attempted hash calculations were "
+                               "erroneous; bogus");
+                       return sec_status_bogus;
+               } else if(*calc >= MAX_NSEC3_CALCULATIONS) {
+                       verbose(VERB_ALGO, "nsec3 nameerror proof: could not 
prove "
+                               "that the applicable wildcard did not exist; "
+                               "reached MAX_NSEC3_CALCULATIONS (%d); "
+                               "unchecked still",
+                               MAX_NSEC3_CALCULATIONS);
+                       return sec_status_unchecked;
+               }
                verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
                        "that the applicable wildcard did not exist.");
                return sec_status_bogus;
@@ -1064,14 +1180,13 @@ nsec3_do_prove_nameerror(struct module_env* env, struct 
nsec3_filter* flt,
 enum sec_status
 nsec3_prove_nameerror(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)
+       struct query_info* qinfo, struct key_entry_key* kkey,
+       struct nsec3_cache_table* ct, int* calc)
 {
-       rbtree_type ct;
        struct nsec3_filter flt;
 
        if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
                return sec_status_bogus; /* no valid NSEC3s, bogus */
-       rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
        filter_init(&flt, list, num, qinfo); /* init RR iterator */
        if(!flt.zone)
                return sec_status_bogus; /* no RRs */
@@ -1079,7 +1194,7 @@ nsec3_prove_nameerror(struct module_env* env, struct 
val_env* ve,
                return sec_status_insecure; /* iteration count too high */
        log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone", 
                flt.zone, 0, 0);
-       return nsec3_do_prove_nameerror(env, &flt, &ct, qinfo);
+       return nsec3_do_prove_nameerror(env, &flt, ct, qinfo, calc);
 }
 
 /* 
@@ -1089,8 +1204,9 @@ nsec3_prove_nameerror(struct module_env* env, struct 
val_env* ve,
 
 /** Do the nodata proof */
 static enum sec_status
-nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, 
-       rbtree_type* ct, struct query_info* qinfo)
+nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
+       struct nsec3_cache_table* ct, struct query_info* qinfo,
+       int* calc)
 {
        struct ce_response ce;
        uint8_t* wc;
@@ -1100,7 +1216,7 @@ nsec3_do_prove_nodata(struct module_env* env, struct 
nsec3_filter* flt,
        enum sec_status sec;
 
        if(find_matching_nsec3(env, flt, ct, qinfo->qname, qinfo->qname_len, 
-               &rrset, &rr)) {
+               &rrset, &rr, calc)) {
                /* cases 1 and 2 */
                if(nsec3_has_type(rrset, rr, qinfo->qtype)) {
                        verbose(VERB_ALGO, "proveNodata: Matching NSEC3 "
@@ -1144,11 +1260,23 @@ nsec3_do_prove_nodata(struct module_env* env, struct 
nsec3_filter* flt,
                }
                return sec_status_secure;
        }
+       if(*calc == MAX_NSEC3_ERRORS) {
+               verbose(VERB_ALGO, "proveNodata: all attempted hash "
+                       "calculations were erroneous while finding a matching "
+                       "NSEC3, bogus");
+               return sec_status_bogus;
+       } else if(*calc >= MAX_NSEC3_CALCULATIONS) {
+               verbose(VERB_ALGO, "proveNodata: reached "
*** 1724 LINES SKIPPED ***

Reply via email to